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