1 /*
2  * Copyright (c) 2004,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 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <stdint.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17 
18 #include <bzlib.h>
19 #include <zlib.h>
20 #include <lzma.h>
21 
22 #include "util.h"
23 #include "md5.h"
24 #include "sha256.h"
25 #include "rpmhead.h"
26 #include "cpio.h"
27 #include "cfile.h"
28 #include "deltarpm.h"
29 #include "prelink.h"
30 
31 #define BLKSHIFT 13
32 #define BLKSIZE  (1 << BLKSHIFT)
33 #define BLKMASK  ((1 << BLKSHIFT) - 1)
34 
35 #define SEQCHECK_MD5   (1<<0)
36 #define SEQCHECK_SIZE  (1<<1)
37 
38 #ifndef RPMDUMPHEADER
39 # define RPMDUMPHEADER "rpmdumpheader"
40 #endif
41 
42 
43 /*****************************************************************
44  * openfile, maintain a set of opened files, close descriptors if
45  * limit is reached.
46  */
47 
48 struct openfile {
49   struct openfile *prev;
50   struct openfile *next;
51   char *name;
52   int fd;
53   unsigned int off;
54   struct seqdescr *sd;
55 };
56 
57 struct openfile *openfiles;
58 struct openfile *openfilestail;
59 int nopenfile;
60 int maxopenfile = 50;
61 
62 
63 
64 struct openfile *
newopen(struct seqdescr * sd,struct fileblock * fb)65 newopen(struct seqdescr *sd, struct fileblock *fb)
66 {
67   int fd;
68   char *name;
69   struct openfile *of;
70   struct stat stb;
71 
72   name = fb->filenames[sd->i];
73   if ((fd = open(name, O_RDONLY)) == -1)
74     {
75       perror(name);
76       fprintf(stderr, "cannot reconstruct rpm from disk files\n");
77       exit(1);
78     }
79   if (fstat(fd, &stb) == 0 && stb.st_size != fb->filesizes[sd->i])
80     {
81       unsigned char buf[128];
82       if (is_prelinked(fd, buf, pread(fd, buf, 128, (off_t)0)))
83 	{
84 	  close(fd);
85 	  return 0;
86 	}
87     }
88   if (nopenfile < maxopenfile)
89     {
90       of = xmalloc(sizeof(*of));
91       nopenfile++;
92     }
93   else
94     {
95       of = openfiles;
96       openfiles = of->next;
97       if (openfiles)
98 	openfiles->prev = 0;
99       else
100 	openfilestail = 0;
101       of->sd->f = 0;
102       // printf("closing %s\n", of->name);
103       close(of->fd);
104     }
105   // printf("opening %s\n", name);
106   of->fd = fd;
107   of->name = name;
108   of->off = 0;
109   of->sd = sd;
110   of->prev = of->next = 0;
111   if (openfilestail)
112     {
113       openfilestail->next = of;
114       of->prev = openfilestail;
115       openfilestail = of;
116     }
117   else
118     openfiles = openfilestail = of;
119   sd->f = of;
120   return of;
121 }
122 
123 /*****************************************************************
124  * blk stuff, block contents creation and paging
125  */
126 
127 #define BLK_FREE     0
128 #define BLK_CORE_REC 1
129 #define BLK_CORE_ONE 2
130 #define BLK_PAGE     3
131 
132 struct blk {
133   struct blk *next;
134   int type;
135   int id;
136   union {
137     unsigned int off;
138     unsigned char *buf;
139   } e;
140 };
141 
142 struct blk *coreblks;
143 struct blk *freecoreblks;
144 struct blk *pageblks;
145 int ncoreblk = 0;
146 int npageblk = 0;
147 int ndropblk = 0;
148 
149 int maxcoreblk = 5000;
150 
151 unsigned int *maxblockuse;	/* last time the block will be used */
152 struct blk **vmem;
153 
154 unsigned char *cpiodata;
155 int csdesc = -1;
156 char *symdata;
157 
158 char *fromrpm;
159 int fromrpm_raw;
160 struct cfile *outfp;
161 unsigned int outfpleft;
162 drpmuint outfpleft_raw;
163 int outfpid;
164 
165 
166 int pagefd = -1;
167 
168 
169 void (*fillblock_method)(struct blk *b, int id, struct seqdescr *sdesc, int nsdesc, struct fileblock *fb, int idx);
170 
171 void
pageoutblock(struct blk * cb,int idx)172 pageoutblock(struct blk *cb, int idx)
173 {
174   struct blk *b;
175 
176   // printf("pageoutblock %d\n", cb->id);
177   for (b = pageblks; b; b = b->next)
178     if (b->id == cb->id)
179       {
180         vmem[b->id] = b;
181         return;
182       }
183   for (b = pageblks; b; b = b->next)
184     if (maxblockuse[b->id] < idx)
185       break;
186   if (!b)
187     {
188       b = xmalloc(sizeof(*b));
189       b->next = pageblks;
190       b->type = BLK_PAGE;
191       b->e.off = npageblk;
192       pageblks = b;
193       npageblk++;
194       if (pagefd < 0)
195 	{
196 	  char tmpname[80];
197 	  sprintf(tmpname, "/tmp/deltarpmpageXXXXXX");
198 #ifdef DELTARPM_64BIT
199 	  pagefd = mkstemp(tmpname);
200 #else
201 	  pagefd = mkstemp(tmpname);
202 #endif
203 	  if (pagefd < 0)
204 	    {
205 	      fprintf(stderr, "could not create page area\n");
206 	      exit(1);
207 	    }
208 	  unlink(tmpname);
209 	}
210     }
211   b->id = cb->id;
212 #ifdef DELTARPM_64BIT
213   if (pwrite(pagefd, cb->e.buf, BLKSIZE, (off_t)b->e.off * BLKSIZE) != BLKSIZE)
214     {
215       perror("page area write");
216       exit(1);
217     }
218 #else
219   if (pwrite(pagefd, cb->e.buf, BLKSIZE, (off_t)b->e.off * BLKSIZE) != BLKSIZE)
220     {
221       perror("page area write");
222       exit(1);
223     }
224 #endif
225   vmem[b->id] = b;
226 }
227 
228 void
pageinblock(struct blk * cb,struct blk * b)229 pageinblock(struct blk *cb, struct blk *b)
230 {
231   if (b->type != BLK_PAGE)
232     abort();
233 #ifdef DELTARPM_64BIT
234   if (pread(pagefd, cb->e.buf, BLKSIZE, (off_t)b->e.off * BLKSIZE) != BLKSIZE)
235     {
236       perror("page area read");
237       exit(1);
238     }
239 #else
240   if (pread(pagefd, cb->e.buf, BLKSIZE, (off_t)b->e.off * BLKSIZE) != BLKSIZE)
241     {
242       perror("page area read");
243       exit(1);
244     }
245 #endif
246   cb->id = b->id;
247   cb->type = BLK_CORE_ONE;
248   vmem[cb->id] = cb;
249 }
250 
251 struct blk *
newcoreblk(void)252 newcoreblk(void)
253 {
254   struct blk *b;
255   b = xmalloc(sizeof(*b) + BLKSIZE);
256   b->next = coreblks;
257   b->type = BLK_FREE;
258   b->e.buf = (unsigned char *)(b + 1);
259   coreblks = b;
260   ncoreblk++;
261   // printf("created new coreblk, have now %d\n", ncoreblk);
262   return b;
263 }
264 
265 void
pushblock(struct blk * nb,int idx)266 pushblock(struct blk *nb, int idx)
267 {
268   struct blk *b;
269 
270   b = freecoreblks;
271   if (b)
272     {
273       freecoreblks = b->next;
274       b->next = coreblks;
275       coreblks = b;
276     }
277   if (!b && ncoreblk < maxcoreblk)
278     b = newcoreblk();
279   if (!b)
280     {
281       /* could not find in-core place */
282       if (nb->type == BLK_CORE_ONE)
283         pageoutblock(nb, idx);
284       else
285 	vmem[nb->id] = 0;
286       return;
287     }
288   b->type = nb->type;
289   b->id = nb->id;
290   memcpy(b->e.buf, nb->e.buf, BLKSIZE);
291   vmem[b->id] = b;
292 }
293 
294 void
createcpiohead(struct seqdescr * sd,struct fileblock * fb)295 createcpiohead(struct seqdescr *sd, struct fileblock *fb)
296 {
297   int i = sd->i;
298   unsigned int lsize, rdev;
299   char *np;
300 
301   if (i == -1)
302     {
303       sprintf((char *)cpiodata, "%s%c%c%c%c", "07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000b00000000TRAILER!!!", 0, 0, 0, 0);
304       return;
305     }
306   lsize = rdev = 0;
307   np = fb->filenames[i];
308   if (*np == '/')
309     np++;
310   if (S_ISREG(fb->filemodes[i]))
311     lsize = fb->filesizes[i];
312   else if (S_ISLNK(fb->filemodes[i]))
313     {
314       symdata = fb->filelinktos[i];
315       lsize = strlen(fb->filelinktos[i]);
316     }
317   if (S_ISBLK(fb->filemodes[i]) || S_ISCHR(fb->filemodes[i]))
318     rdev = fb->filerdevs[i];
319   sprintf((char *)cpiodata, "07070100000000%08x00000000000000000000000100000000%08x0000000000000000%08x%08x%08x00000000./%s%c%c%c%c", fb->filemodes[i], lsize, devmajor(rdev), devminor(rdev), (int)strlen(np) + 3, np, 0, 0, 0, 0);
320 }
321 
322 int nprelink = 0;
323 
324 void
fillblock_prelink(struct blk * b,int id,struct seqdescr * sd,struct fileblock * fb,int idx)325 fillblock_prelink(struct blk *b, int id, struct seqdescr *sd, struct fileblock *fb, int idx)
326 {
327   int xid = id;
328   drpmuint off;
329   struct stat stb;
330   char *name;
331   int fd = -1;
332   int isp = 0;
333   int l;
334   unsigned char buf[128];
335   unsigned char *bp, saveblk[BLKSIZE];
336 
337   /* go to first block that doesn't start in the middle of a
338    * prelinked file */
339   off = id << BLKSHIFT;
340   for (;;)
341     {
342       while (sd->off > off)
343         sd--;
344       /* now sd contains off */
345       if (sd->i == -1 || sd->datalen == 0 || sd->off + sd->cpiolen >= off)
346 	break;
347       if (S_ISLNK(fb->filemodes[sd->i]))
348 	break;
349       /* off in regular file, check if prelinked */
350       name = fb->filenames[sd->i];
351       if ((fd = open(name, O_RDONLY)) == -1)
352 	{
353 	  perror(name);
354 	  fprintf(stderr, "cannot reconstruct rpm from disk files\n");
355 	  exit(1);
356 	}
357       if (fstat(fd, &stb) != 0 || stb.st_size == fb->filesizes[sd->i])
358 	break;
359       if (!is_prelinked(fd, buf, pread(fd, buf, 128, (off_t)0)))
360 	break;
361       close(fd);
362       fd = -1;
363       /* rewind blocks until we leave the file */
364       do
365 	{
366 	  id--;
367 	  off = id << BLKSHIFT;
368 	}
369       while (sd->off + sd->cpiolen < off);
370     }
371   /* ok, got id, sd and maybe fd. create blocks. */
372   l = BLKSIZE;
373   bp = b->e.buf;
374   if (fd != -1)
375     {
376       unsigned int u = off - (sd->off + sd->cpiolen);
377       if (u && u < fb->filesizes[sd->i])
378 	{
379 	  if (lseek(fd, (off_t)u, SEEK_SET) == (off_t)-1)
380 	    {
381 	      fprintf(stderr, "%s: seek error\n", fb->filenames[sd->i]);
382 	      fprintf(stderr, "cannot reconstruct rpm from disk files\n");
383 	      exit(1);
384 	    }
385 	}
386     }
387   for (;;)
388     {
389       while (l)
390 	{
391 	  while (off >= sd->off + sd->cpiolen + sd->datalen)
392 	    {
393 	      if (fd != -1)
394 		{
395 		  close(fd);
396 		  fd = -1;
397 		}
398 	      sd++;
399 	    }
400 	  if (off < sd->off + sd->cpiolen)
401 	    {
402 	      int o = off - sd->off;
403 	      int l2 = l > sd->cpiolen - o ? sd->cpiolen - o : l;
404 	      createcpiohead(sd, fb);
405 	      memcpy(bp, cpiodata + o, l2);
406 	      bp += l2;
407 	      off += l2;
408 	      l -= l2;
409 	    }
410 	  if (!l)
411 	    break;
412 	  if (sd->i == -1)
413 	    {
414 	      memset(bp, 0, l);
415 	      bp += l;
416 	      off += l;
417 	      l -= l;
418 	    }
419 	  else if (S_ISLNK(fb->filemodes[sd->i]))
420 	    {
421 	      int o = off - (sd->off + sd->cpiolen);
422 	      char *ln = fb->filelinktos[sd->i];
423 	      int l2 = strlen(ln) - o;
424 	      if (l2 < 0)
425 		l2 = 0;
426 	      if (l2 > l)
427 		l2 = l;
428 	      if (l2)
429 		memcpy(bp, ln + o, l2);
430 	      bp += l2;
431 	      off += l2;
432 	      l -= l2;
433 	      o += l2;
434 	      l2 = l > sd->datalen - o ? sd->datalen - o : l;
435 	      if (l2 > 0)
436 		{
437 		  memset(bp, 0, l2);
438 		  bp += l2;
439 		  off += l2;
440 		  l -= l2;
441 		}
442 	    }
443 	  else if (sd->datalen)
444 	    {
445 	      int o = off - (sd->off + sd->cpiolen);
446 	      int l2;
447 	      if (o < fb->filesizes[sd->i])
448 		{
449 		  l2 = l > fb->filesizes[sd->i] - o ? fb->filesizes[sd->i] - o : l;
450 		  if (fd == -1)
451 		    {
452 		      name = fb->filenames[sd->i];
453 		      isp = 0;
454 		      if ((fd = open(name, O_RDONLY)) == -1)
455 			perror(name);
456 		      else if (fstat(fd, &stb) == 0 && stb.st_size != fb->filesizes[sd->i] && is_prelinked(fd, buf, pread(fd, buf, 128, (off_t)0)))
457 			{
458 			  close(fd);
459 			  fd = prelinked_open(name);
460 			  nprelink++;
461 			  isp = 1;
462 			}
463 		      if (fd == -1)
464 			{
465 			  fprintf(stderr, "cannot reconstruct rpm from disk files\n");
466 			  exit(1);
467 			}
468 		    }
469 		  if (read(fd, bp, l2) != l2)
470 		    {
471 		      fprintf(stderr, "%s: read error\n", fb->filenames[sd->i]);
472 		      fprintf(stderr, "(tried to read %d bytes from offset %d\n", l2, o);
473 		      exit(1);
474 		    }
475 		  bp += l2;
476 		  off += l2;
477 		  l -= l2;
478 		  o += l2;
479 		}
480 	      if (o >= fb->filesizes[sd->i])
481 		{
482 		  if (fd)
483 		    {
484 		      close(fd);
485 		      fd = -1;
486 		    }
487 		  l2 = l > sd->datalen - o ? sd->datalen - o : l;
488 		  if (l2)
489 		    memset(bp, 0, l2);
490 		  bp += l2;
491 		  off += l2;
492 		  l -= l2;
493 		}
494 	    }
495 	}
496 
497       b->type = BLK_CORE_ONE;
498       b->id = id;
499       if (id == xid)
500 	memcpy(saveblk, b->e.buf, BLKSIZE);
501       else if (maxblockuse[b->id] > idx || (maxblockuse[b->id] == idx && id > xid))
502 	pushblock(b, idx);
503       /* finished block */
504       if (fd == -1 || !isp)
505 	break;
506       l = BLKSIZE;
507       bp = b->e.buf;
508       id++;
509       off = id << BLKSHIFT;
510     }
511   if (id < xid)
512     {
513       fprintf(stderr, "internal error, could not reach block %d (%d)\n", xid, id);
514       exit(1);
515     }
516   if (fd != -1)
517     close(fd);		/* never prelinked */
518   memcpy(b->e.buf, saveblk, BLKSIZE);
519   b->type = BLK_CORE_ONE;
520   b->id = xid;
521 }
522 
523 void
fillblock_disk(struct blk * b,int id,struct seqdescr * sdesc,int nsdesc,struct fileblock * fb,int idx)524 fillblock_disk(struct blk *b, int id, struct seqdescr *sdesc, int nsdesc, struct fileblock *fb, int idx)
525 {
526   drpmuint off;
527   unsigned int u;
528   struct seqdescr *sd;
529   int i;
530   unsigned int l, l2;
531   unsigned char *bp;
532 
533   l = BLKSIZE;
534   bp = b->e.buf;
535   off = id << BLKSHIFT;
536   i = csdesc >= 0 ? csdesc : 0;
537   for (sd = sdesc + i; i > 0 && sd->off > off; i--, sd--)
538     ;
539   for (; i < nsdesc; i++, sd++)
540     if (sd->off <= off && sd->off + sd->cpiolen + sd->datalen > off)
541       break;
542   if (i == nsdesc)
543     {
544       fprintf(stderr, "fillblock_disk: block %d out of range\n", id);
545       exit(1);
546     }
547   if (i != csdesc)
548     {
549       csdesc = i;
550       createcpiohead(sd, fb);
551     }
552   i = sd->i;
553   while (l > 0)
554     {
555       if (off < sd->off + sd->cpiolen)
556 	{
557 	  u = off - sd->off;
558 	  l2 = sd->cpiolen - u;
559 	  if (l2 > l)
560 	    l2 = l;
561 	  memcpy(bp, cpiodata + u, l2);
562 	  bp += l2;
563 	  off += l2;
564 	  l -= l2;
565 	  continue;
566 	}
567       if (i == -1)
568 	{
569 	  memset(bp, 0, l);
570 	  l = 0;
571 	  break;
572 	}
573       if (off < sd->off + sd->cpiolen + sd->datalen)
574 	{
575 	  u = off - (sd->off + sd->cpiolen);
576 	  if (S_ISLNK(fb->filemodes[i]))
577 	    {
578 	      l2 = sd->datalen - u;
579 	      if (l2 > l)
580 		l2 = l;
581 	      if (u > strlen(symdata))
582 		memset(bp, 0, l2);
583 	      else
584 		strncpy((char *)bp, symdata + u, l2);
585 	    }
586 	  else if (u < fb->filesizes[i])
587 	    {
588 	      struct openfile *of;
589 	      l2 = fb->filesizes[i] - u;
590 	      if (l2 > l)
591 		l2 = l;
592 	      if (!(of = sd->f))
593 		of = newopen(sd, fb);
594 	      if (!of)
595 		{
596 		  fillblock_prelink(b, id, sd, fb, idx);
597 		  csdesc = -1;
598 		  return;
599 		}
600 	      if (of->next)
601 		{
602 		  of->next->prev = of->prev;
603 		  if (of->prev)
604 		    of->prev->next = of->next;
605 		  else
606 		    openfiles = of->next;
607 		  of->next = 0;
608 		  of->prev = openfilestail;
609 		  openfilestail->next = of;
610 		  openfilestail = of;
611 		}
612 	      if (of->off != u)
613 		{
614 		  if (lseek(of->fd, (off_t)u, SEEK_SET) == (off_t)-1)
615 		    {
616 		      fprintf(stderr, "%s: seek error\n", of->name);
617 		      fprintf(stderr, "cannot reconstruct rpm from disk files\n");
618 		      exit(1);
619 		    }
620 		}
621 	      if (read(of->fd, bp, l2) != l2)
622 		{
623 		  fprintf(stderr, "%s: read error\n", of->name);
624 		  fprintf(stderr, "(tried to read %d bytes from offset %d)\n", l2, u);
625 		  fprintf(stderr, "cannot reconstruct rpm from disk files\n");
626 		  exit(1);
627 		}
628 	      of->off = u + l2;
629 	    }
630 	  else
631 	    {
632 	      l2 = sd->datalen - u;
633 	      if (l2 > l)
634 		l2 = l;
635 	      memset(bp, 0, l2);
636 	    }
637 	  bp += l2;
638 	  off += l2;
639 	  l -= l2;
640 	  continue;
641         }
642       csdesc++;
643       sd++;
644       createcpiohead(sd, fb);
645       i = sd->i;
646     }
647   b->id = id;
648   b->type = BLK_CORE_REC;
649 }
650 
651 void
fillblock_rawrpm(struct blk * b,int id,struct seqdescr * sdesc,int nsdesc,struct fileblock * fb,int idx)652 fillblock_rawrpm(struct blk *b, int id, struct seqdescr *sdesc, int nsdesc, struct fileblock *fb, int idx)
653 {
654   unsigned char *bp;
655   unsigned int l2;
656 
657   for (;;)
658     {
659       bp = b->e.buf;
660       l2 = outfpleft_raw > BLKSIZE ? BLKSIZE : outfpleft_raw;
661       if (outfp->read(outfp, bp, l2) != l2)
662 	{
663 	  fprintf(stderr, "read error");
664 	  exit(1);
665 	}
666       outfpleft_raw -= l2;
667       if (l2 < BLKSIZE)
668 	memset(bp + l2, 0, BLKSIZE - l2);
669       b->type = BLK_CORE_ONE;
670       b->id = outfpid++;
671       if (b->id == id)
672 	 return;
673       if (b->id > id)
674 	{
675 	  fprintf(stderr, "internal error, cannot rewind blocks (%d %d)\n", b->id, id);
676 	  exit(1);
677 	}
678       if (maxblockuse[b->id] > idx)
679 	pushblock(b, idx);
680     }
681 }
682 
683 void
fillblock_rpm(struct blk * b,int id,struct seqdescr * sdesc,int nsdesc,struct fileblock * fb,int idx)684 fillblock_rpm(struct blk *b, int id, struct seqdescr *sdesc, int nsdesc, struct fileblock *fb, int idx)
685 {
686   unsigned int size, nsize;
687   unsigned char *bp;
688   char *np;
689   int i;
690   unsigned int l, l2, u;
691   struct seqdescr *sd;
692   struct cpiophys cph;
693   static char *namebuf;
694   static int namebufl;
695   char skipbuf[4096];
696 
697   l = BLKSIZE;
698   bp = b->e.buf;
699   for (;;)
700     {
701       if (outfpleft)
702 	{
703 	  sd = sdesc + csdesc;
704 	  if (outfpleft > sd->datalen)
705 	    {
706 	      u = sd->cpiolen + sd->datalen - outfpleft;
707 	      l2 = sd->cpiolen - u;
708 	      if (l2 > l)
709 		l2 = l;
710 	      memcpy(bp, cpiodata + u, l2);
711 	      bp += l2;
712 	      outfpleft -= l2;
713 	      l -= l2;
714 	    }
715 	  if (l && outfpleft)
716 	    {
717 	      l2 = outfpleft;
718 	      if (l2 > l)
719 		l2 = l;
720 	      if (S_ISLNK(fb->filemodes[sd->i]))
721 		{
722 		  strncpy((char *)bp, symdata, l2);
723 		  if (strlen(symdata) < l2)
724 		    symdata += strlen(symdata);
725 		  else
726 		    symdata += l2;
727 		}
728 	      else
729 		{
730 		  if (outfp->read(outfp, bp, l2) != l2)
731 		    {
732 		      fprintf(stderr, "read error");
733 		      exit(1);
734 		    }
735 		}
736 	      bp += l2;
737 	      outfpleft -= l2;
738 	      l -= l2;
739 	    }
740 	}
741       if (l && csdesc >= 0 && sdesc[csdesc].i == -1)
742 	{
743 	  memset(bp, 0, l); /* blocks are empty after trailer */
744 	  l = 0;
745 	}
746       if (l == 0)
747 	{
748 	  b->type = BLK_CORE_ONE;
749 	  b->id = outfpid++;
750 	  if (b->id == id)
751 	     return;
752 	  if (b->id > id)
753 	    {
754 	      fprintf(stderr, "internal error, cannot rewind blocks (%d %d)\n", b->id, id);
755 	      exit(1);
756 	    }
757 	  if (maxblockuse[b->id] > idx)
758 	    pushblock(b, idx);
759 	  l = BLKSIZE;
760 	  bp = b->e.buf;
761 	  continue;
762 	}
763       csdesc++;
764       sd = sdesc + csdesc;
765       i = sd->i;
766       if (i == -1)
767 	{
768 	  createcpiohead(sd, fb);
769 	  outfpleft = sd->cpiolen + sd->datalen;
770 	  continue;
771 	}
772       for (;;)
773 	{
774 	  if (outfp->read(outfp, &cph, sizeof(cph)) != sizeof(cph))
775 	    {
776 	      fprintf(stderr, "read error");
777 	      exit(1);
778 	    }
779 	  if (memcmp(cph.magic, "070701", 6))
780 	    {
781 	      fprintf(stderr, "read error: bad cpio archive\n");
782 	      exit(1);
783 	    }
784 	  size = cpion(cph.filesize);
785 	  nsize = cpion(cph.namesize);
786 	  nsize += (4 - ((nsize + 2) & 3)) & 3;
787 	  if (nsize > namebufl)
788 	    {
789 	      namebuf = xrealloc(namebuf, nsize);
790 	      namebufl = nsize;
791 	    }
792 	  if (outfp->read(outfp, namebuf, nsize) != nsize)
793 	    {
794 	      fprintf(stderr, "read failed (name)\n");
795 	      exit(1);
796 	    }
797 	  namebuf[nsize - 1] = 0;
798 	  if (!strcmp(namebuf, "TRAILER!!!"))
799 	    {
800 	      fprintf(stderr, "cpio end reached, bad rpm\n");
801 	      exit(1);
802 	    }
803 	  np = namebuf;
804 	  if (*np == '.' && np[1] == '/')
805 	    np += 2;
806 	  if (!strcmp(fb->filenames[i][0] == '/' ? fb->filenames[i] + 1 : fb->filenames[i], np))
807 	    break;
808 	  if (size & 3)
809 	    size += 4 - (size & 3);
810 	  while (size > 0)
811 	    {
812 	      l2 = size > sizeof(skipbuf) ? sizeof(skipbuf) : size;
813 	      if (outfp->read(outfp, skipbuf, l2) != l2)
814 		{
815 		  fprintf(stderr, "read failed (name)\n");
816 		  exit(1);
817 		}
818 	      size -= l2;
819 	    }
820 	}
821       createcpiohead(sd, fb);
822       if (size & 3)
823 	size += 4 - (size & 3);
824       if (!S_ISREG(fb->filemodes[i]))
825 	{
826 	  while (size > 0)
827 	    {
828 	      l2 = size > sizeof(skipbuf) ? sizeof(skipbuf) : size;
829 	      if (outfp->read(outfp, skipbuf, l2) != l2)
830 		{
831 		  fprintf(stderr, "read failed (data skip)\n");
832 		  exit(1);
833 		}
834 	      size -= l2;
835 	    }
836 	}
837       else if (size != sd->datalen)
838 	{
839 	  fprintf(stderr, "cpio data size mismatch, bad rpm\n");
840 	  exit(1);
841 	}
842       outfpleft = sd->cpiolen + sd->datalen;
843     }
844 }
845 
846 
847 /* construct the block "id". Note that the tupel (idx, id) will
848  * only get bigger, so we use this to recycly no longer needed
849  * blocks */
850 
851 struct blk *
getblock(int id,struct seqdescr * sdesc,int nsdesc,struct fileblock * fb,int idx)852 getblock(int id, struct seqdescr *sdesc, int nsdesc, struct fileblock *fb, int idx)
853 {
854   struct blk *b, **bb;
855   struct blk *pb;
856   static int cleanup_cnt;
857 
858 // printf("%d %d %d\n", idx, id, maxblockuse[id]);
859   b = vmem[id];
860   if (b && (b->type == BLK_CORE_REC || b->type == BLK_CORE_ONE))
861     return b;
862 
863   b = freecoreblks;
864   if (b)
865     {
866       freecoreblks = b->next;
867       b->next = coreblks;
868       coreblks = b;
869     }
870 
871   if (!b && ncoreblk < maxcoreblk && (++cleanup_cnt & 7) != 0)
872     b = newcoreblk();
873 
874   if (!b)
875     {
876       for (bb = &coreblks; (b = *bb) != 0; bb = &b->next)
877 	{
878 	  if (maxblockuse[b->id] < idx || (maxblockuse[b->id] == idx && b->id < id))
879 	    {
880 	      *bb = b->next;
881 	      vmem[b->id] = 0;
882 	      b->type = BLK_FREE;
883 	      b->next = freecoreblks;
884 	      freecoreblks = b;
885 	    }
886 	  else
887 	    bb = &b->next;
888 	}
889       b = freecoreblks;
890       if (b)
891 	{
892 	  freecoreblks = b->next;
893 	  b->next = coreblks;
894 	  coreblks = b;
895 	}
896     }
897 
898   if (!b && ncoreblk < maxcoreblk)
899     b = newcoreblk();
900   if (!b)
901     {
902       /* use first created block */
903       for (bb = &coreblks; (b = *bb); bb = &b->next)
904 	if (b->next == 0)
905 	  break;
906       *bb = 0;
907       b->next = coreblks;
908       coreblks = b;
909       if (b->type == BLK_CORE_ONE)
910 	pageoutblock(b, idx);
911       else
912 	{
913 	  vmem[b->id] = 0;
914 	  ndropblk++;
915 	}
916       b->type = BLK_FREE;
917     }
918 
919   /* got destination block, now fill it with data */
920   pb = vmem[id];
921   if (pb && pb->type == BLK_PAGE)
922     {
923       pageinblock(b, pb);
924       return b;
925     }
926   fillblock_method(b, id, sdesc, nsdesc, fb, idx);
927   vmem[id] = b;
928   return b;
929 }
930 
931 int
cfile_write_uncomp(struct cfile * f,void * buf,int len)932 cfile_write_uncomp(struct cfile *f, void *buf, int len)
933 {
934   int l2;
935   if (!len)
936     return 0;
937   l2 = len > f->len ? f->len : len;
938   if (fwrite(buf, l2, 1, (FILE *)f->fp) != 1)
939     return -1;
940   if (l2 && f->ctxup)
941     f->ctxup(f->ctx, buf, l2);
942   f->len -= l2;
943   if (f->len)
944     return l2;
945   f = cfile_open(CFILE_OPEN_WR, CFILE_IO_REOPEN, f, f->comp, CFILE_LEN_UNLIMITED, f->ctxup, f->ctx);
946   if (!f)
947     {
948       fprintf(stderr, "payload re-open error\n");
949       exit(1);
950     }
951   if (f->write(f, buf + l2, len - l2) != len - l2)
952     return -1;
953   return len;
954 }
955 
956 typedef struct {
957   union {
958     MD5_CTX md5ctx;
959     SHA256_ctx sha256ctx;
960   } ctx;
961 } DIG_CTX;
962 
963 
964 static inline void
DIG_Init(DIG_CTX * ctx,int digestalgo)965 DIG_Init(DIG_CTX *ctx, int digestalgo)
966 {
967   if (digestalgo == 1)
968     rpmMD5Init(&ctx->ctx.md5ctx);
969   else if (digestalgo == 8)
970     SHA256_init(&ctx->ctx.sha256ctx);
971 }
972 
973 static inline void
DIG_Update(DIG_CTX * ctx,int digestalgo,unsigned char const * buf,unsigned len)974 DIG_Update(DIG_CTX *ctx, int digestalgo, unsigned char const *buf, unsigned len)
975 {
976   if (digestalgo == 1)
977     rpmMD5Update(&ctx->ctx.md5ctx, buf, len);
978   else if (digestalgo == 8)
979     SHA256_update(&ctx->ctx.sha256ctx, buf, len);
980 }
981 
982 static inline void
DIG_Final(DIG_CTX * ctx,int digestalgo,unsigned char * digest)983 DIG_Final(DIG_CTX *ctx, int digestalgo, unsigned char *digest)
984 {
985   if (digestalgo == 1)
986     rpmMD5Final(digest, &ctx->ctx.md5ctx);
987   else if (digestalgo == 8)
988     {
989       SHA256_final(&ctx->ctx.sha256ctx);
990       SHA256_digest(&ctx->ctx.sha256ctx, digest);
991     }
992   else
993     *digest = 0;
994 }
995 
996 static inline int
DIG_Len(int digestalgo)997 DIG_Len(int digestalgo)
998 {
999   if (digestalgo == 1)
1000     return 16;
1001   if (digestalgo == 8)
1002     return 32;
1003   return 0;
1004 }
1005 
1006 int
checkprelinked(char * name,int digestalgo,unsigned char * hmd5,unsigned int size)1007 checkprelinked(char *name, int digestalgo, unsigned char *hmd5, unsigned int size)
1008 {
1009   int fd, l;
1010   unsigned char buf[4096];
1011   DIG_CTX ctx;
1012   unsigned char md5[32];
1013 
1014   nprelink++;
1015   if ((fd = prelinked_open(name)) < 0)
1016     {
1017       perror(name);
1018       return -1;
1019     }
1020   DIG_Init(&ctx, digestalgo);
1021   while (size && (l = read(fd, buf, sizeof(buf))) > 0)
1022     {
1023       if (l > size)
1024 	l = size;
1025       DIG_Update(&ctx, digestalgo, buf, l);
1026       size -= l;
1027     }
1028   close(fd);
1029   DIG_Final(&ctx, digestalgo, md5);
1030   if (memcmp(md5, hmd5, DIG_Len(digestalgo)))
1031     {
1032       fprintf(stderr, "%s: contents have been changed\n", name);
1033       return -1;
1034     }
1035   return 0;
1036 }
1037 
1038 int
checkfilemd5(char * name,int digestalgo,unsigned char * hmd5,unsigned int size)1039 checkfilemd5(char *name, int digestalgo, unsigned char *hmd5, unsigned int size)
1040 {
1041   int fd, l;
1042   unsigned char buf[4096];
1043   DIG_CTX ctx;
1044   unsigned char md5[32];
1045   struct stat stb;
1046 
1047   if ((fd = open(name, O_RDONLY)) < 0 || fstat(fd, &stb))
1048     {
1049       perror(name);
1050       return -1;
1051     }
1052   DIG_Init(&ctx, digestalgo);
1053   if (stb.st_size > size && (l = read(fd, buf, sizeof(buf))) > 0)
1054     {
1055       if (is_prelinked(fd, buf, l))
1056 	{
1057 	  close(fd);
1058 	  return checkprelinked(name, digestalgo, hmd5, size);
1059 	}
1060       if (l > size)
1061 	l = size;
1062       DIG_Update(&ctx, digestalgo, buf, l);
1063       size -= l;
1064     }
1065   while (size && (l = read(fd, buf, sizeof(buf))) > 0)
1066     {
1067       if (l > size)
1068 	l = size;
1069       DIG_Update(&ctx, digestalgo, buf, l);
1070       size -= l;
1071     }
1072   close(fd);
1073   DIG_Final(&ctx, digestalgo, md5);
1074   if (memcmp(md5, hmd5, DIG_Len(digestalgo)))
1075     {
1076       fprintf(stderr, "%s: contents have been changed\n", name);
1077       return -1;
1078     }
1079   return 0;
1080 }
1081 
1082 int
checkfilesize(char * name,int digestalgo,unsigned char * hmd5,unsigned int size)1083 checkfilesize(char *name, int digestalgo, unsigned char *hmd5, unsigned int size)
1084 {
1085   struct stat stb;
1086   unsigned char buf[128];
1087   int l;
1088 
1089   if (stat(name, &stb) == -1)
1090     {
1091       perror(name);
1092       return -1;
1093     }
1094   if (stb.st_size == size)
1095     return 0;
1096   if (stb.st_size > size)
1097     {
1098       int fd;
1099       fd = open(name, O_RDONLY);
1100       if (fd != -1 && (l = read(fd, buf, sizeof(buf))) > 0 && is_prelinked(fd, buf, l))
1101 	{
1102 	  close(fd);
1103 	  return checkprelinked(name, digestalgo, hmd5, size);
1104 	}
1105       if (fd != -1)
1106         close(fd);
1107     }
1108   fprintf(stderr, "%s: contents have been changed\n", name);
1109   return -1;
1110 }
1111 
1112 /*****************************************************************
1113  * main program
1114  */
1115 
1116 int
main(int argc,char ** argv)1117 main(int argc, char **argv)
1118 {
1119   int c, i;
1120   char *deltarpm;
1121   struct rpmhead *h;
1122   int fd;
1123   struct cfile *bfp = 0;
1124   struct cfile *obfp;
1125   char *fnevr;
1126   unsigned int inn;
1127   unsigned int *in;
1128   unsigned int outn;
1129   unsigned int *out;
1130   drpmuint off, paywritten;
1131   struct fileblock fb;
1132   struct seqdescr *sdesc;
1133   int nsdesc;
1134   struct blk *lastblk = 0;
1135   int idx;
1136   int on;
1137   unsigned int len, l;
1138   int bs, be;
1139   unsigned char buf[4096];
1140   MD5_CTX wrmd5;
1141   unsigned char wrmd5res[16];
1142   int nofullmd5 = 0;
1143   FILE *ofp;
1144   int numblks;
1145   int percent = 0;
1146   int curpercent;
1147   int lastpercent = -1;
1148   int verbose = 0;
1149   int seqcheck = 0;
1150   int check = 0;
1151   int checkflags = 0;
1152   int info = 0;
1153   bz_stream addbz2strm;
1154   z_stream addgzstrm;
1155   int addblkcomp;
1156   unsigned char *addblkbuf = 0;
1157   unsigned char *b;
1158   int seqmatches = 1;
1159   FILE *vfp;
1160   struct deltarpm d;
1161   char *arch = 0;
1162 
1163   while ((c = getopt(argc, argv, "cCisvpr:a:")) != -1)
1164     {
1165       switch(c)
1166 	{
1167 	case 'v':
1168           verbose++;
1169 	  break;
1170 	case 'p':
1171           percent++;
1172 	  break;
1173 	case 'r':
1174 	  fromrpm = optarg;
1175 	  break;
1176 	case 's':
1177 	  check = 1;
1178 	  seqcheck = 1;
1179 	  break;
1180 	case 'i':
1181 	  info = 1;
1182 	  break;
1183 	case 'c':
1184 	  checkflags = SEQCHECK_MD5;
1185 	  check = 1;
1186 	  break;
1187 	case 'C':
1188 	  checkflags = SEQCHECK_SIZE;
1189 	  check = 1;
1190 	  break;
1191 	case 'a':
1192 	  arch = optarg;
1193 	  break;
1194 	default:
1195 	  fprintf(stderr, "usage: applydeltarpm [-r <rpm>] deltarpm rpm\n");
1196           exit(1);
1197 	}
1198     }
1199 
1200   if (optind + (check || info ? 1 : 2) != argc)
1201     {
1202       fprintf(stderr, "usage: applydeltarpm [-r <rpm>] deltarpm rpm\n");
1203       exit(1);
1204     }
1205   if (checkflags && fromrpm)
1206     {
1207       fprintf(stderr, "on-disk checking does not work with the -r option.\n");
1208       exit(1);
1209     }
1210 
1211   vfp = !(check || info) && !strcmp(argv[argc - 1], "-") ? stderr : stdout;
1212 
1213   deltarpm = argv[optind];
1214 
1215   bfp = 0;
1216   if (seqcheck)
1217     {
1218       char *hex;
1219       int nevrl;
1220 
1221       if (info)
1222 	{
1223 	  fprintf(stderr, "need real delta-rpm for info\n");
1224 	  exit(1);
1225 	}
1226       memset(&d, 0, sizeof(d));
1227       d.name = deltarpm;
1228       d.seql = strlen(deltarpm);
1229       if (d.seql < 34 || (hex = strrchr(deltarpm, '-')) == 0)
1230 	{
1231 	  fprintf(stderr, "%s: bad sequence\n", deltarpm);
1232 	  exit(1);
1233 	}
1234       d.nevr = deltarpm;
1235       nevrl = hex - deltarpm;
1236       d.seql -= nevrl + 1;
1237       *hex++ = 0;
1238       d.seql = (d.seql + 1) / 2;
1239       d.seq = xmalloc(d.seql);
1240       if (parsehex(hex, d.seq, d.seql) != d.seql)
1241 	{
1242 	  fprintf(stderr, "bad sequence\n");
1243 	  exit(1);
1244 	}
1245     }
1246   else
1247     {
1248       if (verbose)
1249 	fprintf(vfp, "reading deltarpm\n");
1250       readdeltarpm(deltarpm, &d, &bfp);
1251       nofullmd5 = !memcmp("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", d.targetmd5, 16);
1252 #ifdef DELTARPM_64BIT
1253       if (d.outlen >= 0xffffffffULL << BLKSHIFT)
1254 	{
1255 	  fprintf(stderr, "cpio size too big\n");
1256 	  exit(1);
1257 	}
1258 #endif
1259       numblks = (unsigned int)(d.outlen >> BLKSHIFT);
1260       if ((d.outlen & (BLKSIZE - 1)) != 0)
1261 	numblks++;
1262 
1263       maxblockuse = xcalloc(numblks, sizeof(unsigned int));
1264       vmem = xcalloc(numblks, sizeof(struct blk *));
1265 
1266       if (verbose > 1)
1267 	{
1268 	  fprintf(vfp, "%llu bytes source payload size\n", (unsigned long long)d.outlen);
1269 	  fprintf(vfp, "%llu bytes target payload size\n", (unsigned long long)d.paylen);
1270 	  fprintf(vfp, "%llu bytes internal data size\n", (unsigned long long)d.inlen);
1271 	  fprintf(vfp, "%u bytes add data size\n", d.addblklen);
1272 	  fprintf(vfp, "%d blocks\n", numblks);
1273 	  fprintf(vfp, "%d copy instructions\n", d.inn + d.outn);
1274 	}
1275       off = 0;
1276       for (i = 0; i < d.outn; i++)
1277         {
1278 	  off += (int)d.out[2 * i];
1279 	  bs = off >> BLKSHIFT;
1280 	  off += d.out[2 * i + 1];
1281 	  be = (off - 1) >> BLKSHIFT;
1282 	  for (; bs <= be; bs++)
1283 	    maxblockuse[bs] = i;
1284 	}
1285     }
1286 
1287   addblkcomp = CFILE_COMP_BZ;
1288   if (d.addblklen > 9 && d.addblk[0] == 0x1f && d.addblk[1] == 0x8b)
1289     addblkcomp = CFILE_COMP_GZ;
1290   else if (d.addblklen > 3 && (d.addblk[0] == 255 && d.addblk[1] == 'L' && d.addblk[2] == 'Z'))
1291     addblkcomp = CFILE_COMP_LZMA;
1292   else if (d.addblklen > 6 && (d.addblk[0] == 0xfd && d.addblk[1] == '7' && d.addblk[2] == 'z' && d.addblk[3] == 'X' && d.addblk[4] == 'Z'))
1293     addblkcomp = CFILE_COMP_XZ;
1294   if (info)
1295     {
1296       unsigned int *size;
1297       if (d.version)
1298 	printf("deltarpm version: %c\n", d.version & 0xff);
1299       printf("deltarpm type: %s\n", d.h ? "standard" : d.targetcomp != CFILE_COMP_UN || d.inn != 0 || d.outn != 0 ? "rpm-only" : "rpm-only, no diff");
1300       printf("deltarpm compression: %s\n", cfile_comp2str(d.deltacomp));
1301       printf("sequence: %s-", d.nevr);
1302       for (i = 0; i < d.seql; i++)
1303 	printf("%02x", d.seq[i]);
1304       putchar('\n');
1305       printf("source rpm: %s\n", d.nevr);
1306       if (d.h || d.targetcomp != CFILE_COMP_UN || d.inn != 0 || d.outn != 0)
1307         printf("source payload size: %llu\n", (unsigned long long)d.outlen);
1308       printf("target rpm: %s\n", d.targetnevr);
1309       if (d.h || d.targetcomp != CFILE_COMP_UN || d.inn != 0 || d.outn != 0)
1310 	{
1311 	  printf("target payload size: %llu\n", (unsigned long long)d.paylen);
1312 	  if (d.targetcomp != CFILE_COMP_XX)
1313 	    printf("target payload compression: %s\n", cfile_comp2str(d.targetcomp));
1314 	}
1315       if (d.targetsize == 0)
1316 	{
1317           struct rpmhead *dsigh = readhead_buf(d.lead + 96, d.leadl - 96, 0);
1318 	  if (dsigh && (size = headint32(dsigh, 1000, (int *)0)) != 0)
1319 	    {
1320 	      d.targetsize = d.leadl + *size;
1321 	      free(size);
1322 	    }
1323 	  xfree(dsigh);
1324 	}
1325       if (d.targetsize)
1326         printf("target size: %u\n", d.targetsize);
1327       printf("target md5: ");
1328       for (i = 0; i < 16; i++)
1329 	printf("%02x", d.targetmd5[i]);
1330       putchar('\n');
1331       if (d.h || d.targetcomp != CFILE_COMP_UN || d.inn != 0 || d.outn != 0)
1332 	{
1333 	  printf("internal data size: %llu\n", (unsigned long long)d.inlen);
1334 	  printf("compressed add data size: %d\n", d.addblklen);
1335 	  if (d.addblklen)
1336 	    printf("compressed add data compression: %s\n", cfile_comp2str(addblkcomp));
1337 	  printf("instructions: %d\n", d.inn + d.outn);
1338 	}
1339       if (bfp)
1340         bfp->close(bfp);
1341       exit(0);
1342     }
1343 
1344   if (d.targetcompparalen)
1345     {
1346       fprintf(stderr, "deltarpm contains unknown compression parameters\n");
1347       exit(1);
1348     }
1349 
1350   if (!fromrpm)
1351     {
1352       pid_t pid;
1353       int pi[2];
1354 
1355       if (!seqcheck && !d.h)
1356 	{
1357 	  fprintf(stderr, "this deltarpm does not work from filesystem, use '-r <oldrpm>'.\n");
1358 	  exit(1);
1359 	}
1360       if (!seqcheck && !headstring(d.h, TAG_SOURCERPM))
1361 	{
1362 	  fprintf(stderr, "cannot reconstruct source rpms from filesystem\n");
1363 	  exit(1);
1364 	}
1365       if (pipe(pi))
1366 	{
1367 	  perror("pipe");
1368 	  exit(1);
1369 	}
1370       if ((pid = fork()) == (pid_t)-1)
1371 	{
1372 	  perror("fork");
1373 	  exit(1);
1374 	}
1375       if (pid == 0)
1376 	{
1377 	  close(pi[0]);
1378 	  if (pi[1] != 1)
1379 	    {
1380 	      dup2(pi[1], 1);
1381 	      close(pi[1]);
1382 	    }
1383 	  if (arch)
1384 	    execlp(RPMDUMPHEADER, RPMDUMPHEADER, "-a", arch, d.nevr, (char *)0);
1385 	  else
1386 	    execlp(RPMDUMPHEADER, RPMDUMPHEADER, d.nevr, (char *)0);
1387 	  perror(RPMDUMPHEADER);
1388 	  _exit(1);
1389 	}
1390       close(pi[1]);
1391       fd = pi[0];
1392     }
1393   else
1394     {
1395       unsigned char rpmlead[96];
1396 
1397       if ((fd = open(fromrpm, O_RDONLY)) < 0)
1398 	{
1399 	  perror(fromrpm);
1400 	  exit(1);
1401 	}
1402       if (read(fd, rpmlead, 96) != 96 || rpmlead[0] != 0xed || rpmlead[1] != 0xab || rpmlead[2] != 0xee || rpmlead[3] != 0xdb)
1403 	{
1404 	  fprintf(stderr, "%s: not a rpm\n", fromrpm);
1405 	  exit(1);
1406 	}
1407       if (rpmlead[4] != 0x03 || rpmlead[0x4e] != 0 || rpmlead[0x4f] != 5)
1408 	{
1409 	  fprintf(stderr, "%s: not a v3 rpm or not new header styles\n", fromrpm);
1410 	  exit(1);
1411 	}
1412       h = readhead(fd, 1);
1413       if (!h)
1414 	{
1415 	  fprintf(stderr, "could not read signature header\n");
1416 	  exit(1);
1417 	}
1418       if (!d.h)
1419 	{
1420 	  unsigned char *hmd5 = headbin(h, 1004, 16);
1421 	  if (!hmd5 || memcmp(hmd5, d.seq, 16) != 0)
1422 	    seqmatches = 0;
1423 	  if (seqcheck)
1424 	    {
1425 	      /* we don't know if this is a rpm-only deltarpm or not,
1426                * so we assume yes if seqmatches is true */
1427 	      if (seqmatches && d.seql == 16)
1428 		seqcheck = 0;	/* assume rpm-only, no expandseq */
1429 	      else
1430 	        seqmatches = 1;	/* assume normal, run expandseq */
1431 	    }
1432 	}
1433       free(h);
1434     }
1435   h = readhead(fd, 0);
1436   if (!h)
1437     {
1438       if (fromrpm)
1439         fprintf(stderr, "could not read header\n");
1440       exit(1);
1441     }
1442   fnevr = headtonevr(h);
1443   if (strcmp(fnevr, (char *)d.nevr) != 0)
1444     {
1445       fprintf(stderr, "delta rpm made for %s, not %s\n", d.nevr, fnevr);
1446       exit(1);
1447     }
1448   if (!seqmatches)
1449     {
1450       fprintf(stderr, "rpm does not match the one used for creating the deltarpm\n");
1451       exit(1);
1452     }
1453   if (d.h || seqcheck)
1454     {
1455       int (*checkfunc)(char *, int, unsigned char *, unsigned int);
1456       if (headtofb(h, &fb))
1457 	{
1458 	  fprintf(stderr, "bad header\n");
1459 	  exit(1);
1460 	}
1461       checkfunc = 0;
1462       if ((checkflags & SEQCHECK_MD5) != 0)
1463 	checkfunc = checkfilemd5;
1464       else if ((checkflags & SEQCHECK_SIZE) != 0)
1465 	checkfunc = checkfilesize;
1466       sdesc = expandseq(d.seq, d.seql, &nsdesc, &fb, checkfunc);
1467       if (!sdesc)
1468 	{
1469 	  fprintf(stderr, "could not expand sequence data\n");
1470 	  exit(1);
1471 	}
1472     }
1473   else
1474     {
1475       nsdesc = 0;
1476       sdesc = 0;
1477     }
1478   if (!fromrpm)
1479     {
1480       int status;
1481       close(fd);
1482       wait(&status);
1483     }
1484   if (check)
1485     exit(0);
1486 
1487   l = 0;
1488   for (i = 0; i < nsdesc; i++)
1489     if (sdesc[i].cpiolen > l)
1490       l = sdesc[i].cpiolen;
1491   if (l < 124)
1492     l = 124;			/* room for tailer */
1493   cpiodata = xmalloc(l + 4);	/* extra room for padding */
1494 
1495 
1496   rpmMD5Init(&wrmd5);
1497   if (!strcmp(argv[optind + 1], "-"))
1498     ofp = stdout;
1499   else if ((ofp = fopen(argv[optind + 1], "w")) == 0)
1500     {
1501       perror(argv[optind + 1]);
1502       exit(1);
1503     }
1504   if (fwrite(d.lead, d.leadl, 1, ofp) != 1)
1505     {
1506       fprintf(stderr, "write error\n");
1507       exit(1);
1508     }
1509   if (!nofullmd5)
1510     rpmMD5Update(&wrmd5, d.lead, d.leadl);
1511   if (!d.h)
1512     fromrpm_raw = 1;
1513 
1514   if (fromrpm_raw && d.targetcomp == CFILE_COMP_UN && d.inn == 0 && d.outn == 0)
1515     {
1516       /* no diff, copy-through mode */
1517       if (fwrite(h->intro, 16, 1, ofp) != 1 || fwrite(h->data, 16 * h->cnt + h->dcnt, 1, ofp) != 1)
1518 	{
1519 	  fprintf(stderr, "write error\n");
1520 	  exit(1);
1521 	}
1522       rpmMD5Update(&wrmd5, h->intro, 16);
1523       rpmMD5Update(&wrmd5, h->data, 16 * h->cnt + h->dcnt);
1524       while ((l = read(fd, buf, sizeof(buf))) > 0)
1525 	{
1526 	  if (fwrite(buf, l, 1, ofp) != 1)
1527 	    {
1528 	      fprintf(stderr, "write error\n");
1529 	      exit(1);
1530 	    }
1531 	  rpmMD5Update(&wrmd5, buf, l);
1532 	}
1533       if (fflush(ofp) || (ofp != stdout && fclose(ofp) != 0))
1534 	{
1535 	  fprintf(stderr, "write error\n");
1536 	  exit(1);
1537 	}
1538       rpmMD5Final(wrmd5res, &wrmd5);
1539       if (nofullmd5)
1540         {
1541           struct rpmhead *dsigh = readhead_buf(d.lead + 96, d.leadl - 96, 0);
1542           if (dsigh)
1543             {
1544               unsigned char *hmd5 = headbin(dsigh, SIGTAG_MD5, 16);
1545               if (hmd5)
1546                 {
1547                   if (memcmp(wrmd5res, hmd5, 16) != 0)
1548                     {
1549                       fprintf(stderr, "%s: md5 mismatch of result\n", deltarpm);
1550                       exit(1);
1551                     }
1552                 }
1553               xfree(dsigh);
1554             }
1555         }
1556       else if (memcmp(wrmd5res, d.targetmd5, 16) != 0)
1557 	{
1558 	  fprintf(stderr, "%s: md5 mismatch of result\n", deltarpm);
1559 	  exit(1);
1560 	}
1561       exit(0);
1562     }
1563 
1564   if (!fromrpm_raw)
1565     {
1566       if (fwrite(d.h->intro, 16, 1, ofp) != 1)
1567 	{
1568 	  fprintf(stderr, "write error\n");
1569 	  exit(1);
1570 	}
1571       rpmMD5Update(&wrmd5, d.h->intro, 16);
1572       strncpy((char *)d.h->dp + d.payformatoff, "cpio", 4);
1573       if (fwrite(d.h->data, 16 * d.h->cnt + d.h->dcnt, 1, ofp) != 1)
1574 	{
1575 	  fprintf(stderr, "write error\n");
1576 	  exit(1);
1577 	}
1578       rpmMD5Update(&wrmd5, d.h->data, 16 * d.h->cnt + d.h->dcnt);
1579     }
1580 
1581   if (fromrpm)
1582     {
1583       if ((outfp = cfile_open(CFILE_OPEN_RD, fd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, 0, 0)) == 0)
1584 	{
1585 	  fprintf(stderr, "%s: payload open failed\n", deltarpm);
1586 	  exit(1);
1587 	}
1588     }
1589 
1590   if (d.addblklen)
1591     {
1592       switch (addblkcomp)
1593 	{
1594 	case CFILE_COMP_GZ:
1595 	  if (memcmp(d.addblk, "\037\213\010\0\0\0\0\0\0\003", 10) != 0)
1596 	    {
1597 	      fprintf(stderr, "addblk: unsupported gz stream\n");
1598 	      exit(1);
1599 	    }
1600 	  addgzstrm.zalloc = NULL;
1601 	  addgzstrm.zfree = NULL;
1602 	  addgzstrm.opaque = NULL;
1603 	  if (inflateInit2(&addgzstrm, -MAX_WBITS) != Z_OK)
1604 	    {
1605 	      fprintf(stderr, "addblk: inflateInit2 error\n");
1606 	      exit(1);
1607 	    }
1608 	  addgzstrm.next_in = d.addblk + 10;
1609 	  addgzstrm.avail_in = d.addblklen - 10;
1610 	  break;
1611 	default:
1612 	  addbz2strm.bzalloc = NULL;
1613 	  addbz2strm.bzfree = NULL;
1614 	  addbz2strm.opaque = NULL;
1615 	  if (BZ2_bzDecompressInit(&addbz2strm, 0, 0) != BZ_OK)
1616 	    {
1617 	      fprintf(stderr, "addblk: BZ2_bzDecompressInit error\n");
1618 	      exit(1);
1619 	    }
1620 	  addbz2strm.next_in = (char *)d.addblk;
1621 	  addbz2strm.avail_in = d.addblklen;
1622 	  break;
1623 	}
1624       addblkbuf = xmalloc(BLKSIZE);
1625     }
1626 
1627   obfp = cfile_open(CFILE_OPEN_WR, CFILE_IO_FILE, ofp, d.compheadlen ? CFILE_COMP_UN : d.targetcomp, CFILE_LEN_UNLIMITED, (cfile_ctxup)rpmMD5Update, &wrmd5);
1628   if (!obfp)
1629     {
1630       fprintf(stderr, "payload write error\n");
1631       exit(1);
1632     }
1633   if (d.compheadlen)
1634     {
1635       obfp->comp = d.targetcomp;
1636       obfp->len = d.compheadlen;
1637       obfp->write = cfile_write_uncomp;
1638     }
1639   if (fromrpm)
1640     fillblock_method = fillblock_rpm;
1641   else
1642     fillblock_method = fillblock_disk;
1643   if (fromrpm_raw)
1644     {
1645       fillblock_method = fillblock_rawrpm;
1646       if (outfp->unread(outfp, h->data, 16 * h->cnt + h->dcnt) || outfp->unread(outfp, h->intro, 16))
1647 	{
1648 	  fprintf(stderr, "could not unread header\n");
1649 	  exit(1);
1650 	}
1651       outfpleft_raw = d.outlen;
1652     }
1653   if (verbose)
1654     fprintf(vfp, "applying delta\n");
1655   idx = 0;
1656   paywritten = 0;
1657   inn = d.inn;
1658   outn = d.outn;
1659   in = d.in;
1660   out = d.out;
1661   off = 0;
1662   while (inn > 0)
1663     {
1664       on = *in++;
1665       if (on > outn)
1666 	{
1667 	  fprintf(stderr, "corrupt delta instructions\n");
1668 	  exit(1);
1669 	}
1670       while (on > 0)
1671 	{
1672 	  off += (int)*out++;
1673 	  len = *out++;
1674 	  paywritten += len;
1675 	  outn--;
1676 	  on--;
1677 	  bs = off >> BLKSHIFT;
1678 	  while (len > 0)
1679 	    {
1680 	      if (!lastblk || bs != lastblk->id)
1681 		{
1682 		  lastblk = vmem[bs];
1683 		  if (!lastblk || lastblk->type == BLK_PAGE)
1684 		    lastblk = getblock(bs, sdesc, nsdesc, &fb, idx);
1685 		}
1686 	      l = off & BLKMASK;
1687 	      if (l + len > BLKSIZE)
1688 		l = BLKSIZE - l;
1689 	      else
1690 		l = len;
1691 	      b = lastblk->e.buf + (off & BLKMASK);
1692 	      if (d.addblklen)
1693 	        {
1694 		  if (addblkcomp == CFILE_COMP_GZ)
1695 		    {
1696 		      addgzstrm.next_out = addblkbuf;
1697 		      addgzstrm.avail_out = l;
1698 		      inflate(&addgzstrm, Z_NO_FLUSH);
1699 		      if (addgzstrm.avail_out != 0)
1700 			{
1701 			  fprintf(stderr, "addblk: inflate error\n");
1702 			  exit(1);
1703 			}
1704 		    }
1705 		  else
1706 		    {
1707 		      addbz2strm.next_out = (char *)addblkbuf;
1708 		      addbz2strm.avail_out = l;
1709 		      BZ2_bzDecompress(&addbz2strm);
1710 		      if (addbz2strm.avail_out != 0)
1711 			{
1712 			  fprintf(stderr, "addblk: BZ2_bzDecompress error\n");
1713 			  exit(1);
1714 			}
1715 		    }
1716 		  for (i = 0; i < l; i++)
1717 		    addblkbuf[i] += b[i];
1718 		  b = addblkbuf;
1719 	        }
1720 	      if (obfp->write(obfp, b, l) != l)
1721 		{
1722 		  fprintf(stderr, "write error\n");
1723 		  exit(1);
1724 		}
1725 	      len -= l;
1726 	      off += l;
1727 	      bs++;
1728 	    }
1729 	  idx++;
1730           if (percent)
1731 	    {
1732 	      if (d.paylen >= 0x1000000)
1733 	        curpercent = (paywritten >> 8) * 100 / (d.paylen >> 8);
1734 	      else if (d.paylen)
1735 	        curpercent = paywritten * 100 / d.paylen;
1736 	      else
1737 	        curpercent = 0;
1738 	      if (curpercent != lastpercent)
1739 		{
1740 		  if (percent > 1)
1741 		    fprintf(vfp, "%d percent finished.\n", curpercent);
1742 		  else
1743 		    fprintf(vfp, "\r%d percent finished.", curpercent);
1744 		  fflush(vfp);
1745 		  lastpercent = curpercent;
1746 		}
1747 	    }
1748 	}
1749       len = *in++;
1750       paywritten += len;
1751       while (len > 0)
1752 	{
1753 	  l = len > sizeof(buf) ? sizeof(buf) : len;
1754 	  if (bfp->read(bfp, buf, l) != l)
1755 	    {
1756 	      fprintf(stderr, "%s: read error data area\n", deltarpm);
1757 	      exit(1);
1758 	    }
1759 	  if (obfp->write(obfp, buf, l) != l)
1760 	    {
1761 	      fprintf(stderr, "write error\n");
1762 	      exit(1);
1763 	    }
1764 	  len -= l;
1765 	}
1766       inn--;
1767       if (percent)
1768 	{
1769 	  curpercent = paywritten * 100. / (d.paylen ? d.paylen : 1);
1770 	  if (curpercent != lastpercent)
1771 	    {
1772 	      if (percent > 1)
1773 		fprintf(vfp, "%d percent finished.\n", curpercent);
1774 	      else
1775 		fprintf(vfp, "\r%d percent finished.", curpercent);
1776 	      fflush(vfp);
1777 	      lastpercent = curpercent;
1778 	    }
1779 	}
1780     }
1781   if (percent > 1)
1782     fprintf(vfp, "100 percent finished.\n");
1783   else if (percent)
1784     fprintf(vfp, "\r100 percent finished.\n");
1785   if (obfp->close(obfp) == -1)
1786     {
1787       fprintf(stderr, "write error\n");
1788       exit(1);
1789     }
1790   if (fflush(ofp) || (ofp != stdout && fclose(ofp) != 0))
1791     {
1792       fprintf(stderr, "write error\n");
1793       exit(1);
1794     }
1795   if (outfp)
1796     outfp->close(outfp);
1797   if (bfp)
1798     bfp->close(bfp);
1799   if (d.addblklen)
1800     {
1801       if (addblkcomp == CFILE_COMP_GZ)
1802         inflateEnd(&addgzstrm);
1803       else
1804         BZ2_bzDecompressEnd(&addbz2strm);
1805     }
1806   if (verbose > 1)
1807     {
1808       fprintf(vfp, "used %d core pages\n", ncoreblk);
1809       fprintf(vfp, "used %d swap pages\n", npageblk);
1810       fprintf(vfp, "had to recreate %d core pages\n", ndropblk);
1811       if (nprelink)
1812         fprintf(vfp, "had to call prelink %d times\n", nprelink);
1813     }
1814   rpmMD5Final(wrmd5res, &wrmd5);
1815   if (nofullmd5)
1816     {
1817       struct rpmhead *dsigh = readhead_buf(d.lead + 96, d.leadl - 96, 0);
1818       if (dsigh)
1819         {
1820           unsigned char *hmd5 = headbin(dsigh, SIGTAG_MD5, 16);
1821           if (hmd5)
1822             {
1823               if (memcmp(wrmd5res, hmd5, 16) != 0)
1824                 {
1825                   fprintf(stderr, "%s: md5 mismatch of result\n", deltarpm);
1826                   exit(1);
1827                 }
1828             }
1829           xfree(dsigh);
1830         }
1831     }
1832   else if (memcmp(wrmd5res, d.targetmd5, 16) != 0)
1833     {
1834       fprintf(stderr, "%s: md5 mismatch of result\n", deltarpm);
1835       exit(1);
1836     }
1837   exit(0);
1838 }
1839