X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ext%2Frepo_rpmdb.c;h=b98720a938c4c8f975796a7589b00f90cd04e6b5;hb=e1659dc4ce74d3c47f465103951dafff8fc0cf9f;hp=e84b8ec71ae17c972a1322b1077d20c99d396dc1;hpb=83145da7966e63a78a5065ec2c186d182488e494;p=platform%2Fupstream%2Flibsolv.git diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index e84b8ec..b98720a 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -24,6 +24,8 @@ #include #include +#ifdef ENABLE_RPMDB + #include #include #ifndef RPM5 @@ -39,6 +41,8 @@ # endif #endif +#endif + #include "pool.h" #include "repo.h" #include "hash.h" @@ -46,10 +50,17 @@ #include "queue.h" #include "chksum.h" #include "repo_rpmdb.h" +#include "repo_solv.h" +#ifdef ENABLE_COMPLEX_DEPS +#include "pool_parserpmrichdep.h" +#endif /* 3: added triggers */ /* 4: fixed triggers */ -#define RPMDB_COOKIE_VERSION 4 +/* 5: fixed checksum copying */ +/* 6: add SOLVABLE_PREREQ_IGNOREINST support */ +/* 7: fix bug in ignoreinst logic */ +#define RPMDB_COOKIE_VERSION 7 #define TAG_NAME 1000 #define TAG_VERSION 1001 @@ -60,7 +71,7 @@ #define TAG_BUILDTIME 1006 #define TAG_BUILDHOST 1007 #define TAG_INSTALLTIME 1008 -#define TAG_SIZE 1009 +#define TAG_SIZE 1009 #define TAG_DISTRIBUTION 1010 #define TAG_VENDOR 1011 #define TAG_LICENSE 1014 @@ -101,14 +112,14 @@ #define TAG_BASENAMES 1117 #define TAG_DIRNAMES 1118 #define TAG_PAYLOADFORMAT 1124 -#define TAG_PATCHESNAME 1133 +#define TAG_PATCHESNAME 1133 #define TAG_FILECOLORS 1140 -#define TAG_SUGGESTSNAME 1156 -#define TAG_SUGGESTSVERSION 1157 -#define TAG_SUGGESTSFLAGS 1158 -#define TAG_ENHANCESNAME 1159 -#define TAG_ENHANCESVERSION 1160 -#define TAG_ENHANCESFLAGS 1161 +#define TAG_OLDSUGGESTSNAME 1156 +#define TAG_OLDSUGGESTSVERSION 1157 +#define TAG_OLDSUGGESTSFLAGS 1158 +#define TAG_OLDENHANCESNAME 1159 +#define TAG_OLDENHANCESVERSION 1160 +#define TAG_OLDENHANCESFLAGS 1161 /* rpm5 tags */ #define TAG_DISTEPOCH 1218 @@ -116,6 +127,18 @@ /* rpm4 tags */ #define TAG_LONGFILESIZES 5008 #define TAG_LONGSIZE 5009 +#define TAG_RECOMMENDNAME 5046 +#define TAG_RECOMMENDVERSION 5047 +#define TAG_RECOMMENDFLAGS 5048 +#define TAG_SUGGESTNAME 5049 +#define TAG_SUGGESTVERSION 5050 +#define TAG_SUGGESTFLAGS 5051 +#define TAG_SUPPLEMENTNAME 5052 +#define TAG_SUPPLEMENTVERSION 5053 +#define TAG_SUPPLEMENTFLAGS 5054 +#define TAG_ENHANCENAME 5055 +#define TAG_ENHANCEVERSION 5056 +#define TAG_ENHANCEFLAGS 5057 /* signature tags */ #define TAG_SIGBASE 256 @@ -131,23 +154,30 @@ #define DEP_GREATER (1 << 2) #define DEP_EQUAL (1 << 3) #define DEP_STRONG (1 << 27) -#define DEP_PRE ((1 << 6) | (1 << 9) | (1 << 10) | (1 << 11) | (1 << 12)) +#define DEP_PRE_IN ((1 << 6) | (1 << 9) | (1 << 10)) +#define DEP_PRE_UN ((1 << 6) | (1 << 11) | (1 << 12)) #define FILEFLAG_GHOST (1 << 6) #ifdef RPM5 -# define RPM_INDEX_SIZE 4 +# define RPM_INDEX_SIZE 4 /* just the rpmdbid */ #else -# define RPM_INDEX_SIZE 8 +# define RPM_INDEX_SIZE 8 /* rpmdbid + array index */ #endif +/* some limits to guard against corrupt rpms */ +#define MAX_SIG_CNT 0x100000 +#define MAX_SIG_DSIZE 0x100000 + +#define MAX_HDR_CNT 0x100000 +#define MAX_HDR_DSIZE 0x2000000 typedef struct rpmhead { int cnt; - int dcnt; + unsigned int dcnt; unsigned char *dp; - int forcebinary; /* sigh */ + int forcebinary; /* sigh, see rh#478907 */ unsigned char data[1]; } RpmHead; @@ -184,7 +214,7 @@ headint32array(RpmHead *h, int tag, int *cnt) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (o + 4 * i > h->dcnt) + if (o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt) return 0; d = h->dp + o; r = solv_calloc(i ? i : 1, sizeof(unsigned int)); @@ -206,12 +236,37 @@ headint32(RpmHead *h, int tag) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (i == 0 || o + 4 * i > h->dcnt) + if (i == 0 || o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt) return 0; d = h->dp + o; return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; } +static unsigned long long * +headint64array(RpmHead *h, int tag, int *cnt) +{ + unsigned int i, o; + unsigned long long *r; + unsigned char *d = headfindtag(h, tag); + + if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5) + return 0; + o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; + i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; + if (o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt) + return 0; + d = h->dp + o; + r = solv_calloc(i ? i : 1, sizeof(unsigned long long)); + if (cnt) + *cnt = i; + for (o = 0; o < i; o++, d += 8) + { + unsigned int x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; + r[o] = (unsigned long long)x << 32 | (unsigned int)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); + } + return r; +} + /* returns the first entry of an 64bit integer array */ static unsigned long long headint64(RpmHead *h, int tag) @@ -222,11 +277,11 @@ headint64(RpmHead *h, int tag) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (i == 0 || o + 8 * i > h->dcnt) + if (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt) return 0; d = h->dp + o; i = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; - return (unsigned long long)i << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); + return (unsigned long long)i << 32 | (unsigned int)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); } static unsigned int * @@ -239,7 +294,7 @@ headint16array(RpmHead *h, int tag, int *cnt) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (o + 4 * i > h->dcnt) + if (o > h->dcnt || i > h->dcnt || o + 2 * i > h->dcnt) return 0; d = h->dp + o; r = solv_calloc(i ? i : 1, sizeof(unsigned int)); @@ -275,6 +330,8 @@ headstringarray(RpmHead *h, int tag, int *cnt) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; + if (o > h->dcnt || i > h->dcnt) + return 0; r = solv_calloc(i ? i : 1, sizeof(char *)); if (cnt) *cnt = i; @@ -302,7 +359,7 @@ headbinary(RpmHead *h, int tag, unsigned int *sizep) return 0; o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11]; i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15]; - if (o > h->dcnt || o + i < o || o + i > h->dcnt) + if (o > h->dcnt || i > h->dcnt || o + i > h->dcnt) return 0; if (sizep) *sizep = i; @@ -354,82 +411,24 @@ static char *headtoevr(RpmHead *h) static void setutf8string(Repodata *repodata, Id handle, Id tag, const char *str) { - const unsigned char *cp; - int state = 0; - int c; - unsigned char *buf = 0, *bp; - - /* check if it's already utf8, code taken from screen ;-) */ - cp = (const unsigned char *)str; - while ((c = *cp++) != 0) + if (str[solv_validutf8(str)]) { - if (state) - { - if ((c & 0xc0) != 0x80) - break; /* encoding error */ - c = (c & 0x3f) | (state << 6); - if (!(state & 0x40000000)) - { - /* check for overlong sequences */ - if ((c & 0x820823e0) == 0x80000000) - c = 0xfdffffff; - else if ((c & 0x020821f0) == 0x02000000) - c = 0xfff7ffff; - else if ((c & 0x000820f8) == 0x00080000) - c = 0xffffd000; - else if ((c & 0x0000207c) == 0x00002000) - c = 0xffffff70; - } - } - else - { - /* new sequence */ - if (c >= 0xfe) - break; - else if (c >= 0xfc) - c = (c & 0x01) | 0xbffffffc; /* 5 bytes to follow */ - else if (c >= 0xf8) - c = (c & 0x03) | 0xbfffff00; /* 4 */ - else if (c >= 0xf0) - c = (c & 0x07) | 0xbfffc000; /* 3 */ - else if (c >= 0xe0) - c = (c & 0x0f) | 0xbff00000; /* 2 */ - else if (c >= 0xc2) - c = (c & 0x1f) | 0xfc000000; /* 1 */ - else if (c >= 0x80) - break; - } - state = (c & 0x80000000) ? c : 0; + char *ustr = solv_latin1toutf8(str); /* not utf8, assume latin1 */ + repodata_set_str(repodata, handle, tag, ustr); + solv_free(ustr); } - if (c) - { - /* not utf8, assume latin1 */ - buf = solv_malloc(2 * strlen(str) + 1); - cp = (const unsigned char *)str; - str = (char *)buf; - bp = buf; - while ((c = *cp++) != 0) - { - if (c >= 0xc0) - { - *bp++ = 0xc3; - c ^= 0x80; - } - else if (c >= 0x80) - *bp++ = 0xc2; - *bp++ = c; - } - *bp++ = 0; - } - repodata_set_str(repodata, handle, tag, str); - if (buf) - solv_free(buf); + else + repodata_set_str(repodata, handle, tag, str); } - -#define MAKEDEPS_FILTER_WEAK (1 << 0) -#define MAKEDEPS_FILTER_STRONG (1 << 1) -#define MAKEDEPS_NO_RPMLIB (1 << 2) +static int +ignq_sortcmp(const void *va, const void *vb, void *dp) +{ + int r = *(Id *)va - *(Id *)vb; + if (!r) + r = ((Id *)va)[1] - ((Id *)vb)[1]; + return r; +} /* * strong: 0: ignore strongness @@ -437,18 +436,50 @@ setutf8string(Repodata *repodata, Id handle, Id tag, const char *str) * 2: filter to weak */ static unsigned int -makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags) +makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq) { char **n, **v; unsigned int *f; int i, cc, nc, vc, fc; - int haspre; + int haspre, premask, has_ign; unsigned int olddeps; Id *ida; - int strong; + int strong = 0; - strong = flags & (MAKEDEPS_FILTER_STRONG|MAKEDEPS_FILTER_WEAK); n = headstringarray(rpmhead, tagn, &nc); + if (!n) + { + switch (tagn) + { + case TAG_SUGGESTNAME: + tagn = TAG_OLDSUGGESTSNAME; + tagv = TAG_OLDSUGGESTSVERSION; + tagf = TAG_OLDSUGGESTSFLAGS; + strong = -1; + break; + case TAG_ENHANCENAME: + tagn = TAG_OLDENHANCESNAME; + tagv = TAG_OLDENHANCESVERSION; + tagf = TAG_OLDENHANCESFLAGS; + strong = -1; + break; + case TAG_RECOMMENDNAME: + tagn = TAG_OLDSUGGESTSNAME; + tagv = TAG_OLDSUGGESTSVERSION; + tagf = TAG_OLDSUGGESTSFLAGS; + strong = 1; + break; + case TAG_SUPPLEMENTNAME: + tagn = TAG_OLDENHANCESNAME; + tagv = TAG_OLDENHANCESVERSION; + tagf = TAG_OLDENHANCESFLAGS; + strong = 1; + break; + default: + return 0; + } + n = headstringarray(rpmhead, tagn, &nc); + } if (!n || !nc) return 0; vc = fc = 0; @@ -467,27 +498,28 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, cc = nc; haspre = 0; /* add no prereq marker */ - if (flags) + premask = tagn == TAG_REQUIRENAME ? DEP_PRE_IN | DEP_PRE_UN : 0; + if ((flags & RPM_ADD_NO_RPMLIBREQS) || strong) { /* we do filtering */ cc = 0; for (i = 0; i < nc; i++) { - if (strong && (f[i] & DEP_STRONG) != (strong == MAKEDEPS_FILTER_WEAK ? 0 : DEP_STRONG)) + if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG)) continue; - if ((flags & MAKEDEPS_NO_RPMLIB) != 0) + if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0) if (!strncmp(n[i], "rpmlib(", 7)) continue; - if ((f[i] & DEP_PRE) != 0) + if ((f[i] & premask) != 0) haspre = 1; cc++; } } - else if (tagn == TAG_REQUIRENAME) + else if (premask) { /* no filtering, just look for the first prereq */ for (i = 0; i < nc; i++) - if ((f[i] & DEP_PRE) != 0) + if ((f[i] & premask) != 0) { haspre = 1; break; @@ -500,11 +532,14 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, solv_free(f); return 0; } - cc += haspre; + cc += haspre; /* add slot for the prereq marker */ olddeps = repo_reserve_ids(repo, 0, cc); ida = repo->idarraydata + olddeps; + + has_ign = 0; for (i = 0; ; i++) { + Id id; if (i == nc) { if (haspre != 1) @@ -513,43 +548,100 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, i = 0; *ida++ = SOLVABLE_PREREQMARKER; } - if (strong && (f[i] & DEP_STRONG) != (strong == MAKEDEPS_FILTER_WEAK ? 0 : DEP_STRONG)) + if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG)) continue; - if (haspre == 1 && (f[i] & DEP_PRE) != 0) - continue; - if (haspre == 2 && (f[i] & DEP_PRE) == 0) - continue; - if ((flags & MAKEDEPS_NO_RPMLIB) != 0) + if (haspre) + { + if (haspre == 1 && (f[i] & premask) != 0) + continue; + if (haspre == 2 && (f[i] & premask) == 0) + continue; + } + if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0) if (!strncmp(n[i], "rpmlib(", 7)) continue; +#ifdef ENABLE_COMPLEX_DEPS + if ((f[i] & (DEP_LESS|DEP_EQUAL|DEP_GREATER)) == 0 && n[i][0] == '(') + { + id = pool_parserpmrichdep(pool, n[i]); + if (id) + *ida++ = id; + else + cc--; + continue; + } +#endif + id = pool_str2id(pool, n[i], 1); if (f[i] & (DEP_LESS|DEP_GREATER|DEP_EQUAL)) { - Id name, evr; - int flags = 0; + Id evr; + int fl = 0; if ((f[i] & DEP_LESS) != 0) - flags |= 4; + fl |= REL_LT; if ((f[i] & DEP_EQUAL) != 0) - flags |= 2; + fl |= REL_EQ; if ((f[i] & DEP_GREATER) != 0) - flags |= 1; - name = pool_str2id(pool, n[i], 1); + fl |= REL_GT; if (v[i][0] == '0' && v[i][1] == ':' && v[i][2]) evr = pool_str2id(pool, v[i] + 2, 1); else evr = pool_str2id(pool, v[i], 1); - *ida++ = pool_rel2id(pool, name, evr, flags, 1); + id = pool_rel2id(pool, id, evr, fl, 1); + } + *ida++ = id; + if (haspre == 2 && ignq) + { + int is_ign = (f[i] & DEP_PRE_IN) != 0 && (f[i] & DEP_PRE_UN) == 0 ? 1 : 0; + has_ign |= is_ign; + queue_push2(ignq, id, is_ign); } - else - *ida++ = pool_str2id(pool, n[i], 1); } *ida++ = 0; repo->idarraysize += cc + 1; solv_free(n); solv_free(v); solv_free(f); + if (ignq && ignq->count) + { + int j = 0; + if (has_ign && ignq->count == 2) + j = 1; + else if (has_ign) + { + Id id, lastid = 0; + + solv_sort(ignq->elements, ignq->count / 2, sizeof(Id) * 2, ignq_sortcmp, 0); + for (i = j = 0; i < ignq->count; i += 2) + { + id = ignq->elements[i]; + if (id != lastid && ignq->elements[i + 1] > 0) + ignq->elements[j++] = id; + lastid = id; + } + } + queue_truncate(ignq, j); + } return olddeps; } +static Id +repodata_str2dir_rooted(Repodata *data, char *str, int create) +{ + char buf[256], *bp; + int l = strlen(str); + Id id; + + if (l + 2 <= sizeof(buf)) + bp = buf; + else + bp = solv_malloc(l + 2); + bp[0] = '/'; + strcpy(bp + 1, str); + id = repodata_str2dir(data, bp, create); + if (bp != buf) + solv_free(bp); + return id; +} static void adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dc) @@ -557,17 +649,34 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int * Id did; int i, fszc; unsigned int *fkb, *fn, *fsz, *fm, *fino; + unsigned long long *fsz64; unsigned int inotest[256], inotestok; if (!fc) return; - /* XXX: use TAG_LONGFILESIZES if available */ - fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc); - if (!fsz || fc != fszc) + if ((fsz64 = headint64array(rpmhead, TAG_LONGFILESIZES, &fszc)) != 0) + { + /* convert to kbyte */ + fsz = solv_malloc2(fszc, sizeof(*fsz)); + for (i = 0; i < fszc; i++) + fsz[i] = fsz64[i] ? fsz64[i] / 1024 + 1 : 0; + solv_free(fsz64); + } + else if ((fsz = headint32array(rpmhead, TAG_FILESIZES, &fszc)) != 0) + { + /* convert to kbyte */ + for (i = 0; i < fszc; i++) + if (fsz[i]) + fsz[i] = fsz[i] / 1024 + 1; + } + else + return; + if (fc != fszc) { solv_free(fsz); return; } + /* stupid rpm records sizes of directories, so we have to check the mode */ fm = headint16array(rpmhead, TAG_FILEMODES, &fszc); if (!fm || fc != fszc) @@ -584,15 +693,18 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int * solv_free(fino); return; } + + /* kill hardlinked entries */ inotestok = 0; if (fc < sizeof(inotest)) { + /* quick test just hashing the inode numbers */ memset(inotest, 0, sizeof(inotest)); for (i = 0; i < fc; i++) { int off, bit; if (fsz[i] == 0 || !S_ISREG(fm[i])) - continue; + continue; /* does not matter */ off = (fino[i] >> 5) & (sizeof(inotest)/sizeof(*inotest) - 1); bit = 1 << (fino[i] & 31); if ((inotest[off] & bit) != 0) @@ -600,10 +712,11 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int * inotest[off] |= bit; } if (i == fc) - inotestok = 1; + inotestok = 1; /* no conflict found */ } if (!inotestok) { + /* hardlinked files are possible, check ino/dev pairs */ unsigned int *fdev = headint32array(rpmhead, TAG_FILEDEVICES, &fszc); unsigned int *fx, j; unsigned int mask, hash, hh; @@ -650,16 +763,18 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int * solv_free(fdev); } solv_free(fino); + + /* sum up inode count and kbytes for each directory */ fn = solv_calloc(dc, sizeof(unsigned int)); fkb = solv_calloc(dc, sizeof(unsigned int)); for (i = 0; i < fc; i++) { if (di[i] >= dc) - continue; + continue; /* corrupt entry */ fn[di[i]]++; if (fsz[i] == 0 || !S_ISREG(fm[i])) continue; - fkb[di[i]] += fsz[i] / 1024 + 1; + fkb[di[i]] += fsz[i]; } solv_free(fsz); solv_free(fm); @@ -668,13 +783,13 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int * { if (!fn[i]) continue; - if (!*dn[i]) + if (dn[i][0] != '/') { - Solvable *s = data->repo->pool->solvables + handle; + Solvable *s = data->repo->pool->solvables + handle; if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) did = repodata_str2dir(data, "/usr/src", 1); else - continue; /* work around rpm bug */ + did = repodata_str2dir_rooted(data, dn[i], 1); } else did = repodata_str2dir(data, dn[i], 1); @@ -684,16 +799,32 @@ adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int * solv_free(fkb); } +static int +is_filtered(const char *dir) +{ + if (!dir) + return 1; + /* the dirs always have a trailing / in rpm */ + if (strstr(dir, "bin/")) + return 0; + if (!strncmp(dir, "/etc/", 5)) + return 0; + if (!strcmp(dir, "/usr/lib/")) + return 2; + return 1; +} + static void -addfilelist(Repodata *data, Id handle, RpmHead *rpmhead) +addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags) { char **bn; char **dn; unsigned int *di; int bnc, dnc, dic; int i; - Id lastdid = 0; - int lastdii = -1; + Id did; + unsigned int lastdii = -1; + int lastfiltered = 0; if (!data) return; @@ -721,23 +852,34 @@ addfilelist(Repodata *data, Id handle, RpmHead *rpmhead) adddudata(data, handle, rpmhead, dn, di, bnc, dnc); + did = -1; for (i = 0; i < bnc; i++) { - Id did; char *b = bn[i]; - if (di[i] == lastdii) - did = lastdid; - else + if (did < 0 || di[i] != lastdii) { - did = repodata_str2dir(data, dn[di[i]], 1); - if (!did) - did = repodata_str2dir(data, "/", 1); - lastdid = did; + if (di[i] >= dnc) + continue; /* corrupt entry */ + did = 0; lastdii = di[i]; + if ((flags & RPM_ADD_FILTERED_FILELIST) != 0) + { + lastfiltered = is_filtered(dn[di[i]]); + if (lastfiltered == 1) + continue; + } + if (dn[lastdii][0] != '/') + did = repodata_str2dir_rooted(data, dn[lastdii], 1); + else + did = repodata_str2dir(data, dn[lastdii], 1); } - if (b && *b == '/') /* work around rpm bug */ + if (!b) + continue; + if (*b == '/') /* work around rpm bug */ b++; + if (lastfiltered && (lastfiltered != 2 || strcmp(b, "sendmail"))) + continue; repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b); } solv_free(bn); @@ -771,9 +913,9 @@ addchangelog(Repodata *data, Id handle, RpmHead *rpmhead) if (ct[i]) repodata_set_num(data, h, SOLVABLE_CHANGELOG_TIME, ct[i]); if (cn[i]) - repodata_set_str(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]); + setutf8string(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]); if (cx[i]) - repodata_set_str(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]); + setutf8string(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]); queue_push(&hq, h); } for (i = 0; i < hq.count; i++) @@ -784,13 +926,58 @@ addchangelog(Repodata *data, Id handle, RpmHead *rpmhead) solv_free(cn); } +static void +set_description_author(Repodata *data, Id handle, char *str) +{ + char *aut, *p; + for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++) + if (!strncmp(aut, "\nAuthors:\n--------\n", 19)) + break; + if (aut) + { + /* oh my, found SUSE special author section */ + int l = aut - str; + str = solv_strdup(str); + aut = str + l; + str[l] = 0; + while (l > 0 && str[l - 1] == '\n') + str[--l] = 0; + if (l) + setutf8string(data, handle, SOLVABLE_DESCRIPTION, str); + p = aut + 19; + aut = str; /* copy over */ + while (*p == ' ' || *p == '\n') + p++; + while (*p) + { + if (*p == '\n') + { + *aut++ = *p++; + while (*p == ' ') + p++; + continue; + } + *aut++ = *p++; + } + while (aut != str && aut[-1] == '\n') + aut--; + *aut = 0; + if (*str) + setutf8string(data, handle, SOLVABLE_AUTHORS, str); + free(str); + } + else if (*str) + setutf8string(data, handle, SOLVABLE_DESCRIPTION, str); +} static int -rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags) +rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags) { char *name; char *evr; char *sourcerpm; + Queue ignq; + Id ignqbuf[64]; name = headstring(rpmhead, TAG_NAME); if (!name) @@ -817,19 +1004,25 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, s->evr = pool_str2id(pool, evr, 1); s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1); - s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0); + queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf)); + + s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0, 0); if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0); - s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, (flags & RPM_ADD_NO_RPMLIBREQS) ? MAKEDEPS_NO_RPMLIB : 0); - s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0); - s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0); + s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags, &ignq); + s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0, 0); + s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0, 0); - s->recommends = makedeps(pool, repo, rpmhead, TAG_SUGGESTSNAME, TAG_SUGGESTSVERSION, TAG_SUGGESTSFLAGS, MAKEDEPS_FILTER_STRONG); - s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTSNAME, TAG_SUGGESTSVERSION, TAG_SUGGESTSFLAGS, MAKEDEPS_FILTER_WEAK); - s->supplements = makedeps(pool, repo, rpmhead, TAG_ENHANCESNAME, TAG_ENHANCESVERSION, TAG_ENHANCESFLAGS, MAKEDEPS_FILTER_STRONG); - s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCESNAME, TAG_ENHANCESVERSION, TAG_ENHANCESFLAGS, MAKEDEPS_FILTER_WEAK); - s->supplements = repo_fix_supplements(repo, s->provides, s->supplements, 0); - s->conflicts = repo_fix_conflicts(repo, s->conflicts); + s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0, 0); + s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0, 0); + s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0, 0); + s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0, 0); + + repo_rewrite_suse_deps(s, 0); + + if (data && ignq.count) + repodata_set_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, &ignq); + queue_free(&ignq); if (data) { @@ -844,47 +1037,7 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, setutf8string(data, handle, SOLVABLE_SUMMARY, str); str = headstring(rpmhead, TAG_DESCRIPTION); if (str) - { - char *aut, *p; - for (aut = str; (aut = strchr(aut, '\n')) != 0; aut++) - if (!strncmp(aut, "\nAuthors:\n--------\n", 19)) - break; - if (aut) - { - /* oh my, found SUSE special author section */ - int l = aut - str; - str = solv_strdup(str); - aut = str + l; - str[l] = 0; - while (l > 0 && str[l - 1] == '\n') - str[--l] = 0; - if (l) - setutf8string(data, handle, SOLVABLE_DESCRIPTION, str); - p = aut + 19; - aut = str; /* copy over */ - while (*p == ' ' || *p == '\n') - p++; - while (*p) - { - if (*p == '\n') - { - *aut++ = *p++; - while (*p == ' ') - p++; - continue; - } - *aut++ = *p++; - } - while (aut != str && aut[-1] == '\n') - aut--; - *aut = 0; - if (*str) - setutf8string(data, handle, SOLVABLE_AUTHORS, str); - free(str); - } - else if (*str) - setutf8string(data, handle, SOLVABLE_DESCRIPTION, str); - } + set_description_author(data, handle, str); str = headstring(rpmhead, TAG_GROUP); if (str) repodata_set_poolstr(data, handle, SOLVABLE_GROUP, str); @@ -935,27 +1088,14 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, repodata_set_sourcepkg(data, handle, sourcerpm); if ((flags & RPM_ADD_TRIGGERS) != 0) { - Id id, lastid; - unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0); - - lastid = 0; - for (; (id = repo->idarraydata[ida]) != 0; ida++) - { - /* we currently do not support rel ids in incore data, so - * strip off versioning information */ - while (ISRELDEP(id)) - { - Reldep *rd = GETRELDEP(pool, id); - id = rd->name; - } - if (id == lastid) - continue; + unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0, 0); + Id id, lastid = 0; + for (lastid = 0; (id = repo->idarraydata[ida]) != 0; ida++, lastid = id) + if (id != lastid) repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id); - lastid = id; - } } if ((flags & RPM_ADD_NO_FILELIST) == 0) - addfilelist(data, handle, rpmhead); + addfilelist(data, handle, rpmhead, flags); if ((flags & RPM_ADD_WITH_CHANGELOG) != 0) addchangelog(data, handle, rpmhead); } @@ -963,24 +1103,35 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, return 1; } +static inline unsigned int +getu32(const unsigned char *dp) +{ + return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3]; +} + /******************************************************************/ /* Rpm Database stuff */ struct rpmdbstate { - Pool *pool; + Pool *pool; char *rootdir; RpmHead *rpmhead; /* header storage space */ int rpmheadsize; +#ifdef ENABLE_RPMDB int dbopened; DB_ENV *dbenv; /* database environment */ DB *db; /* packages database */ int byteswapped; /* endianess of packages database */ + int is_ostree; /* read-only db that lives in /usr/share/rpm */ +#endif }; +#ifdef ENABLE_RPMDB + struct rpmdbentry { Id rpmdbid; Id nameoff; @@ -990,7 +1141,8 @@ struct rpmdbentry { #define NAMEDATA_BLOCK 1023 -static inline Id db2rpmdbid(unsigned char *db, int byteswapped) +static inline Id +db2rpmdbid(unsigned char *db, int byteswapped) { #ifdef RPM5 return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3]; @@ -1006,7 +1158,8 @@ static inline Id db2rpmdbid(unsigned char *db, int byteswapped) #endif } -static inline void rpmdbid2db(unsigned char *db, Id id, int byteswapped) +static inline void +rpmdbid2db(unsigned char *db, Id id, int byteswapped) { #ifdef RPM5 db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id; @@ -1022,10 +1175,41 @@ static inline void rpmdbid2db(unsigned char *db, Id id, int byteswapped) #endif } +#ifdef FEDORA +int +serialize_dbenv_ops(struct rpmdbstate *state) +{ + char lpath[PATH_MAX]; + mode_t oldmask; + int fd; + struct flock fl; + + snprintf(lpath, PATH_MAX, "%s/var/lib/rpm/.dbenv.lock", state->rootdir ? state->rootdir : ""); + oldmask = umask(022); + fd = open(lpath, (O_RDWR|O_CREAT), 0644); + umask(oldmask); + if (fd < 0) + return -1; + memset(&fl, 0, sizeof(fl)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + for (;;) + { + if (fcntl(fd, F_SETLKW, &fl) != -1) + return fd; + if (errno != EINTR) + break; + } + close(fd); + return -1; +} +#endif + /* should look in /usr/lib/rpm/macros instead, but we want speed... */ static int -opendbenv(struct rpmdbstate *state, const char *rootdir) +opendbenv(struct rpmdbstate *state) { + const char *rootdir = state->rootdir; char dbpath[PATH_MAX]; DB_ENV *dbenv = 0; int r; @@ -1038,12 +1222,19 @@ opendbenv(struct rpmdbstate *state, const char *rootdir) snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm", rootdir ? rootdir : ""); if (access(dbpath, W_OK) == -1) { + snprintf(dbpath, PATH_MAX, "%s/usr/share/rpm/Packages", rootdir ? rootdir : ""); + if (access(dbpath, R_OK) == 0) + state->is_ostree = 1; + snprintf(dbpath, PATH_MAX, "%s%s", rootdir ? rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm"); r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); } else { #ifdef FEDORA + int serialize_fd = serialize_dbenv_ops(state); r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 0644); + if (serialize_fd >= 0) + close(serialize_fd); #else r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); #endif @@ -1058,20 +1249,85 @@ opendbenv(struct rpmdbstate *state, const char *rootdir) return 1; } +static void +closedbenv(struct rpmdbstate *state) +{ +#ifdef FEDORA + uint32_t eflags = 0; +#endif + + if (!state->dbenv) + return; +#ifdef FEDORA + (void)state->dbenv->get_open_flags(state->dbenv, &eflags); + if (!(eflags & DB_PRIVATE)) + { + int serialize_fd = serialize_dbenv_ops(state); + state->dbenv->close(state->dbenv, 0); + if (serialize_fd >= 0) + close(serialize_fd); + } + else + state->dbenv->close(state->dbenv, 0); +#else + state->dbenv->close(state->dbenv, 0); +#endif + state->dbenv = 0; +} + +#endif + +static void +freestate(struct rpmdbstate *state) +{ + /* close down */ + if (!state) + return; +#ifdef ENABLE_RPMDB + if (state->db) + state->db->close(state->db, 0); + if (state->dbenv) + closedbenv(state); +#endif + if (state->rootdir) + solv_free(state->rootdir); + solv_free(state->rpmhead); +} + +void * +rpm_state_create(Pool *pool, const char *rootdir) +{ + struct rpmdbstate *state; + state = solv_calloc(1, sizeof(*state)); + state->pool = pool; + if (rootdir) + state->rootdir = solv_strdup(rootdir); + return state; +} + +void * +rpm_state_free(void *state) +{ + freestate(state); + return solv_free(state); +} + + +#ifdef ENABLE_RPMDB + static int openpkgdb(struct rpmdbstate *state) { if (state->dbopened) return state->dbopened > 0 ? 1 : 0; state->dbopened = -1; - if (!state->dbenv && !opendbenv(state, state->rootdir)) + if (!state->dbenv && !opendbenv(state)) return 0; if (db_create(&state->db, state->dbenv, 0)) { pool_error(state->pool, 0, "db_create: %s", strerror(errno)); state->db = 0; - state->dbenv->close(state->dbenv, 0); - state->dbenv = 0; + closedbenv(state); return 0; } if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664)) @@ -1079,8 +1335,7 @@ openpkgdb(struct rpmdbstate *state) pool_error(state->pool, 0, "db->open Packages: %s", strerror(errno)); state->db->close(state->db, 0); state->db = 0; - state->dbenv->close(state->dbenv, 0); - state->dbenv = 0; + closedbenv(state); return 0; } if (state->db->get_byteswapped(state->db, &state->byteswapped)) @@ -1088,8 +1343,7 @@ openpkgdb(struct rpmdbstate *state) pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno)); state->db->close(state->db, 0); state->db = 0; - state->dbenv->close(state->dbenv, 0); - state->dbenv = 0; + closedbenv(state); return 0; } state->dbopened = 1; @@ -1120,7 +1374,7 @@ getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *ma if (namedatap) *namedatap = 0; - if (!state->dbenv && !opendbenv(state, state->rootdir)) + if (!state->dbenv && !opendbenv(state)) return 0; dbenv = state->dbenv; if (db_create(&db, dbenv, 0)) @@ -1190,23 +1444,50 @@ getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *ma return entries; } -/* retrive header by rpmdbid */ +/* common code, return dbid on success, -1 on error */ static int -getrpmdbid(struct rpmdbstate *state, Id rpmdbid) +getrpm_dbdata(struct rpmdbstate *state, DBT *dbdata, int dbid) { - unsigned char buf[16]; - DBT dbkey; - DBT dbdata; + unsigned int dsize, cnt, l; RpmHead *rpmhead; - if (!rpmdbid) + if (dbdata->size < 8) + return pool_error(state->pool, -1, "corrupt rpm database (size)"); + cnt = getu32((const unsigned char *)dbdata->data); + dsize = getu32((const unsigned char *)dbdata->data + 4); + if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE) + return pool_error(state->pool, -1, "corrupt rpm database (cnt/dcnt)"); + l = cnt * 16 + dsize; + if (8 + l > dbdata->size) + return pool_error(state->pool, -1, "corrupt rpm database (data size)"); + if (l + 1 > state->rpmheadsize) { - pool_error(state->pool, 0, "illegal rpmdbid"); - return -1; + state->rpmheadsize = l + 128; + state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize); } + rpmhead = state->rpmhead; + rpmhead->forcebinary = 1; + rpmhead->cnt = cnt; + rpmhead->dcnt = dsize; + memcpy(rpmhead->data, (unsigned char *)dbdata->data + 8, l); + rpmhead->data[l] = 0; + rpmhead->dp = rpmhead->data + cnt * 16; + return dbid; +} + +/* retrive header by rpmdbid, returns 0 if not found, -1 on error */ +static int +getrpm_dbid(struct rpmdbstate *state, Id dbid) +{ + unsigned char buf[4]; + DBT dbkey; + DBT dbdata; + + if (dbid <= 0) + return pool_error(state->pool, -1, "illegal rpmdbid %d", dbid); if (state->dbopened != 1 && !openpkgdb(state)) return -1; - rpmdbid2db(buf, rpmdbid, state->byteswapped); + rpmdbid2db(buf, dbid, state->byteswapped); memset(&dbkey, 0, sizeof(dbkey)); memset(&dbdata, 0, sizeof(dbdata)); dbkey.data = buf; @@ -1215,39 +1496,15 @@ getrpmdbid(struct rpmdbstate *state, Id rpmdbid) dbdata.size = 0; if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0)) return 0; - if (dbdata.size < 8) - { - pool_error(state->pool, 0, "corrupt rpm database (size)"); - return -1; - } - if (dbdata.size > state->rpmheadsize) - { - state->rpmheadsize = dbdata.size + 128; - state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - memcpy(buf, dbdata.data, 8); - rpmhead->forcebinary = 1; - rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; - rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]; - if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size) - { - pool_error(state->pool, 0, "corrupt rpm database (data size)"); - return -1; - } - memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt); - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return 1; + return getrpm_dbdata(state, &dbdata, dbid); } -/* retrive header by berkeleydb cursor */ +/* retrive header by berkeleydb cursor, returns 0 on EOF, -1 on error */ static Id -getrpmcursor(struct rpmdbstate *state, DBC *dbc) +getrpm_cursor(struct rpmdbstate *state, DBC *dbc) { - unsigned char buf[16]; DBT dbkey; DBT dbdata; - RpmHead *rpmhead; Id dbid; memset(&dbkey, 0, sizeof(dbkey)); @@ -1257,65 +1514,16 @@ getrpmcursor(struct rpmdbstate *state, DBC *dbc) if (dbkey.size != 4) return pool_error(state->pool, -1, "corrupt Packages database (key size)"); dbid = db2rpmdbid(dbkey.data, state->byteswapped); - if (dbid == 0) /* the join key */ - continue; - if (dbdata.size < 8) - return pool_error(state->pool, -1, "corrupt rpm database (size %u)\n", dbdata.size); - if (dbdata.size > state->rpmheadsize) - { - state->rpmheadsize = dbdata.size + 128; - state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - memcpy(buf, dbdata.data, 8); - rpmhead->forcebinary = 1; - rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; - rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7]; - if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size) - return pool_error(state->pool, -1, "corrupt rpm database (data size)\n"); - memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt); - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return dbid; + if (dbid) /* ignore join key */ + return getrpm_dbdata(state, &dbdata, dbid); } return 0; } -static void -freestate(struct rpmdbstate *state) -{ - /* close down */ - if (!state) - return; - if (state->rootdir) - solv_free(state->rootdir); - if (state->db) - state->db->close(state->db, 0); - if (state->dbenv) - state->dbenv->close(state->dbenv, 0); - solv_free(state->rpmhead); -} - -void * -rpm_state_create(Pool *pool, const char *rootdir) -{ - struct rpmdbstate *state; - state = solv_calloc(1, sizeof(*state)); - state->pool = pool; - if (rootdir) - state->rootdir = solv_strdup(rootdir); - return state; -} - -void * -rpm_state_free(void *state) -{ - freestate(state); - return solv_free(state); -} - static int -count_headers(Pool *pool, const char *rootdir, DB_ENV *dbenv) +count_headers(struct rpmdbstate *state) { + Pool *pool = state->pool; char dbpath[PATH_MAX]; struct stat statbuf; DB *db = 0; @@ -1324,12 +1532,12 @@ count_headers(Pool *pool, const char *rootdir, DB_ENV *dbenv) DBT dbkey; DBT dbdata; - snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Name", rootdir ? rootdir : ""); + snprintf(dbpath, PATH_MAX, "%s%s/Name", state->rootdir ? state->rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm"); if (stat(dbpath, &statbuf)) return 0; memset(&dbkey, 0, sizeof(dbkey)); memset(&dbdata, 0, sizeof(dbdata)); - if (db_create(&db, dbenv, 0)) + if (db_create(&db, state->dbenv, 0)) { pool_error(pool, 0, "db_create: %s", strerror(errno)); return 0; @@ -1355,29 +1563,12 @@ count_headers(Pool *pool, const char *rootdir, DB_ENV *dbenv) /******************************************************************/ -static Id -copyreldep(Pool *pool, Pool *frompool, Id id) -{ - Reldep *rd = GETRELDEP(frompool, id); - Id name = rd->name, evr = rd->evr; - if (ISRELDEP(name)) - name = copyreldep(pool, frompool, name); - else - name = pool_str2id(pool, pool_id2str(frompool, name), 1); - if (ISRELDEP(evr)) - evr = copyreldep(pool, frompool, evr); - else - evr = pool_str2id(pool, pool_id2str(frompool, evr), 1); - return pool_rel2id(pool, name, evr, rd->flags, 1); -} - static Offset copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo) { int cc; - Id id, *ida, *from; + Id *ida, *from; Offset ido; - Pool *frompool = fromrepo->pool; if (!fromoff) return 0; @@ -1388,46 +1579,40 @@ copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo) return 0; ido = repo_reserve_ids(repo, 0, cc); ida = repo->idarraydata + ido; - if (frompool && pool != frompool) - { - while (*from) - { - id = *from++; - if (ISRELDEP(id)) - id = copyreldep(pool, frompool, id); - else - id = pool_str2id(pool, pool_id2str(frompool, id), 1); - *ida++ = id; - } - *ida = 0; - } - else - memcpy(ida, from, (cc + 1) * sizeof(Id)); + memcpy(ida, from, (cc + 1) * sizeof(Id)); repo->idarraysize += cc + 1; return ido; } #define COPYDIR_DIRCACHE_SIZE 512 -static Id copydir_complex(Pool *pool, Repodata *data, Stringpool *fromspool, Repodata *fromdata, Id did, Id *cache); +static Id copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache); static inline Id -copydir(Pool *pool, Repodata *data, Stringpool *fromspool, Repodata *fromdata, Id did, Id *cache) +copydir(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache) { - if (cache && cache[did & 255] == did) + if (cache && did && cache[did & 255] == did) return cache[(did & 255) + 256]; - return copydir_complex(pool, data, fromspool, fromdata, did, cache); + return copydir_complex(pool, data, fromdata, did, cache); } static Id -copydir_complex(Pool *pool, Repodata *data, Stringpool *fromspool, Repodata *fromdata, Id did, Id *cache) +copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache) { - Id parent = dirpool_parent(&fromdata->dirpool, did); - Id compid = dirpool_compid(&fromdata->dirpool, did); + Id parent, compid; + if (!did) + { + /* make sure that the dirpool has an entry */ + if (!data->dirpool.ndirs) + dirpool_add_dir(&data->dirpool, 0, 0, 1); + return 0; + } + parent = dirpool_parent(&fromdata->dirpool, did); + compid = dirpool_compid(&fromdata->dirpool, did); if (parent) - parent = copydir(pool, data, fromspool, fromdata, parent, cache); - if (fromspool != &pool->ss) - compid = pool_str2id(pool, stringpool_id2str(fromspool, compid), 1); + parent = copydir(pool, data, fromdata, parent, cache); + if (data->localpool || fromdata->localpool) + compid = repodata_translate_id(data, fromdata, compid, 1); compid = dirpool_add_dir(&data->dirpool, parent, compid, 1); if (cache) { @@ -1451,26 +1636,17 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K Id id, keyname; Repodata *data = cbdata->data; Id handle = cbdata->handle; - Pool *pool = data->repo->pool, *frompool = fromdata->repo->pool; - Stringpool *fromspool = fromdata->localpool ? &fromdata->spool : &frompool->ss; + Pool *pool = data->repo->pool; keyname = key->name; - if (keyname >= ID_NUM_INTERNAL && pool != frompool) - keyname = pool_str2id(pool, pool_id2str(frompool, keyname), 1); switch(key->type) { case REPOKEY_TYPE_ID: case REPOKEY_TYPE_CONSTANTID: case REPOKEY_TYPE_IDARRAY: /* used for triggers */ id = kv->id; - assert(!data->localpool); /* implement me! */ - if (pool != frompool || fromdata->localpool) - { - if (ISRELDEP(id)) - id = copyreldep(pool, frompool, id); - else - id = pool_str2id(pool, stringpool_id2str(fromspool, id), 1); - } + if (data->localpool || fromdata->localpool) + id = repodata_translate_id(data, fromdata, id, 1); if (key->type == REPOKEY_TYPE_ID) repodata_set_id(data, handle, keyname, id); else if (key->type == REPOKEY_TYPE_CONSTANTID) @@ -1492,15 +1668,15 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K break; case REPOKEY_TYPE_DIRNUMNUMARRAY: id = kv->id; - assert(!data->localpool); /* implement me! */ - id = copydir(pool, data, fromspool, fromdata, id, cbdata->dircache); - repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2); + id = copydir(pool, data, fromdata, id, cbdata->dircache); + if (id) + repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2); break; case REPOKEY_TYPE_DIRSTRARRAY: id = kv->id; - assert(!data->localpool); /* implement me! */ - id = copydir(pool, data, fromspool, fromdata, id, cbdata->dircache); - repodata_add_dirstr(data, handle, keyname, id, kv->str); + id = copydir(pool, data, fromdata, id, cbdata->dircache); + if (id) + repodata_add_dirstr(data, handle, keyname, id, kv->str); break; case REPOKEY_TYPE_FLEXARRAY: if (kv->eof == 2) @@ -1519,6 +1695,11 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K repodata_add_flexarray(data, cbdata->subhandle, keyname, cbdata->handle); break; default: + if (solv_chksum_len(key->type)) + { + repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str); + break; + } break; } return 0; @@ -1527,30 +1708,17 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K static void solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache) { + int p, i; Repo *repo = s->repo; - Repo *fromrepo = r->repo; Pool *pool = repo->pool; + Repo *fromrepo = r->repo; struct solvable_copy_cbdata cbdata; /* copy solvable data */ - if (pool == fromrepo->pool) - { - s->name = r->name; - s->evr = r->evr; - s->arch = r->arch; - s->vendor = r->vendor; - } - else - { - if (r->name) - s->name = pool_str2id(pool, pool_id2str(fromrepo->pool, r->name), 1); - if (r->evr) - s->evr = pool_str2id(pool, pool_id2str(fromrepo->pool, r->evr), 1); - if (r->arch) - s->arch = pool_str2id(pool, pool_id2str(fromrepo->pool, r->arch), 1); - if (r->vendor) - s->vendor = pool_str2id(pool, pool_id2str(fromrepo->pool, r->vendor), 1); - } + s->name = r->name; + s->evr = r->evr; + s->arch = r->arch; + s->vendor = r->vendor; s->provides = copydeps(pool, repo, r->provides, fromrepo); s->requires = copydeps(pool, repo, r->requires, fromrepo); s->conflicts = copydeps(pool, repo, r->conflicts, fromrepo); @@ -1567,7 +1735,17 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache) cbdata.handle = s - pool->solvables; cbdata.subhandle = 0; cbdata.dircache = dircache; - repo_search(fromrepo, (r - fromrepo->pool->solvables), 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata); + p = r - fromrepo->pool->solvables; +#if 0 + repo_search(fromrepo, p, 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata); +#else + FOR_REPODATAS(fromrepo, i, data) + { + if (p >= data->start && p < data->end) + repodata_search(data, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata); + cbdata.dircache = 0; /* only for first repodata */ + } +#endif } /* used to sort entries by package name that got returned in some database order */ @@ -1619,12 +1797,24 @@ swap_solvables(Repo *repo, Repodata *data, Id pa, Id pb) } static void -mkrpmdbcookie(struct stat *st, unsigned char *cookie) +mkrpmdbcookie(struct stat *st, unsigned char *cookie, int flags) { + int f = 0; memset(cookie, 0, 32); cookie[3] = RPMDB_COOKIE_VERSION; memcpy(cookie + 16, &st->st_ino, sizeof(st->st_ino)); memcpy(cookie + 24, &st->st_dev, sizeof(st->st_dev)); + if ((flags & RPM_ADD_WITH_PKGID) != 0) + f |= 1; + if ((flags & RPM_ADD_WITH_HDRID) != 0) + f |= 2; + if ((flags & RPM_ADD_WITH_CHANGELOG) != 0) + f |= 4; + if ((flags & RPM_ADD_NO_FILELIST) == 0) + f |= 8; + if ((flags & RPM_ADD_NO_RPMLIBREQS) != 0) + cookie[1] = 1; + cookie[0] = f; } /* @@ -1643,7 +1833,6 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) Id oldcookietype = 0; Repodata *data; int count = 0, done = 0; - const char *rootdir = 0; struct rpmdbstate state; int i; Solvable *s; @@ -1652,26 +1841,33 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) now = solv_timems(0); memset(&state, 0, sizeof(state)); state.pool = pool; + if (flags & REPO_USE_ROOTDIR) + state.rootdir = solv_strdup(pool_get_rootdir(pool)); data = repo_add_repodata(repo, flags); - if (ref && !(ref->nsolvables && ref->rpmdbid)) - ref = 0; + if (ref && !(ref->nsolvables && ref->rpmdbid && ref->pool == repo->pool)) + { + if ((flags & RPMDB_EMPTY_REFREPO) != 0) + repo_empty(ref, 1); + ref = 0; + } - if (flags & REPO_USE_ROOTDIR) - rootdir = pool_get_rootdir(pool); - if (!opendbenv(&state, rootdir)) - return -1; + if (!opendbenv(&state)) + { + solv_free(state.rootdir); + return -1; + } /* XXX: should get ro lock of Packages database! */ - snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Packages", rootdir ? rootdir : ""); + snprintf(dbpath, PATH_MAX, "%s%s/Packages", state.rootdir ? state.rootdir : "", state.is_ostree ? "/usr/share/rpm" : "/var/lib/rpm"); if (stat(dbpath, &packagesstat)) { pool_error(pool, -1, "%s: %s", dbpath, strerror(errno)); freestate(&state); return -1; } - mkrpmdbcookie(&packagesstat, newcookie); + mkrpmdbcookie(&packagesstat, newcookie, flags); repodata_set_bin_checksum(data, SOLVID_META, REPOSITORY_RPMDBCOOKIE, REPOKEY_TYPE_SHA256, newcookie); if (ref) @@ -1682,8 +1878,10 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) Id dbid; DBC *dbc = 0; + if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0) + repo_empty(ref, 1); /* get it out of the way */ if ((flags & RPMDB_REPORT_PROGRESS) != 0) - count = count_headers(pool, rootdir, state.dbenv); + count = count_headers(&state); if (!openpkgdb(&state)) { freestate(&state); @@ -1696,7 +1894,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) } i = 0; s = 0; - while ((dbid = getrpmcursor(&state, dbc)) != 0) + while ((dbid = getrpm_cursor(&state, dbc)) != 0) { if (dbid == -1) { @@ -1714,7 +1912,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) if (!repo->rpmdbid) repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid; - if (rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS)) + if (rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS)) { i++; s = 0; @@ -1820,7 +2018,10 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) } } - s = pool_id2solvable(pool, repo_add_solvable_block(repo, nentries)); + if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0) + s = pool_id2solvable(pool, repo_add_solvable_block_before(repo, nentries, ref)); + else + s = pool_id2solvable(pool, repo_add_solvable_block(repo, nentries)); if (!repo->rpmdbid) repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); @@ -1847,18 +2048,18 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) } } } - res = getrpmdbid(&state, dbid); + res = getrpm_dbid(&state, dbid); if (res <= 0) { if (!res) - return pool_error(pool, -1, "inconsistent rpm database, key %d not found. run 'rpm --rebuilddb' to fix.", dbid); + pool_error(pool, -1, "inconsistent rpm database, key %d not found. run 'rpm --rebuilddb' to fix.", dbid); freestate(&state); solv_free(entries); solv_free(namedata); solv_free(refhash); return -1; } - rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS); + rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS); if ((flags & RPMDB_REPORT_PROGRESS) != 0) { if (done < count) @@ -1871,6 +2072,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) solv_free(entries); solv_free(namedata); solv_free(refhash); + if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0) + repo_empty(ref, 1); } freestate(&state); @@ -1884,13 +2087,34 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags) return 0; } - -static inline unsigned int -getu32(const unsigned char *dp) +int +repo_add_rpmdb_reffp(Repo *repo, FILE *fp, int flags) { - return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3]; + int res; + Repo *ref = 0; + + if (!fp) + return repo_add_rpmdb(repo, 0, flags); + ref = repo_create(repo->pool, "add_rpmdb_reffp"); + if (repo_add_solv(ref, fp, 0) != 0) + { + repo_free(ref, 1); + ref = 0; + } + if (ref && ref->start == ref->end) + { + repo_free(ref, 1); + ref = 0; + } + if (ref) + repo_disable_paging(ref); + res = repo_add_rpmdb(repo, ref, flags | RPMDB_EMPTY_REFREPO); + if (ref) + repo_free(ref, 1); + return res; } +#endif Id repo_add_rpm(Repo *repo, const char *rpm, int flags) @@ -1911,8 +2135,8 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) unsigned char hdrid[32]; int pkgidtype, leadsigidtype, hdridtype; Id chksumtype = 0; - void *chksumh = 0; - void *leadsigchksumh = 0; + Chksum *chksumh = 0; + Chksum *leadsigchksumh = 0; int forcebinary = 0; data = repo_add_repodata(repo, flags); @@ -1962,7 +2186,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) } sigcnt = getu32(lead + 96 + 8); sigdsize = getu32(lead + 96 + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x100000) + if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE) { pool_error(pool, -1, "%s: bad signature header", rpm); fclose(fp); @@ -1975,7 +2199,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0) { /* extract pkgid or hdrid from the signature header */ - if (sigdsize > rpmheadsize) + if (sigdsize + 1 > rpmheadsize) { rpmheadsize = sigdsize + 128; rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); @@ -1986,6 +2210,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) fclose(fp); return 0; } + rpmhead->data[sigdsize] = 0; if (chksumh) solv_chksum_add(chksumh, rpmhead->data, sigdsize); if (leadsigchksumh) @@ -2060,7 +2285,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) } sigcnt = getu32(lead + 8); sigdsize = getu32(lead + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x2000000) + if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE) { pool_error(pool, -1, "%s: bad header", rpm); fclose(fp); @@ -2068,7 +2293,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) } l = sigdsize + sigcnt * 16; headerend = headerstart + 16 + l; - if (l > rpmheadsize) + if (l + 1 > rpmheadsize) { rpmheadsize = l + 128; rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); @@ -2079,6 +2304,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) fclose(fp); return 0; } + rpmhead->data[l] = 0; if (chksumh) solv_chksum_add(chksumh, rpmhead->data, l); rpmhead->forcebinary = forcebinary; @@ -2109,7 +2335,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) solv_chksum_add(chksumh, lead, l); fclose(fp); s = pool_id2solvable(pool, repo_add_solvable(repo)); - if (!rpm2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID))) + if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID))) { repo_free_solvable(repo, s - pool->solvables, 1); solv_chksum_free(chksumh, 0); @@ -2132,8 +2358,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags) repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, chksumtype, solv_chksum_get(chksumh, 0)); chksumh = solv_chksum_free(chksumh, 0); } - if (rpmhead) - solv_free(rpmhead); + solv_free(rpmhead); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); return s - pool->solvables; @@ -2162,7 +2387,7 @@ repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags) return 0; } s = pool_id2solvable(pool, repo_add_solvable(repo)); - if (!rpm2solv(pool, repo, data, s, rpmhead, flags)) + if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags)) { repo_free_solvable(repo, s - pool->solvables, 1); return 0; @@ -2255,7 +2480,7 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0) { co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2); - if (!co || cnt != cnt2) + if (co && cnt != cnt2) { solv_free(co); solv_free(md); @@ -2333,8 +2558,7 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * info.digest = md5; } } - if (co) - info.color = co[i]; + info.color = co ? co[i] : 0; (*cb)(cbdata, space, &info); } solv_free(space); @@ -2415,6 +2639,8 @@ rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound) return notfound; } +#ifdef ENABLE_RPMDB + int rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq) { @@ -2438,12 +2664,14 @@ rpm_byrpmdbid(void *rpmstate, Id rpmdbid) struct rpmdbstate *state = rpmstate; int r; - r = getrpmdbid(state, rpmdbid); + r = getrpm_dbid(state, rpmdbid); if (!r) pool_error(state->pool, 0, "header #%d not in database", rpmdbid); return r <= 0 ? 0 : state->rpmhead; } +#endif + void * rpm_byfp(void *rpmstate, FILE *fp, const char *name) { @@ -2472,7 +2700,7 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name) } sigcnt = getu32(lead + 96 + 8); sigdsize = getu32(lead + 96 + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x100000) + if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE) { pool_error(state->pool, 0, "%s: bad signature header", name); return 0; @@ -2502,14 +2730,14 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name) } sigcnt = getu32(lead + 8); sigdsize = getu32(lead + 12); - if (sigcnt >= 0x100000 || sigdsize >= 0x2000000) + if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE) { pool_error(state->pool, 0, "%s: bad header", name); return 0; } l = sigdsize + sigcnt * 16; /* headerend = headerstart + 16 + l; */ - if (l > state->rpmheadsize) + if (l + 1 > state->rpmheadsize) { state->rpmheadsize = l + 128; state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); @@ -2520,6 +2748,7 @@ rpm_byfp(void *rpmstate, FILE *fp, const char *name) pool_error(state->pool, 0, "%s: unexpected EOF", name); return 0; } + rpmhead->data[l] = 0; rpmhead->forcebinary = forcebinary; rpmhead->cnt = sigcnt; rpmhead->dcnt = sigdsize; @@ -2546,19 +2775,22 @@ rpm_byrpmh(void *rpmstate, Header h) return 0; sigcnt = getu32(uh); sigdsize = getu32(uh + 4); + if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE) + return 0; l = sigdsize + sigcnt * 16; - if (l > state->rpmheadsize) + if (l + 1 > state->rpmheadsize) { state->rpmheadsize = l + 128; state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); } rpmhead = state->rpmhead; - memcpy(rpmhead->data, uh + 8, l - 8); + memcpy(rpmhead->data, uh + 8, l); + rpmhead->data[l] = 0; free((void *)uh); rpmhead->forcebinary = 0; rpmhead->cnt = sigcnt; rpmhead->dcnt = sigdsize; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; + rpmhead->dp = rpmhead->data + sigcnt * 16; return rpmhead; }