X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ext%2Frepo_rpmdb.c;h=67ce81daf1e4ef2e5b6f7bdf8e4a03d393b72991;hb=b712cabb59f7155205489f15a37addb4ac8b0069;hp=0755fac48c91acc04aed044420a05e2b39b79d1e;hpb=55f5371d10bc44570b2d50bb737aba8a3ae1e93f;p=platform%2Fupstream%2Flibsolv.git diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c index 0755fac..67ce81d 100644 --- a/ext/repo_rpmdb.c +++ b/ext/repo_rpmdb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Novell Inc. + * Copyright (c) 2007-2018, SUSE Inc. * * This program is licensed under the BSD license, read LICENSE.BSD * for further information @@ -22,6 +22,9 @@ #include #include #include +#include + +#ifdef ENABLE_RPMDB #include #include @@ -30,12 +33,6 @@ #endif #include -#ifndef DB_CREATE -# ifdef FEDORA -# include -# else -# include -# endif #endif #include "pool.h" @@ -45,10 +42,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 @@ -59,7 +63,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 @@ -85,9 +89,13 @@ #define TAG_TRIGGERNAME 1066 #define TAG_TRIGGERVERSION 1067 #define TAG_TRIGGERFLAGS 1068 +#define TAG_CHANGELOGTIME 1080 +#define TAG_CHANGELOGNAME 1081 +#define TAG_CHANGELOGTEXT 1082 #define TAG_OBSOLETENAME 1090 #define TAG_FILEDEVICES 1095 #define TAG_FILEINODES 1096 +#define TAG_SOURCEPACKAGE 1106 #define TAG_PROVIDEFLAGS 1112 #define TAG_PROVIDEVERSION 1113 #define TAG_OBSOLETEFLAGS 1114 @@ -96,14 +104,39 @@ #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 + +/* 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 +#define TAG_SIGMD5 (TAG_SIGBASE + 5) +#define TAG_SHA1HEADER (TAG_SIGBASE + 13) +#define TAG_SHA256HEADER (TAG_SIGBASE + 17) #define SIGTAG_SIZE 1000 #define SIGTAG_PGP 1002 /* RSA signature */ @@ -114,30 +147,40 @@ #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) +#define FILEFLAG_GHOST (1 << 6) -#ifdef RPM5 -# define RPM_INDEX_SIZE 4 -#else -# define RPM_INDEX_SIZE 8 -#endif +/* some limits to guard against corrupt rpms */ +/* dsize limits taken from rpm's lib/header.c */ +#define MAX_SIG_CNT 0x10000 +#define MAX_SIG_DSIZE 0x4000000 -struct rpmid { - unsigned int dbid; - char *name; -}; +#define MAX_HDR_CNT 0x10000 +#define MAX_HDR_DSIZE 0x10000000 + + +#ifndef ENABLE_RPMPKG_LIBRPM typedef struct rpmhead { int cnt; - int dcnt; + unsigned int dcnt; unsigned char *dp; unsigned char data[1]; } RpmHead; +static inline void +headinit(RpmHead *h, unsigned int cnt, unsigned int dcnt) +{ + h->cnt = (int)cnt; + h->dcnt = dcnt; + h->dp = h->data + 16 * cnt; + h->dp[dcnt] = 0; +} + static inline unsigned char * headfindtag(RpmHead *h, int tag) { @@ -160,20 +203,21 @@ headexists(RpmHead *h, int tag) return headfindtag(h, tag) ? 1 : 0; } -static unsigned int * +static uint32_t * headint32array(RpmHead *h, int tag, int *cnt) { - unsigned int i, o, *r; + uint32_t *r; + unsigned int i, o; unsigned char *d = headfindtag(h, tag); if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4) 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 = sat_calloc(i ? i : 1, sizeof(unsigned int)); + r = solv_calloc(i ? i : 1, sizeof(uint32_t)); if (cnt) *cnt = i; for (o = 0; o < i; o++, d += 4) @@ -182,7 +226,7 @@ headint32array(RpmHead *h, int tag, int *cnt) } /* returns the first entry of an integer array */ -static unsigned int +static uint32_t headint32(RpmHead *h, int tag) { unsigned int i, o; @@ -192,26 +236,71 @@ 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 int * +static uint64_t * +headint64array(RpmHead *h, int tag, int *cnt) +{ + uint64_t *r; + unsigned int i, o; + 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(uint64_t)); + if (cnt) + *cnt = i; + for (o = 0; o < i; o++, d += 8) + { + uint32_t x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; + r[o] = (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); + } + return r; +} + +/* returns the first entry of an 64bit integer array */ +static uint64_t +headint64(RpmHead *h, int tag) +{ + uint32_t x; + unsigned int i, o; + 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 (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt) + return 0; + d = h->dp + o; + x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3]; + return (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]); +} + +static uint16_t * headint16array(RpmHead *h, int tag, int *cnt) { - unsigned int i, o, *r; + uint16_t *r; + unsigned int i, o; unsigned char *d = headfindtag(h, tag); if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 3) 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 = sat_calloc(i ? i : 1, sizeof(unsigned int)); + r = solv_calloc(i ? i : 1, sizeof(uint16_t)); if (cnt) *cnt = i; for (o = 0; o < i; o++, d += 2) @@ -244,7 +333,9 @@ 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]; - r = sat_calloc(i ? i : 1, sizeof(char *)); + if (o > h->dcnt || i > h->dcnt) + return 0; + r = solv_calloc(i ? i : 1, sizeof(char *)); if (cnt) *cnt = i; d = h->dp + o; @@ -255,7 +346,7 @@ headstringarray(RpmHead *h, int tag, int *cnt) d += strlen((char *)d) + 1; if (d >= h->dp + h->dcnt) { - sat_free(r); + solv_free(r); return 0; } } @@ -271,42 +362,162 @@ 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; return h->dp + o; } +static int +headissourceheuristic(RpmHead *h) +{ + unsigned int i, o; + unsigned char *d = headfindtag(h, TAG_DIRNAMES); + if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 8) + 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]; + return i == 1 && o < h->dcnt && !h->dp[o] ? 1 : 0; +} + +static inline void +headfree(RpmHead *h) +{ + solv_free(h); +} + +#else + +typedef struct headerToken_s RpmHead; + +static int +headexists(RpmHead *h, int tag) +{ + return headerIsEntry(h, tag); +} + +static void *headget(RpmHead *h, int tag, int *cnt, int alloc) +{ + struct rpmtd_s td; + if (!headerGet(h, tag, &td, alloc ? HEADERGET_ALLOC : HEADERGET_MINMEM)) + return 0; + if (cnt) + *cnt = td.count; + return td.data; +} + +static uint32_t * +headint32array(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +static uint32_t +headint32(RpmHead *h, int tag) +{ + uint32_t *arr = headget(h, tag, 0, 0); + return arr ? arr[0] : 0; +} + +static uint64_t * +headint64array(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +/* returns the first entry of an 64bit integer array */ +static uint64_t +headint64(RpmHead *h, int tag) +{ + uint64_t *arr = headget(h, tag, 0, 0); + return arr ? arr[0] : 0; +} + +static uint16_t * +headint16array(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +static char * +headstring(RpmHead *h, int tag) +{ + return headget(h, tag, 0, 0); +} + +static char ** +headstringarray(RpmHead *h, int tag, int *cnt) +{ + return headget(h, tag, cnt, 1); +} + +static unsigned char * +headbinary(RpmHead *h, int tag, unsigned int *sizep) +{ + unsigned char *b = headget(h, tag, (int *)sizep, 0); + if (b && sizep && (tag == TAG_SIGMD5 || tag == SIGTAG_MD5) && *sizep > 16) { + /* due to a bug in rpm the count may be bigger if HEADERIMPORT_FAST is used */ + *sizep = 16; + } + return b; +} + +static int +headissourceheuristic(RpmHead *h) +{ + struct rpmtd_s td; + int issource; + if (!headerGet(h, TAG_DIRNAMES, &td, HEADERGET_MINMEM)) + return 0; + issource = td.count == 1 && td.data && ((char **)td.data)[0] && !((char **)td.data)[0][0]; + rpmtdFreeData(&td); + return issource; +} + +static inline void +headfree(RpmHead *h) +{ + headerFree(h); +} + +#endif + static char *headtoevr(RpmHead *h) { unsigned int epoch; char *version, *v; char *release; char *evr; + char *distepoch; version = headstring(h, TAG_VERSION); release = headstring(h, TAG_RELEASE); epoch = headint32(h, TAG_EPOCH); if (!version || !release) - { - fprintf(stderr, "headtoevr: bad rpm header\n"); - exit(1); - } - for (v = version; *v >= 0 && *v <= '9'; v++) + return 0; + for (v = version; *v >= '0' && *v <= '9'; v++) ; if (epoch || (v != version && *v == ':')) { char epochbuf[11]; /* 32bit decimal will fit in */ sprintf(epochbuf, "%u", epoch); - evr = sat_malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1); + evr = solv_malloc(strlen(epochbuf) + 1 + strlen(version) + 1 + strlen(release) + 1); sprintf(evr, "%s:%s-%s", epochbuf, version, release); } else { - evr = sat_malloc(strlen(version) + 1 + strlen(release) + 1); + evr = solv_malloc(strlen(version) + 1 + strlen(release) + 1); sprintf(evr, "%s-%s", version, release); } + distepoch = headstring(h, TAG_DISTEPOCH); + if (distepoch && *distepoch) + { + int l = strlen(evr); + evr = solv_realloc(evr, l + strlen(distepoch) + 2); + evr[l++] = ':'; + strcpy(evr + l, distepoch); + } return evr; } @@ -314,82 +525,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 (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; - } - if (c) + if (str[solv_validutf8(str)]) { - /* not utf8, assume latin1 */ - buf = sat_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; + char *ustr = solv_latin1toutf8(str); /* not utf8, assume latin1 */ + repodata_set_str(repodata, handle, tag, ustr); + solv_free(ustr); } - repodata_set_str(repodata, handle, tag, str); - if (buf) - sat_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 @@ -397,62 +550,90 @@ 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; + uint32_t *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) - return 0; - v = headstringarray(rpmhead, tagv, &vc); - if (!v) { - sat_free(n); - return 0; + 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; + v = headstringarray(rpmhead, tagv, &vc); f = headint32array(rpmhead, tagf, &fc); - if (!f) - { - sat_free(n); - free(v); + if (!v || !f || nc != vc || nc != fc) + { + char *pkgname = rpm_query(rpmhead, 0); + pool_error(pool, 0, "bad dependency entries for %s: %d %d %d", pkgname ? pkgname : "", nc, vc, fc); + solv_free(pkgname); + solv_free(n); + solv_free(v); + solv_free(f); return 0; } - if (nc != vc || nc != fc) - { - fprintf(stderr, "bad dependency entries\n"); - exit(1); - } 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; @@ -460,16 +641,19 @@ makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, } if (cc == 0) { - sat_free(n); - sat_free(v); - sat_free(f); + solv_free(n); + solv_free(v); + 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) @@ -478,111 +662,165 @@ 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)) - continue; - if (haspre == 1 && (f[i] & DEP_PRE) != 0) + if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG)) 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; - sat_free(n); - sat_free(v); - sat_free(f); + 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; -#ifdef USE_FILEFILTER - -#define FILEFILTER_EXACT 0 -#define FILEFILTER_STARTS 1 -#define FILEFILTER_CONTAINS 2 - -struct filefilter { - int dirmatch; - char *dir; - char *base; -}; - -static struct filefilter filefilters[] = { - { FILEFILTER_CONTAINS, "/bin/", 0}, - { FILEFILTER_CONTAINS, "/sbin/", 0}, - { FILEFILTER_CONTAINS, "/lib/", 0}, - { FILEFILTER_CONTAINS, "/lib64/", 0}, - { FILEFILTER_CONTAINS, "/etc/", 0}, - { FILEFILTER_STARTS, "/usr/games/", 0}, - { FILEFILTER_EXACT, "/usr/share/dict/", "words"}, - { FILEFILTER_STARTS, "/usr/share/", "magic.mime"}, - { FILEFILTER_STARTS, "/opt/gnome/games/", 0}, -}; - -#endif + 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(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dc) +adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, uint32_t *di, int fc, int dc) { - Id handle, did; + Id did; int i, fszc; - unsigned int *fkb, *fn, *fsz, *fm, *fino; + unsigned int *fkb, *fn; + uint64_t *fsz64; + uint32_t *fsz, *fino; + uint16_t *fm; unsigned int inotest[256], inotestok; if (!fc) return; - 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) { - sat_free(fsz); + 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) { - sat_free(fsz); - sat_free(fm); + solv_free(fsz); + solv_free(fm); return; } fino = headint32array(rpmhead, TAG_FILEINODES, &fszc); if (!fino || fc != fszc) { - sat_free(fsz); - sat_free(fm); - sat_free(fino); + solv_free(fsz); + solv_free(fm); + 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) @@ -590,19 +828,20 @@ adddudata(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, 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; if (!fdev || fc != fszc) { - sat_free(fsz); - sat_free(fm); - sat_free(fdev); - sat_free(fino); + solv_free(fsz); + solv_free(fm); + solv_free(fdev); + solv_free(fino); return; } mask = fc; @@ -610,7 +849,7 @@ adddudata(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, mask = mask & (mask - 1); mask <<= 2; if (mask > sizeof(inotest)/sizeof(*inotest)) - fx = sat_calloc(mask, sizeof(unsigned int)); + fx = solv_calloc(mask, sizeof(unsigned int)); else { fx = inotest; @@ -636,219 +875,237 @@ adddudata(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, fx[hash] = i + 1; } if (fx != inotest) - sat_free(fx); - sat_free(fdev); + solv_free(fx); + solv_free(fdev); } - sat_free(fino); - fn = sat_calloc(dc, sizeof(unsigned int)); - fkb = sat_calloc(dc, sizeof(unsigned int)); + 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]; } - sat_free(fsz); - sat_free(fm); + solv_free(fsz); + solv_free(fm); /* commit */ - handle = s - pool->solvables; for (i = 0; i < dc; i++) { if (!fn[i]) continue; - if (!*dn[i]) + if (dn[i][0] != '/') { + 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); repodata_add_dirnumnum(data, handle, SOLVABLE_DISKUSAGE, did, fkb[i], fn[i]); } - sat_free(fn); - sat_free(fkb); + solv_free(fn); + solv_free(fkb); } -/* assumes last processed array is provides! */ -static unsigned int -addfileprovides(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, unsigned int olddeps) +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, int flags) { char **bn; char **dn; - unsigned int *di; + uint32_t *di; int bnc, dnc, dic; int i; -#ifdef USE_FILEFILTER - int j; - struct filefilter *ff; -#endif -#if 0 - char *fn = 0; - int fna = 0; -#endif + Id did; + uint32_t lastdii = -1; + int lastfiltered = 0; if (!data) - return olddeps; + return; bn = headstringarray(rpmhead, TAG_BASENAMES, &bnc); if (!bn) - return olddeps; + return; dn = headstringarray(rpmhead, TAG_DIRNAMES, &dnc); if (!dn) { - sat_free(bn); - return olddeps; + solv_free(bn); + return; } di = headint32array(rpmhead, TAG_DIRINDEXES, &dic); if (!di) { - sat_free(bn); - sat_free(dn); - return olddeps; + solv_free(bn); + solv_free(dn); + return; } if (bnc != dic) { - fprintf(stderr, "bad filelist\n"); - exit(1); + pool_error(data->repo->pool, 0, "bad filelist"); + return; } - if (data) - adddudata(pool, repo, data, s, rpmhead, dn, di, bnc, dnc); + adddudata(data, handle, rpmhead, dn, di, bnc, dnc); + did = -1; for (i = 0; i < bnc; i++) { -#ifdef USE_FILEFILTER - ff = filefilters; - for (j = 0; j < sizeof(filefilters)/sizeof(*filefilters); j++, ff++) + char *b = bn[i]; + + if (did < 0 || di[i] != lastdii) { - if (ff->dir) - { - switch (ff->dirmatch) - { - case FILEFILTER_STARTS: - if (strncmp(dn[di[i]], ff->dir, strlen(ff->dir))) - continue; - break; - case FILEFILTER_CONTAINS: - if (!strstr(dn[di[i]], ff->dir)) - continue; - break; - case FILEFILTER_EXACT: - default: - if (strcmp(dn[di[i]], ff->dir)) - continue; - break; - } - } - if (ff->base) + if (di[i] >= dnc) + continue; /* corrupt entry */ + did = 0; + lastdii = di[i]; + if ((flags & RPM_ADD_FILTERED_FILELIST) != 0) { - if (strcmp(bn[i], ff->base)) + lastfiltered = is_filtered(dn[di[i]]); + if (lastfiltered == 1) continue; } - break; + if (dn[lastdii][0] != '/') + did = repodata_str2dir_rooted(data, dn[lastdii], 1); + else + did = repodata_str2dir(data, dn[lastdii], 1); } - if (j == sizeof(filefilters)/sizeof(*filefilters)) + if (!b) continue; -#endif -#if 0 - j = strlen(bn[i]) + strlen(dn[di[i]]) + 1; - if (j > fna) - { - fna = j + 256; - fn = sat_realloc(fn, fna); - } - strcpy(fn, dn[di[i]]); - strcat(fn, bn[i]); - olddeps = repo_addid_dep(repo, olddeps, pool_str2id(pool, fn, 1), SOLVABLE_FILEMARKER); -#endif - if (data) - { - Id handle, did; - char *b = bn[i]; + 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); + solv_free(dn); + solv_free(di); +} + +static void +addchangelog(Repodata *data, Id handle, RpmHead *rpmhead) +{ + char **cn; + char **cx; + uint32_t *ct; + int i, cnc, cxc, ctc = 0; + Queue hq; + + ct = headint32array(rpmhead, TAG_CHANGELOGTIME, &ctc); + cx = headstringarray(rpmhead, TAG_CHANGELOGTEXT, &cxc); + cn = headstringarray(rpmhead, TAG_CHANGELOGNAME, &cnc); + if (!ct || !cx || !cn || !ctc || ctc != cxc || ctc != cnc) + { + solv_free(ct); + solv_free(cx); + solv_free(cn); + return; + } + queue_init(&hq); + for (i = 0; i < ctc; i++) + { + Id h = repodata_new_handle(data); + if (ct[i]) + repodata_set_num(data, h, SOLVABLE_CHANGELOG_TIME, ct[i]); + if (cn[i]) + setutf8string(data, h, SOLVABLE_CHANGELOG_AUTHOR, cn[i]); + if (cx[i]) + setutf8string(data, h, SOLVABLE_CHANGELOG_TEXT, cx[i]); + queue_push(&hq, h); + } + for (i = 0; i < hq.count; i++) + repodata_add_flexarray(data, handle, SOLVABLE_CHANGELOG, hq.elements[i]); + queue_free(&hq); + solv_free(ct); + solv_free(cx); + solv_free(cn); +} - handle = s - pool->solvables; - did = repodata_str2dir(data, dn[di[i]], 1); - if (!did) +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') { - did = repodata_str2dir(data, "/", 1); - if (b && b[0] == '/') - b++; /* work around rpm bug */ + *aut++ = *p++; + while (*p == ' ') + p++; + continue; } - repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b); + *aut++ = *p++; } + while (aut != str && aut[-1] == '\n') + aut--; + *aut = 0; + if (*str) + setutf8string(data, handle, SOLVABLE_AUTHORS, str); + free(str); } -#if 0 - if (fn) - sat_free(fn); -#endif - sat_free(bn); - sat_free(dn); - sat_free(di); - return olddeps; + else if (*str) + setutf8string(data, handle, SOLVABLE_DESCRIPTION, str); } -static void -addsourcerpm(Pool *pool, Repodata *data, Id handle, char *sourcerpm, char *name, char *evr) +static int +rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags) { - const char *p, *sevr, *sarch; - - p = strrchr(sourcerpm, '.'); - if (!p || strcmp(p, ".rpm") != 0) - return; - p--; - while (p > sourcerpm && *p != '.') - p--; - if (*p != '.' || p == sourcerpm) - return; - sarch = p-- + 1; - while (p > sourcerpm && *p != '-') - p--; - if (*p != '-' || p == sourcerpm) - return; - p--; - while (p > sourcerpm && *p != '-') - p--; - if (*p != '-' || p == sourcerpm) - return; - sevr = p + 1; - if (!strcmp(sarch, "src.rpm")) - repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_SRC); - else if (!strcmp(sarch, "nosrc.rpm")) - repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_NOSRC); - else - repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1)); - if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0) - repodata_set_void(data, handle, SOLVABLE_SOURCEEVR); - else - repodata_set_id(data, handle, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1)); - if (name && !strncmp(sourcerpm, name, sevr - sourcerpm - 1) && name[sevr - sourcerpm - 1] == 0) - repodata_set_void(data, handle, SOLVABLE_SOURCENAME); - else - repodata_set_id(data, handle, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcerpm, sevr - sourcerpm - 1, 1)); -} - -static int -rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags) -{ - char *name; - char *evr; - char *sourcerpm; + char *name; + char *evr; + char *sourcerpm; + Queue ignq; + Id ignqbuf[64]; name = headstring(rpmhead, TAG_NAME); - if (!strcmp(name, "gpg-pubkey")) - return 0; - s->name = pool_str2id(pool, name, 1); - if (!s->name) + if (!name) { - fprintf(stderr, "package has no name\n"); - exit(1); + pool_error(pool, 0, "package has no name"); + return 0; } + if (!(flags & RPMDB_KEEP_GPG_PUBKEY) && !strcmp(name, "gpg-pubkey")) + return 0; + s->name = pool_str2id(pool, name, 1); sourcerpm = headstring(rpmhead, TAG_SOURCERPM); - if (sourcerpm) + if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead))) s->arch = pool_str2id(pool, headstring(rpmhead, TAG_ARCH), 1); else { @@ -861,29 +1118,35 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, s->arch = ARCH_NOARCH; evr = headtoevr(rpmhead); s->evr = pool_str2id(pool, evr, 1); + solv_free(evr); s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1); - s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0); - if ((flags & RPM_ADD_NO_FILELIST) == 0) - s->provides = addfileprovides(pool, repo, data, s, rpmhead, s->provides); + 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_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); - 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); + 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) { Id handle; char *str; unsigned int u32; + unsigned long long u64; handle = s - pool->solvables; str = headstring(rpmhead, TAG_SUMMARY); @@ -891,47 +1154,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 = 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); @@ -947,66 +1170,222 @@ rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, str = headstring(rpmhead, TAG_PACKAGER); if (str) repodata_set_poolstr(data, handle, SOLVABLE_PACKAGER, str); + if ((flags & RPM_ADD_WITH_PKGID) != 0) + { + unsigned char *chksum; + unsigned int chksumsize; + chksum = headbinary(rpmhead, TAG_SIGMD5, &chksumsize); + if (chksum && chksumsize == 16) + repodata_set_bin_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, chksum); + } + if ((flags & RPM_ADD_WITH_HDRID) != 0) + { + str = headstring(rpmhead, TAG_SHA1HEADER); + if (str && strlen(str) == 40) + repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA1, str); + else if (str && strlen(str) == 64) + repodata_set_checksum(data, handle, SOLVABLE_HDRID, REPOKEY_TYPE_SHA256, str); + } u32 = headint32(rpmhead, TAG_BUILDTIME); if (u32) repodata_set_num(data, handle, SOLVABLE_BUILDTIME, u32); + str = headstring(rpmhead, TAG_BUILDHOST); + if (str) + repodata_set_str(data, handle, SOLVABLE_BUILDHOST, str); u32 = headint32(rpmhead, TAG_INSTALLTIME); if (u32) repodata_set_num(data, handle, SOLVABLE_INSTALLTIME, u32); - u32 = headint32(rpmhead, TAG_SIZE); - if (u32) - repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, (u32 + 1023) / 1024); + u64 = headint64(rpmhead, TAG_LONGSIZE); + if (u64) + repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u64); + else + { + u32 = headint32(rpmhead, TAG_SIZE); + if (u32) + repodata_set_num(data, handle, SOLVABLE_INSTALLSIZE, u32); + } if (sourcerpm) - addsourcerpm(pool, data, handle, sourcerpm, name, evr); + 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, flags); + if ((flags & RPM_ADD_WITH_CHANGELOG) != 0) + addchangelog(data, handle, rpmhead); } - sat_free(evr); return 1; } -static Id -copyreldep(Pool *pool, Pool *frompool, Id id) +static inline unsigned int +getu32(const unsigned char *dp) { - 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); + return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3]; +} + +#ifdef ENABLE_RPMDB + +struct rpmdbentry { + Id rpmdbid; + Id nameoff; +}; + +#define ENTRIES_BLOCK 255 +#define NAMEDATA_BLOCK 1023 + +# ifdef ENABLE_RPMDB_LIBRPM +# include "repo_rpmdb_librpm.h" +# else +# include "repo_rpmdb_bdb.h" +# endif + +#else + +/* dummy state just to store pool/rootdir and header data */ +struct rpmdbstate { + Pool *pool; + char *rootdir; + + RpmHead *rpmhead; /* header storage space */ + unsigned int rpmheadsize; +}; + +#endif + + +#ifndef ENABLE_RPMPKG_LIBRPM + +static inline RpmHead * +realloc_head(struct rpmdbstate *state, unsigned int len) +{ + if (len > state->rpmheadsize) + { + state->rpmheadsize = len + 128; + state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); + } + return state->rpmhead; +} + +static int +headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2) +{ + unsigned int len = 16 * cnt + dsize + pad; + RpmHead *rpmhead = realloc_head(state, len + 1); + if (fread(rpmhead->data, len, 1, fp) != 1) + return pool_error(state->pool, 0, "%s: unexpected EOF", name); + if (chk1) + solv_chksum_add(chk1, rpmhead->data, len); + if (chk2) + solv_chksum_add(chk2, rpmhead->data, len); + headinit(rpmhead, cnt, dsize); + return 1; +} + +# if defined(ENABLE_RPMDB) && (!defined(ENABLE_RPMDB_LIBRPM) || defined(HAVE_RPMDBNEXTITERATORHEADERBLOB)) + +static int +headfromhdrblob(struct rpmdbstate *state, const unsigned char *data, unsigned int size) +{ + unsigned int dsize, cnt, len; + RpmHead *rpmhead; + if (size < 8) + return pool_error(state->pool, 0, "corrupt rpm database (size)"); + cnt = getu32(data); + dsize = getu32(data + 4); + if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE) + return pool_error(state->pool, 0, "corrupt rpm database (cnt/dcnt)"); + if (8 + cnt * 16 + dsize > size) + return pool_error(state->pool, 0, "corrupt rpm database (data size)"); + len = 16 * cnt + dsize; + rpmhead = realloc_head(state, len + 1); + memcpy(rpmhead->data, data + 8, len); + headinit(rpmhead, cnt, dsize); + return 1; +} + +# endif + +#else + +static int +headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2) +{ + unsigned int len = 16 * cnt + dsize + pad; + char *buf = solv_malloc(8 + len); + Header h; + memcpy(buf, lead + 8, 8); + if (fread(buf + 8, len, 1, fp) != 1) + { + solv_free(buf); + return pool_error(state->pool, 0, "%s: unexpected EOF", name); + } + if (chk1) + solv_chksum_add(chk1, buf + 8, len); + if (chk2) + solv_chksum_add(chk2, buf + 8, len); + h = headerImport(buf, 8 + len - pad, HEADERIMPORT_FAST); + if (!h) + { + solv_free(buf); + return pool_error(state->pool, 0, "%s: headerImport error", name); + } + if (state->rpmhead) + headfree(state->rpmhead); + state->rpmhead = h; + return 1; +} + +#endif + +static void +freestate(struct rpmdbstate *state) +{ + /* close down */ +#ifdef ENABLE_RPMDB + if (state->dbenvopened) + closedbenv(state); +#endif + if (state->rootdir) + solv_free(state->rootdir); + headfree(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) +{ + if (state) + freestate(state); + return solv_free(state); } + +#ifdef ENABLE_RPMDB + + +/******************************************************************/ + 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; @@ -1017,158 +1396,77 @@ 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 inline Id -copydir(Pool *pool, Repodata *data, Stringpool *fromspool, Repodata *fromdata, Id did, Id *cache) -{ - if (cache && cache[did & 255] == did) - return cache[(did & 255) + 256]; - return copydir_complex(pool, data, fromspool, fromdata, did, cache); -} - -static Id -copydir_complex(Pool *pool, Repodata *data, Stringpool *fromspool, Repodata *fromdata, Id did, Id *cache) -{ - Id parent = dirpool_parent(&fromdata->dirpool, did); - Id 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); - compid = dirpool_add_dir(&data->dirpool, parent, compid, 1); - if (cache) - { - cache[did & 255] = did; - cache[(did & 255) + 256] = compid; - } - return compid; -} - struct solvable_copy_cbdata { Repodata *data; Id handle; + Id subhandle; Id *dircache; + int bad; }; static int solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, KeyValue *kv) { struct solvable_copy_cbdata *cbdata = vcbdata; - 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; - keyname = key->name; - if (keyname >= ID_NUM_INTERNAL) - keyname = pool_str2id(pool, pool_id2str(frompool, keyname), 1); - switch(key->type) + switch (key->type) { case REPOKEY_TYPE_ID: case REPOKEY_TYPE_CONSTANTID: - 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 (key->type == REPOKEY_TYPE_ID) - repodata_set_id(data, handle, keyname, id); - else - repodata_set_constantid(data, handle, keyname, id); - break; - case REPOKEY_TYPE_STR: - repodata_set_str(data, handle, keyname, kv->str); - break; - case REPOKEY_TYPE_VOID: - repodata_set_void(data, handle, keyname); - break; - case REPOKEY_TYPE_NUM: - repodata_set_num(data, handle, keyname, kv->num); - break; - case REPOKEY_TYPE_CONSTANT: - repodata_set_constant(data, handle, keyname, kv->num); + case REPOKEY_TYPE_IDARRAY: /* used for triggers */ + if (data->localpool || fromdata->localpool) + kv->id = repodata_translate_id(data, fromdata, kv->id, 1); 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); - 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); - break; - case REPOKEY_TYPE_IDARRAY: /* used for triggers */ - id = kv->id; - assert(!data->localpool); /* implement me! */ - if (ISRELDEP(id)) - break; /* can't do those at the moment */ - if (pool != frompool || fromdata->localpool) - id = pool_str2id(pool, stringpool_id2str(fromspool, id), 1); - repodata_add_idarray(data, handle, keyname, id); + kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0); + if (!kv->id) + { + cbdata->bad = 1; /* oops, cannot copy this */ + return 0; + } break; + case REPOKEY_TYPE_FIXARRAY: + cbdata->handle = repodata_new_handle(data); + repodata_add_fixarray(data, handle, key->name, cbdata->handle); + repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata); + cbdata->handle = handle; + return 0; + case REPOKEY_TYPE_FLEXARRAY: + cbdata->handle = repodata_new_handle(data); + repodata_add_flexarray(data, handle, key->name, cbdata->handle); + repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata); + cbdata->handle = handle; + return 0; default: break; } + repodata_set_kv(data, handle, key->name, key->type, kv); return 0; } -static void -solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache) +static int +solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip) { + int p, i; Repo *repo = s->repo; - Repo *fromrepo = r->repo; Pool *pool = repo->pool; + Repo *fromrepo = r->repo; struct solvable_copy_cbdata cbdata; + Id *keyskip; /* 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); @@ -1179,24 +1477,50 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache) s->enhances = copydeps(pool, repo, r->enhances, fromrepo); /* copy all attributes */ - if (!data) - return; + if (!data || fromrepo->nrepodata < 2) + return 1; cbdata.data = data; cbdata.handle = s - pool->solvables; + cbdata.subhandle = 0; cbdata.dircache = dircache; - repo_search(fromrepo, (r - fromrepo->pool->solvables), 0, 0, SEARCH_NO_STORAGE_SOLVABLE, solvable_copy_cb, &cbdata); + cbdata.bad = 0; + p = r - fromrepo->pool->solvables; + if (fromrepo->nrepodata == 2) + { + Repodata *fromdata = repo_id2repodata(fromrepo, 1); + if (p >= fromdata->start && p < fromdata->end) + repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata); + } + else + { + keyskip = repo_create_keyskip(repo, p, oldkeyskip); + FOR_REPODATAS(fromrepo, i, data) + { + if (p >= data->start && p < data->end) + repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata); + } + } + if (cbdata.bad) + { + repodata_unset_uninternalized(data, cbdata.handle, 0); + memset(s, 0, sizeof(*s)); + s->repo = repo; + return 0; + } + return 1; } -/* used to sort entries returned in some database order */ +/* used to sort entries by package name that got returned in some database order */ static int rpmids_sort_cmp(const void *va, const void *vb, void *dp) { - struct rpmid const *a = va, *b = vb; + struct rpmdbentry const *a = va, *b = vb; + char *namedata = dp; int r; - r = strcmp(a->name, b->name); + r = strcmp(namedata + a->nameoff, namedata + b->nameoff); if (r) return r; - return a->dbid - b->dbid; + return a->rpmdbid - b->rpmdbid; } static int @@ -1230,131 +1554,29 @@ swap_solvables(Repo *repo, Repodata *data, Id pa, Id pb) repo->rpmdbid[pb - repo->start] = tmpid; } /* only works if nothing is already internalized! */ - if (data && data->attrs) - { - Id *tmpattrs = data->attrs[pa - data->start]; - data->attrs[pa - data->start] = data->attrs[pb - data->start]; - data->attrs[pb - data->start] = tmpattrs; - } -} - - -static inline Id db2rpmdbid(unsigned char *db, int byteswapped) -{ -#ifdef RPM5 - return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3]; -#else -# if defined(WORDS_BIGENDIAN) - if (!byteswapped) -# else - if (byteswapped) -# endif - return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3]; - else - return db[3] << 24 | db[2] << 16 | db[1] << 8 | db[0]; -#endif -} - -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; -#else -# if defined(WORDS_BIGENDIAN) - if (!byteswapped) -# else - if (byteswapped) -# endif - db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id; - else - db[3] = id >> 24, db[2] = id >> 16, db[1] = id >> 8, db[0] = id; -#endif + if (data) + repodata_swap_attrs(data, pa, 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)); -} - -/* should look in /usr/lib/rpm/macros instead, but we want speed... */ -static DB_ENV * -opendbenv(const char *rootdir) -{ - char dbpath[PATH_MAX]; - DB_ENV *dbenv = 0; - int r; - - if (db_env_create(&dbenv, 0)) - { - perror("db_env_create"); - return 0; - } -#if defined(FEDORA) && (DB_VERSION_MAJOR >= 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)) - dbenv->set_thread_count(dbenv, 8); -#endif - snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm", rootdir ? rootdir : ""); - if (access(dbpath, W_OK) == -1) - { - r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); - } - else - { -#ifdef FEDORA - r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 0644); -#else - r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0); -#endif - } - if (r) - { - perror("dbenv open"); - dbenv->close(dbenv, 0); - return 0; - } - return dbenv; -} - - -static int -count_headers(const char *rootdir, DB_ENV *dbenv) -{ - char dbpath[PATH_MAX]; - struct stat statbuf; - DB *db = 0; - DBC *dbc = 0; - int count = 0; - DBT dbkey; - DBT dbdata; - - snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Name", rootdir); - if (stat(dbpath, &statbuf)) - return 0; - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - if (db_create(&db, dbenv, 0)) - { - perror("db_create"); - exit(1); - } - if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - perror("db->open Name index"); - exit(1); - } - if (db->cursor(db, NULL, &dbc, 0)) - { - perror("db->cursor"); - exit(1); - } - while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0) - count += dbdata.size / RPM_INDEX_SIZE; - dbc->c_close(dbc); - db->close(db, 0); - return count; + 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; } /* @@ -1362,96 +1584,77 @@ count_headers(const char *rootdir, DB_ENV *dbenv) * */ -void -repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir, int flags) +int +repo_add_rpmdb(Repo *repo, Repo *ref, int flags) { Pool *pool = repo->pool; - unsigned char buf[16]; - DB *db = 0; - DBC *dbc = 0; - int byteswapped; - unsigned int dbid; - unsigned char *dp; - int dl, nrpmids; - struct rpmid *rpmids, *rp; - int i; - int rpmheadsize; - RpmHead *rpmhead; - Solvable *s; - Id id, *refhash; - unsigned int refmask, h; - char dbpath[PATH_MAX]; - DB_ENV *dbenv = 0; - DBT dbkey; - DBT dbdata; struct stat packagesstat; unsigned char newcookie[32]; const unsigned char *oldcookie = 0; Id oldcookietype = 0; Repodata *data; int count = 0, done = 0; + struct rpmdbstate state; + int i; + Solvable *s; unsigned int now; - now = sat_timems(0); - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - - if (!rootdir) - rootdir = ""; + 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 (!(dbenv = opendbenv(rootdir))) - exit(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); - if (stat(dbpath, &packagesstat)) + if (stat_database(&state, &packagesstat)) { - perror(dbpath); - exit(1); + 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) oldcookie = repo_lookup_bin_checksum(ref, SOLVID_META, REPOSITORY_RPMDBCOOKIE, &oldcookietype); if (!ref || !oldcookie || oldcookietype != REPOKEY_TYPE_SHA256 || memcmp(oldcookie, newcookie, 32) != 0) { - Id *pkgids; int solvstart = 0, solvend = 0; + Id dbid; + 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(rootdir, dbenv); - if (db_create(&db, dbenv, 0)) - { - perror("db_create"); - exit(1); - } - if (db->open(db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - perror("db->open Packages index"); - exit(1); - } - if (db->get_byteswapped(db, &byteswapped)) - { - perror("db->get_byteswapped"); - exit(1); - } - if (db->cursor(db, NULL, &dbc, 0)) + count = count_headers(&state); + if (pkgdb_cursor_open(&state)) { - perror("db->cursor"); - exit(1); + freestate(&state); + return -1; } - rpmheadsize = 0; - rpmhead = 0; i = 0; s = 0; - while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0) + while ((dbid = pkgdb_cursor_getrpm(&state)) != 0) { + if (dbid == -1) + { + pkgdb_cursor_close(&state); + freestate(&state); + return -1; + } if (!s) { s = pool_id2solvable(pool, repo_add_solvable(repo)); @@ -1461,39 +1664,11 @@ repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir, int flags) } if (!repo->rpmdbid) repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); - if (dbkey.size != 4) + repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid; + if (rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS)) { - fprintf(stderr, "corrupt Packages database (key size)\n"); - exit(1); - } - dbid = db2rpmdbid(dbkey.data, byteswapped); - if (dbid == 0) /* the join key */ - continue; - if (dbdata.size < 8) - { - fprintf(stderr, "corrupt rpm database (size %u)\n", dbdata.size); - exit(1); - } - if (dbdata.size > rpmheadsize) - { - rpmheadsize = dbdata.size + 128; - rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); - } - memcpy(buf, dbdata.data, 8); - 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) - { - fprintf(stderr, "corrupt rpm database (data size)\n"); - exit(1); - } - memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt); - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid; - if (rpm2solv(pool, repo, data, s, rpmhead, flags | RPM_ADD_TRIGGERS)) - { - i++; - s = 0; + i++; + s = 0; } else { @@ -1507,26 +1682,23 @@ repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir, int flags) if (done < count) done++; if (done < count && (done - 1) * 100 / count != done * 100 / count) - pool_debug(pool, SAT_ERROR, "%%%% %d\n", done * 100 / count); + pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count); } } + pkgdb_cursor_close(&state); if (s) { /* oops, could not reuse. free it instead */ - repo_free_solvable_block(repo, s - pool->solvables, 1, 1); + s = solvable_free(s, 1); solvend--; - s = 0; } - dbc->c_close(dbc); - db->close(db, 0); - db = 0; /* now sort all solvables in the new solvstart..solvend block */ if (solvend - solvstart > 1) { - pkgids = sat_malloc2(solvend - solvstart, sizeof(Id)); + Id *pkgids = solv_malloc2(solvend - solvstart, sizeof(Id)); for (i = solvstart; i < solvend; i++) pkgids[i - solvstart] = i; - sat_sort(pkgids, solvend - solvstart, sizeof(Id), pkgids_sort_cmp, repo); + solv_sort(pkgids, solvend - solvstart, sizeof(Id), pkgids_sort_cmp, repo); /* adapt order */ for (i = solvstart; i < solvend; i++) { @@ -1536,67 +1708,35 @@ repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir, int flags) if (j != i) swap_solvables(repo, data, i, j); } - sat_free(pkgids); + solv_free(pkgids); } } else { - Id dircache[COPYDIR_DIRCACHE_SIZE]; /* see copydir */ + Id *dircache; + Id *oldkeyskip = 0; + struct rpmdbentry *entries = 0, *rp; + int nentries = 0; + char *namedata = 0; + unsigned int refmask, h; + Id id, *refhash; + int res; - memset(dircache, 0, sizeof(dircache)); - if (db_create(&db, dbenv, 0)) - { - perror("db_create"); - exit(1); - } - if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - perror("db->open Name index"); - exit(1); - } - if (db->get_byteswapped(db, &byteswapped)) + /* get ids of installed rpms */ + entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata, flags & RPMDB_KEEP_GPG_PUBKEY); + if (!entries) { - perror("db->get_byteswapped"); - exit(1); + freestate(&state); + return -1; } - if (db->cursor(db, NULL, &dbc, 0)) - { - perror("db->cursor"); - exit(1); - } - nrpmids = 0; - rpmids = 0; - while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0) - { - if (dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10)) - continue; - dl = dbdata.size; - dp = dbdata.data; - while(dl >= RPM_INDEX_SIZE) - { - rpmids = sat_extend(rpmids, nrpmids, 1, sizeof(*rpmids), 255); - rpmids[nrpmids].dbid = db2rpmdbid(dp, byteswapped); - rpmids[nrpmids].name = sat_malloc((int)dbkey.size + 1); - memcpy(rpmids[nrpmids].name, dbkey.data, (int)dbkey.size); - rpmids[nrpmids].name[(int)dbkey.size] = 0; - nrpmids++; - dp += RPM_INDEX_SIZE; - dl -= RPM_INDEX_SIZE; - } - } - dbc->c_close(dbc); - db->close(db, 0); - db = 0; - - /* sort rpmids */ - sat_sort(rpmids, nrpmids, sizeof(*rpmids), rpmids_sort_cmp, 0); - rpmheadsize = 0; - rpmhead = 0; + /* sort by name */ + if (nentries > 1) + solv_sort(entries, nentries, sizeof(*entries), rpmids_sort_cmp, namedata); /* create hash from dbid to ref */ refmask = mkmask(ref->nsolvables); - refhash = sat_calloc(refmask + 1, sizeof(Id)); + refhash = solv_calloc(refmask + 1, sizeof(Id)); for (i = 0; i < ref->end - ref->start; i++) { if (!ref->rpmdbid[i]) @@ -1610,11 +1750,11 @@ repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir, int flags) /* count the misses, they will cost us time */ if ((flags & RPMDB_REPORT_PROGRESS) != 0) { - for (i = 0, rp = rpmids; i < nrpmids; i++, rp++) + for (i = 0, rp = entries; i < nentries; i++, rp++) { - dbid = rp->dbid; if (refhash) { + Id dbid = rp->rpmdbid; h = dbid & refmask; while ((id = refhash[h])) { @@ -1629,14 +1769,18 @@ repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir, int flags) } } - s = pool_id2solvable(pool, repo_add_solvable_block(repo, nrpmids)); + 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)); - for (i = 0, rp = rpmids; i < nrpmids; i++, rp++, s++) + dircache = repodata_create_dirtranscache(data); + for (i = 0, rp = entries; i < nentries; i++, rp++, s++) { - dbid = rp->dbid; - repo->rpmdbid[(s - pool->solvables) - repo->start] = rp->dbid; + Id dbid = rp->rpmdbid; + repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid; if (refhash) { h = dbid & refmask; @@ -1649,113 +1793,88 @@ repo_add_rpmdb(Repo *repo, Repo *ref, const char *rootdir, int flags) if (id) { Solvable *r = ref->pool->solvables + ref->start + (id - 1); - if (r->repo == ref) - { - solvable_copy(s, r, data, dircache); - continue; - } - } - } - if (!db) - { - if (db_create(&db, dbenv, 0)) - { - perror("db_create"); - exit(1); - } - if (db->open(db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - perror("db->open var/lib/rpm/Packages"); - exit(1); - } - if (db->get_byteswapped(db, &byteswapped)) - { - perror("db->get_byteswapped"); - exit(1); + if (r->repo == ref && solvable_copy(s, r, data, dircache, &oldkeyskip)) + continue; } } - rpmdbid2db(buf, rp->dbid, byteswapped); - dbkey.data = buf; - dbkey.size = 4; - dbdata.data = 0; - dbdata.size = 0; - if (db->get(db, NULL, &dbkey, &dbdata, 0)) - { - perror("db->get"); - fprintf(stderr, "corrupt rpm database, key %d not found\n", dbid); - fprintf(stderr, "please run 'rpm --rebuilddb' to recreate the database index files\n"); - exit(1); - } - if (dbdata.size < 8) - { - fprintf(stderr, "corrupt rpm database (size)\n"); - exit(1); - } - if (dbdata.size > rpmheadsize) - { - rpmheadsize = dbdata.size + 128; - rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); - } - memcpy(buf, dbdata.data, 8); - 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) + res = getrpm_dbid(&state, dbid); + if (res <= 0) { - fprintf(stderr, "corrupt rpm database (data size)\n"); - exit(1); + if (!res) + 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); + dircache = repodata_free_dirtranscache(dircache); + return -1; } - memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt); - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - - rpm2solv(pool, repo, data, s, 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) done++; if (done < count && (done - 1) * 100 / count != done * 100 / count) - pool_debug(pool, SAT_ERROR, "%%%% %d\n", done * 100 / count); + pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count); } } + dircache = repodata_free_dirtranscache(dircache); - if (refhash) - sat_free(refhash); - if (rpmids) - { - for (i = 0; i < nrpmids; i++) - sat_free(rpmids[i].name); - sat_free(rpmids); - } + solv_free(oldkeyskip); + solv_free(entries); + solv_free(namedata); + solv_free(refhash); + if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0) + repo_empty(ref, 1); } - if (db) - db->close(db, 0); - dbenv->close(dbenv, 0); - if (rpmhead) - sat_free(rpmhead); + + freestate(&state); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); if ((flags & RPMDB_REPORT_PROGRESS) != 0) - pool_debug(pool, SAT_ERROR, "%%%% 100\n"); - POOL_DEBUG(SAT_DEBUG_STATS, "repo_add_rpmdb took %d ms\n", sat_timems(now)); - POOL_DEBUG(SAT_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables); - POOL_DEBUG(SAT_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", data->incoredatalen/1024, repo->idarraysize / (int)(1024/sizeof(Id))); + pool_debug(pool, SOLV_ERROR, "%%%% 100\n"); + POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_rpmdb took %d ms\n", solv_timems(now)); + POOL_DEBUG(SOLV_DEBUG_STATS, "repo size: %d solvables\n", repo->nsolvables); + POOL_DEBUG(SOLV_DEBUG_STATS, "repo memory used: %d K incore, %d K idarray\n", repodata_memused(data)/1024, repo->idarraysize / (int)(1024/sizeof(Id))); + 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 /* ENABLE_RPMDB */ -void -repo_add_rpms(Repo *repo, const char **rpms, int nrpms, int flags) +Id +repo_add_rpm(Repo *repo, const char *rpm, int flags) { - int i, sigdsize, sigcnt, l; + unsigned int sigdsize, sigcnt, sigpad, l; Pool *pool = repo->pool; Solvable *s; - RpmHead *rpmhead = 0; - int rpmheadsize = 0; + struct rpmdbstate state; char *payloadformat; FILE *fp; unsigned char lead[4096]; @@ -1763,9 +1882,12 @@ repo_add_rpms(Repo *repo, const char **rpms, int nrpms, int flags) struct stat stb; Repodata *data; unsigned char pkgid[16]; - int gotpkgid; + unsigned char leadsigid[16]; + unsigned char hdrid[32]; + int pkgidtype, leadsigidtype, hdridtype; Id chksumtype = 0; - void *chksumh = 0; + Chksum *chksumh = 0; + Chksum *leadsigchksumh = 0; data = repo_add_repodata(repo, flags); @@ -1773,188 +1895,253 @@ repo_add_rpms(Repo *repo, const char **rpms, int nrpms, int flags) chksumtype = REPOKEY_TYPE_SHA256; else if ((flags & RPM_ADD_WITH_SHA1SUM) != 0) chksumtype = REPOKEY_TYPE_SHA1; - for (i = 0; i < nrpms; i++) + + /* open rpm */ + if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, rpm) : rpm, "r")) == 0) { - if ((fp = fopen(rpms[i], "r")) == 0) - { - perror(rpms[i]); - continue; - } - if (fstat(fileno(fp), &stb)) - { - perror("stat"); - continue; - } - if (chksumh) - chksumh = sat_chksum_free(chksumh, 0); - if (chksumtype) - chksumh = sat_chksum_create(chksumtype); - if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb) - { - fprintf(stderr, "%s: not a rpm\n", rpms[i]); - fclose(fp); - continue; - } - if (chksumh) - sat_chksum_add(chksumh, lead, 96 + 16); - if (lead[78] != 0 || lead[79] != 5) - { - fprintf(stderr, "%s: not a V5 header\n", rpms[i]); - fclose(fp); - continue; - } - if (getu32(lead + 96) != 0x8eade801) - { - fprintf(stderr, "%s: bad signature header\n", rpms[i]); - fclose(fp); - continue; - } - sigcnt = getu32(lead + 96 + 8); - sigdsize = getu32(lead + 96 + 12); - if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000) + pool_error(pool, -1, "%s: %s", rpm, strerror(errno)); + return 0; + } + if (fstat(fileno(fp), &stb)) + { + pool_error(pool, -1, "fstat: %s", strerror(errno)); + fclose(fp); + return 0; + } + + /* setup state */ + memset(&state, 0, sizeof(state)); + state.pool = pool; + + /* process lead */ + if (chksumtype) + chksumh = solv_chksum_create(chksumtype); + if ((flags & RPM_ADD_WITH_LEADSIGID) != 0) + leadsigchksumh = solv_chksum_create(REPOKEY_TYPE_MD5); + if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb) + { + pool_error(pool, -1, "%s: not a rpm", rpm); + solv_chksum_free(leadsigchksumh, 0); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } + if (chksumh) + solv_chksum_add(chksumh, lead, 96 + 16); + if (leadsigchksumh) + solv_chksum_add(leadsigchksumh, lead, 96 + 16); + + /* process signature header */ + if (lead[78] != 0 || lead[79] != 5) + { + pool_error(pool, -1, "%s: not a rpm v5 header", rpm); + solv_chksum_free(leadsigchksumh, 0); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } + if (getu32(lead + 96) != 0x8eade801) + { + pool_error(pool, -1, "%s: bad signature header", rpm); + solv_chksum_free(leadsigchksumh, 0); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } + sigcnt = getu32(lead + 96 + 8); + sigdsize = getu32(lead + 96 + 12); + if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE) + { + pool_error(pool, -1, "%s: bad signature header", rpm); + solv_chksum_free(leadsigchksumh, 0); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } + sigpad = sigdsize & 7 ? 8 - (sigdsize & 7) : 0; + headerstart = 96 + 16 + sigcnt * 16 + sigdsize + sigpad; + pkgidtype = leadsigidtype = hdridtype = 0; + if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0) + { + if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh)) { - fprintf(stderr, "%s: bad signature header\n", rpms[i]); + solv_chksum_free(leadsigchksumh, 0); + solv_chksum_free(chksumh, 0); fclose(fp); - continue; + return 0; } - sigdsize += sigcnt * 16; - sigdsize = (sigdsize + 7) & ~7; - headerstart = 96 + 16 + sigdsize; - gotpkgid = 0; if ((flags & RPM_ADD_WITH_PKGID) != 0) { unsigned char *chksum; unsigned int chksumsize; - /* extract pkgid from the signature header */ - if (sigdsize > rpmheadsize) - { - rpmheadsize = sigdsize + 128; - rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); - } - if (fread(rpmhead->data, sigdsize, 1, fp) != 1) - { - fprintf(stderr, "%s: unexpected EOF\n", rpms[i]); - fclose(fp); - continue; - } - if (chksumh) - sat_chksum_add(chksumh, rpmhead->data, sigdsize); - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize - sigcnt * 16; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - chksum = headbinary(rpmhead, SIGTAG_MD5, &chksumsize); + chksum = headbinary(state.rpmhead, SIGTAG_MD5, &chksumsize); if (chksum && chksumsize == 16) { - gotpkgid = 1; + pkgidtype = REPOKEY_TYPE_MD5; memcpy(pkgid, chksum, 16); } } - else + if ((flags & RPM_ADD_WITH_HDRID) != 0) { - /* just skip the signature header */ - while (sigdsize) + const char *str = headstring(state.rpmhead, TAG_SHA1HEADER); + if (str && strlen(str) == 40) { - l = sigdsize > 4096 ? 4096 : sigdsize; - if (fread(lead, l, 1, fp) != 1) - { - fprintf(stderr, "%s: unexpected EOF\n", rpms[i]); - fclose(fp); - continue; - } - if (chksumh) - sat_chksum_add(chksumh, lead, l); - sigdsize -= l; + if (solv_hex2bin(&str, hdrid, 20) == 20) + hdridtype = REPOKEY_TYPE_SHA1; + } + else if (str && strlen(str) == 64) + { + if (solv_hex2bin(&str, hdrid, 32) == 32) + hdridtype = REPOKEY_TYPE_SHA256; } } - if (fread(lead, 16, 1, fp) != 1) - { - fprintf(stderr, "%s: unexpected EOF\n", rpms[i]); - fclose(fp); - continue; - } - if (chksumh) - sat_chksum_add(chksumh, lead, 16); - if (getu32(lead) != 0x8eade801) - { - fprintf(stderr, "%s: bad header\n", rpms[i]); - fclose(fp); - continue; - } - sigcnt = getu32(lead + 8); - sigdsize = getu32(lead + 12); - if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000) - { - fprintf(stderr, "%s: bad header\n", rpms[i]); - fclose(fp); - continue; - } - l = sigdsize + sigcnt * 16; - headerend = headerstart + 16 + l; - if (l > rpmheadsize) - { - rpmheadsize = l + 128; - rpmhead = sat_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize); - } - if (fread(rpmhead->data, l, 1, fp) != 1) - { - fprintf(stderr, "%s: unexpected EOF\n", rpms[i]); - fclose(fp); - continue; - } - if (chksumh) - sat_chksum_add(chksumh, rpmhead->data, l); - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - if (headexists(rpmhead, TAG_PATCHESNAME)) - { - /* this is a patch rpm, ignore */ - fclose(fp); - continue; - } - payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT); - if (payloadformat && !strcmp(payloadformat, "drpm")) - { - /* this is a delta rpm */ - fclose(fp); - continue; - } - if (chksumh) - while ((l = fread(lead, 1, sizeof(lead), fp)) > 0) - sat_chksum_add(chksumh, lead, l); - fclose(fp); - s = pool_id2solvable(pool, repo_add_solvable(repo)); - rpm2solv(pool, repo, data, s, rpmhead, flags); - if (data) + } + else + { + /* just skip the signature header */ + unsigned int len = sigcnt * 16 + sigdsize + sigpad; + while (len) { - Id handle = s - pool->solvables; - repodata_set_location(data, handle, 0, 0, rpms[i]); - if (S_ISREG(stb.st_mode)) - repodata_set_num(data, handle, SOLVABLE_DOWNLOADSIZE, (unsigned int)((stb.st_size + 1023) / 1024)); - repodata_set_num(data, handle, SOLVABLE_HEADEREND, headerend); - if (gotpkgid) - repodata_set_bin_checksum(data, handle, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid); + l = len > 4096 ? 4096 : len; + if (fread(lead, l, 1, fp) != 1) + { + pool_error(pool, -1, "%s: unexpected EOF", rpm); + solv_chksum_free(leadsigchksumh, 0); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } if (chksumh) - repodata_set_bin_checksum(data, handle, SOLVABLE_CHECKSUM, chksumtype, sat_chksum_get(chksumh, 0)); + solv_chksum_add(chksumh, lead, l); + if (leadsigchksumh) + solv_chksum_add(leadsigchksumh, lead, l); + len -= l; } } + if (leadsigchksumh) + { + leadsigchksumh = solv_chksum_free(leadsigchksumh, leadsigid); + leadsigidtype = REPOKEY_TYPE_MD5; + } + + /* process main header */ + if (fread(lead, 16, 1, fp) != 1) + { + pool_error(pool, -1, "%s: unexpected EOF", rpm); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } if (chksumh) - chksumh = sat_chksum_free(chksumh, 0); - if (rpmhead) - sat_free(rpmhead); + solv_chksum_add(chksumh, lead, 16); + if (getu32(lead) != 0x8eade801) + { + pool_error(pool, -1, "%s: bad header", rpm); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } + sigcnt = getu32(lead + 8); + sigdsize = getu32(lead + 12); + if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE) + { + pool_error(pool, -1, "%s: bad header", rpm); + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } + headerend = headerstart + 16 + sigdsize + sigcnt * 16; + + if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0)) + { + solv_chksum_free(chksumh, 0); + fclose(fp); + return 0; + } + if (headexists(state.rpmhead, TAG_PATCHESNAME)) + { + /* this is a patch rpm, ignore */ + pool_error(pool, -1, "%s: is patch rpm", rpm); + fclose(fp); + solv_chksum_free(chksumh, 0); + headfree(state.rpmhead); + return 0; + } + payloadformat = headstring(state.rpmhead, TAG_PAYLOADFORMAT); + if (payloadformat && !strcmp(payloadformat, "drpm")) + { + /* this is a delta rpm */ + pool_error(pool, -1, "%s: is delta rpm", rpm); + fclose(fp); + solv_chksum_free(chksumh, 0); + headfree(state.rpmhead); + return 0; + } + if (chksumh) + while ((l = fread(lead, 1, sizeof(lead), fp)) > 0) + solv_chksum_add(chksumh, lead, l); + fclose(fp); + s = pool_id2solvable(pool, repo_add_solvable(repo)); + if (!rpmhead2solv(pool, repo, data, s, state.rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID))) + { + s = solvable_free(s, 1); + solv_chksum_free(chksumh, 0); + headfree(state.rpmhead); + return 0; + } + if (!(flags & REPO_NO_LOCATION)) + repodata_set_location(data, s - pool->solvables, 0, 0, rpm); + if (S_ISREG(stb.st_mode)) + repodata_set_num(data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE, (unsigned long long)stb.st_size); + repodata_set_num(data, s - pool->solvables, SOLVABLE_HEADEREND, headerend); + if (pkgidtype) + repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_PKGID, pkgidtype, pkgid); + if (hdridtype) + repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_HDRID, hdridtype, hdrid); + if (leadsigidtype) + repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_LEADSIGID, leadsigidtype, leadsigid); + if (chksumh) + { + repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, chksumtype, solv_chksum_get(chksumh, 0)); + chksumh = solv_chksum_free(chksumh, 0); + } + headfree(state.rpmhead); if (!(flags & REPO_NO_INTERNALIZE)) repodata_internalize(data); + return s - pool->solvables; } Id -repo_add_rpm(Repo *repo, const char *rpm, int flags) +repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags) { - int end = repo->end; - repo_add_rpms(repo, &rpm, 1, flags); - if (end == repo->end) - return 0; - else - return repo->end - 1; + Pool *pool = repo->pool; + Repodata *data; + RpmHead *rpmhead = rpmhandle; + Solvable *s; + char *payloadformat; + + data = repo_add_repodata(repo, flags); + if (headexists(rpmhead, TAG_PATCHESNAME)) + { + pool_error(pool, -1, "is a patch rpm"); + return 0; + } + payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT); + if (payloadformat && !strcmp(payloadformat, "drpm")) + { + /* this is a delta rpm */ + pool_error(pool, -1, "is a delta rpm"); + return 0; + } + s = pool_id2solvable(pool, repo_add_solvable(repo)); + if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags)) + { + s = solvable_free(s, 1); + return 0; + } + if (!(flags & REPO_NO_INTERNALIZE)) + repodata_internalize(data); + return s - pool->solvables; } static inline void @@ -1967,31 +2154,29 @@ linkhash(const char *lt, char *hash) l = strlen(lt); while ((c = *str++) != 0) r += (r << 3) + c; - sprintf(hash, "%08x", r); - sprintf(hash + 8, "%08x", l); - sprintf(hash + 16, "%08x", 0); - sprintf(hash + 24, "%08x", 0); + sprintf(hash, "%08x%08x%08x%08x", r, l, 0, 0); } void -rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, int, const char *), void *cbdata) +rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char *, struct filelistinfo *), void *cbdata) { RpmHead *rpmhead = rpmhandle; char **bn; char **dn; char **md = 0; char **lt = 0; - unsigned int *di, diidx; - unsigned int *co = 0; - unsigned int *ff = 0; + uint32_t *di, diidx; + uint32_t *co = 0; + uint32_t *ff = 0; + uint16_t *fm; unsigned int lastdir; int lastdirl; - unsigned int *fm; int cnt, dcnt, cnt2; int i, l1, l; char *space = 0; int spacen = 0; - char md5[33], *md5p = 0; + char md5[33]; + struct filelistinfo info; dn = headstringarray(rpmhead, TAG_DIRNAMES, &dcnt); if (!dn) @@ -1999,31 +2184,31 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * if ((flags & RPM_ITERATE_FILELIST_ONLYDIRS) != 0) { for (i = 0; i < dcnt; i++) - (*cb)(cbdata, dn[i], 0, (char *)0); - sat_free(dn); + (*cb)(cbdata, dn[i], 0); + solv_free(dn); return; } bn = headstringarray(rpmhead, TAG_BASENAMES, &cnt); if (!bn) { - sat_free(dn); + solv_free(dn); return; } di = headint32array(rpmhead, TAG_DIRINDEXES, &cnt2); if (!di || cnt != cnt2) { - sat_free(di); - sat_free(bn); - sat_free(dn); + solv_free(di); + solv_free(bn); + solv_free(dn); return; } fm = headint16array(rpmhead, TAG_FILEMODES, &cnt2); if (!fm || cnt != cnt2) { - sat_free(fm); - sat_free(di); - sat_free(bn); - sat_free(dn); + solv_free(fm); + solv_free(di); + solv_free(bn); + solv_free(dn); return; } if ((flags & RPM_ITERATE_FILELIST_WITHMD5) != 0) @@ -2031,25 +2216,25 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * md = headstringarray(rpmhead, TAG_FILEMD5S, &cnt2); if (!md || cnt != cnt2) { - sat_free(md); - sat_free(fm); - sat_free(di); - sat_free(bn); - sat_free(dn); + solv_free(md); + solv_free(fm); + solv_free(di); + solv_free(bn); + solv_free(dn); return; } } if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0) { co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2); - if (!co || cnt != cnt2) - { - sat_free(co); - sat_free(md); - sat_free(fm); - sat_free(di); - sat_free(bn); - sat_free(dn); + if (co && cnt != cnt2) + { + solv_free(co); + solv_free(md); + solv_free(fm); + solv_free(di); + solv_free(bn); + solv_free(dn); return; } } @@ -2058,18 +2243,19 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * ff = headint32array(rpmhead, TAG_FILEFLAGS, &cnt2); if (!ff || cnt != cnt2) { - sat_free(ff); - sat_free(co); - sat_free(md); - sat_free(fm); - sat_free(di); - sat_free(bn); - sat_free(dn); + solv_free(ff); + solv_free(co); + solv_free(md); + solv_free(fm); + solv_free(di); + solv_free(bn); + solv_free(dn); return; } } lastdir = dcnt; lastdirl = 0; + memset(&info, 0, sizeof(info)); for (i = 0; i < cnt; i++) { if (ff && (ff[i] & FILEFLAG_GHOST) != 0) @@ -2078,13 +2264,11 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * if (diidx >= dcnt) continue; l1 = lastdir == diidx ? lastdirl : strlen(dn[diidx]); - if (l1 == 0) - continue; l = l1 + strlen(bn[i]) + 1; if (l > spacen) { spacen = l + 16; - space = sat_realloc(space, spacen); + space = solv_realloc(space, spacen); } if (lastdir != diidx) { @@ -2093,41 +2277,46 @@ rpm_iterate_filelist(void *rpmhandle, int flags, void (*cb)(void *, const char * lastdirl = l1; } strcpy(space + l1, bn[i]); + info.diridx = diidx; + info.dirlen = l1; + if (fm) + info.mode = fm[i]; if (md) { - md5p = md[i]; - if (S_ISLNK(fm[i])) + info.digest = md[i]; + if (fm && S_ISLNK(fm[i])) { - md5p = 0; + info.digest = 0; if (!lt) { lt = headstringarray(rpmhead, TAG_FILELINKTOS, &cnt2); if (cnt != cnt2) - lt = sat_free(lt); + lt = solv_free(lt); } if (lt) { linkhash(lt[i], md5); - md5p = md5; + info.digest = md5; } } - if (!md5p) + if (!info.digest) { sprintf(md5, "%08x%08x%08x%08x", (fm[i] >> 12) & 65535, 0, 0, 0); - md5p = md5; + info.digest = md5; } } - (*cb)(cbdata, space, co ? (fm[i] | co[i] << 24) : fm[i], md5p); - } - sat_free(space); - sat_free(lt); - sat_free(md); - sat_free(fm); - sat_free(di); - sat_free(bn); - sat_free(dn); - sat_free(co); - sat_free(ff); + info.color = co ? co[i] : 0; + (*cb)(cbdata, space, &info); + } + solv_free(space); + solv_free(lt); + solv_free(md); + solv_free(fm); + solv_free(di); + solv_free(bn); + solv_free(dn); + solv_free(co); + solv_free(ff); } char * @@ -2141,12 +2330,12 @@ rpm_query(void *rpmhandle, Id what) r = 0; switch (what) { - case 0: + case 0: /* return canonical name of rpm */ name = headstring(rpmhead, TAG_NAME); if (!name) name = ""; sourcerpm = headstring(rpmhead, TAG_SOURCERPM); - if (sourcerpm) + if (sourcerpm || !(headexists(rpmhead, TAG_SOURCEPACKAGE) || headissourceheuristic(rpmhead))) arch = headstring(rpmhead, TAG_ARCH); else { @@ -2158,14 +2347,22 @@ rpm_query(void *rpmhandle, Id what) if (!arch) arch = "noarch"; evr = headtoevr(rpmhead); - l = strlen(name) + 1 + strlen(evr) + 1 + strlen(arch) + 1; - r = sat_malloc(l); - sprintf(r, "%s-%s.%s", name, evr, arch); - free(evr); + l = strlen(name) + 1 + strlen(evr ? evr : "") + 1 + strlen(arch) + 1; + r = solv_malloc(l); + sprintf(r, "%s-%s.%s", name, evr ? evr : "", arch); + solv_free(evr); break; case SOLVABLE_NAME: name = headstring(rpmhead, TAG_NAME); - r = strdup(name); + r = solv_strdup(name); + break; + case SOLVABLE_SUMMARY: + name = headstring(rpmhead, TAG_SUMMARY); + r = solv_strdup(name); + break; + case SOLVABLE_DESCRIPTION: + name = headstring(rpmhead, TAG_DESCRIPTION); + r = solv_strdup(name); break; case SOLVABLE_EVR: r = headtoevr(rpmhead); @@ -2174,332 +2371,155 @@ rpm_query(void *rpmhandle, Id what) return r; } - -struct rpm_by_state { - RpmHead *rpmhead; - int rpmheadsize; - - int dbopened; - DB_ENV *dbenv; - DB *db; - int byteswapped; -}; - -struct rpmdbentry { - Id rpmdbid; - Id nameoff; -}; - -#define ENTRIES_BLOCK 255 -#define NAMEDATA_BLOCK 1023 - -static struct rpmdbentry * -getinstalledrpmdbids(struct rpm_by_state *state, const char *index, const char *match, int *nentriesp, char **namedatap) +unsigned long long +rpm_query_num(void *rpmhandle, Id what, unsigned long long notfound) { - DB_ENV *dbenv = 0; - DB *db = 0; - DBC *dbc = 0; - int byteswapped; - DBT dbkey; - DBT dbdata; - unsigned char *dp; - int dl; - - char *namedata = 0; - int namedatal = 0; - struct rpmdbentry *entries = 0; - int nentries = 0; - - *nentriesp = 0; - *namedatap = 0; + RpmHead *rpmhead = rpmhandle; + unsigned int u32; - dbenv = state->dbenv; - if (db_create(&db, dbenv, 0)) - { - perror("db_create"); - return 0; - } - if (db->open(db, 0, index, 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - perror("db->open index"); - db->close(db, 0); - return 0; - } - if (db->get_byteswapped(db, &byteswapped)) - { - perror("db->get_byteswapped"); - db->close(db, 0); - return 0; - } - if (db->cursor(db, NULL, &dbc, 0)) - { - perror("db->cursor"); - db->close(db, 0); - return 0; - } - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - if (match) - { - dbkey.data = (void *)match; - dbkey.size = strlen(match); - } - while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0) + switch (what) { - if (!match && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10)) - continue; - dl = dbdata.size; - dp = dbdata.data; - while(dl >= RPM_INDEX_SIZE) - { - entries = sat_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK); - entries[nentries].rpmdbid = db2rpmdbid(dp, byteswapped); - entries[nentries].nameoff = namedatal; - nentries++; - namedata = sat_extend(namedata, namedatal, dbkey.size + 1, 1, NAMEDATA_BLOCK); - memcpy(namedata + namedatal, dbkey.data, dbkey.size); - namedata[namedatal + dbkey.size] = 0; - namedatal += dbkey.size + 1; - dp += RPM_INDEX_SIZE; - dl -= RPM_INDEX_SIZE; - } - if (match) - break; + case SOLVABLE_INSTALLTIME: + u32 = headint32(rpmhead, TAG_INSTALLTIME); + return u32 ? u32 : notfound; } - dbc->c_close(dbc); - db->close(db, 0); - *nentriesp = nentries; - *namedatap = namedata; - return entries; + return notfound; } -static void -freestate(struct rpm_by_state *state) -{ - /* close down */ - if (!state) - return; - if (state->db) - state->db->close(state->db, 0); - if (state->dbenv) - state->dbenv->close(state->dbenv, 0); - sat_free(state->rpmhead); -} +#ifdef ENABLE_RPMDB int -rpm_installedrpmdbids(const char *rootdir, const char *index, const char *match, Queue *rpmdbidq) +rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq) { - struct rpm_by_state state; struct rpmdbentry *entries; int nentries, i; - char *namedata; - if (!index) - index = "Name"; - if (rpmdbidq) - queue_empty(rpmdbidq); - memset(&state, 0, sizeof(state)); - if (!(state.dbenv = opendbenv(rootdir))) - return 0; - entries = getinstalledrpmdbids(&state, index, match, &nentries, &namedata); + entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0, 0); if (rpmdbidq) - for (i = 0; i < nentries; i++) - queue_push(rpmdbidq, entries[i].rpmdbid); - sat_free(entries); - sat_free(namedata); - freestate(&state); + { + queue_empty(rpmdbidq); + for (i = 0; i < nentries; i++) + queue_push(rpmdbidq, entries[i].rpmdbid); + } + solv_free(entries); return nentries; } -void * -rpm_byrpmdbid(Id rpmdbid, const char *rootdir, void **statep) +int +rpm_hash_database_state(void *rpmstate, Chksum *chk) { - struct rpm_by_state *state = *statep; - unsigned char buf[16]; - DBT dbkey; - DBT dbdata; - RpmHead *rpmhead; + struct rpmdbstate *state = rpmstate; + struct stat stb; + if (stat_database(state, &stb)) + return -1; + if (state->dbenvopened != 1 && !opendbenv(state)) + return -1; + solv_chksum_add(chk, &stb.st_mtime, sizeof(stb.st_mtime)); + solv_chksum_add(chk, &stb.st_size, sizeof(stb.st_size)); + solv_chksum_add(chk, &stb.st_ino, sizeof(stb.st_ino)); + hash_name_index(rpmstate, chk); + return 0; +} - if (!rpmdbid) - { - /* close down */ - freestate(state); - sat_free(state); - *statep = (void *)0; - return 0; - } +int +rpm_stat_database(void *rpmstate, void *stb) +{ + return stat_database((struct rpmdbstate *)rpmstate, (struct stat *)stb) ? -1 : 0; +} - if (!state) - { - state = sat_calloc(1, sizeof(*state)); - *statep = state; - } - if (!state->dbopened) - { - state->dbopened = 1; - if (!state->dbenv && !(state->dbenv = opendbenv(rootdir))) - return 0; - if (db_create(&state->db, state->dbenv, 0)) - { - perror("db_create"); - state->db = 0; - state->dbenv->close(state->dbenv, 0); - state->dbenv = 0; - return 0; - } - if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664)) - { - perror("db->open var/lib/rpm/Packages"); - state->db->close(state->db, 0); - state->db = 0; - state->dbenv->close(state->dbenv, 0); - state->dbenv = 0; - return 0; - } - if (state->db->get_byteswapped(state->db, &state->byteswapped)) - { - perror("db->get_byteswapped"); - state->db->close(state->db, 0); - state->db = 0; - state->dbenv->close(state->dbenv, 0); - state->dbenv = 0; - return 0; - } - } - rpmdbid2db(buf, rpmdbid, state->byteswapped); - memset(&dbkey, 0, sizeof(dbkey)); - memset(&dbdata, 0, sizeof(dbdata)); - dbkey.data = buf; - dbkey.size = 4; - dbdata.data = 0; - dbdata.size = 0; - if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0)) - { - perror("db->get"); - return 0; - } - if (dbdata.size < 8) - { - fprintf(stderr, "corrupt rpm database (size)\n"); - return 0; - } - if (dbdata.size > state->rpmheadsize) - { - state->rpmheadsize = dbdata.size + 128; - state->rpmhead = sat_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - memcpy(buf, dbdata.data, 8); - 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) - { - fprintf(stderr, "corrupt rpm database (data size)\n"); - return 0; - } - memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt); - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return rpmhead; +void * +rpm_byrpmdbid(void *rpmstate, Id rpmdbid) +{ + struct rpmdbstate *state = rpmstate; + int r; + + 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 /* ENABLE_RPMDB */ + void * -rpm_byfp(FILE *fp, const char *name, void **statep) +rpm_byfp(void *rpmstate, FILE *fp, const char *name) { - struct rpm_by_state *state = *statep; - /* int headerstart, headerend; */ - RpmHead *rpmhead; - int sigdsize, sigcnt, l; + struct rpmdbstate *state = rpmstate; + unsigned int sigdsize, sigcnt, l; unsigned char lead[4096]; - if (!fp) - return rpm_byrpmdbid(0, 0, statep); - if (!state) - { - state = sat_calloc(1, sizeof(*state)); - *statep = state; - } if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb) { - fprintf(stderr, "%s: not a rpm\n", name); + pool_error(state->pool, 0, "%s: not a rpm", name); return 0; } if (lead[78] != 0 || lead[79] != 5) { - fprintf(stderr, "%s: not a V5 header\n", name); + pool_error(state->pool, 0, "%s: not a V5 header", name); return 0; } + + /* skip signature header */ if (getu32(lead + 96) != 0x8eade801) { - fprintf(stderr, "%s: bad signature header\n", name); + pool_error(state->pool, 0, "%s: bad signature header", name); return 0; } sigcnt = getu32(lead + 96 + 8); sigdsize = getu32(lead + 96 + 12); - if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000) + if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE) { - fprintf(stderr, "%s: bad signature header\n", name); + pool_error(state->pool, 0, "%s: bad signature header", name); return 0; } sigdsize += sigcnt * 16; sigdsize = (sigdsize + 7) & ~7; - /* headerstart = 96 + 16 + sigdsize; */ while (sigdsize) { l = sigdsize > 4096 ? 4096 : sigdsize; if (fread(lead, l, 1, fp) != 1) { - fprintf(stderr, "%s: unexpected EOF\n", name); + pool_error(state->pool, 0, "%s: unexpected EOF", name); return 0; } sigdsize -= l; } + if (fread(lead, 16, 1, fp) != 1) { - fprintf(stderr, "%s: unexpected EOF\n", name); + pool_error(state->pool, 0, "%s: unexpected EOF", name); return 0; } if (getu32(lead) != 0x8eade801) { - fprintf(stderr, "%s: bad header\n", name); - fclose(fp); + pool_error(state->pool, 0, "%s: bad header", name); return 0; } sigcnt = getu32(lead + 8); sigdsize = getu32(lead + 12); - if (sigcnt >= 0x4000000 || sigdsize >= 0x40000000) - { - fprintf(stderr, "%s: bad header\n", name); - fclose(fp); - return 0; - } - l = sigdsize + sigcnt * 16; - /* headerend = headerstart + 16 + l; */ - if (l > state->rpmheadsize) - { - state->rpmheadsize = l + 128; - state->rpmhead = sat_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - if (fread(rpmhead->data, l, 1, fp) != 1) + if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE) { - fprintf(stderr, "%s: unexpected EOF\n", name); - fclose(fp); + pool_error(state->pool, 0, "%s: bad header", name); return 0; } - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return rpmhead; + if (!headfromfp(state, name, fp, lead, sigcnt, sigdsize, 0, 0, 0)) + return 0; + return state->rpmhead; } +#if defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM) + void * -rpm_byrpmh(Header h, void **statep) +rpm_byrpmh(void *rpmstate, Header h) { - struct rpm_by_state *state = *statep; + struct rpmdbstate *state = rpmstate; +#ifndef ENABLE_RPMPKG_LIBRPM const unsigned char *uh; - int sigdsize, sigcnt, l; + unsigned int dsize, cnt, len; RpmHead *rpmhead; + if (!h) + return 0; #ifndef RPM5 uh = headerUnload(h); #else @@ -2507,634 +2527,27 @@ rpm_byrpmh(Header h, void **statep) #endif if (!uh) return 0; - sigcnt = getu32(uh); - sigdsize = getu32(uh + 4); - l = sigdsize + sigcnt * 16; - if (!state) - { - state = sat_calloc(1, sizeof(*state)); - *statep = state; - } - if (l > state->rpmheadsize) + cnt = getu32(uh); + dsize = getu32(uh + 4); + if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE) { - state->rpmheadsize = l + 128; - state->rpmhead = sat_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize); - } - rpmhead = state->rpmhead; - memcpy(rpmhead->data, uh + 8, l - 8); - free((void *)uh); - rpmhead->cnt = sigcnt; - rpmhead->dcnt = sigdsize; - rpmhead->dp = rpmhead->data + rpmhead->cnt * 16; - return rpmhead; -} - - -static char * -r64dec1(char *p, unsigned int *vp, int *eofp) -{ - int i, x; - unsigned int v = 0; - - for (i = 0; i < 4; ) - { - x = *p++; - if (!x) - return 0; - if (x >= 'A' && x <= 'Z') - x -= 'A'; - else if (x >= 'a' && x <= 'z') - x -= 'a' - 26; - else if (x >= '0' && x <= '9') - x -= '0' - 52; - else if (x == '+') - x = 62; - else if (x == '/') - x = 63; - else if (x == '=') - { - x = 0; - if (i == 0) - { - *eofp = 3; - *vp = 0; - return p - 1; - } - *eofp += 1; - } - else - continue; - v = v << 6 | x; - i++; - } - *vp = v; - return p; -} - -static unsigned int -crc24(unsigned char *p, int len) -{ - unsigned int crc = 0xb704ceL; - int i; - - while (len--) - { - crc ^= (*p++) << 16; - for (i = 0; i < 8; i++) - if ((crc <<= 1) & 0x1000000) - crc ^= 0x1864cfbL; - } - return crc & 0xffffffL; -} - -static unsigned char * -unarmor(char *pubkey, int *pktlp) -{ - char *p; - int l, eof; - unsigned char *buf, *bp; - unsigned int v; - - *pktlp = 0; - while (strncmp(pubkey, "-----BEGIN PGP PUBLIC KEY BLOCK-----", 36) != 0) - { - pubkey = strchr(pubkey, '\n'); - if (!pubkey) - return 0; - pubkey++; - } - pubkey = strchr(pubkey, '\n'); - if (!pubkey++) - return 0; - /* skip header lines */ - for (;;) - { - while (*pubkey == ' ' || *pubkey == '\t') - pubkey++; - if (*pubkey == '\n') - break; - pubkey = strchr(pubkey, '\n'); - if (!pubkey++) - return 0; - } - pubkey++; - p = strchr(pubkey, '='); - if (!p) - return 0; - l = p - pubkey; - bp = buf = sat_malloc(l * 3 / 4 + 4); - eof = 0; - while (!eof) - { - pubkey = r64dec1(pubkey, &v, &eof); - if (!pubkey) - { - sat_free(buf); - return 0; - } - *bp++ = v >> 16; - *bp++ = v >> 8; - *bp++ = v; - } - while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r') - pubkey++; - bp -= eof; - if (*pubkey != '=' || (pubkey = r64dec1(pubkey + 1, &v, &eof)) == 0) - { - sat_free(buf); + free((void *)uh); return 0; } - if (v != crc24(buf, bp - buf)) - { - sat_free(buf); - return 0; - } - while (*pubkey == ' ' || *pubkey == '\t' || *pubkey == '\n' || *pubkey == '\r') - pubkey++; - if (strncmp(pubkey, "-----END PGP PUBLIC KEY BLOCK-----", 34) != 0) - { - sat_free(buf); - return 0; - } - *pktlp = bp - buf; - return buf; -} - -static void -parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl) -{ - int x, tag, l; - unsigned char keyid[8]; - unsigned int kcr = 0, maxex = 0; - unsigned char *pubkey = 0; - unsigned char *userid = 0; -#if 0 - int pubkeyl = 0; - int useridl = 0; -#endif - - for (; pl; p += l, pl -= l) - { - x = *p++; - pl--; - if (!(x & 128) || pl <= 0) - return; - if ((x & 64) == 0) - { - /* old format */ - tag = (x & 0x3c) >> 2; - x &= 3; - if (x == 3) - return; - l = 1 << x; - if (pl < l) - return; - x = 0; - while (l--) - { - x = x << 8 | *p++; - pl--; - } - l = x; - } - else - { - tag = (x & 0x3f); - x = *p++; - pl--; - if (x < 192) - l = x; - else if (x >= 192 && x < 224) - { - if (pl <= 0) - return; - l = ((x - 192) << 8) + *p++ + 192; - pl--; - } - else if (x == 255) - { - if (pl <= 4) - return; - l = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; - p += 4; - pl -= 4; - } - else - return; - } - if (pl < l) - return; - if (tag == 6) - { - pubkey = sat_realloc(pubkey, l); - if (l) - memcpy(pubkey, p, l); -#if 0 - pubkeyl = l; -#endif - kcr = 0; - if (p[0] == 3) - { - unsigned int ex; - void *h; - kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; - ex = 0; - if (p[5] || p[6]) - { - ex = kcr + 24*3600 * (p[5] << 8 | p[6]); - if (ex > maxex) - maxex = ex; - } - memset(keyid, 0, 8); - if (p[7] == 1) /* RSA */ - { - int i, ql; - unsigned char fp[16]; - char fpx[32 + 1]; - unsigned char *q; - - ql = ((p[8] << 8 | p[9]) + 7) / 8; - memcpy(keyid, p + 10 + ql - 8, 8); - h = sat_chksum_create(REPOKEY_TYPE_MD5); - sat_chksum_add(h, p + 10, ql); - q = p + 10 + ql; - ql = ((q[0] << 8 | q[1]) + 7) / 8; - sat_chksum_add(h, q + 2, ql); - sat_chksum_free(h, fp); - for (i = 0; i < 16; i++) - sprintf(fpx + i * 2, "%02x", fp[i]); - setutf8string(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); - } - } - else if (p[0] == 4) - { - int i; - void *h; - unsigned char hdr[3]; - unsigned char fp[20]; - char fpx[40 + 1]; - - kcr = p[1] << 24 | p[2] << 16 | p[3] << 8 | p[4]; - hdr[0] = 0x99; - hdr[1] = l >> 8; - hdr[2] = l; - h = sat_chksum_create(REPOKEY_TYPE_SHA1); - sat_chksum_add(h, hdr, 3); - sat_chksum_add(h, p, l); - sat_chksum_free(h, fp); - for (i = 0; i < 20; i++) - sprintf(fpx + i * 2, "%02x", fp[i]); - setutf8string(data, s - s->repo->pool->solvables, PUBKEY_FINGERPRINT, fpx); - memcpy(keyid, fp + 12, 8); - } - } - if (tag == 2) - { - if (p[0] == 3 && p[1] == 5) - { -#if 0 - Id htype = 0; -#endif - // printf("V3 signature packet\n"); - if (l < 17) - continue; - if (p[2] != 0x10 && p[2] != 0x11 && p[2] != 0x12 && p[2] != 0x13 && p[2] != 0x1f) - continue; - if (!memcmp(keyid, p + 6, 8)) - { - // printf("SELF SIG\n"); - } - else - { - // printf("OTHER SIG\n"); - } -#if 0 - if (p[16] == 1) - htype = REPOKEY_TYPE_MD5; - else if (p[16] == 2) - htype = REPOKEY_TYPE_SHA1; - else if (p[16] == 8) - htype = REPOKEY_TYPE_SHA256; - if (htype) - { - void *h = sat_chksum_create(htype); - unsigned char b[3], *cs; - - b[0] = 0x99; - b[1] = pubkeyl >> 8; - b[2] = pubkeyl; - sat_chksum_add(h, b, 3); - sat_chksum_add(h, pubkey, pubkeyl); - if (p[2] >= 0x10 && p[2] <= 0x13) - sat_chksum_add(h, userid, useridl); - sat_chksum_add(h, p + 2, 5); - cs = sat_chksum_get(h, 0); - sat_chksum_free(h, 0); - } -#endif - } - if (p[0] == 4) - { - int j, ql, haveissuer; - unsigned char *q; - unsigned int ex = 0; -#if 0 - unsigned int scr = 0; -#endif - unsigned char issuer[8]; - - // printf("V4 signature packet\n"); - if (l < 6) - continue; - if (p[1] != 0x10 && p[1] != 0x11 && p[1] != 0x12 && p[1] != 0x13 && p[1] != 0x1f) - continue; - haveissuer = 0; - ex = 0; - q = p + 4; - for (j = 0; q && j < 2; j++) - { - if (q + 2 > p + l) - { - q = 0; - break; - } - ql = q[0] << 8 | q[1]; - q += 2; - if (q + ql > p + l) - { - q = 0; - break; - } - while (ql) - { - int sl; - x = *q++; - ql--; - if (x < 192) - sl = x; - else if (x == 255) - { - if (ql < 4) - { - q = 0; - break; - } - sl = q[0] << 24 | q[1] << 16 | q[2] << 8 | q[3]; - q += 4; - ql -= 4; - } - else - { - if (ql < 1) - { - q = 0; - break; - } - sl = ((x - 192) << 8) + *q++ + 192; - ql--; - } - if (ql < sl) - { - q = 0; - break; - } - x = q[0] & 127; - // printf("%d SIGSUB %d %d\n", j, x, sl); - if (x == 16 && sl == 9 && !haveissuer) - { - memcpy(issuer, q + 1, 8); - haveissuer = 1; - } -#if 0 - if (x == 2 && j == 0) - scr = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4]; -#endif - if (x == 9 && j == 0) - ex = q[1] << 24 | q[2] << 16 | q[3] << 8 | q[4]; - q += sl; - ql -= sl; - } - } - if (ex) - ex += kcr; - if (haveissuer) - { -#if 0 - Id htype = 0; - if (p[3] == 1) - htype = REPOKEY_TYPE_MD5; - else if (p[3] == 2) - htype = REPOKEY_TYPE_SHA1; - else if (p[3] == 8) - htype = REPOKEY_TYPE_SHA256; - if (htype && pubkeyl) - { - void *h = sat_chksum_create(htype); - unsigned char b[6], *cs; - unsigned int hl; - - b[0] = 0x99; - b[1] = pubkeyl >> 8; - b[2] = pubkeyl; - sat_chksum_add(h, b, 3); - sat_chksum_add(h, pubkey, pubkeyl); - if (p[1] >= 0x10 && p[1] <= 0x13) - { - b[0] = 0xb4; - b[1] = useridl >> 24; - b[2] = useridl >> 16; - b[3] = useridl >> 8; - b[4] = useridl; - sat_chksum_add(h, b, 5); - sat_chksum_add(h, userid, useridl); - } - hl = 6 + (p[4] << 8 | p[5]); - sat_chksum_add(h, p, hl); - b[0] = 4; - b[1] = 0xff; - b[2] = hl >> 24; - b[3] = hl >> 16; - b[4] = hl >> 8; - b[5] = hl; - sat_chksum_add(h, b, 6); - cs = sat_chksum_get(h, 0); - sat_chksum_free(h, 0); - } -#endif - if (!memcmp(keyid, issuer, 8)) - { - // printf("SELF SIG cr %d ex %d\n", cr, ex); - if (ex > maxex) - maxex = ex; - } - else - { - // printf("OTHER SIG cr %d ex %d\n", cr, ex); - } - } - } - } - if (tag == 13) - { - userid = sat_realloc(userid, l); - if (l) - memcpy(userid, p, l); -#if 0 - useridl = l; -#endif - } - } - if (maxex) - repodata_set_num(data, s - s->repo->pool->solvables, PUBKEY_EXPIRES, maxex); - sat_free(pubkey); - sat_free(userid); -} - -/* this is private to rpm, but rpm lacks an interface to retrieve - * the values. Sigh. */ -struct pgpDigParams_s { - const char * userid; - const unsigned char * hash; - const char * params[4]; - unsigned char tag; - unsigned char version; /*!< version number. */ - unsigned char time[4]; /*!< time that the key was created. */ - unsigned char pubkey_algo; /*!< public key algorithm. */ - unsigned char hash_algo; - unsigned char sigtype; - unsigned char hashlen; - unsigned char signhash16[2]; - unsigned char signid[8]; - unsigned char saved; -}; - -struct pgpDig_s { - struct pgpDigParams_s signature; - struct pgpDigParams_s pubkey; -}; - -static int -pubkey2solvable(Solvable *s, Repodata *data, char *pubkey) -{ - Pool *pool = s->repo->pool; - unsigned char *pkts; - unsigned int btime; - int pktsl, i; - pgpDig dig = 0; - char keyid[16 + 1]; - char evrbuf[8 + 1 + 8 + 1]; - - pkts = unarmor(pubkey, &pktsl); - if (!pkts) - return 0; - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_DESCRIPTION, pubkey); - parsekeydata(s, data, pkts, pktsl); - /* only rpm knows how to do the release calculation, we don't dare - * to recreate all the bugs */ -#ifndef RPM5 - dig = pgpNewDig(); + len = 16 * cnt + dsize; + rpmhead = realloc_head(state, len + 1);; + memcpy(rpmhead->data, uh + 8, len); + headinit(rpmhead, cnt, dsize); + free((void *)uh); #else - dig = pgpDigNew(RPMVSF_DEFAULT, 0); + if (!h) + return 0; + if (state->rpmhead) + headfree(state->rpmhead); + state->rpmhead = headerLink(h); #endif - (void) pgpPrtPkts(pkts, pktsl, dig, 0); - btime = dig->pubkey.time[0] << 24 | dig->pubkey.time[1] << 16 | dig->pubkey.time[2] << 8 | dig->pubkey.signid[3]; - sprintf(evrbuf, "%02x%02x%02x%02x-%02x%02x%02x%02x", dig->pubkey.signid[4], dig->pubkey.signid[5], dig->pubkey.signid[6], dig->pubkey.signid[7], dig->pubkey.time[0], dig->pubkey.time[1], dig->pubkey.time[2], dig->pubkey.time[3]); - repodata_set_num(data, s - s->repo->pool->solvables, SOLVABLE_BUILDTIME, btime); - - s->name = pool_str2id(pool, "gpg-pubkey", 1); - s->evr = pool_str2id(pool, evrbuf, 1); - s->arch = 1; - for (i = 0; i < 8; i++) - sprintf(keyid + 2 * i, "%02x", dig->pubkey.signid[i]); - repodata_set_str(data, s - s->repo->pool->solvables, PUBKEY_KEYID, keyid); - if (dig->pubkey.userid) - setutf8string(data, s - s->repo->pool->solvables, SOLVABLE_SUMMARY, dig->pubkey.userid); - (void)pgpFreeDig(dig); - sat_free((void *)pkts); - return 1; + return state->rpmhead; } -void -repo_add_rpmdb_pubkeys(Repo *repo, const char *rootdir, int flags) -{ - Pool *pool = repo->pool; - struct rpm_by_state state; - struct rpmdbentry *entries; - int nentries, i; - char *namedata, *str; - unsigned int u32; - Repodata *data; - Solvable *s; +#endif /* defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM) */ - data = repo_add_repodata(repo, flags); - - memset(&state, 0, sizeof(state)); - if (!(state.dbenv = opendbenv(rootdir))) - return; - entries = getinstalledrpmdbids(&state, "Name", "gpg-pubkey", &nentries, &namedata); - for (i = 0 ; i < nentries; i++) - { - void *statep = &state; - RpmHead *rpmhead = rpm_byrpmdbid(entries[i].rpmdbid, rootdir, &statep); - if (!rpmhead) - continue; - str = headstring(rpmhead, TAG_DESCRIPTION); - if (!str) - continue; - s = pool_id2solvable(pool, repo_add_solvable(repo)); - pubkey2solvable(s, data, str); - u32 = headint32(rpmhead, TAG_INSTALLTIME); - if (u32) - repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, u32); - if (!repo->rpmdbid) - repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id)); - repo->rpmdbid[s - pool->solvables - repo->start] = entries[i].rpmdbid; - } - sat_free(entries); - sat_free(namedata); - freestate(&state); - if (!(flags & REPO_NO_INTERNALIZE)) - repodata_internalize(data); -} - -void -repo_add_pubkeys(Repo *repo, const char **keys, int nkeys, int flags) -{ - Pool *pool = repo->pool; - Repodata *data; - Solvable *s; - char *buf; - int i, bufl, l, ll; - FILE *fp; - - data = repo_add_repodata(repo, flags); - buf = 0; - bufl = 0; - for (i = 0; i < nkeys; i++) - { - if ((fp = fopen(keys[i], "r")) == 0) - { - perror(keys[i]); - continue; - } - for (l = 0; ;) - { - if (bufl - l < 4096) - { - bufl += 4096; - buf = sat_realloc(buf, bufl); - } - ll = fread(buf, 1, bufl - l, fp); - if (ll <= 0) - break; - l += ll; - } - buf[l] = 0; - fclose(fp); - s = pool_id2solvable(pool, repo_add_solvable(repo)); - pubkey2solvable(s, data, buf); - } - sat_free(buf); - if (!(flags & REPO_NO_INTERNALIZE)) - repodata_internalize(data); -}