summaryrefslogtreecommitdiff
path: root/makedeltarpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'makedeltarpm.c')
-rw-r--r--makedeltarpm.c1543
1 files changed, 1543 insertions, 0 deletions
diff --git a/makedeltarpm.c b/makedeltarpm.c
new file mode 100644
index 0000000..a757962
--- /dev/null
+++ b/makedeltarpm.c
@@ -0,0 +1,1543 @@
+/*
+ * Copyright (c) 2004 Michael Schroeder (mls@suse.de)
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <bzlib.h>
+#include <zlib.h>
+#include <lzma.h>
+
+#include "util.h"
+#include "md5.h"
+#include "rpmhead.h"
+#include "rpml.h"
+#include "cpio.h"
+#include "delta.h"
+#include "cfile.h"
+#include "deltarpm.h"
+
+char *
+headtofiles(struct rpmhead *h, struct rpmlfile **filesp, int *nfilesp)
+{
+ char *nevr, *n;
+ int cnt, i;
+ struct rpmlfile *files;
+ unsigned int *fileflags, *filemodes;
+ char **filelist, **filemd5s;
+
+ nevr = headtonevr(h);
+ if (!nevr)
+ return 0;
+ filelist = headexpandfilelist(h, &cnt);
+ if (!filelist || !cnt)
+ {
+ *nfilesp = 0;
+ *filesp = 0;
+ return nevr;
+ }
+ fileflags = headint32(h, TAG_FILEFLAGS, (int *)0);
+ filemd5s = headstringarray(h, TAG_FILEMD5S, (int *)0);
+ filemodes = headint16(h, TAG_FILEMODES, (int *)0);
+ files = xmalloc2(cnt, sizeof(*files));
+ for (i = 0; i < cnt; i++)
+ {
+ n = filelist[i];
+ if (*n == '/')
+ n++;
+ files[i].name = xmalloc(strlen(n) + 1);
+ strcpy(files[i].name, n);
+ files[i].mode = filemodes[i];
+ files[i].fflags = fileflags[i];
+ parsemd5(filemd5s[i], files[i].md5);
+ }
+ *filesp = files;
+ *nfilesp = cnt;
+ free(fileflags);
+ free(filemd5s);
+ free(filemodes);
+ free(filelist);
+ return nevr;
+}
+
+unsigned char *seq;
+int seqp;
+int seql;
+
+int lastseq = -1;
+int lastseqstart = 0;
+
+void
+addtoseqn(int n)
+{
+ int l = 1, j = 8;
+ while (n >= j)
+ {
+ j *= 8;
+ l++;
+ }
+ if (seqp + l > seql * 2)
+ {
+ seq = xrealloc(seq, seql + 32);
+ seql += 32;
+ }
+ while (l-- > 0)
+ {
+ if (seqp & 1)
+ seq[seqp / 2] |= (n & 7) | (l ? 8 : 0);
+ else
+ seq[seqp / 2] = ((n & 7) | (l ? 8 : 0)) << 4;
+ seqp++;
+ n >>= 3;
+ }
+}
+
+void
+addtoseq(int i)
+{
+ int n;
+ // fprintf(stderr, "addtoseq %d lastseqstart=%d lastseq=%d\n", i, lastseqstart, lastseq);
+ if (i == lastseq + 1)
+ {
+ lastseq = i;
+ return;
+ }
+ n = lastseq - lastseqstart + 1;
+ if (n)
+ addtoseqn(n);
+ if (i > lastseq + 1 && lastseq >= 0)
+ {
+ addtoseqn(i - lastseq - 1);
+ }
+ else if (i != -1)
+ {
+ addtoseqn(0);
+ addtoseqn(i);
+ }
+ lastseq = lastseqstart = i;
+}
+
+struct prune {
+ char *name;
+};
+
+struct prune *prunes;
+int prunen;
+
+void
+read_prunelist(char *file)
+{
+ FILE *fp;
+ char *buf, *bp;
+ int i, c, bufl;
+ struct prune *p;
+
+ if ((fp = fopen(file, "r")) == 0)
+ {
+ perror(file);
+ exit(1);
+ }
+ bufl = 256;
+ buf = xmalloc(256);
+ prunes = xmalloc(sizeof(*prunes) * 16);
+ for (i = 0;;)
+ {
+ c = getc(fp);
+ if (c && c != EOF && c != '\n')
+ {
+ buf[i++] = c;
+ if (i == bufl)
+ {
+ bufl += 256;
+ buf = xrealloc(buf, bufl);
+ }
+ continue;
+ }
+ buf[i] = 0;
+ bp = buf;
+ if (*bp == '/')
+ bp++;
+ else if (*bp == '.' && bp[1] == '/')
+ bp += 2;
+ if (!*bp && c == EOF)
+ break;
+ if (!*bp)
+ continue;
+ if ((prunen & 15) == 0)
+ prunes = xrealloc2(prunes, prunen + 16, sizeof(*prunes));
+ p = prunes + prunen++;
+ p->name = xmalloc(i + 1 - (bp - buf));
+ memcpy(p->name, bp, i + 1 - (bp - buf));
+ i = 0;
+ }
+ fclose(fp);
+}
+
+int
+is_pruned(char *n)
+{
+ int i;
+ struct prune *p = prunes;
+
+ for (i = 0; i < prunen; i++, p++)
+ if (!strcmp(p->name, n))
+ return 1;
+ return 0;
+}
+
+
+int
+is_unpatched(char *n, struct rpmlfile *files1, int nfiles1, struct rpmlfile *files2, int nfiles2, char *md5s)
+{
+ int i;
+ unsigned char md5[16];
+
+ for (i = 0; i < nfiles2; i++)
+ if (!strcmp(n, files2[i].name))
+ break;
+ if (i == nfiles2)
+ return 0;
+ if (!(files2[i].fflags & FILE_UNPATCHED))
+ return 0;
+ for (i = 0; i < nfiles1; i++)
+ if (!strcmp(n, files1[i].name))
+ break;
+ if (i == nfiles1)
+ return 1; /* should not happen... */
+ parsemd5(md5s, md5);
+ if (memcmp(md5, files1[i].md5, 16))
+ return 1; /* file content may be different */
+ return 0;
+}
+
+struct streamdata {
+ bsuint bsize;
+
+ unsigned char *old;
+ bsuint oldl;
+ bsuint oldskip;
+ int oldeof;
+
+ unsigned char *new;
+ bsuint newl;
+ bsuint newskip;
+ int neweof;
+
+ struct cfile *newf;
+ unsigned char *xnewdata;
+ bsuint xnewdatal;
+
+ void *stepd;
+ bsuint scan;
+ bsuint lastpos;
+ bsuint lastscan;
+
+ struct cfile *cfa; /* add block */
+ struct cfile *cfi; /* in data */
+
+ struct instr *instr;
+ int instrlen;
+};
+
+struct streamdata sd; /* hack: global for now */
+
+void
+addtocpio_stream(unsigned char *d, int l)
+{
+ bsuint bsize = sd.bsize;
+ if (sd.lastscan == sd.newl && sd.neweof)
+ {
+ sd.oldskip += sd.oldl + l;
+ sd.oldl = 0;
+ return;
+ }
+ for (;;)
+ {
+ if (sd.oldl < bsize && !sd.oldeof)
+ {
+ int l2 = bsize - sd.oldl;
+ if (l2 > l)
+ l2 = l;
+ memcpy(sd.old + sd.oldl, d, l2);
+ sd.oldl += l2;
+ l -= l2;
+ d += l2;
+ if (sd.oldl < bsize)
+ return;
+ }
+ while (sd.newl < bsize && !sd.neweof)
+ {
+ int l2 = bsize - sd.newl;
+ if (sd.xnewdatal)
+ {
+ if (l2 > sd.xnewdatal)
+ l2 = sd.xnewdatal;
+ memcpy(sd.new + sd.newl, sd.xnewdata, l2);
+ sd.newl += l2;
+ sd.xnewdata += l2;
+ sd.xnewdatal -= l2;
+ continue;
+ }
+ l2 = sd.newf->read(sd.newf, sd.new + sd.newl, l2);
+ if (l2 < 0)
+ {
+ fprintf(stderr, "payload read failed\n");
+ exit(1);
+ }
+ if (l2 == 0)
+ sd.neweof = 1;
+ sd.newl += l2;
+ }
+ if (sd.lastscan != sd.newl)
+ {
+ struct instr instr;
+ mkdiff_step(sd.stepd, sd.old, sd.oldl, sd.new, sd.newl, &instr, &sd.scan, &sd.lastpos, &sd.lastscan);
+ if (instr.copyout && !sd.oldeof && (sd.lastscan == sd.newl || instr.copyoutoff + instr.copyout == sd.oldl))
+ {
+ /* incomplete match, ignore indata part */
+ instr.copyin = 0;
+ sd.scan = sd.lastscan = instr.copyinoff;
+ sd.lastpos = instr.copyoutoff + instr.copyout;
+ }
+ else if (!instr.copyout && sd.lastscan == sd.newl)
+ {
+ /* no match found in old data, advance if we're behind */
+ if (sd.lastpos + sd.oldskip < sd.lastscan + sd.newskip)
+ sd.lastpos = sd.oldl;
+ }
+ /* printf("INSTR: %d@%d %d@%d\n", instr.copyout, instr.copyoutoff + sd.oldskip, instr.copyin, instr.copyinoff + sd.newskip); */
+ if (instr.copyin)
+ {
+ if (instr.copyinoff + instr.copyin > sd.newl)
+ abort();
+ if (sd.cfi->write(sd.cfi, sd.new + instr.copyinoff, instr.copyin) != instr.copyin)
+ {
+ fprintf(stderr, "could not create indata block\n");
+ exit(1);
+ }
+ }
+ if (instr.copyout && sd.cfa)
+ {
+ bsuint lenf = instr.copyout;
+ bsuint lastpos = instr.copyoutoff;
+ bsuint lastscan = instr.copyinoff - lenf;
+ if (instr.copyoutoff + instr.copyout > sd.oldl)
+ abort();
+ if (instr.copyinoff - lenf + instr.copyout > sd.newl)
+ abort();
+ while (lenf > 0)
+ {
+ unsigned char addblk[4096];
+ int len2, i;
+
+ len2 = lenf > 4096 ? 4096 : lenf;
+ for (i = 0; i < len2; i++)
+ addblk[i] = sd.new[lastscan + i] - sd.old[lastpos + i];
+ if (sd.cfa->write(sd.cfa, addblk, len2) != len2)
+ {
+ fprintf(stderr, "could not create compressed add block\n");
+ exit(1);
+ }
+ lastscan += len2;
+ lastpos += len2;
+ lenf -= len2;
+ }
+ }
+ instr.copyinoff += sd.newskip;
+ instr.copyoutoff += sd.oldskip;
+ if (sd.instrlen && sd.instr[sd.instrlen - 1].copyin == 0 && sd.instr[sd.instrlen - 1].copyoutoff + sd.instr[sd.instrlen - 1].copyout == instr.copyoutoff)
+ {
+ /* just add to last instruction */
+ sd.instr[sd.instrlen - 1].copyin = instr.copyin;
+ sd.instr[sd.instrlen - 1].copyinoff = instr.copyinoff;
+ sd.instr[sd.instrlen - 1].copyout += instr.copyout;
+ }
+ else if (instr.copyin || instr.copyout)
+ {
+ if ((sd.instrlen & 31) == 0)
+ {
+ if (sd.instr)
+ sd.instr = realloc(sd.instr, sizeof(*sd.instr) * (sd.instrlen + 32));
+ else
+ sd.instr = malloc(sizeof(*sd.instr) * (sd.instrlen + 32));
+ if (!sd.instr)
+ {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ }
+ sd.instr[sd.instrlen] = instr;
+ sd.instrlen++;
+ }
+ }
+ if (sd.lastscan > bsize / 4 && !sd.neweof)
+ {
+ if (sd.newl > sd.lastscan)
+ memmove(sd.new, sd.new + sd.lastscan, sd.newl - sd.lastscan);
+ sd.newl -= sd.lastscan;
+ sd.newskip += sd.lastscan;
+ sd.scan -= sd.lastscan;
+ sd.lastscan = 0;
+ }
+ if (sd.lastpos > bsize / 2 && !sd.oldeof)
+ {
+ bsuint move = sd.lastpos - bsize / 4;
+ if (sd.lastpos + sd.oldskip + bsize < sd.lastscan + sd.newskip)
+ move = sd.lastpos;
+ if (move > sd.lastpos)
+ move = sd.lastpos;
+ if (sd.oldl > move)
+ memmove(sd.old, sd.old + move, sd.oldl - move);
+ sd.oldl -= move;
+ sd.oldskip += move;
+ sd.lastpos -= move;
+ mkdiff_step_freedata(sd.stepd);
+ }
+ if (sd.lastscan == sd.newl && sd.neweof)
+ {
+ sd.oldskip += sd.oldl + l;
+ sd.oldl = 0;
+ mkdiff_step_freedata(sd.stepd);
+ return;
+ }
+ }
+}
+
+void
+addtocpio(unsigned char **cpiop, bsuint *cpiol, unsigned char *d, int l)
+{
+ bsuint cpl = *cpiol;
+ if (*cpiop == (unsigned char *)&sd)
+ {
+ *cpiol += l;
+ addtocpio_stream(d, l);
+ return;
+ }
+ if (cpl + l < cpl || cpl + l + 65535 < cpl + l)
+ {
+ fprintf(stderr, "cpio archive to big\n");
+ exit(1);
+ }
+ if (cpl == 0 || ((cpl - 1) & 65535) + l >= 65536)
+ *cpiop = xrealloc(*cpiop, (cpl + l + 65535) & ~65535);
+ memcpy(*cpiop + cpl, d, l);
+ *cpiol = cpl + l;
+}
+
+void
+convertinstr(struct instr *instr, int instrlen, struct deltarpm *d)
+{
+ int i, j;
+ bsuint x1, x2, x3, off;
+ unsigned int *b1;
+ int nb1;
+ unsigned int *b2;
+ int nb2;
+
+ b1 = b2 = 0;
+ nb1 = nb2 = 0;
+ j = 0;
+ off = 0;
+ for (i = 0; i < instrlen; i++)
+ {
+ x1 = instr[i].copyout;
+ x2 = instr[i].copyin;
+ x3 = instr[i].copyoutoff;
+ if (!x1 && !x2)
+ continue;
+ if (x1)
+ {
+retry1:
+ if ((nb2 & 15) == 0)
+ b2 = xrealloc2(b2, nb2 + 16, 2 * sizeof(unsigned int));
+ if (x3 > off && x3 - off >= 0x80000000)
+ {
+ b2[2 * nb2] = 0x7fffffff;
+ b2[2 * nb2 + 1] = 0;
+ nb2++;
+ off += 0x7fffffff;
+ j++;
+ goto retry1;
+ }
+ if (x3 < off && off - x3 >= 0x80000000)
+ {
+ b2[2 * nb2] = -0x7fffffff;
+ b2[2 * nb2 + 1] = 0;
+ nb2++;
+ off -= 0x7fffffff;
+ j++;
+ goto retry1;
+ }
+ b2[2 * nb2] = (int)(x3 - off);
+ if (x1 >= 0x80000000)
+ {
+ b2[2 * nb2 + 1] = 0x7fffffff;
+ nb2++;
+ x1 -= 0x7fffffff;
+ off = x3 = x3 + 0x7fffffff;
+ j++;
+ goto retry1;
+ }
+ b2[2 * nb2 + 1] = x1;
+ nb2++;
+ off = x3 + x1;
+ j++;
+ }
+ if (x2)
+ {
+retry2:
+ if ((nb1 & 15) == 0)
+ b1 = xrealloc2(b1, nb1 + 16, 2 * sizeof(unsigned int));
+ b1[2 * nb1] = j;
+ j = 0;
+ if (x2 >= 0x80000000)
+ {
+ b1[2 * nb1 + 1] = 0x7fffffff;
+ x2 -= 0x7fffffff;
+ nb1++;
+ goto retry2;
+ }
+ b1[2 * nb1 + 1] = x2;
+ nb1++;
+ }
+ }
+ if (j)
+ {
+ if ((nb1 & 15) == 0)
+ b1 = xrealloc2(b1, nb1 + 16, 2 * sizeof(unsigned int));
+ b1[2 * nb1] = j;
+ b1[2 * nb1 + 1] = 0;
+ nb1++;
+ }
+ d->inn = nb1;
+ d->in = b1;
+ d->outn = nb2;
+ d->out = b2;
+}
+
+unsigned char **
+createindatalist(struct instr *instr, int instrlen, struct deltarpm *d, unsigned char *new)
+{
+ int i, j;
+ bsuint off, left, todo;
+ unsigned char **indatalist;
+
+ left = off = 0;
+ j = 0;
+ d->inlen = 0;
+ indatalist = xcalloc(d->inn, sizeof(unsigned char *));
+ for (i = 0; i < d->inn; i++)
+ {
+ todo = d->in[2 * i + 1];
+ while (!left && todo)
+ {
+ off = instr[j].copyinoff;
+ left = instr[j].copyin;
+ j++;
+ }
+ indatalist[i] = new + off;
+ off += todo;
+ left -= todo;
+ d->inlen += todo;
+ }
+ return indatalist;
+}
+
+int
+str2comp(char *comp)
+{
+ int n = strlen(comp);
+ if (n > 2 && n < 20 && comp[n - 2] == '.' && comp[n - 1] >= '0' && comp[n - 1] <= '9')
+ {
+ char buf[20];
+ strcpy(buf, comp);
+ buf[n - 2] = 0;
+ return cfile_setlevel(str2comp(buf), comp[n - 1] - '0');
+ }
+ if (!strcmp(comp, "bzip2"))
+ return CFILE_COMP_BZ;
+ if (!strcmp(comp, "gzip"))
+ return CFILE_COMP_GZ;
+#ifdef CFILE_COMP_GZ_RSYNC
+ if (!strcmp(comp, "gzip rsyncable"))
+ return CFILE_COMP_GZ_RSYNC;
+#endif
+ if (!strcmp(comp, "lzma"))
+ return CFILE_COMP_LZMA;
+ if (!strcmp(comp, "xz"))
+ return CFILE_COMP_XZ;
+ if (!strcmp(comp, "uncompressed"))
+ return CFILE_COMP_UN;
+ fprintf(stderr, "unknown compression type: %s\n", comp);
+ exit(1);
+}
+
+void
+createaddblock(struct instr *instr, int instrlen, struct deltarpm *d, unsigned char *old, unsigned char *new, int comp)
+{
+ struct cfile *cfa;
+ unsigned int l, l2;
+ unsigned char blk[4096];
+ unsigned char *o;
+ int i, j;
+
+ cfa = cfile_open(CFILE_OPEN_WR, CFILE_IO_ALLOC, &d->addblk, comp, CFILE_LEN_UNLIMITED, 0, 0);
+ if (!cfa)
+ {
+ fprintf(stderr, "could not create compressed add block\n");
+ exit(1);
+ }
+ for (i = 0; i < instrlen; i++)
+ {
+ l = instr[i].copyout;
+ o = old + instr[i].copyoutoff;
+ while (l)
+ {
+ l2 = l > sizeof(blk) ? sizeof(blk) : l;
+ for (j = 0; j < l2; j++)
+ blk[j] = new[j] - o[j];
+ if (cfa->write(cfa, blk, l2) != l2)
+ {
+ fprintf(stderr, "could not create compressed add block\n");
+ exit(1);
+ }
+ new += l2;
+ o += l2;
+ l -= l2;
+ }
+ new += instr[i].copyin;
+ }
+ d->addblklen = cfa->close(cfa);
+}
+
+void
+write_seqfile(struct deltarpm *d, char *seqfile)
+{
+ FILE *ifp;
+ int i;
+
+ if ((ifp = fopen(seqfile, "w")) == 0)
+ {
+ perror(seqfile);
+ exit(1);
+ }
+ fprintf(ifp, "%s-", d->nevr);
+ for (i = 0; i < d->seql; i++)
+ fprintf(ifp, "%02x", d->seq[i]);
+ fprintf(ifp, "\n");
+ if (fclose(ifp))
+ {
+ perror("fclose seqfile");
+ exit(1);
+ }
+}
+
+static int
+in_multilib_dir(char *fn)
+{
+ char *dirs[] = { "lib/", "lib64/", "lib32/", NULL };
+ int i;
+
+ for (i = 0; dirs[i] != NULL; i++)
+ if (strstr(fn, dirs[i]) != NULL)
+ return 1;
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ char *rpmname;
+ unsigned char rpmlead[96];
+ struct rpmhead *h, *sigh;
+ char *nevr;
+ int filecnt;
+ char **filenames, **filemd5s, **filelinktos;
+ unsigned int *fileflags, *filemodes, *filerdevs, *filesizes, *fileverify, *filecolors;
+ int digestalgo = 1;
+ unsigned int *digestalgoarray;
+ int i, l, l2, l3;
+ int fd, nfd;
+ struct cfile *bfd;
+ struct cpiophys cph;
+ char *namebuf;
+ int namebufl;
+ char *np;
+ char buf[4096];
+ int c, skip;
+ char *prunelist = 0;
+ int cpiocnt = 0;
+ int skipped_notfound = 0;
+ int skipped_pruned = 0;
+ int skipped_unpatched = 0;
+ int skipped_badsize = 0;
+ int skipped_fileflags = 0;
+ int skipped_verifyflags = 0;
+ int skipped_multilib = 0;
+ int skipped_all = 0;
+ int pinfo = 0;
+ struct rpmlfile *files1 = 0;
+ int nfiles1 = 0;
+ char *nevr1 = 0;
+ struct rpmlfile *files2 = 0;
+ int nfiles2 = 0;
+ char *nevr2 = 0;
+ struct rpmhead *h2 = 0;
+ char *seqfile = 0;
+ MD5_CTX seqmd5;
+ unsigned char seqmd5res[16];
+
+ unsigned char *oldcpio = 0;
+ bsuint oldcpiolen = 0;
+ unsigned char *newcpio = 0;
+ bsuint newcpiolen = 0;
+
+ bsuint cpiopos, oldadjust;
+ unsigned int *offadjs = 0;
+ unsigned int offadjn = 0;
+
+ char *payformat;
+ MD5_CTX fullmd5;
+ unsigned char fullmd5res[16];
+ unsigned int fullsize = 0;
+
+ struct cfile *newbz;
+
+ struct instr *instr = 0;
+ int instrlen = 0;
+
+ int verbose = 0;
+ int version = 3;
+ struct deltarpm d;
+ unsigned char **indatalist = 0;
+ int rpmonly = 0;
+ int alone = 0;
+ FILE *vfp = 0;
+
+ char *compopt = 0;
+ int paycomp = CFILE_COMP_XX;
+ int addblkcomp = CFILE_COMP_BZ;
+ int targetcomp = CFILE_COMP_XX;
+ char *payloadflags;
+
+ bsuint stream = 0;
+
+ memset(&d, 0, sizeof(d));
+ memset(&sd, 0, sizeof(sd));
+ while ((c = getopt(argc, argv, "vV:prl:s:z:um:")) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ prunelist = optarg;
+ break;
+ case 'u':
+ alone = 1;
+ break;
+ case 's':
+ seqfile = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'V':
+ version = atoi(optarg);
+ break;
+ case 'p':
+ pinfo = 1;
+ break;
+ case 'r':
+ rpmonly = 1;
+ break;
+ case 'z':
+ compopt = optarg;
+ break;
+ case 'm':
+ stream = atoi(optarg) * (1024 * 256);
+ break;
+ default:
+ fprintf(stderr, "usage: makedeltarpm [-l <file>] [-s seq] oldrpm newrpm deltarpm\n");
+ exit(1);
+ }
+ }
+ if (verbose)
+ vfp = !strcmp("-", argv[argc - 1]) ? stderr : stdout;
+ if (compopt)
+ {
+ char *c2 = strchr(compopt, ',');
+ if (c2)
+ *c2++ = 0;
+ if (*compopt && strcmp(compopt, "rpm") != 0)
+ paycomp = str2comp(compopt);
+ if (c2)
+ {
+ if (!strcmp(c2, "off") != 0)
+ addblkcomp = -1;
+ else
+ addblkcomp = str2comp(c2);
+ }
+ }
+ if (prunelist)
+ read_prunelist(prunelist);
+
+ if (argc - optind != (pinfo ? 5 : 3) - alone)
+ {
+ fprintf(stderr, "usage: makedeltarpm [-l <file>] [-s seq] oldrpm newrpm deltarpm\n");
+ exit(1);
+ }
+ if (version != 1 && version != 2 && version != 3)
+ {
+ fprintf(stderr, "illegal version: %d\n", version);
+ exit(1);
+ }
+ if (pinfo)
+ {
+ FILE *pfp;
+ int pfd;
+
+ pfp = fopen(argv[argc - 5 + alone], "r");
+ if (!pfp)
+ {
+ perror(argv[argc - 5 + alone]);
+ exit(1);
+ }
+ nevr1 = rpmlread(pfp, argv[argc - 5 + alone], 0, &files1, &nfiles1);
+ fclose(pfp);
+ pfd = open(argv[argc - 4 + alone], O_RDONLY);
+ if (pfd < 0)
+ {
+ perror(argv[argc - 4 + alone]);
+ exit(1);
+ }
+ if (read(pfd, rpmlead, 4) != 4)
+ {
+ fprintf(stderr, "%s: not a rpm or rpmlist\n", argv[argc - 4 + alone]);
+ exit(1);
+ }
+ if (rpmlead[0] != 0xed || rpmlead[1] != 0xab || rpmlead[2] != 0xee || rpmlead[3] != 0xdb)
+ {
+ pfp = fdopen(pfd, "r");
+ if (!pfp)
+ {
+ perror(argv[argc - 4 + alone]);
+ exit(1);
+ }
+ nevr2 = rpmlread(pfp, argv[argc - 4 + alone], 1, &files2, &nfiles2);
+ fclose(pfp);
+ }
+ else
+ {
+ if (read(pfd, rpmlead + 4, 92) != 92 || rpmlead[4] != 0x03 || rpmlead[0x4e] != 0 || rpmlead[0x4f] != 5)
+ {
+ fprintf(stderr, "%s: not a v3 rpm or not new header styles\n", argv[argc - 4 + alone]);
+ exit(1);
+ }
+ h2 = readhead(pfd, 1);
+ if (!h2)
+ {
+ fprintf(stderr, "could not read signature header\n");
+ exit(1);
+ }
+ free(h2);
+ h2 = readhead(pfd, 0);
+ if (!h2)
+ {
+ fprintf(stderr, "could not read header\n");
+ exit(1);
+ }
+ close(pfd);
+ nevr2 = headtofiles(h2, &files2, &nfiles2);
+ }
+ }
+
+ rpmMD5Init(&seqmd5);
+
+ /* open old rpm */
+ /* (if alone == 1, oldrpm == newrpm) */
+ rpmname = argv[argc - 3 + alone];
+ if (!strcmp(rpmname, "-"))
+ fd = 0;
+ else if ((fd = open(rpmname, O_RDONLY)) < 0)
+ {
+ perror(rpmname);
+ exit(1);
+ }
+ if (read(fd, rpmlead, 96) != 96 || rpmlead[0] != 0xed || rpmlead[1] != 0xab || rpmlead[2] != 0xee || rpmlead[3] != 0xdb)
+ {
+ fprintf(stderr, "%s: not a rpm\n", rpmname);
+ exit(1);
+ }
+ if (rpmlead[4] != 0x03 || rpmlead[0x4e] != 0 || rpmlead[0x4f] != 5)
+ {
+ fprintf(stderr, "%s: not a v3 rpm or not new header styles\n", rpmname);
+ exit(1);
+ }
+ sigh = readhead(fd, 1);
+ if (!sigh)
+ {
+ fprintf(stderr, "could not read signature header\n");
+ exit(1);
+ }
+ h = readhead(fd, 0);
+ if (!h)
+ {
+ fprintf(stderr, "could not read header\n");
+ exit(1);
+ }
+ nevr = headtonevr(h);
+
+ if (alone && rpmonly)
+ {
+ /* this mode just updates the lead and signatures, no need to do a real diff */
+ if (verbose)
+ fprintf(vfp, "reading rpm header...\n");
+ rpmMD5Init(&fullmd5);
+ /* don't have to compare, write a "no diff" deltarpm */
+ d.h = 0;
+ d.name = argv[argc - 1];
+ d.version = 0x444c5430 + version;
+ memcpy(d.rpmlead, rpmlead, 96);
+ d.leadl = 96 + 16 + sigh->cnt * 16 + sigh->dcnt;
+ d.lead = xmalloc(d.leadl);
+ memcpy(d.lead, rpmlead, 96);
+ memcpy(d.lead + 96, sigh->intro, 16);
+ memcpy(d.lead + 96 + 16, sigh->data, d.leadl - 96 - 16);
+ d.inn = d.outn = 0;
+ d.in = d.out = 0;
+ d.nevr = nevr;
+ d.seql = 16;
+ d.seq = xmalloc(d.seql);
+ /* calculate seqmd5 and targetmd5 */
+ rpmMD5Update(&fullmd5, d.lead , d.leadl);
+ rpmMD5Update(&fullmd5, h->intro , 16);
+ rpmMD5Update(&fullmd5, h->data, 16 * h->cnt + h->dcnt);
+ rpmMD5Update(&seqmd5, h->intro , 16);
+ rpmMD5Update(&seqmd5, h->data, 16 * h->cnt + h->dcnt);
+ fullsize = d.leadl + 16 + 16 * h->cnt + h->dcnt;
+ while ((l = read(fd, buf, sizeof(buf))) > 0)
+ {
+ rpmMD5Update(&fullmd5, (unsigned char *)buf, l);
+ rpmMD5Update(&seqmd5, (unsigned char *)buf, l);
+ fullsize += l;
+ }
+ if (l == -1)
+ {
+ fprintf(stderr, "read error\n");
+ exit(1);
+ }
+ rpmMD5Final(d.seq, &seqmd5);
+ rpmMD5Final(d.targetmd5, &fullmd5);
+ targetcomp = CFILE_COMP_UN;
+ if (paycomp == CFILE_COMP_XX)
+ paycomp = CFILE_COMP_GZ; /* no need for better compression */
+ if (addblkcomp == CFILE_COMP_XX)
+ addblkcomp = CFILE_COMP_GZ;
+ d.targetsize = fullsize;
+ d.targetcomp = targetcomp;
+ d.targetcomppara = 0;
+ d.targetcompparalen = 0;
+ d.targetnevr = headtonevr(h);
+ d.compheadlen = 16 + 16 * h->cnt + h->dcnt;
+ d.offadjn = 0;
+ d.offadjs = 0;
+ d.payformatoff = 0;
+ d.outlen = 0;
+ d.deltacomp = paycomp;
+ d.addblk = 0;
+ d.addblklen = 0;
+ if (verbose)
+ fprintf(vfp, "writing delta rpm...\n");
+ writedeltarpm(&d, 0);
+ if (seqfile)
+ write_seqfile(&d, seqfile);
+ sigh = xfree(sigh);
+ h = xfree(h);
+ d.seq = xfree(d.seq);
+ d.seql = 0;
+ d.lead = xfree(d.lead);
+ d.leadl = 0;
+ seq = xfree(seq);
+ d.targetnevr = xfree(d.targetnevr);
+ exit(0);
+ }
+
+ if (!alone)
+ sigh = xfree(sigh);
+
+ if (pinfo)
+ {
+ if (strcmp(nevr, nevr1) != 0)
+ {
+ fprintf(stderr, "pinfo rpmlist1 (%s) does not match rpm (%s)\n", nevr1, nevr);
+ exit(1);
+ }
+ if (strcmp(nevr, nevr2) != 0)
+ {
+ fprintf(stderr, "pinfo rpmlist2 (%s) does not match rpm (%s)\n", nevr2, nevr);
+ exit(1);
+ }
+ }
+ filenames = headexpandfilelist(h, &filecnt);
+ fileflags = headint32(h, TAG_FILEFLAGS, (int *)0);
+ filemd5s = headstringarray(h, TAG_FILEMD5S, (int *)0);
+ filerdevs = headint16(h, TAG_FILERDEVS, (int *)0);
+ filesizes = headint32(h, TAG_FILESIZES, (int *)0);
+ filemodes = headint16(h, TAG_FILEMODES, (int *)0);
+ fileverify = headint32(h, TAG_FILEVERIFY, (int *)0);
+ filelinktos = headstringarray(h, TAG_FILELINKTOS, (int *)0);
+ filecolors = headint32(h, TAG_FILECOLORS, (int *)0);
+
+ if ((digestalgoarray = headint32(h, TAG_FILEDIGESTALGO, (int *)0)))
+ {
+ digestalgo = digestalgoarray[0];
+ free(digestalgoarray);
+ }
+ if (digestalgo != 1 && digestalgo != 8)
+ {
+ fprintf(stderr, "Unknown digest type: %d\n", digestalgo);
+ exit(1);
+ }
+
+/***************************************************************************/
+
+ if (alone)
+ {
+ if (verbose)
+ fprintf(vfp, "reading rpm...\n");
+ nfd = fd;
+ fd = -1;
+ d.h = h;
+ h = 0;
+ stream = 0; /* sorry! */
+ }
+ else
+ {
+ if (verbose)
+ fprintf(vfp, "reading new rpm...\n");
+ rpmname = argv[argc - 2];
+ if (!strcmp(rpmname, "-"))
+ nfd = 0;
+ else if ((nfd = open(rpmname, O_RDONLY)) < 0)
+ {
+ perror(rpmname);
+ exit(1);
+ }
+ if (read(nfd, rpmlead, 96) != 96 || rpmlead[0] != 0xed || rpmlead[1] != 0xab || rpmlead[2] != 0xee || rpmlead[3] != 0xdb)
+ {
+ fprintf(stderr, "%s: not a rpm\n", rpmname);
+ exit(1);
+ }
+ if (rpmlead[4] != 0x03 || rpmlead[0x4e] != 0 || rpmlead[0x4f] != 5)
+ {
+ fprintf(stderr, "%s: not a v3 rpm or not new header styles\n", rpmname);
+ exit(1);
+ }
+ sigh = readhead(nfd, 1);
+ if (!sigh)
+ {
+ fprintf(stderr, "could not read signature header\n");
+ exit(1);
+ }
+ d.h = readhead(nfd, 0);
+ if (!d.h)
+ {
+ fprintf(stderr, "could not read header\n");
+ exit(1);
+ }
+ }
+ rpmMD5Init(&fullmd5);
+ rpmMD5Update(&fullmd5, rpmlead, 96);
+ rpmMD5Update(&fullmd5, sigh->intro, 16);
+ rpmMD5Update(&fullmd5, sigh->data, sigh->cnt * 16 + sigh->dcnt);
+ rpmMD5Update(&fullmd5, d.h->intro, 16);
+ rpmMD5Update(&fullmd5, d.h->data, d.h->cnt * 16 + d.h->dcnt);
+ if (rpmonly)
+ {
+ /* add new header to cpio */
+ addtocpio(&newcpio, &newcpiolen, d.h->intro, 16);
+ addtocpio(&newcpio, &newcpiolen, d.h->data, 16 * d.h->cnt + d.h->dcnt);
+ }
+ fullsize = 96 + 16 + sigh->cnt * 16 + sigh->dcnt + 16 + d.h->cnt * 16 + d.h->dcnt;
+ newbz = cfile_open(CFILE_OPEN_RD, nfd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, (cfile_ctxup)rpmMD5Update, &fullmd5);
+ if (!newbz)
+ {
+ fprintf(stderr, "payload open failed\n");
+ exit(1);
+ }
+ if (cfile_detect_rsync(newbz))
+ {
+ fprintf(stderr, "detect_rsync failed\n");
+ exit(1);
+ }
+ targetcomp = newbz->comp;
+ if ((payloadflags = headstring(d.h, TAG_PAYLOADFLAGS)) != 0)
+ if (*payloadflags >= '1' && *payloadflags <= '9')
+ targetcomp = cfile_setlevel(targetcomp, *payloadflags - '0');
+ if (paycomp == CFILE_COMP_XX)
+ paycomp = targetcomp;
+ if (addblkcomp == CFILE_COMP_XX)
+ addblkcomp = targetcomp;
+
+ if (stream)
+ {
+ memset(&sd, 0, sizeof(sd));
+ sd.xnewdata = newcpio;
+ sd.xnewdatal = newcpiolen;
+ sd.newf = newbz;
+ sd.bsize = stream;
+ sd.old = xmalloc(sd.bsize);
+ sd.new = xmalloc(sd.bsize);
+ if (addblkcomp != -1)
+ sd.cfa = cfile_open(CFILE_OPEN_WR, CFILE_IO_ALLOC, &d.addblk, addblkcomp, CFILE_LEN_UNLIMITED, 0, 0);
+ sd.cfi = cfile_open(CFILE_OPEN_WR, CFILE_IO_ALLOC, &d.indata, CFILE_COMP_UN, CFILE_LEN_UNLIMITED, 0, 0);
+ oldcpio = (void *)&sd;
+ oldcpiolen = 0;
+ sd.stepd = mkdiff_step_setup(DELTAMODE_HASH | (addblkcomp == -1 ? DELTAMODE_NOADDBLK : 0));
+ }
+ else
+ {
+ while ((l = newbz->read(newbz, buf, sizeof(buf))) > 0)
+ addtocpio(&newcpio, &newcpiolen, (unsigned char *)buf, l);
+ if (l < 0)
+ {
+ fprintf(stderr, "payload read failed\n");
+ exit(1);
+ }
+ }
+
+/***************************************************************************/
+
+ if (rpmonly)
+ {
+ /* add old header to cpio */
+ addtocpio(&oldcpio, &oldcpiolen, h->intro, 16);
+ addtocpio(&oldcpio, &oldcpiolen, h->data, 16 * h->cnt + h->dcnt);
+ rpmMD5Update(&seqmd5, h->intro, 16);
+ rpmMD5Update(&seqmd5, h->data, 16 * h->cnt + h->dcnt);
+ bfd = cfile_open(CFILE_OPEN_RD, fd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, (cfile_ctxup)rpmMD5Update, &seqmd5);
+ }
+ else if (alone)
+ bfd = cfile_open(CFILE_OPEN_RD, CFILE_IO_BUFFER, newcpio, CFILE_COMP_UN, newcpiolen, 0, 0);
+ else
+ bfd = cfile_open(CFILE_OPEN_RD, fd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, 0, 0);
+ if (!bfd)
+ {
+ fprintf(stderr, "payload open failed\n");
+ exit(1);
+ }
+ if (verbose && !alone)
+ fprintf(vfp, "reading old rpm...\n");
+ if (rpmonly)
+ {
+ while ((l = bfd->read(bfd, buf, sizeof(buf))) > 0)
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)buf, l);
+ }
+ else
+ {
+ namebufl = 1;
+ namebuf = xmalloc(namebufl);
+ cpiopos = oldcpiolen;
+ oldadjust = oldcpiolen;
+ for (;;)
+ {
+ unsigned int size, nsize, lsize, nlink, rdev, hsize;
+
+ if (bfd->read(bfd, &cph, sizeof(cph)) != sizeof(cph))
+ {
+ fprintf(stderr, "payload read failed (header)\n");
+ exit(1);
+ }
+ cpiopos += sizeof(cph);
+ if (memcmp(cph.magic, "070701", 6))
+ {
+ fprintf(stderr, "bad cpio archive\n");
+ exit(1);
+ }
+ size = cpion(cph.filesize);
+ nsize = cpion(cph.namesize);
+ nlink = cpion(cph.nlink);
+ nsize += (4 - ((nsize + 2) & 3)) & 3;
+ if (nsize > namebufl)
+ {
+ namebuf = xrealloc(namebuf, nsize);
+ namebufl = nsize;
+ }
+ if (bfd->read(bfd, namebuf, nsize) != nsize)
+ {
+ fprintf(stderr, "payload read failed (name)\n");
+ exit(1);
+ }
+ cpiopos += nsize;
+ namebuf[nsize - 1] = 0;
+ if (!strcmp(namebuf, "TRAILER!!!"))
+ break;
+ cpiocnt++;
+ np = namebuf;
+ if (*np == '.' && np[1] == '/')
+ np += 2;
+ skip = 1;
+ /* look it up in the header */
+ for (i = 0; i < filecnt; i++)
+ if (!strcmp(filenames[i] + (filenames[i][0] == '/' ? 1 : 0), np))
+ break;
+ rdev = lsize = 0;
+ if (i == filecnt)
+ {
+ if (verbose > 1)
+ fprintf(vfp, "%s not found in rpm header\n", np);
+ skipped_notfound++;
+ }
+ else if (prunes && is_pruned(np))
+ {
+ if (verbose > 1)
+ fprintf(vfp, "skipping %s: pruned\n", np);
+ skipped_pruned++;
+ }
+ else if (pinfo && S_ISREG(filemodes[i]) && is_unpatched(np, files1, nfiles1, files2, nfiles2, filemd5s[i]))
+ {
+ if (verbose > 1)
+ fprintf(vfp, "skipping %s: unpatched but different\n", np);
+ skipped_unpatched++;
+ }
+ else if (S_ISREG(filemodes[i]))
+ {
+ if (size != filesizes[i])
+ {
+ if (verbose > 1)
+ fprintf(vfp, "skipping %s: size missmatch\n", np);
+ skipped_badsize++;
+ }
+ else if ((fileflags[i] & (FILE_CONFIG|FILE_MISSINGOK|FILE_GHOST)) != 0)
+ {
+ if (verbose > 1)
+ fprintf(vfp, "skipping %s: bad file flags\n", np);
+ skipped_fileflags++;
+ }
+ else if ((fileverify[i] & (VERIFY_MD5|VERIFY_FILESIZE)) != (VERIFY_MD5|VERIFY_FILESIZE))
+ {
+ if (verbose > 1)
+ fprintf(vfp, "skipping %s: bad verify flags %x\n", np, fileverify[i]);
+ skipped_verifyflags++;
+ }
+ else if (filecolors && (filecolors[i] & (RPMFC_ELF32 | RPMFC_ELF64)) != 0 && !in_multilib_dir(np))
+ {
+ if (verbose > 1)
+ fprintf(vfp, "skipping %s: colored file in non-multilib dir\n", np);
+ skipped_multilib++;
+ }
+ else
+ {
+ if (verbose > 1)
+ fprintf(vfp, "USING FILE %s\n", np);
+ lsize = size;
+ skip = 0;
+ }
+ }
+ else if (S_ISLNK(filemodes[i]))
+ {
+ if (verbose > 1)
+ fprintf(vfp, "USING SYMLINK %s\n", np);
+ lsize = strlen(filelinktos[i]);
+ skip = 0;
+ }
+ else
+ {
+ if (verbose > 1)
+ fprintf(vfp, "USING ELEMENT %s\n", np);
+ if (S_ISBLK(filemodes[i]) || S_ISCHR(filemodes[i]))
+ rdev = filerdevs[i];
+ skip = 0;
+ }
+
+ if (i == filecnt)
+ hsize = 0;
+ else
+ {
+ hsize = 2 + strlen(np) + 1;
+ hsize += (4 - ((hsize + 2) & 3)) & 3;
+ hsize += S_ISREG(filemodes[i]) ? filesizes[i] : S_ISLNK(filemodes[i]) ? strlen(filelinktos[i]) : 0;
+ hsize += (4 - (hsize & 3)) & 3;
+ }
+ l = nsize + size;
+ l += (4 - (l & 3)) & 3;
+
+ if (!skip)
+ {
+ unsigned char cpiobuf[110 + 3];
+ int ns = strlen(np);
+ if (oldcpiolen != cpiopos - sizeof(cph) - nsize)
+ {
+oaretry1:
+ if ((offadjn & 15) == 0)
+ offadjs = xrealloc2(offadjs, offadjn + 16, 2 * sizeof(unsigned int));
+ if (oldcpiolen - oldadjust >= 0x80000000)
+ {
+ offadjs[2 * offadjn] = 0x7fffffff;
+ offadjs[2 * offadjn + 1] = 0;
+ oldadjust += 0x7fffffff;
+ offadjn++;
+ goto oaretry1;
+ }
+ offadjs[2 * offadjn] = oldcpiolen - oldadjust;
+ oldadjust = oldcpiolen;
+ if (cpiopos - sizeof(cph) - nsize >= oldcpiolen)
+ {
+ drpmuint a = cpiopos - sizeof(cph) - nsize - oldcpiolen;
+ if (a >= 0x80000000)
+ {
+ offadjs[2 * offadjn + 1] = 0x7fffffff;
+ cpiopos -= 0x7fffffff;
+ offadjn++;
+ goto oaretry1;
+ }
+ offadjs[2 * offadjn + 1] = a;
+ }
+ else
+ {
+ drpmuint a = oldcpiolen - (cpiopos - sizeof(cph) - nsize);
+ if (a >= 0x80000000)
+ {
+ offadjs[2 * offadjn + 1] = (unsigned int)-((int)0x7fffffff);
+ cpiopos += 0x7fffffff;
+ offadjn++;
+ goto oaretry1;
+ }
+ offadjs[2 * offadjn + 1] = (unsigned int)(-(int)a);
+ }
+ offadjn++;
+ cpiopos = oldcpiolen + sizeof(cph) + nsize;
+ }
+ sprintf((char *)cpiobuf, "07070100000000%08x00000000000000000000000100000000%08x0000000000000000%08x%08x%08x00000000./", filemodes[i], lsize, devmajor(rdev), devminor(rdev), ns + 3);
+ addtocpio(&oldcpio, &oldcpiolen, cpiobuf, 112);
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)np, ns + 1);
+ ns += 3 - 2;
+ for (; ns & 3 ; ns++)
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)"", 1);
+ rpmMD5Update(&seqmd5, (unsigned char *)np, strlen(np) + 1);
+ rpmMD5Update32(&seqmd5, filemodes[i]);
+ rpmMD5Update32(&seqmd5, lsize);
+ rpmMD5Update32(&seqmd5, rdev);
+ if (S_ISLNK(filemodes[i]))
+ {
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)filelinktos[i], lsize);
+ for (; lsize & 3 ; lsize++)
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)"", 1);
+ skip = 1;
+ rpmMD5Update(&seqmd5, (unsigned char *)filelinktos[i], strlen(filelinktos[i]) + 1);
+ }
+ if (S_ISREG(filemodes[i]) && lsize)
+ {
+ unsigned char fmd5[32];
+ if (digestalgo == 1)
+ {
+ parsemd5(filemd5s[i], fmd5);
+ rpmMD5Update(&seqmd5, fmd5, 16);
+ }
+ else
+ {
+ parsesha256(filemd5s[i], fmd5);
+ rpmMD5Update(&seqmd5, fmd5, 32);
+ }
+ }
+ addtoseq(i);
+ }
+ else
+ skipped_all++;
+ l = l2 = size;
+ while (l > 0)
+ {
+ l3 = l > sizeof(buf) ? sizeof(buf) : l;
+ if (bfd->read(bfd, buf, l3) != l3)
+ {
+ fprintf(stderr, "payload read failed (data)\n");
+ exit(1);
+ }
+ cpiopos += l3;
+ if (!skip)
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)buf, l3);
+ l -= l3;
+ }
+ if ((l2 & 3) != 0)
+ {
+ l2 = 4 - (l2 & 3);
+ if (bfd->read(bfd, buf, l2) != l2)
+ {
+ fprintf(stderr, "payload read failed (pad)\n");
+ exit(1);
+ }
+ cpiopos += l2;
+ if (!skip)
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)"\0\0\0", l2);
+ }
+ }
+ namebuf = xfree(namebuf);
+ namebufl = 0;
+ addtocpio(&oldcpio, &oldcpiolen, (unsigned char *)"07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000b00000000TRAILER!!!\0\0\0\0", 124);
+ if (verbose)
+ {
+ fprintf(vfp, "files used: %4d/%d = %.1f%%\n", (cpiocnt - skipped_all), cpiocnt, (cpiocnt - skipped_all) * 100. / (cpiocnt ? cpiocnt : 1));
+ fprintf(vfp, "files skipped: %4d/%d = %.1f%%\n", skipped_all, cpiocnt, skipped_all * 100. / (cpiocnt ? cpiocnt : 1));
+ if (skipped_notfound)
+ fprintf(vfp, " not found: %4d/%d = %.1f%%\n", skipped_notfound, skipped_all, skipped_notfound * 100. / skipped_all);
+ if (skipped_pruned)
+ fprintf(vfp, " pruned: %4d/%d = %.1f%%\n", skipped_pruned, skipped_all, skipped_pruned * 100. / skipped_all);
+ if (skipped_unpatched)
+ fprintf(vfp, " unpatched: %4d/%d = %.1f%%\n", skipped_unpatched, skipped_all, skipped_unpatched * 100. / skipped_all);
+ if (skipped_badsize)
+ fprintf(vfp, " bad size: %4d/%d = %.1f%%\n", skipped_badsize, skipped_all, skipped_badsize * 100. / skipped_all);
+ if (skipped_fileflags)
+ fprintf(vfp, " file flags: %4d/%d = %.1f%%\n", skipped_fileflags, skipped_all, skipped_fileflags * 100. / skipped_all);
+ if (skipped_verifyflags)
+ fprintf(vfp, " verify flags: %4d/%d = %.1f%%\n", skipped_verifyflags, skipped_all, skipped_verifyflags * 100. / skipped_all);
+ if (skipped_multilib)
+ fprintf(vfp, " colored-not-in-multidir: %4d/%d = %.1f%%\n", skipped_multilib, skipped_all, skipped_multilib * 100. / skipped_all);
+ }
+ addtoseq(-1);
+ if (verbose > 1)
+ {
+ fprintf(vfp, "sequence: ");
+ for (i = 0; i < (seqp + 1) / 2; i++)
+ fprintf(vfp, "%02x", seq[i]);
+ fprintf(vfp, "\n");
+ }
+ }
+ bfd->close(bfd);
+
+ if (stream)
+ {
+ /* finish */
+ sd.oldeof = 1;
+ addtocpio(&oldcpio, &oldcpiolen, 0, 0);
+ if (sd.cfa)
+ d.addblklen = sd.cfa->close(sd.cfa);
+ d.inlen = sd.cfi->close(sd.cfi);
+ sd.cfa = 0;
+ sd.cfi = 0;
+ instr = sd.instr;
+ sd.instr = 0;
+ instrlen = sd.instrlen;
+ sd.instrlen = 0;
+ mkdiff_step_free(sd.stepd);
+ oldcpio = 0;
+ }
+
+ /* close old rpm */
+ /* fd == -1 in "alone" mode */
+ if (fd != -1 && strcmp(argv[argc - 3 + alone], "-") != 0)
+ close(fd);
+
+ rpmMD5Final(seqmd5res, &seqmd5);
+
+ fileflags = xfree(fileflags);
+ filemd5s = xfree(filemd5s);
+ filerdevs = xfree(filerdevs);
+ filesizes = xfree(filesizes);
+ filemodes = xfree(filemodes);
+ fileverify = xfree(fileverify);
+ filelinktos = xfree(filelinktos);
+ filenames = xfree(filenames);
+ filecolors = xfree(filecolors);
+ h = xfree(h);
+
+ /* close new rpm */
+ fullsize += newbz->bytes;
+ if (newbz->close(newbz))
+ {
+ fprintf(stderr, "junk at end of payload\n");
+ exit(1);
+ }
+ if (strcmp(rpmname, "-") != 0)
+ close(nfd);
+ rpmMD5Final(fullmd5res, &fullmd5);
+
+/****************************************************************/
+
+ payformat = headstring(d.h, TAG_PAYLOADFORMAT);
+ if (!payformat || strcmp(payformat, "cpio") != 0)
+ {
+ fprintf(stderr, "payload format is not cpio\n");
+ exit(1);
+ }
+ if (!stream)
+ {
+ if (verbose)
+ fprintf(vfp, "creating diff...\n");
+ d.addblk = 0;
+ d.addblklen = 0;
+ mkdiff(DELTAMODE_HASH | (addblkcomp == -1 ? DELTAMODE_NOADDBLK : 0), oldcpio, oldcpiolen, newcpio, newcpiolen, &instr, &instrlen, (unsigned char **)0, (unsigned int *)0, (addblkcomp == CFILE_COMP_BZ ? &d.addblk : 0), (addblkcomp == CFILE_COMP_BZ ? &d.addblklen : 0), (unsigned char **)0, (unsigned int *)0);
+ }
+
+/****************************************************************/
+
+ if (verbose)
+ fprintf(vfp, "writing delta rpm...\n");
+ if (!stream && addblkcomp != -1 && addblkcomp != CFILE_COMP_BZ)
+ createaddblock(instr, instrlen, &d, oldcpio, newcpio, addblkcomp);
+ d.name = argv[argc - 1];
+ d.version = 0x444c5430 + version;
+ memcpy(d.rpmlead, rpmlead, 96);
+ d.leadl = 96 + 16 + sigh->cnt * 16 + sigh->dcnt;
+ d.lead = xmalloc(d.leadl);
+ memcpy(d.lead, rpmlead, 96);
+ memcpy(d.lead + 96, sigh->intro, 16);
+ memcpy(d.lead + 96 + 16, sigh->data, d.leadl - 96 - 16);
+ convertinstr(instr, instrlen, &d);
+ if (!stream)
+ indatalist = createindatalist(instr, instrlen, &d, newcpio);
+ d.nevr = nevr;
+ d.seql = 16 + (seqp + 1) / 2;
+ d.seq = xmalloc(d.seql);
+ memcpy(d.seq, seqmd5res, 16);
+ memcpy(d.seq + 16, seq, d.seql - 16);
+ memcpy(d.targetmd5, fullmd5res, 16);
+ d.targetnevr = headtonevr(d.h);
+ d.targetsize = fullsize;
+ d.targetcomp = targetcomp;
+ d.targetcomppara = 0;
+ d.targetcompparalen = 0;
+ d.compheadlen = rpmonly ? 16 + 16 * d.h->cnt + d.h->dcnt : 0;
+ d.offadjn = offadjn;
+ d.offadjs = offadjs;
+ d.payformatoff = payformat - (char *)d.h->dp;
+ d.outlen = oldcpiolen;
+ if (rpmonly)
+ d.h = xfree(d.h);
+ d.deltacomp = paycomp;
+ writedeltarpm(&d, indatalist);
+ if (seqfile)
+ write_seqfile(&d, seqfile);
+ d.addblk = xfree(d.addblk);
+ d.addblklen = 0;
+ instr = xfree(instr);
+ instrlen = 0;
+ oldcpio = xfree(oldcpio);
+ newcpio = xfree(newcpio);
+ sigh = xfree(sigh);
+ d.h = xfree(d.h);
+ indatalist = xfree(indatalist);
+ d.indata = xfree(d.indata);
+ d.in = xfree(d.in);
+ d.out = xfree(d.out);
+ d.inn = d.outn = 0;
+ d.seq = xfree(d.seq);
+ d.seql = 0;
+ d.lead = xfree(d.lead);
+ d.leadl = 0;
+ nevr = xfree(nevr);
+ seq = xfree(seq);
+ sd.old = xfree(sd.old);
+ sd.new = xfree(sd.new);
+ offadjs = xfree(offadjs);
+ d.targetnevr = xfree(d.targetnevr);
+ exit(0);
+}
+