summaryrefslogtreecommitdiff
path: root/readdeltarpm.c
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-11-01 13:04:04 -0700
committerAnas Nashif <anas.nashif@intel.com>2012-11-01 13:04:04 -0700
commit9e0ff569ee66e4031b697bbfab669412cf90cb8a (patch)
tree63423730ef69bdd076ad9a131199c57e8b01f32c /readdeltarpm.c
downloaddeltarpm-upstream.tar.gz
deltarpm-upstream.tar.bz2
deltarpm-upstream.zip
Imported Upstream version 3.5.gitupstream/3.5.gitupstream
Diffstat (limited to 'readdeltarpm.c')
-rw-r--r--readdeltarpm.c548
1 files changed, 548 insertions, 0 deletions
diff --git a/readdeltarpm.c b/readdeltarpm.c
new file mode 100644
index 0000000..9cfec87
--- /dev/null
+++ b/readdeltarpm.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2005 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 <bzlib.h>
+#include <zlib.h>
+#include <lzma.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "md5.h"
+#include "rpmhead.h"
+#include "cfile.h"
+#include "deltarpm.h"
+
+/*****************************************************************
+ * fileblock handling, maintain everything we want to know about the
+ * filelist
+ *
+ */
+
+int
+headtofb(struct rpmhead *h, struct fileblock *fb)
+{
+ unsigned int *digestalgoarray;
+ fb->h = h;
+ fb->filelinktos = fb->filemd5s = 0;
+ fb->filemodes = fb->filesizes = 0;
+ fb->filenames = headexpandfilelist(h, &fb->cnt);
+ if (!fb->filenames)
+ {
+ fb->cnt = 0;
+ return 0;
+ }
+ fb->filemodes = headint16(h, TAG_FILEMODES, (int *)0);
+ fb->filesizes = headint32(h, TAG_FILESIZES, (int *)0);
+ fb->filerdevs = headint16(h, TAG_FILERDEVS, (int *)0);
+ fb->filelinktos = headstringarray(h, TAG_FILELINKTOS, (int *)0);
+ fb->filemd5s = headstringarray(h, TAG_FILEMD5S, (int *)0);
+ fb->digestalgo = 1;
+ if ((digestalgoarray = headint32(h, TAG_FILEDIGESTALGO, (int *)0)))
+ {
+ fb->digestalgo = digestalgoarray[0];
+ free(digestalgoarray);
+ }
+ if (fb->digestalgo != 1 && fb->digestalgo != 8)
+ {
+ fprintf(stderr, "Unknown digest type: %d\n", fb->digestalgo);
+ exit(1);
+ }
+ return 0;
+}
+
+/*****************************************************************
+ * sequence handling, uncompress the sequence string, check if
+ * it matches the installed rpm header, check files if requested.
+ */
+
+struct seqdescr *
+expandseq(unsigned char *seq, int seql, int *nump, struct fileblock *fb, int (*checkfunc)(char *, int, unsigned char *, unsigned int))
+{
+ unsigned char *s;
+ char *fn;
+ int *res;
+ int i, n, n2, num, nib, shi, tog, jump, pos;
+ unsigned int rdev, lsize;
+ MD5_CTX seqmd5;
+ unsigned char seqmd5res[16];
+ struct seqdescr *sd;
+ drpmuint off;
+ unsigned char fmd5[32];
+ int error = 0;
+
+ n = num = nib = shi = jump = pos = 0;
+ tog = 1;
+
+ res = xmalloc2(fb->cnt, sizeof(unsigned int));
+ seql -= 16;
+ for (i = 0, s = seq + 16; i < seql; )
+ {
+ if (!nib)
+ n2 = (*s >> 4);
+ else
+ {
+ n2 = (*s & 0x0f);
+ s++;
+ i++;
+ }
+ nib ^= 1;
+ if (n2 & 8)
+ {
+ n2 ^= 8;
+ if (shi)
+ n2 <<= shi;
+ n |= n2;
+ shi += 3;
+ continue;
+ }
+ if (shi)
+ n2 <<= shi;
+ shi = 0;
+ n2 |= n;
+ n = 0;
+ if (jump)
+ {
+ jump = 0;
+ pos = n2;
+ tog = 1;
+ continue;
+ }
+ if (n2 == 0)
+ {
+ jump = 1;
+ continue;
+ }
+ if (!tog)
+ {
+ pos += n2;
+ tog = 1;
+ continue;
+ }
+ for (; n2 > 0; n2--)
+ {
+ if (num >= fb->cnt || pos >= fb->cnt)
+ {
+ fprintf(stderr, "corrupt delta: bad sequence\n");
+ exit(1);
+ }
+ res[num++] = pos++;
+ }
+ tog = 0;
+ }
+ if (shi)
+ {
+ fprintf(stderr, "corrupt delta: bad sequence\n");
+ exit(1);
+ }
+ res = xrealloc2(res, num, sizeof(unsigned int));
+ sd = xmalloc2(num + 1, sizeof(*sd));
+ if (nump)
+ *nump = num + 1;
+ rpmMD5Init(&seqmd5);
+ off = 0;
+ for (n = 0; n < num; n++)
+ {
+ i = sd[n].i = res[n];
+ lsize = rdev = 0;
+ if (S_ISREG(fb->filemodes[i]))
+ lsize = fb->filesizes[i];
+ else if (S_ISLNK(fb->filemodes[i]))
+ lsize = strlen(fb->filelinktos[i]);
+ if (S_ISBLK(fb->filemodes[i]) || S_ISCHR(fb->filemodes[i]))
+ rdev = fb->filerdevs[i];
+ fn = fb->filenames[i];
+ if (*fn == '/')
+ fn++;
+ rpmMD5Update(&seqmd5, (unsigned char *)fn, strlen(fn) + 1);
+ rpmMD5Update32(&seqmd5, fb->filemodes[i]);
+ rpmMD5Update32(&seqmd5, lsize);
+ rpmMD5Update32(&seqmd5, rdev);
+ sd[n].cpiolen = 110 + 2 + strlen(fn) + 1;
+ if (sd[n].cpiolen & 3)
+ sd[n].cpiolen += 4 - (sd[n].cpiolen & 3);
+ sd[n].datalen = lsize;
+ if (sd[n].datalen & 3)
+ sd[n].datalen += 4 - (sd[n].datalen & 3);
+ if (S_ISLNK(fb->filemodes[i]))
+ rpmMD5Update(&seqmd5, (unsigned char *)fb->filelinktos[i], strlen(fb->filelinktos[i]) + 1);
+ else if (S_ISREG(fb->filemodes[i]) && lsize)
+ {
+ if (fb->digestalgo == 1)
+ parsemd5(fb->filemd5s[i], fmd5);
+ else
+ parsesha256(fb->filemd5s[i], fmd5);
+ if (checkfunc && checkfunc(fb->filenames[i], fb->digestalgo, fmd5, lsize))
+ error = 1;
+ if (fb->digestalgo == 1)
+ rpmMD5Update(&seqmd5, fmd5, 16);
+ else
+ rpmMD5Update(&seqmd5, fmd5, 32);
+ }
+ sd[n].off = off;
+ off += sd[n].cpiolen + sd[n].datalen;
+ sd[n].f = 0;
+ }
+ sd[n].i = -1;
+ sd[n].cpiolen = 124;
+ sd[n].datalen = 0;
+ sd[n].off = off;
+ sd[n].f = 0;
+ rpmMD5Final(seqmd5res, &seqmd5);
+ free(res);
+ if (memcmp(seqmd5res, seq, 16) || error)
+ {
+ fprintf(stderr, "delta does not match installed data\n");
+ exit(1);
+ }
+ return sd;
+}
+
+static unsigned int bzread4(struct cfile *bfp)
+{
+ unsigned char d[4];
+ if (bfp->read(bfp, d, 4) != 4)
+ {
+ perror("bzread4 error");
+ exit(1);
+ }
+ return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+}
+
+void
+readdeltarpm(char *n, struct deltarpm *d, struct cfile **cfp)
+{
+ int dfd;
+ struct cfile *bfp;
+ unsigned int nevrl;
+ drpmuint off;
+ int i;
+
+ memset((char *)d, 0, sizeof(*d));
+ d->name = n;
+ if (!strcmp(n, "-"))
+ dfd = 0;
+ else if ((dfd = open(n, O_RDONLY)) < 0)
+ {
+ perror(n);
+ exit(1);
+ }
+ if (xread(dfd, d->rpmlead, 12) != 12)
+ {
+ fprintf(stderr, "%s: not a delta rpm\n", n);
+ exit(1);
+ }
+ if (d->rpmlead[0] == 'd' && d->rpmlead[1] == 'r' && d->rpmlead[2] == 'p' && d->rpmlead[3] == 'm')
+ {
+ unsigned char *p;
+ d->version = (d->rpmlead[4] << 24) | (d->rpmlead[5] << 16) | (d->rpmlead[6] << 8) | d->rpmlead[7];
+ if ((d->version & 0xffffff00) != 0x444c5400)
+ {
+ fprintf(stderr, "%s: not a delta rpm\n", n);
+ exit(1);
+ }
+ if (d->version != 0x444c5431 && d->version != 0x444c5432 && d->version != 0x444c5433)
+ {
+ fprintf(stderr, "%s: unsupported version: %c\n", n, (d->version & 255));
+ exit(1);
+ }
+ nevrl = (d->rpmlead[8] << 24) | (d->rpmlead[9] << 16) | (d->rpmlead[10] << 8) | d->rpmlead[11];
+ d->targetnevr = xmalloc(nevrl + 4); /* also room for 4 bytes addblklen */
+ if (xread(dfd, d->targetnevr, nevrl + 4) != nevrl + 4)
+ {
+ fprintf(stderr, "%s: read error add data\n", n);
+ exit(1);
+ }
+ p = (unsigned char *)d->targetnevr + nevrl;
+ d->addblklen = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ d->targetnevr[nevrl] = 0;
+ if (d->addblklen)
+ {
+ d->addblk = xmalloc(d->addblklen);
+ if (xread(dfd, d->addblk, d->addblklen) != d->addblklen)
+ {
+ fprintf(stderr, "%s: read error add data\n", n);
+ exit(1);
+ }
+ }
+ d->h = 0;
+ if ((bfp = cfile_open(CFILE_OPEN_RD, dfd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, 0, 0)) == 0)
+ {
+ fprintf(stderr, "%s: payload open failed\n", n);
+ exit(1);
+ }
+ }
+ else
+ {
+ if (d->rpmlead[0] != 0xed || d->rpmlead[1] != 0xab || d->rpmlead[2] != 0xee || d->rpmlead[3] != 0xdb)
+ {
+ fprintf(stderr, "%s: not a delta rpm\n", n);
+ exit(1);
+ }
+ if (xread(dfd, d->rpmlead + 12, 96 - 12) != 96 - 12)
+ {
+ fprintf(stderr, "%s: not a delta rpm\n", n);
+ exit(1);
+ }
+ if (d->rpmlead[4] != 0x03 || d->rpmlead[0x4e] != 0 || d->rpmlead[0x4f] != 5)
+ {
+ fprintf(stderr, "%s: not a v3 rpm or not new header styles\n", n);
+ exit(1);
+ }
+ d->h = readhead(dfd, 1);
+ if (!d->h)
+ {
+ fprintf(stderr, "%s: could not read signature header\n", n);
+ exit(1);
+
+ }
+ free(d->h);
+ d->h = readhead(dfd, 0);
+ if (!d->h)
+ {
+ fprintf(stderr, "%s: could not read header\n", n);
+ exit(1);
+ }
+ d->targetnevr = headtonevr(d->h);
+ if ((bfp = cfile_open(CFILE_OPEN_RD, dfd, 0, CFILE_COMP_XX, CFILE_LEN_UNLIMITED, 0, 0)) == 0)
+ {
+ fprintf(stderr, "%s: payload open failed\n", n);
+ exit(1);
+ }
+ d->addblklen = 0;
+ }
+ d->deltacomp = bfp->comp;
+ d->version = bzread4(bfp);
+ if ((d->version & 0xffffff00) != 0x444c5400)
+ {
+ fprintf(stderr, "%s: not a delta rpm\n", n);
+ exit(1);
+ }
+ if (d->version != 0x444c5431 && d->version != 0x444c5432 && d->version != 0x444c5433)
+ {
+ fprintf(stderr, "%s: unsupported version: %c\n", n, (d->version & 255));
+ exit(1);
+ }
+ if (!d->h && d->version < 0x444c5433)
+ {
+ fprintf(stderr, "%s: rpm only deltarpm with old version\n", n);
+ exit(1);
+ }
+ nevrl = bzread4(bfp);
+ d->nevr = xmalloc(nevrl + 1);
+ d->nevr[nevrl] = 0;
+ if (bfp->read(bfp, d->nevr, nevrl) != nevrl)
+ {
+ fprintf(stderr, "%s: read error nevr\n", n);
+ exit(1);
+ }
+ d->seql = bzread4(bfp);
+ if (d->seql < 16)
+ {
+ fprintf(stderr, "%s: corrupt delta\n", n);
+ exit(1);
+ }
+ d->seq = xmalloc(d->seql);
+ if (bfp->read(bfp, d->seq, d->seql) != d->seql)
+ {
+ fprintf(stderr, "%s: read error seq\n", n);
+ exit(1);
+ }
+ if (bfp->read(bfp, d->targetmd5, 16) != 16)
+ {
+ fprintf(stderr, "%s: read error md5\n", n);
+ exit(1);
+ }
+ d->targetcomppara = 0;
+ d->offadjn = 0;
+ d->offadjs = 0;
+ if (d->version != 0x444c5431)
+ {
+ d->targetsize = bzread4(bfp);
+ d->targetcomp = bzread4(bfp);
+ d->targetcompparalen = bzread4(bfp);
+ if (d->targetcompparalen)
+ {
+ d->targetcomppara = xmalloc(d->targetcompparalen);
+ if (bfp->read(bfp, d->targetcomppara, d->targetcompparalen) != d->targetcompparalen)
+ {
+ fprintf(stderr, "%s: read error comppara\n", n);
+ exit(1);
+ }
+ }
+ if (d->version != 0x444c5432)
+ {
+ d->compheadlen = bzread4(bfp);
+ d->offadjn = bzread4(bfp);
+ d->offadjs = 0;
+ if (d->offadjn)
+ {
+ d->offadjs = xmalloc2(d->offadjn, 2 * sizeof(unsigned int));
+ for (i = 0; i < d->offadjn; i++)
+ d->offadjs[2 * i] = bzread4(bfp);
+ for (i = 0; i < d->offadjn; i++)
+ {
+ unsigned int a = bzread4(bfp);
+ if ((a & 0x80000000) != 0)
+ a = (unsigned int)(-(int)(a ^ 0x80000000));
+ d->offadjs[2 * i + 1] = a;
+ }
+ }
+ }
+ }
+ else
+ {
+ char *compressor = headstring(d->h, TAG_PAYLOADCOMPRESSOR);
+ if (compressor && !strcmp(compressor, "lzma"))
+ d->targetcomp = CFILE_COMP_LZMA;
+ else if (compressor && !strcmp(compressor, "bzip2"))
+ d->targetcomp = CFILE_COMP_BZ;
+ else
+ d->targetcomp = CFILE_COMP_GZ;
+ d->targetsize = 0;
+ d->targetcompparalen = 0;
+ }
+ d->leadl = bzread4(bfp);
+ if (d->leadl < 96 + 16)
+ {
+ fprintf(stderr, "%s: corrupt delta\n", n);
+ exit(1);
+ }
+ d->lead = xmalloc(d->leadl);
+ if (bfp->read(bfp, d->lead, d->leadl) != d->leadl)
+ {
+ fprintf(stderr, "%s: read error lead\n", n);
+ exit(1);
+ }
+ d->payformatoff = bzread4(bfp);
+ if (d->h && d->payformatoff > d->h->dcnt - 4)
+ {
+ fprintf(stderr, "%s: bad payformat offset\n", n);
+ exit(1);
+ }
+ d->inn = bzread4(bfp);
+ d->outn = bzread4(bfp);
+ d->in = xmalloc2(d->inn, 2 * sizeof(unsigned int));
+ d->out = xmalloc2(d->outn, 2 * sizeof(unsigned int));
+ d->paylen = 0;
+ for (i = 0; i < d->inn; i++)
+ d->in[2 * i] = bzread4(bfp);
+ for (i = 0; i < d->inn; i++)
+ {
+ d->in[2 * i + 1] = bzread4(bfp);
+ d->paylen += d->in[2 * i + 1];
+ }
+ for (i = 0; i < d->outn; i++)
+ d->out[2 * i] = bzread4(bfp);
+ for (i = 0; i < d->outn; i++)
+ {
+ d->out[2 * i + 1] = bzread4(bfp);
+ d->paylen += d->out[2 * i + 1];
+ }
+
+ d->outlen = 0;
+ if (d->version > 0x444c5432)
+ {
+#ifdef DELTARPM_64BIT
+ d->outlen = (drpmuint)bzread4(bfp) << 32;
+#else
+ if (bzread4(bfp) != 0)
+ {
+ fprintf(stderr, "%s: deltarpm needs support for archives > 4GB\n", n);
+ exit(1);
+ }
+#endif
+ }
+ d->outlen |= bzread4(bfp);
+ if (d->addblklen)
+ {
+ if (bzread4(bfp))
+ {
+ fprintf(stderr, "%s: two add data blocks\n", n);
+ exit(1);
+ }
+ }
+ else
+ {
+ d->addblklen = bzread4(bfp);
+ if (d->addblklen)
+ {
+ d->addblk = xmalloc(d->addblklen);
+ if (bfp->read(bfp, d->addblk, d->addblklen) != d->addblklen)
+ {
+ fprintf(stderr, "%s: read error add data\n", n);
+ exit(1);
+ }
+ }
+ }
+ d->inlen = 0;
+ if (d->version > 0x444c5432)
+ {
+#ifdef DELTARPM_64BIT
+ d->inlen = (drpmuint)bzread4(bfp) << 32;
+#else
+ if (bzread4(bfp) != 0)
+ {
+ fprintf(stderr, "%s: deltarpm needs support for archives > 4GB\n", n);
+ exit(1);
+ }
+#endif
+ }
+ d->inlen |= bzread4(bfp);
+ if (cfp)
+ *cfp = bfp;
+ else
+ {
+ d->indata = xmalloc(d->inlen);
+ if (bfp->read(bfp, d->indata, d->inlen) != d->inlen)
+ {
+ fprintf(stderr, "%s: read error deltarpm data\n", n);
+ exit(1);
+ }
+ bfp->close(bfp);
+ }
+ off = 0;
+ for (i = 0; i < d->inn; i++)
+ {
+ off += d->in[2 * i + 1];
+ if (off > d->inlen)
+ {
+ fprintf(stderr, "%s: corrupt delta instructions\n", n);
+ exit(1);
+ }
+ }
+ off = 0;
+ for (i = 0; i < d->outn; i++)
+ {
+ if (d->out[2 * i] & 0x80000000)
+ d->out[2 * i] = (unsigned int)(-(int)(d->out[2 * i] ^ 0x80000000));
+ off += (int)d->out[2 * i];
+ if (off > d->outlen)
+ {
+ fprintf(stderr, "corrupt delta instructions (outdata off %llu > %llu)\n", (unsigned long long)off, (unsigned long long)d->outlen);
+ exit(1);
+ }
+ off += d->out[2 * i + 1];
+ if (off < 1 || off > d->outlen)
+ {
+ fprintf(stderr, "corrupt delta instructions (outdata off + len %llu > %llu)\n", (unsigned long long)off, (unsigned long long)d->outlen);
+ exit(1);
+ }
+ }
+ d->sdesc = 0;
+ d->nsdesc = 0;
+ d->outptr = 0;
+ d->next = d->prev = 0;
+ if (!cfp && strcmp(d->name, "-") != 0)
+ close(dfd);
+}