#include <stdint.h>
#include <errno.h>
+#ifdef ENABLE_RPMDB
+
#include <rpm/rpmio.h>
#include <rpm/rpmpgp.h>
#ifndef RPM5
# endif
#endif
+#endif
+
#include "pool.h"
#include "repo.h"
#include "hash.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 */
/* 5: fixed checksum copying */
-#define RPMDB_COOKIE_VERSION 5
+/* 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
#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
#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
#ifdef RPM5
-# define RPM_INDEX_SIZE 4
+# define RPM_INDEX_SIZE 4 /* just the rpmdbid */
#else
-# define RPM_INDEX_SIZE 8
+# define RPM_INDEX_SIZE 8 /* rpmdbid + array index */
#endif
+/* some limits to guard against corrupt rpms */
+#define MAX_SIG_CNT 0x100000
+#define MAX_SIG_DSIZE 0x100000
+
+#define MAX_HDR_CNT 0x100000
+#define MAX_HDR_DSIZE 0x2000000
typedef struct rpmhead {
int cnt;
- int dcnt;
+ unsigned int dcnt;
unsigned char *dp;
int forcebinary; /* sigh, see rh#478907 */
unsigned char data[1];
return 0;
o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
- if (o + 4 * i > h->dcnt)
+ if (o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
return 0;
d = h->dp + o;
r = solv_calloc(i ? i : 1, sizeof(unsigned int));
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];
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 + 8 * i > h->dcnt)
+ if (o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
return 0;
d = h->dp + o;
r = solv_calloc(i ? i : 1, sizeof(unsigned long long));
for (o = 0; o < i; o++, d += 8)
{
unsigned int x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
- r[o] = (unsigned long long)x << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
+ r[o] = (unsigned long long)x << 32 | (unsigned int)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
}
return r;
}
return 0;
o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
- if (i == 0 || o + 8 * i > h->dcnt)
+ if (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
return 0;
d = h->dp + o;
i = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
- return (unsigned long long)i << 32 | (d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
+ return (unsigned long long)i << 32 | (unsigned int)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
}
static unsigned int *
return 0;
o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
- if (o + 4 * i > h->dcnt)
+ if (o > h->dcnt || i > h->dcnt || o + 2 * i > h->dcnt)
return 0;
d = h->dp + o;
r = solv_calloc(i ? i : 1, sizeof(unsigned int));
return 0;
o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
i = d[12] << 24 | d[13] << 16 | d[14] << 8 | d[15];
+ if (o > h->dcnt || i > h->dcnt)
+ return 0;
r = solv_calloc(i ? i : 1, sizeof(char *));
if (cnt)
*cnt = i;
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;
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
* 2: filter to weak
*/
static unsigned int
-makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags)
+makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq)
{
char **n, **v;
unsigned int *f;
int i, cc, nc, vc, fc;
- int haspre, premask;
+ int haspre, premask, has_ign;
unsigned int olddeps;
Id *ida;
- int strong;
+ int strong = 0;
- strong = flags & (MAKEDEPS_FILTER_STRONG|MAKEDEPS_FILTER_WEAK);
n = headstringarray(rpmhead, tagn, &nc);
+ if (!n)
+ {
+ switch (tagn)
+ {
+ case TAG_SUGGESTNAME:
+ tagn = TAG_OLDSUGGESTSNAME;
+ tagv = TAG_OLDSUGGESTSVERSION;
+ tagf = TAG_OLDSUGGESTSFLAGS;
+ strong = -1;
+ break;
+ case TAG_ENHANCENAME:
+ tagn = TAG_OLDENHANCESNAME;
+ tagv = TAG_OLDENHANCESVERSION;
+ tagf = TAG_OLDENHANCESFLAGS;
+ strong = -1;
+ break;
+ case TAG_RECOMMENDNAME:
+ tagn = TAG_OLDSUGGESTSNAME;
+ tagv = TAG_OLDSUGGESTSVERSION;
+ tagf = TAG_OLDSUGGESTSFLAGS;
+ strong = 1;
+ break;
+ case TAG_SUPPLEMENTNAME:
+ tagn = TAG_OLDENHANCESNAME;
+ tagv = TAG_OLDENHANCESVERSION;
+ tagf = TAG_OLDENHANCESFLAGS;
+ strong = 1;
+ break;
+ default:
+ return 0;
+ }
+ n = headstringarray(rpmhead, tagn, &nc);
+ }
if (!n || !nc)
return 0;
vc = fc = 0;
cc = nc;
haspre = 0; /* add no prereq marker */
- premask = DEP_PRE_IN | DEP_PRE_UN;
- 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] & premask) != 0)
cc++;
}
}
- else if (tagn == TAG_REQUIRENAME)
+ else if (premask)
{
/* no filtering, just look for the first prereq */
for (i = 0; i < nc; i++)
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)
i = 0;
*ida++ = SOLVABLE_PREREQMARKER;
}
- if (strong && (f[i] & DEP_STRONG) != (strong == MAKEDEPS_FILTER_WEAK ? 0 : DEP_STRONG))
- continue;
- if (haspre == 1 && (f[i] & premask) != 0)
- continue;
- if (haspre == 2 && (f[i] & premask) == 0)
+ if (strong && (f[i] & DEP_STRONG) != (strong < 0 ? 0 : DEP_STRONG))
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 |= REL_LT;
+ fl |= REL_LT;
if ((f[i] & DEP_EQUAL) != 0)
- flags |= REL_EQ;
+ fl |= REL_EQ;
if ((f[i] & DEP_GREATER) != 0)
- flags |= REL_GT;
- name = pool_str2id(pool, n[i], 1);
+ fl |= REL_GT;
if (v[i][0] == '0' && v[i][1] == ':' && v[i][2])
evr = pool_str2id(pool, v[i] + 2, 1);
else
evr = pool_str2id(pool, v[i], 1);
- *ida++ = pool_rel2id(pool, name, evr, flags, 1);
+ id = pool_rel2id(pool, id, evr, fl, 1);
+ }
+ *ida++ = id;
+ if (haspre == 2 && ignq)
+ {
+ int is_ign = (f[i] & DEP_PRE_IN) != 0 && (f[i] & DEP_PRE_UN) == 0 ? 1 : 0;
+ has_ign |= is_ign;
+ queue_push2(ignq, id, is_ign);
}
- else
- *ida++ = pool_str2id(pool, n[i], 1);
}
*ida++ = 0;
repo->idarraysize += cc + 1;
solv_free(n);
solv_free(v);
solv_free(f);
+ if (ignq && ignq->count)
+ {
+ int j = 0;
+ if (has_ign && ignq->count == 2)
+ j = 1;
+ else if (has_ign)
+ {
+ Id id, lastid = 0;
+
+ solv_sort(ignq->elements, ignq->count / 2, sizeof(Id) * 2, ignq_sortcmp, 0);
+ for (i = j = 0; i < ignq->count; i += 2)
+ {
+ id = ignq->elements[i];
+ if (id != lastid && ignq->elements[i + 1] > 0)
+ ignq->elements[j++] = id;
+ lastid = id;
+ }
+ }
+ queue_truncate(ignq, j);
+ }
return olddeps;
}
+static Id
+repodata_str2dir_rooted(Repodata *data, char *str, int create)
+{
+ char buf[256], *bp;
+ int l = strlen(str);
+ Id id;
+
+ if (l + 2 <= sizeof(buf))
+ bp = buf;
+ else
+ bp = solv_malloc(l + 2);
+ bp[0] = '/';
+ strcpy(bp + 1, str);
+ id = repodata_str2dir(data, bp, create);
+ if (bp != buf)
+ solv_free(bp);
+ return id;
+}
static void
adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dc)
{
if (!fn[i])
continue;
- if (!*dn[i])
+ if (dn[i][0] != '/')
{
- Solvable *s = data->repo->pool->solvables + handle;
+ Solvable *s = data->repo->pool->solvables + handle;
if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
did = repodata_str2dir(data, "/usr/src", 1);
else
- continue; /* work around rpm bug */
+ did = repodata_str2dir_rooted(data, dn[i], 1);
}
else
did = repodata_str2dir(data, dn[i], 1);
solv_free(fkb);
}
+static int
+is_filtered(const char *dir)
+{
+ if (!dir)
+ return 1;
+ /* the dirs always have a trailing / in rpm */
+ if (strstr(dir, "bin/"))
+ return 0;
+ if (!strncmp(dir, "/etc/", 5))
+ return 0;
+ if (!strcmp(dir, "/usr/lib/"))
+ return 2;
+ return 1;
+}
+
static void
-addfilelist(Repodata *data, Id handle, RpmHead *rpmhead)
+addfilelist(Repodata *data, Id handle, RpmHead *rpmhead, int flags)
{
char **bn;
char **dn;
unsigned int *di;
int bnc, dnc, dic;
int i;
- Id lastdid = 0;
+ Id did;
unsigned int lastdii = -1;
+ int lastfiltered = 0;
if (!data)
return;
adddudata(data, handle, rpmhead, dn, di, bnc, dnc);
+ did = -1;
for (i = 0; i < bnc; i++)
{
- Id did;
char *b = bn[i];
- if (di[i] == lastdii)
- did = lastdid;
- else
+ if (did < 0 || di[i] != lastdii)
{
if (di[i] >= dnc)
continue; /* corrupt entry */
- did = repodata_str2dir(data, dn[di[i]], 1);
- if (!did)
- did = repodata_str2dir(data, "/", 1);
- lastdid = did;
+ did = 0;
lastdii = di[i];
+ if ((flags & RPM_ADD_FILTERED_FILELIST) != 0)
+ {
+ lastfiltered = is_filtered(dn[di[i]]);
+ if (lastfiltered == 1)
+ continue;
+ }
+ if (dn[lastdii][0] != '/')
+ did = repodata_str2dir_rooted(data, dn[lastdii], 1);
+ else
+ did = repodata_str2dir(data, dn[lastdii], 1);
}
- if (b && *b == '/') /* work around rpm bug */
+ if (!b)
+ continue;
+ if (*b == '/') /* work around rpm bug */
b++;
+ if (lastfiltered && (lastfiltered != 2 || strcmp(b, "sendmail")))
+ continue;
repodata_add_dirstr(data, handle, SOLVABLE_FILELIST, did, b);
}
solv_free(bn);
}
static int
-rpm2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
+rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhead, int flags)
{
char *name;
char *evr;
char *sourcerpm;
+ Queue ignq;
+ Id ignqbuf[64];
name = headstring(rpmhead, TAG_NAME);
if (!name)
s->evr = pool_str2id(pool, evr, 1);
s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1);
- s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0);
+ queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf));
+
+ s->provides = makedeps(pool, repo, rpmhead, TAG_PROVIDENAME, TAG_PROVIDEVERSION, TAG_PROVIDEFLAGS, 0, 0);
if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
- s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, (flags & RPM_ADD_NO_RPMLIBREQS) ? MAKEDEPS_NO_RPMLIB : 0);
- s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0);
- s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0);
+ s->requires = makedeps(pool, repo, rpmhead, TAG_REQUIRENAME, TAG_REQUIREVERSION, TAG_REQUIREFLAGS, flags, &ignq);
+ s->conflicts = makedeps(pool, repo, rpmhead, TAG_CONFLICTNAME, TAG_CONFLICTVERSION, TAG_CONFLICTFLAGS, 0, 0);
+ s->obsoletes = makedeps(pool, repo, rpmhead, TAG_OBSOLETENAME, TAG_OBSOLETEVERSION, TAG_OBSOLETEFLAGS, 0, 0);
+
+ s->recommends = makedeps(pool, repo, rpmhead, TAG_RECOMMENDNAME, TAG_RECOMMENDVERSION, TAG_RECOMMENDFLAGS, 0, 0);
+ s->suggests = makedeps(pool, repo, rpmhead, TAG_SUGGESTNAME, TAG_SUGGESTVERSION, TAG_SUGGESTFLAGS, 0, 0);
+ s->supplements = makedeps(pool, repo, rpmhead, TAG_SUPPLEMENTNAME, TAG_SUPPLEMENTVERSION, TAG_SUPPLEMENTFLAGS, 0, 0);
+ s->enhances = makedeps(pool, repo, rpmhead, TAG_ENHANCENAME, TAG_ENHANCEVERSION, TAG_ENHANCEFLAGS, 0, 0);
+
+ repo_rewrite_suse_deps(s, 0);
- 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);
+ if (data && ignq.count)
+ repodata_set_idarray(data, s - pool->solvables, SOLVABLE_PREREQ_IGNOREINST, &ignq);
+ queue_free(&ignq);
if (data)
{
repodata_set_sourcepkg(data, handle, sourcerpm);
if ((flags & RPM_ADD_TRIGGERS) != 0)
{
- Id id, lastid;
- unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0);
-
- lastid = 0;
- for (; (id = repo->idarraydata[ida]) != 0; ida++)
- {
- /* we currently do not support rel ids in incore data, so
- * strip off versioning information */
- while (ISRELDEP(id))
- {
- Reldep *rd = GETRELDEP(pool, id);
- id = rd->name;
- }
- if (id == lastid)
- continue;
+ unsigned int ida = makedeps(pool, repo, rpmhead, TAG_TRIGGERNAME, TAG_TRIGGERVERSION, TAG_TRIGGERFLAGS, 0, 0);
+ Id id, lastid = 0;
+ for (lastid = 0; (id = repo->idarraydata[ida]) != 0; ida++, lastid = id)
+ if (id != lastid)
repodata_add_idarray(data, handle, SOLVABLE_TRIGGERS, id);
- lastid = id;
- }
}
if ((flags & RPM_ADD_NO_FILELIST) == 0)
- addfilelist(data, handle, rpmhead);
+ addfilelist(data, handle, rpmhead, flags);
if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
addchangelog(data, handle, rpmhead);
}
return 1;
}
+static inline unsigned int
+getu32(const unsigned char *dp)
+{
+ return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
+}
+
/******************************************************************/
/* Rpm Database stuff
RpmHead *rpmhead; /* header storage space */
int rpmheadsize;
+#ifdef ENABLE_RPMDB
int dbopened;
DB_ENV *dbenv; /* database environment */
DB *db; /* packages database */
int byteswapped; /* endianess of packages database */
+ int is_ostree; /* read-only db that lives in /usr/share/rpm */
+#endif
};
+#ifdef ENABLE_RPMDB
+
struct rpmdbentry {
Id rpmdbid;
Id nameoff;
#define NAMEDATA_BLOCK 1023
-static inline Id db2rpmdbid(unsigned char *db, int byteswapped)
+static inline Id
+db2rpmdbid(unsigned char *db, int byteswapped)
{
#ifdef RPM5
return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
#endif
}
-static inline void rpmdbid2db(unsigned char *db, Id id, int byteswapped)
+static inline void
+rpmdbid2db(unsigned char *db, Id id, int byteswapped)
{
#ifdef RPM5
db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
serialize_dbenv_ops(struct rpmdbstate *state)
{
char lpath[PATH_MAX];
- mode_t oldmask = umask(022);
+ mode_t oldmask;
int fd;
struct flock fl;
snprintf(lpath, PATH_MAX, "%s/var/lib/rpm/.dbenv.lock", state->rootdir ? state->rootdir : "");
+ oldmask = umask(022);
fd = open(lpath, (O_RDWR|O_CREAT), 0644);
umask(oldmask);
if (fd < 0)
snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm", rootdir ? rootdir : "");
if (access(dbpath, W_OK) == -1)
{
+ snprintf(dbpath, PATH_MAX, "%s/usr/share/rpm/Packages", rootdir ? rootdir : "");
+ if (access(dbpath, R_OK) == 0)
+ state->is_ostree = 1;
+ snprintf(dbpath, PATH_MAX, "%s%s", rootdir ? rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
}
else
state->dbenv = 0;
}
+#endif
+
+static void
+freestate(struct rpmdbstate *state)
+{
+ /* close down */
+ if (!state)
+ return;
+#ifdef ENABLE_RPMDB
+ if (state->db)
+ state->db->close(state->db, 0);
+ if (state->dbenv)
+ closedbenv(state);
+#endif
+ if (state->rootdir)
+ solv_free(state->rootdir);
+ solv_free(state->rpmhead);
+}
+
+void *
+rpm_state_create(Pool *pool, const char *rootdir)
+{
+ struct rpmdbstate *state;
+ state = solv_calloc(1, sizeof(*state));
+ state->pool = pool;
+ if (rootdir)
+ state->rootdir = solv_strdup(rootdir);
+ return state;
+}
+
+void *
+rpm_state_free(void *state)
+{
+ freestate(state);
+ return solv_free(state);
+}
+
+
+#ifdef ENABLE_RPMDB
+
static int
openpkgdb(struct rpmdbstate *state)
{
return entries;
}
-/* retrive header by rpmdbid */
+/* common code, return dbid on success, -1 on error */
static int
-getrpmdbid(struct rpmdbstate *state, Id rpmdbid)
+getrpm_dbdata(struct rpmdbstate *state, DBT *dbdata, int dbid)
{
- unsigned char buf[16];
- DBT dbkey;
- DBT dbdata;
+ unsigned int dsize, cnt, l;
RpmHead *rpmhead;
- if (!rpmdbid)
+ if (dbdata->size < 8)
+ return pool_error(state->pool, -1, "corrupt rpm database (size)");
+ cnt = getu32((const unsigned char *)dbdata->data);
+ dsize = getu32((const unsigned char *)dbdata->data + 4);
+ if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
+ return pool_error(state->pool, -1, "corrupt rpm database (cnt/dcnt)");
+ l = cnt * 16 + dsize;
+ if (8 + l > dbdata->size)
+ return pool_error(state->pool, -1, "corrupt rpm database (data size)");
+ if (l + 1 > state->rpmheadsize)
{
- pool_error(state->pool, 0, "illegal rpmdbid");
- return -1;
+ state->rpmheadsize = l + 128;
+ state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
}
+ rpmhead = state->rpmhead;
+ rpmhead->forcebinary = 1;
+ rpmhead->cnt = cnt;
+ rpmhead->dcnt = dsize;
+ memcpy(rpmhead->data, (unsigned char *)dbdata->data + 8, l);
+ rpmhead->data[l] = 0;
+ rpmhead->dp = rpmhead->data + cnt * 16;
+ return dbid;
+}
+
+/* retrive header by rpmdbid, returns 0 if not found, -1 on error */
+static int
+getrpm_dbid(struct rpmdbstate *state, Id dbid)
+{
+ unsigned char buf[4];
+ DBT dbkey;
+ DBT dbdata;
+
+ if (dbid <= 0)
+ return pool_error(state->pool, -1, "illegal rpmdbid %d", dbid);
if (state->dbopened != 1 && !openpkgdb(state))
return -1;
- rpmdbid2db(buf, rpmdbid, state->byteswapped);
+ rpmdbid2db(buf, dbid, state->byteswapped);
memset(&dbkey, 0, sizeof(dbkey));
memset(&dbdata, 0, sizeof(dbdata));
dbkey.data = buf;
dbdata.size = 0;
if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0))
return 0;
- if (dbdata.size < 8)
- {
- pool_error(state->pool, 0, "corrupt rpm database (size)");
- return -1;
- }
- if (dbdata.size > state->rpmheadsize)
- {
- state->rpmheadsize = dbdata.size + 128;
- state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
- }
- rpmhead = state->rpmhead;
- memcpy(buf, dbdata.data, 8);
- rpmhead->forcebinary = 1;
- rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
- rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7];
- if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size)
- {
- pool_error(state->pool, 0, "corrupt rpm database (data size)");
- return -1;
- }
- memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
- rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
- return 1;
+ return getrpm_dbdata(state, &dbdata, dbid);
}
-/* retrive header by berkeleydb cursor */
+/* retrive header by berkeleydb cursor, returns 0 on EOF, -1 on error */
static Id
-getrpmcursor(struct rpmdbstate *state, DBC *dbc)
+getrpm_cursor(struct rpmdbstate *state, DBC *dbc)
{
- unsigned char buf[16];
DBT dbkey;
DBT dbdata;
- RpmHead *rpmhead;
Id dbid;
memset(&dbkey, 0, sizeof(dbkey));
if (dbkey.size != 4)
return pool_error(state->pool, -1, "corrupt Packages database (key size)");
dbid = db2rpmdbid(dbkey.data, state->byteswapped);
- if (dbid == 0) /* the join key */
- continue;
- if (dbdata.size < 8)
- return pool_error(state->pool, -1, "corrupt rpm database (size %u)\n", dbdata.size);
- if (dbdata.size > state->rpmheadsize)
- {
- state->rpmheadsize = dbdata.size + 128;
- state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
- }
- rpmhead = state->rpmhead;
- memcpy(buf, dbdata.data, 8);
- rpmhead->forcebinary = 1;
- rpmhead->cnt = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
- rpmhead->dcnt = buf[4] << 24 | buf[5] << 16 | buf[6] << 8 | buf[7];
- if (8 + rpmhead->cnt * 16 + rpmhead->dcnt > dbdata.size)
- return pool_error(state->pool, -1, "corrupt rpm database (data size)\n");
- memcpy(rpmhead->data, (unsigned char *)dbdata.data + 8, rpmhead->cnt * 16 + rpmhead->dcnt);
- rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
- return dbid;
+ if (dbid) /* ignore join key */
+ return getrpm_dbdata(state, &dbdata, dbid);
}
return 0;
}
-static void
-freestate(struct rpmdbstate *state)
-{
- /* close down */
- if (!state)
- return;
- if (state->rootdir)
- solv_free(state->rootdir);
- if (state->db)
- state->db->close(state->db, 0);
- if (state->dbenv)
- closedbenv(state);
- solv_free(state->rpmhead);
-}
-
-void *
-rpm_state_create(Pool *pool, const char *rootdir)
-{
- struct rpmdbstate *state;
- state = solv_calloc(1, sizeof(*state));
- state->pool = pool;
- if (rootdir)
- state->rootdir = solv_strdup(rootdir);
- return state;
-}
-
-void *
-rpm_state_free(void *state)
-{
- freestate(state);
- return solv_free(state);
-}
-
static int
-count_headers(Pool *pool, const char *rootdir, DB_ENV *dbenv)
+count_headers(struct rpmdbstate *state)
{
+ Pool *pool = state->pool;
char dbpath[PATH_MAX];
struct stat statbuf;
DB *db = 0;
DBT dbkey;
DBT dbdata;
- snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Name", rootdir ? rootdir : "");
+ snprintf(dbpath, PATH_MAX, "%s%s/Name", state->rootdir ? state->rootdir : "", state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
if (stat(dbpath, &statbuf))
return 0;
memset(&dbkey, 0, sizeof(dbkey));
memset(&dbdata, 0, sizeof(dbdata));
- if (db_create(&db, dbenv, 0))
+ if (db_create(&db, state->dbenv, 0))
{
pool_error(pool, 0, "db_create: %s", strerror(errno));
return 0;
static inline Id
copydir(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
{
- if (cache && cache[did & 255] == did)
+ if (cache && did && cache[did & 255] == did)
return cache[(did & 255) + 256];
return copydir_complex(pool, data, fromdata, did, cache);
}
static Id
copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
{
- Id parent = dirpool_parent(&fromdata->dirpool, did);
- Id compid = dirpool_compid(&fromdata->dirpool, did);
+ Id parent, compid;
+ if (!did)
+ {
+ /* make sure that the dirpool has an entry */
+ if (!data->dirpool.ndirs)
+ dirpool_add_dir(&data->dirpool, 0, 0, 1);
+ return 0;
+ }
+ parent = dirpool_parent(&fromdata->dirpool, did);
+ compid = dirpool_compid(&fromdata->dirpool, did);
if (parent)
parent = copydir(pool, data, fromdata, parent, cache);
if (data->localpool || fromdata->localpool)
case REPOKEY_TYPE_DIRNUMNUMARRAY:
id = kv->id;
id = copydir(pool, data, fromdata, id, cbdata->dircache);
- repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
+ if (id)
+ repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
break;
case REPOKEY_TYPE_DIRSTRARRAY:
id = kv->id;
id = copydir(pool, data, fromdata, id, cbdata->dircache);
- repodata_add_dirstr(data, handle, keyname, id, kv->str);
+ if (id)
+ repodata_add_dirstr(data, handle, keyname, id, kv->str);
break;
case REPOKEY_TYPE_FLEXARRAY:
if (kv->eof == 2)
cbdata->handle = repodata_new_handle(data);
repodata_add_flexarray(data, cbdata->subhandle, keyname, cbdata->handle);
break;
- case REPOKEY_TYPE_MD5:
- case REPOKEY_TYPE_SHA1:
- case REPOKEY_TYPE_SHA256:
- repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str);
- break;
default:
+ if (solv_chksum_len(key->type))
+ {
+ repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str);
+ break;
+ }
break;
}
return 0;
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);
ref = 0;
}
- if (flags & REPO_USE_ROOTDIR)
- state.rootdir = solv_strdup(pool_get_rootdir(pool));
if (!opendbenv(&state))
{
solv_free(state.rootdir);
}
/* XXX: should get ro lock of Packages database! */
- snprintf(dbpath, PATH_MAX, "%s/var/lib/rpm/Packages", state.rootdir ? state.rootdir : "");
+ snprintf(dbpath, PATH_MAX, "%s%s/Packages", state.rootdir ? state.rootdir : "", state.is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
if (stat(dbpath, &packagesstat))
{
pool_error(pool, -1, "%s: %s", dbpath, strerror(errno));
if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
repo_empty(ref, 1); /* get it out of the way */
if ((flags & RPMDB_REPORT_PROGRESS) != 0)
- count = count_headers(pool, state.rootdir, state.dbenv);
+ count = count_headers(&state);
if (!openpkgdb(&state))
{
freestate(&state);
}
i = 0;
s = 0;
- while ((dbid = getrpmcursor(&state, dbc)) != 0)
+ while ((dbid = getrpm_cursor(&state, dbc)) != 0)
{
if (dbid == -1)
{
if (!repo->rpmdbid)
repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
- if (rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS))
+ if (rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS))
{
i++;
s = 0;
}
}
}
- res = getrpmdbid(&state, dbid);
+ res = getrpm_dbid(&state, dbid);
if (res <= 0)
{
if (!res)
solv_free(refhash);
return -1;
}
- rpm2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
+ rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
if ((flags & RPMDB_REPORT_PROGRESS) != 0)
{
if (done < count)
return res;
}
-static inline unsigned int
-getu32(const unsigned char *dp)
-{
- return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
-}
-
+#endif
Id
repo_add_rpm(Repo *repo, const char *rpm, int flags)
}
sigcnt = getu32(lead + 96 + 8);
sigdsize = getu32(lead + 96 + 12);
- if (sigcnt >= 0x100000 || sigdsize >= 0x100000)
+ if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
{
pool_error(pool, -1, "%s: bad signature header", rpm);
fclose(fp);
if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0)
{
/* extract pkgid or hdrid from the signature header */
- if (sigdsize > rpmheadsize)
+ if (sigdsize + 1 > rpmheadsize)
{
rpmheadsize = sigdsize + 128;
rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
fclose(fp);
return 0;
}
+ rpmhead->data[sigdsize] = 0;
if (chksumh)
solv_chksum_add(chksumh, rpmhead->data, sigdsize);
if (leadsigchksumh)
}
sigcnt = getu32(lead + 8);
sigdsize = getu32(lead + 12);
- if (sigcnt >= 0x100000 || sigdsize >= 0x2000000)
+ if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
{
pool_error(pool, -1, "%s: bad header", rpm);
fclose(fp);
}
l = sigdsize + sigcnt * 16;
headerend = headerstart + 16 + l;
- if (l > rpmheadsize)
+ if (l + 1 > rpmheadsize)
{
rpmheadsize = l + 128;
rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
fclose(fp);
return 0;
}
+ rpmhead->data[l] = 0;
if (chksumh)
solv_chksum_add(chksumh, rpmhead->data, l);
rpmhead->forcebinary = forcebinary;
solv_chksum_add(chksumh, lead, l);
fclose(fp);
s = pool_id2solvable(pool, repo_add_solvable(repo));
- if (!rpm2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
+ if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
{
repo_free_solvable(repo, s - pool->solvables, 1);
solv_chksum_free(chksumh, 0);
return 0;
}
s = pool_id2solvable(pool, repo_add_solvable(repo));
- if (!rpm2solv(pool, repo, data, s, rpmhead, flags))
+ if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags))
{
repo_free_solvable(repo, s - pool->solvables, 1);
return 0;
if ((flags & RPM_ITERATE_FILELIST_WITHCOL) != 0)
{
co = headint32array(rpmhead, TAG_FILECOLORS, &cnt2);
- if (!co || cnt != cnt2)
+ if (co && cnt != cnt2)
{
solv_free(co);
solv_free(md);
info.digest = md5;
}
}
- if (co)
- info.color = co[i];
+ info.color = co ? co[i] : 0;
(*cb)(cbdata, space, &info);
}
solv_free(space);
return notfound;
}
+#ifdef ENABLE_RPMDB
+
int
rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queue *rpmdbidq)
{
struct rpmdbstate *state = rpmstate;
int r;
- r = getrpmdbid(state, rpmdbid);
+ r = getrpm_dbid(state, rpmdbid);
if (!r)
pool_error(state->pool, 0, "header #%d not in database", rpmdbid);
return r <= 0 ? 0 : state->rpmhead;
}
+#endif
+
void *
rpm_byfp(void *rpmstate, FILE *fp, const char *name)
{
}
sigcnt = getu32(lead + 96 + 8);
sigdsize = getu32(lead + 96 + 12);
- if (sigcnt >= 0x100000 || sigdsize >= 0x100000)
+ if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
{
pool_error(state->pool, 0, "%s: bad signature header", name);
return 0;
}
sigcnt = getu32(lead + 8);
sigdsize = getu32(lead + 12);
- if (sigcnt >= 0x100000 || sigdsize >= 0x2000000)
+ if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
{
pool_error(state->pool, 0, "%s: bad header", name);
return 0;
}
l = sigdsize + sigcnt * 16;
/* headerend = headerstart + 16 + l; */
- if (l > state->rpmheadsize)
+ if (l + 1 > state->rpmheadsize)
{
state->rpmheadsize = l + 128;
state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
pool_error(state->pool, 0, "%s: unexpected EOF", name);
return 0;
}
+ rpmhead->data[l] = 0;
rpmhead->forcebinary = forcebinary;
rpmhead->cnt = sigcnt;
rpmhead->dcnt = sigdsize;
return 0;
sigcnt = getu32(uh);
sigdsize = getu32(uh + 4);
+ if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
+ return 0;
l = sigdsize + sigcnt * 16;
- if (l > state->rpmheadsize)
+ if (l + 1 > state->rpmheadsize)
{
state->rpmheadsize = l + 128;
state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
}
rpmhead = state->rpmhead;
- memcpy(rpmhead->data, uh + 8, l - 8);
+ memcpy(rpmhead->data, uh + 8, l);
+ rpmhead->data[l] = 0;
free((void *)uh);
rpmhead->forcebinary = 0;
rpmhead->cnt = sigcnt;
rpmhead->dcnt = sigdsize;
- rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
+ rpmhead->dp = rpmhead->data + sigcnt * 16;
return rpmhead;
}