summaryrefslogtreecommitdiff
path: root/lib/rpmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rpmds.c')
-rw-r--r--lib/rpmds.c933
1 files changed, 933 insertions, 0 deletions
diff --git a/lib/rpmds.c b/lib/rpmds.c
new file mode 100644
index 0000000..c9c3b5d
--- /dev/null
+++ b/lib/rpmds.c
@@ -0,0 +1,933 @@
+/** \ingroup rpmdep
+ * \file lib/rpmds.c
+ */
+#include "system.h"
+
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmlib.h> /* rpmvercmp */
+#include <rpm/rpmstring.h>
+#include <rpm/rpmlog.h>
+#include <rpm/rpmds.h>
+
+#include "debug.h"
+
+int _rpmds_debug = 0;
+
+int _rpmds_nopromote = 1;
+
+/**
+ * A package dependency set.
+ */
+struct rpmds_s {
+ const char * Type; /*!< Tag name. */
+ char * DNEVR; /*!< Formatted dependency string. */
+ const char ** N; /*!< Name. */
+ const char ** EVR; /*!< Epoch-Version-Release. */
+ rpmsenseFlags * Flags; /*!< Bit(s) identifying context/comparison. */
+ rpm_color_t * Color; /*!< Bit(s) calculated from file color(s). */
+ rpmTagVal tagN; /*!< Header tag. */
+ int32_t Count; /*!< No. of elements */
+ unsigned int instance; /*!< From rpmdb instance? */
+ int i; /*!< Element index. */
+ unsigned l; /*!< Low element (bsearch). */
+ unsigned u; /*!< High element (bsearch). */
+ int nopromote; /*!< Don't promote Epoch: in rpmdsCompare()? */
+ int nrefs; /*!< Reference count. */
+};
+
+static const char ** rpmdsDupArgv(const char ** argv, int argc);
+
+static int dsType(rpmTagVal tag,
+ const char ** Type, rpmTagVal * tagEVR, rpmTagVal * tagF)
+{
+ int rc = 0;
+ const char *t = NULL;
+ rpmTagVal evr = RPMTAG_NOT_FOUND;
+ rpmTagVal f = RPMTAG_NOT_FOUND;
+
+ if (tag == RPMTAG_PROVIDENAME) {
+ t = "Provides";
+ evr = RPMTAG_PROVIDEVERSION;
+ f = RPMTAG_PROVIDEFLAGS;
+ } else if (tag == RPMTAG_REQUIRENAME) {
+ t = "Requires";
+ evr = RPMTAG_REQUIREVERSION;
+ f = RPMTAG_REQUIREFLAGS;
+ } else if (tag == RPMTAG_CONFLICTNAME) {
+ t = "Conflicts";
+ evr = RPMTAG_CONFLICTVERSION;
+ f = RPMTAG_CONFLICTFLAGS;
+ } else if (tag == RPMTAG_OBSOLETENAME) {
+ t = "Obsoletes";
+ evr = RPMTAG_OBSOLETEVERSION;
+ f = RPMTAG_OBSOLETEFLAGS;
+ } else if (tag == RPMTAG_ORDERNAME) {
+ t = "Order";
+ evr = RPMTAG_ORDERVERSION;
+ f = RPMTAG_ORDERFLAGS;
+ } else if (tag == RPMTAG_TRIGGERNAME) {
+ t = "Trigger";
+ evr = RPMTAG_TRIGGERVERSION;
+ f = RPMTAG_TRIGGERFLAGS;
+ } else {
+ rc = 1;
+ }
+ if (Type) *Type = t;
+ if (tagEVR) *tagEVR = evr;
+ if (tagF) *tagF = f;
+ return rc;
+}
+
+static rpmds rpmdsUnlink(rpmds ds)
+{
+ if (ds)
+ ds->nrefs--;
+ return NULL;
+}
+
+rpmds rpmdsLink(rpmds ds)
+{
+ if (ds)
+ ds->nrefs++;
+ return ds;
+}
+
+rpmds rpmdsFree(rpmds ds)
+{
+ rpmTagVal tagEVR, tagF;
+
+ if (ds == NULL)
+ return NULL;
+
+ if (ds->nrefs > 1)
+ return rpmdsUnlink(ds);
+
+ if (dsType(ds->tagN, NULL, &tagEVR, &tagF))
+ return NULL;
+
+ if (ds->Count > 0) {
+ ds->N = _free(ds->N);
+ ds->EVR = _free(ds->EVR);
+ ds->Flags = _free(ds->Flags);
+ }
+
+ ds->DNEVR = _free(ds->DNEVR);
+ ds->Color = _free(ds->Color);
+
+ (void) rpmdsUnlink(ds);
+ memset(ds, 0, sizeof(*ds)); /* XXX trash and burn */
+ ds = _free(ds);
+ return NULL;
+}
+
+rpmds rpmdsNew(Header h, rpmTagVal tagN, int flags)
+{
+ rpmTagVal tagEVR, tagF;
+ rpmds ds = NULL;
+ const char * Type;
+ struct rpmtd_s names;
+ headerGetFlags hgflags = HEADERGET_ALLOC|HEADERGET_ARGV;
+
+ if (dsType(tagN, &Type, &tagEVR, &tagF))
+ goto exit;
+
+ if (headerGet(h, tagN, &names, hgflags) && rpmtdCount(&names) > 0) {
+ struct rpmtd_s evr, flags;
+
+ ds = xcalloc(1, sizeof(*ds));
+ ds->Type = Type;
+ ds->i = -1;
+ ds->DNEVR = NULL;
+ ds->tagN = tagN;
+ ds->N = names.data;
+ ds->Count = rpmtdCount(&names);
+ ds->nopromote = _rpmds_nopromote;
+ ds->instance = headerGetInstance(h);
+
+ headerGet(h, tagEVR, &evr, hgflags);
+ ds->EVR = evr.data;
+ headerGet(h, tagF, &flags, hgflags);
+ ds->Flags = flags.data;
+ /* ensure rpmlib() requires always have RPMSENSE_RPMLIB flag set */
+ if (tagN == RPMTAG_REQUIRENAME && ds->Flags) {
+ for (int i = 0; i < ds->Count; i++) {
+ if (!(ds->Flags[i] & RPMSENSE_RPMLIB) &&
+ rstreqn(ds->N[i], "rpmlib(", sizeof("rpmlib(")-1))
+ ds->Flags[i] |= RPMSENSE_RPMLIB;
+ }
+ }
+
+ ds = rpmdsLink(ds);
+ }
+
+exit:
+ return ds;
+}
+
+char * rpmdsNewDNEVR(const char * dspfx, const rpmds ds)
+{
+ char * tbuf, * t;
+ size_t nb;
+
+ nb = 0;
+ if (dspfx) nb += strlen(dspfx) + 1;
+ if (ds->N[ds->i]) nb += strlen(ds->N[ds->i]);
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (ds->Flags != NULL && (ds->Flags[ds->i] & RPMSENSE_SENSEMASK)) {
+ if (nb) nb++;
+ if (ds->Flags[ds->i] & RPMSENSE_LESS) nb++;
+ if (ds->Flags[ds->i] & RPMSENSE_GREATER) nb++;
+ if (ds->Flags[ds->i] & RPMSENSE_EQUAL) nb++;
+ }
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (ds->EVR != NULL && ds->EVR[ds->i] && *ds->EVR[ds->i]) {
+ if (nb) nb++;
+ nb += strlen(ds->EVR[ds->i]);
+ }
+
+ t = tbuf = xmalloc(nb + 1);
+ if (dspfx) {
+ t = stpcpy(t, dspfx);
+ *t++ = ' ';
+ }
+ if (ds->N[ds->i])
+ t = stpcpy(t, ds->N[ds->i]);
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (ds->Flags != NULL && (ds->Flags[ds->i] & RPMSENSE_SENSEMASK)) {
+ if (t != tbuf) *t++ = ' ';
+ if (ds->Flags[ds->i] & RPMSENSE_LESS) *t++ = '<';
+ if (ds->Flags[ds->i] & RPMSENSE_GREATER) *t++ = '>';
+ if (ds->Flags[ds->i] & RPMSENSE_EQUAL) *t++ = '=';
+ }
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (ds->EVR != NULL && ds->EVR[ds->i] && *ds->EVR[ds->i]) {
+ if (t != tbuf) *t++ = ' ';
+ t = stpcpy(t, ds->EVR[ds->i]);
+ }
+ *t = '\0';
+ return tbuf;
+}
+
+static rpmds singleDS(rpmTagVal tagN, const char * N, const char * EVR,
+ rpmsenseFlags Flags, unsigned int instance)
+{
+ rpmds ds = NULL;
+ const char * Type;
+
+ if (dsType(tagN, &Type, NULL, NULL))
+ goto exit;
+
+ ds = xcalloc(1, sizeof(*ds));
+ ds->Type = Type;
+ ds->tagN = tagN;
+ ds->Count = 1;
+ ds->nopromote = _rpmds_nopromote;
+ ds->instance = instance;
+
+ ds->N = rpmdsDupArgv(&N, 1);
+ ds->EVR = rpmdsDupArgv(&EVR, 1);
+
+ ds->Flags = xmalloc(sizeof(*ds->Flags));
+ ds->Flags[0] = Flags;
+ ds->i = 0;
+
+exit:
+ return rpmdsLink(ds);
+}
+
+rpmds rpmdsThis(Header h, rpmTagVal tagN, rpmsenseFlags Flags)
+{
+ char *evr = headerGetAsString(h, RPMTAG_EVR);
+ rpmds ds = singleDS(tagN, headerGetString(h, RPMTAG_NAME),
+ evr, Flags, headerGetInstance(h));
+ free(evr);
+ return ds;
+}
+
+rpmds rpmdsSingle(rpmTagVal tagN, const char * N, const char * EVR, rpmsenseFlags Flags)
+{
+ return singleDS(tagN, N, EVR, Flags, 0);
+}
+
+rpmds rpmdsCurrent(rpmds ds)
+{
+ rpmds cds = NULL;
+ if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ cds = singleDS(ds->tagN, ds->N[ds->i], ds->EVR[ds->i],
+ ds->Flags[ds->i], ds->instance);
+ }
+ return cds;
+}
+
+int rpmdsCount(const rpmds ds)
+{
+ return (ds != NULL ? ds->Count : 0);
+}
+
+int rpmdsIx(const rpmds ds)
+{
+ return (ds != NULL ? ds->i : -1);
+}
+
+int rpmdsSetIx(rpmds ds, int ix)
+{
+ int i = -1;
+
+ if (ds != NULL) {
+ i = ds->i;
+ ds->i = ix;
+ ds->DNEVR = _free(ds->DNEVR);
+ }
+ return i;
+}
+
+const char * rpmdsDNEVR(const rpmds ds)
+{
+ const char * DNEVR = NULL;
+
+ if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ if (ds->DNEVR == NULL) {
+ char t[2] = { ds->Type[0], '\0' };
+ ds->DNEVR = rpmdsNewDNEVR(t, ds);
+ }
+ DNEVR = ds->DNEVR;
+ }
+ return DNEVR;
+}
+
+const char * rpmdsN(const rpmds ds)
+{
+ const char * N = NULL;
+
+ if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ if (ds->N != NULL)
+ N = ds->N[ds->i];
+ }
+ return N;
+}
+
+const char * rpmdsEVR(const rpmds ds)
+{
+ const char * EVR = NULL;
+
+ if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ if (ds->EVR != NULL)
+ EVR = ds->EVR[ds->i];
+ }
+ return EVR;
+}
+
+rpmsenseFlags rpmdsFlags(const rpmds ds)
+{
+ rpmsenseFlags Flags = 0;
+
+ if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ if (ds->Flags != NULL)
+ Flags = ds->Flags[ds->i];
+ }
+ return Flags;
+}
+
+rpmTagVal rpmdsTagN(const rpmds ds)
+{
+ rpmTagVal tagN = RPMTAG_NOT_FOUND;
+
+ if (ds != NULL)
+ tagN = ds->tagN;
+ return tagN;
+}
+
+unsigned int rpmdsInstance(rpmds ds)
+{
+ return (ds != NULL) ? ds->instance : 0;
+}
+
+int rpmdsNoPromote(const rpmds ds)
+{
+ int nopromote = 0;
+
+ if (ds != NULL)
+ nopromote = ds->nopromote;
+ return nopromote;
+}
+
+int rpmdsSetNoPromote(rpmds ds, int nopromote)
+{
+ int onopromote = 0;
+
+ if (ds != NULL) {
+ onopromote = ds->nopromote;
+ ds->nopromote = nopromote;
+ }
+ return onopromote;
+}
+
+rpm_color_t rpmdsColor(const rpmds ds)
+{
+ rpm_color_t Color = 0;
+
+ if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ if (ds->Color != NULL)
+ Color = ds->Color[ds->i];
+ }
+ return Color;
+}
+
+rpm_color_t rpmdsSetColor(const rpmds ds, rpm_color_t color)
+{
+ rpm_color_t ocolor = 0;
+
+ if (ds != NULL && ds->i >= 0 && ds->i < ds->Count) {
+ if (ds->Color == NULL) {
+ ds->Color = xcalloc(ds->Count, sizeof(*ds->Color));
+ }
+ ocolor = ds->Color[ds->i];
+ ds->Color[ds->i] = color;
+ }
+ return ocolor;
+}
+
+void rpmdsNotify(rpmds ds, const char * where, int rc)
+{
+ const char *DNEVR;
+
+ if (!rpmIsDebug())
+ return;
+ if (!(ds != NULL && ds->i >= 0 && ds->i < ds->Count))
+ return;
+ if (!(ds->Type != NULL && (DNEVR = rpmdsDNEVR(ds)) != NULL))
+ return;
+
+ rpmlog(RPMLOG_DEBUG, "%9s: %-45s %-s %s\n", ds->Type,
+ (rstreq(DNEVR, "cached") ? DNEVR : DNEVR+2),
+ (rc ? _("NO ") : _("YES")),
+ (where != NULL ? where : ""));
+}
+
+int rpmdsNext(rpmds ds)
+{
+ int i = -1;
+
+ if (ds != NULL && ++ds->i >= 0) {
+ if (ds->i < ds->Count) {
+ i = ds->i;
+ ds->DNEVR = _free(ds->DNEVR);
+ } else
+ ds->i = -1;
+
+if (_rpmds_debug < 0 && i != -1)
+fprintf(stderr, "*** ds %p\t%s[%d]: %s\n", ds, (ds->Type ? ds->Type : "?Type?"), i, (ds->DNEVR ? ds->DNEVR : "?DNEVR?"));
+
+ }
+
+ return i;
+}
+
+rpmds rpmdsInit(rpmds ds)
+{
+ if (ds != NULL) {
+ ds->i = -1;
+ ds->DNEVR = _free(ds->DNEVR);
+ }
+ return ds;
+}
+
+static
+const char ** rpmdsDupArgv(const char ** argv, int argc)
+{
+ const char ** av;
+ size_t nb = 0;
+ int ac = 0;
+ char * t;
+
+ if (argv == NULL)
+ return NULL;
+ for (ac = 0; ac < argc && argv[ac]; ac++) {
+ nb += strlen(argv[ac]) + 1;
+ }
+ nb += (ac + 1) * sizeof(*av);
+
+ av = xmalloc(nb);
+ t = (char *) (av + ac + 1);
+ for (ac = 0; ac < argc && argv[ac]; ac++) {
+ av[ac] = t;
+ t = stpcpy(t, argv[ac]) + 1;
+ }
+ av[ac] = NULL;
+ return av;
+}
+
+static rpmds rpmdsDup(const rpmds ods)
+{
+ rpmds ds = xcalloc(1, sizeof(*ds));
+ size_t nb;
+
+ ds->Type = ods->Type;
+ ds->tagN = ods->tagN;
+ ds->Count = ods->Count;
+ ds->i = ods->i;
+ ds->l = ods->l;
+ ds->u = ods->u;
+ ds->nopromote = ods->nopromote;
+
+ ds->N = rpmdsDupArgv(ods->N, ods->Count);
+
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+assert(ods->EVR != NULL);
+assert(ods->Flags != NULL);
+
+ ds->EVR = rpmdsDupArgv(ods->EVR, ods->Count);
+
+ nb = (ds->Count * sizeof(*ds->Flags));
+ ds->Flags = memcpy(xmalloc(nb), ods->Flags, nb);
+
+ return rpmdsLink(ds);
+
+}
+
+int rpmdsFind(rpmds ds, const rpmds ods)
+{
+ int comparison;
+
+ if (ds == NULL || ods == NULL)
+ return -1;
+
+ ds->l = 0;
+ ds->u = ds->Count;
+ while (ds->l < ds->u) {
+ ds->i = (ds->l + ds->u) / 2;
+
+ comparison = strcmp(ods->N[ods->i], ds->N[ds->i]);
+
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (comparison == 0 && ods->EVR && ds->EVR)
+ comparison = strcmp(ods->EVR[ods->i], ds->EVR[ds->i]);
+ if (comparison == 0 && ods->Flags && ds->Flags)
+ comparison = (ods->Flags[ods->i] - ds->Flags[ds->i]);
+
+ if (comparison < 0)
+ ds->u = ds->i;
+ else if (comparison > 0)
+ ds->l = ds->i + 1;
+ else
+ return ds->i;
+ }
+ return -1;
+}
+
+int rpmdsMerge(rpmds * dsp, rpmds ods)
+{
+ rpmds ds;
+ const char ** N;
+ const char ** EVR;
+ rpmsenseFlags * Flags;
+ int j;
+ int save;
+
+ if (dsp == NULL || ods == NULL)
+ return -1;
+
+ /* If not initialized yet, dup the 1st entry. */
+ if (*dsp == NULL) {
+ save = ods->Count;
+ ods->Count = 1;
+ *dsp = rpmdsDup(ods);
+ ods->Count = save;
+ }
+ ds = *dsp;
+ if (ds == NULL)
+ return -1;
+
+ /*
+ * Add new entries.
+ */
+ save = ods->i;
+ ods = rpmdsInit(ods);
+ while (rpmdsNext(ods) >= 0) {
+ /*
+ * If this entry is already present, don't bother.
+ */
+ if (rpmdsFind(ds, ods) >= 0)
+ continue;
+
+ /*
+ * Insert new entry.
+ */
+ for (j = ds->Count; j > ds->u; j--)
+ ds->N[j] = ds->N[j-1];
+ ds->N[ds->u] = ods->N[ods->i];
+ N = rpmdsDupArgv(ds->N, ds->Count+1);
+ ds->N = _free(ds->N);
+ ds->N = N;
+
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+assert(ods->EVR != NULL);
+assert(ods->Flags != NULL);
+
+ for (j = ds->Count; j > ds->u; j--)
+ ds->EVR[j] = ds->EVR[j-1];
+ ds->EVR[ds->u] = ods->EVR[ods->i];
+ EVR = rpmdsDupArgv(ds->EVR, ds->Count+1);
+ ds->EVR = _free(ds->EVR);
+ ds->EVR = EVR;
+
+ Flags = xmalloc((ds->Count+1) * sizeof(*Flags));
+ if (ds->u > 0)
+ memcpy(Flags, ds->Flags, ds->u * sizeof(*Flags));
+ if (ds->u < ds->Count)
+ memcpy(Flags + ds->u + 1, ds->Flags + ds->u,
+ (ds->Count - ds->u) * sizeof(*Flags));
+ Flags[ds->u] = ods->Flags[ods->i];
+ ds->Flags = _free(ds->Flags);
+ ds->Flags = Flags;
+
+ ds->i = ds->Count;
+ ds->Count++;
+
+ }
+ ods->i = save;
+ return 0;
+}
+
+
+int rpmdsSearch(rpmds ds, rpmds ods)
+{
+ int comparison;
+ int i, l, u;
+
+ if (ds == NULL || ods == NULL)
+ return -1;
+
+ /* Binary search to find the [l,u) subset that contains N */
+ i = -1;
+ l = 0;
+ u = ds->Count;
+ while (l < u) {
+ i = (l + u) / 2;
+
+ comparison = strcmp(ods->N[ods->i], ds->N[i]);
+
+ if (comparison < 0)
+ u = i;
+ else if (comparison > 0)
+ l = i + 1;
+ else {
+ /* Set l to 1st member of set that contains N. */
+ if (!rstreq(ods->N[ods->i], ds->N[l]))
+ l = i;
+ while (l > 0 && rstreq(ods->N[ods->i], ds->N[l-1]))
+ l--;
+ /* Set u to 1st member of set that does not contain N. */
+ if (u >= ds->Count || !rstreq(ods->N[ods->i], ds->N[u]))
+ u = i;
+ while (++u < ds->Count) {
+ if (!rstreq(ods->N[ods->i], ds->N[u]))
+ /*@innerbreak@*/ break;
+ }
+ break;
+ }
+ }
+
+ /* Check each member of [l,u) subset for ranges overlap. */
+ i = -1;
+ if (l < u) {
+ int save = rpmdsSetIx(ds, l-1);
+ while ((l = rpmdsNext(ds)) >= 0 && (l < u)) {
+ if ((i = rpmdsCompare(ods, ds)) != 0)
+ break;
+ }
+ /* Return element index that overlaps, or -1. */
+ if (i)
+ i = rpmdsIx(ds);
+ else {
+ (void) rpmdsSetIx(ds, save);
+ i = -1;
+ }
+ }
+ return i;
+}
+/**
+ * Split EVR into epoch, version, and release components.
+ * @param evr [epoch:]version[-release] string
+ * @retval *ep pointer to epoch
+ * @retval *vp pointer to version
+ * @retval *rp pointer to release
+ */
+static
+void parseEVR(char * evr,
+ const char ** ep,
+ const char ** vp,
+ const char ** rp)
+{
+ const char *epoch;
+ const char *version; /* assume only version is present */
+ const char *release;
+ char *s, *se;
+
+ s = evr;
+ while (*s && risdigit(*s)) s++; /* s points to epoch terminator */
+ se = strrchr(s, '-'); /* se points to version terminator */
+
+ if (*s == ':') {
+ epoch = evr;
+ *s++ = '\0';
+ version = s;
+ if (*epoch == '\0') epoch = "0";
+ } else {
+ epoch = NULL; /* XXX disable epoch compare if missing */
+ version = evr;
+ }
+ if (se) {
+ *se++ = '\0';
+ release = se;
+ } else {
+ release = NULL;
+ }
+
+ if (ep) *ep = epoch;
+ if (vp) *vp = version;
+ if (rp) *rp = release;
+}
+
+int rpmdsCompare(const rpmds A, const rpmds B)
+{
+ char *aEVR, *bEVR;
+ const char *aE, *aV, *aR, *bE, *bV, *bR;
+ int result;
+ int sense;
+
+ /* Different names don't overlap. */
+ if (!rstreq(A->N[A->i], B->N[B->i])) {
+ result = 0;
+ goto exit;
+ }
+
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (!(A->EVR && A->Flags && B->EVR && B->Flags)) {
+ result = 1;
+ goto exit;
+ }
+
+ /* Same name. If either A or B is an existence test, always overlap. */
+ if (!((A->Flags[A->i] & RPMSENSE_SENSEMASK) && (B->Flags[B->i] & RPMSENSE_SENSEMASK))) {
+ result = 1;
+ goto exit;
+ }
+
+ /* If either EVR is non-existent or empty, always overlap. */
+ if (!(A->EVR[A->i] && *A->EVR[A->i] && B->EVR[B->i] && *B->EVR[B->i])) {
+ result = 1;
+ goto exit;
+ }
+
+ /* Both AEVR and BEVR exist. */
+ aEVR = xstrdup(A->EVR[A->i]);
+ parseEVR(aEVR, &aE, &aV, &aR);
+ bEVR = xstrdup(B->EVR[B->i]);
+ parseEVR(bEVR, &bE, &bV, &bR);
+
+ /* Compare {A,B} [epoch:]version[-release] */
+ sense = 0;
+ if (aE && *aE && bE && *bE)
+ sense = rpmvercmp(aE, bE);
+ else if (aE && *aE && atol(aE) > 0) {
+ if (!B->nopromote) {
+ sense = 0;
+ } else
+ sense = 1;
+ } else if (bE && *bE && atol(bE) > 0)
+ sense = -1;
+
+ if (sense == 0) {
+ sense = rpmvercmp(aV, bV);
+ if (sense == 0) {
+ if (aR && *aR && bR && *bR) {
+ sense = rpmvercmp(aR, bR);
+ } else {
+ /* always matches if the side with no release has SENSE_EQUAL */
+ if ((aR && *aR && (B->Flags[B->i] & RPMSENSE_EQUAL)) ||
+ (bR && *bR && (A->Flags[A->i] & RPMSENSE_EQUAL))) {
+ aEVR = _free(aEVR);
+ bEVR = _free(bEVR);
+ result = 1;
+ goto exit;
+ }
+ }
+ }
+ }
+ aEVR = _free(aEVR);
+ bEVR = _free(bEVR);
+
+ /* Detect overlap of {A,B} range. */
+ result = 0;
+ if (sense < 0 && ((A->Flags[A->i] & RPMSENSE_GREATER) || (B->Flags[B->i] & RPMSENSE_LESS))) {
+ result = 1;
+ } else if (sense > 0 && ((A->Flags[A->i] & RPMSENSE_LESS) || (B->Flags[B->i] & RPMSENSE_GREATER))) {
+ result = 1;
+ } else if (sense == 0 &&
+ (((A->Flags[A->i] & RPMSENSE_EQUAL) && (B->Flags[B->i] & RPMSENSE_EQUAL)) ||
+ ((A->Flags[A->i] & RPMSENSE_LESS) && (B->Flags[B->i] & RPMSENSE_LESS)) ||
+ ((A->Flags[A->i] & RPMSENSE_GREATER) && (B->Flags[B->i] & RPMSENSE_GREATER)))) {
+ result = 1;
+ }
+
+exit:
+ return result;
+}
+
+int rpmdsAnyMatchesDep (const Header h, const rpmds req, int nopromote)
+{
+ rpmds provides = NULL;
+ int result = 0;
+
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (req->EVR == NULL || req->Flags == NULL)
+ return 1;
+
+ if (!(req->Flags[req->i] & RPMSENSE_SENSEMASK) || !req->EVR[req->i] || *req->EVR[req->i] == '\0')
+ return 1;
+
+ /* Get provides information from header */
+ provides = rpmdsInit(rpmdsNew(h, RPMTAG_PROVIDENAME, 0));
+ if (provides == NULL)
+ goto exit; /* XXX should never happen */
+ if (nopromote)
+ (void) rpmdsSetNoPromote(provides, nopromote);
+
+ /*
+ * Rpm prior to 3.0.3 did not have versioned provides.
+ * If no provides version info is available, match any/all requires
+ * with same name.
+ */
+ if (provides->EVR == NULL) {
+ result = 1;
+ goto exit;
+ }
+
+ result = 0;
+ while (rpmdsNext(provides) >= 0) {
+
+ /* Filter out provides that came along for the ride. */
+ if (!rstreq(provides->N[provides->i], req->N[req->i]))
+ continue;
+
+ result = rpmdsCompare(provides, req);
+
+ /* If this provide matches the require, we're done. */
+ if (result)
+ break;
+ }
+
+exit:
+ provides = rpmdsFree(provides);
+
+ return result;
+}
+
+int rpmdsNVRMatchesDep(const Header h, const rpmds req, int nopromote)
+{
+ rpmds pkg;
+ int rc = 1; /* XXX assume match, names already match here */
+
+ /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */
+ if (req->EVR == NULL || req->Flags == NULL)
+ return rc;
+
+ if (!((req->Flags[req->i] & RPMSENSE_SENSEMASK) && req->EVR[req->i] && *req->EVR[req->i]))
+ return rc;
+
+ /* Get package information from header */
+ pkg = rpmdsThis(h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
+ if (nopromote)
+ rpmdsSetNoPromote(pkg, nopromote);
+ rc = rpmdsCompare(pkg, req);
+ rpmdsFree(pkg);
+
+ return rc;
+}
+
+/**
+ */
+struct rpmlibProvides_s {
+ const char * featureName;
+ const char * featureEVR;
+ rpmsenseFlags featureFlags;
+ const char * featureDescription;
+};
+
+static const struct rpmlibProvides_s rpmlibProvides[] = {
+ { "rpmlib(VersionedDependencies)", "3.0.3-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("PreReq:, Provides:, and Obsoletes: dependencies support versions.") },
+ { "rpmlib(CompressedFileNames)", "3.0.4-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("file name(s) stored as (dirName,baseName,dirIndex) tuple, not as path.")},
+#if HAVE_BZLIB_H
+ { "rpmlib(PayloadIsBzip2)", "3.0.5-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("package payload can be compressed using bzip2.") },
+#endif
+#if HAVE_LZMA_H
+ { "rpmlib(PayloadIsXz)", "5.2-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("package payload can be compressed using xz.") },
+ { "rpmlib(PayloadIsLzma)", "4.4.2-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("package payload can be compressed using lzma.") },
+#endif
+ { "rpmlib(PayloadFilesHavePrefix)", "4.0-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("package payload file(s) have \"./\" prefix.") },
+ { "rpmlib(ExplicitPackageProvide)", "4.0-1",
+ (RPMSENSE_RPMLIB|RPMSENSE_EQUAL),
+ N_("package name-version-release is not implicitly provided.") },
+ { "rpmlib(HeaderLoadSortsTags)", "4.0.1-1",
+ ( RPMSENSE_EQUAL),
+ N_("header tags are always sorted after being loaded.") },
+ { "rpmlib(ScriptletInterpreterArgs)", "4.0.3-1",
+ ( RPMSENSE_EQUAL),
+ N_("the scriptlet interpreter can use arguments from header.") },
+ { "rpmlib(PartialHardlinkSets)", "4.0.4-1",
+ ( RPMSENSE_EQUAL),
+ N_("a hardlink file set may be installed without being complete.") },
+ { "rpmlib(ConcurrentAccess)", "4.1-1",
+ ( RPMSENSE_EQUAL),
+ N_("package scriptlets may access the rpm database while installing.") },
+#ifdef WITH_LUA
+ { "rpmlib(BuiltinLuaScripts)", "4.2.2-1",
+ ( RPMSENSE_EQUAL),
+ N_("internal support for lua scripts.") },
+#endif
+ { "rpmlib(FileDigests)", "4.6.0-1",
+ ( RPMSENSE_EQUAL),
+ N_("file digest algorithm is per package configurable") },
+#ifdef WITH_CAP
+ { "rpmlib(FileCaps)", "4.6.1-1",
+ ( RPMSENSE_EQUAL),
+ N_("support for POSIX.1e file capabilities") },
+#endif
+ { "rpmlib(ScriptletExpansion)", "4.9.0-1",
+ ( RPMSENSE_EQUAL),
+ N_("package scriptlets can be expanded at install time.") },
+ { NULL, NULL, 0, NULL }
+};
+
+
+int rpmdsRpmlib(rpmds * dsp, const void * tblp)
+{
+ const struct rpmlibProvides_s * rltblp = tblp;
+ const struct rpmlibProvides_s * rlp;
+ int xx;
+
+ if (rltblp == NULL)
+ rltblp = rpmlibProvides;
+
+ for (rlp = rltblp; rlp->featureName != NULL; rlp++) {
+ rpmds ds = rpmdsSingle(RPMTAG_PROVIDENAME, rlp->featureName,
+ rlp->featureEVR, rlp->featureFlags);
+ xx = rpmdsMerge(dsp, ds);
+ ds = rpmdsFree(ds);
+ }
+ return 0;
+}
+