queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c
chksum.c md5.c sha1.c sha2.c solvversion.c selection.c
- fileprovides.c diskusage.c suse.c)
+ fileprovides.c diskusage.c suse.c solver_util.c)
SET (libsolv_HEADERS
bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
static void addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep);
static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded);
-/*-------------------------------------------------------------------
- * Check if dependency is possible
- *
- * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap.
- * used in solver_addpkgrulesforweak and solver_createcleandepsmap.
- */
-
-static inline int
-dep_possible(Solver *solv, Id dep, Map *m)
-{
- Pool *pool = solv->pool;
- Id p, pp;
-
- if (ISRELDEP(dep))
- {
- Reldep *rd = GETRELDEP(pool, dep);
- if (rd->flags >= 8)
- {
- if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
- return 1;
- if (rd->flags == REL_AND)
- {
- if (!dep_possible(solv, rd->name, m))
- return 0;
- return dep_possible(solv, rd->evr, m);
- }
- if (rd->flags == REL_OR)
- {
- if (dep_possible(solv, rd->name, m))
- return 1;
- return dep_possible(solv, rd->evr, m);
- }
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
- return solver_splitprovides(solv, rd->evr, m);
- }
- }
- FOR_PROVIDES(p, pp, dep)
- {
- if (MAPTST(m, p))
- return 1;
- }
- return 0;
-}
-
static inline int
is_otherproviders_dep(Pool *pool, Id dep)
{
/* find possible supplements */
supp = s->repo->idarraydata + s->supplements;
while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, m))
+ if (solver_dep_possible(solv, sup, m))
break;
}
{
supp = s->repo->idarraydata + s->enhances;
while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, m))
+ if (solver_dep_possible(solv, sup, m))
break;
}
/* if nothing found, goto next solvables */
#define DISABLE_INFARCH 2
#define DISABLE_DUP 3
-/*
- * add all installed packages that package p obsoletes to Queue q.
- * Package p is not installed. Also, we know that if
- * solv->keepexplicitobsoletes is not set, p is not in the multiversion map.
- * Entries may get added multiple times.
- */
-static void
-add_obsoletes(Solver *solv, Id p, Queue *q)
-{
- Pool *pool = solv->pool;
- Repo *installed = solv->installed;
- Id p2, pp2;
- Solvable *s = pool->solvables + p;
- Id obs, *obsp;
- Id lastp2 = 0;
-
- if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
- {
- FOR_PROVIDES(p2, pp2, s->name)
- {
- Solvable *ps = pool->solvables + p2;
- if (ps->repo != installed)
- continue;
- if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
- continue;
- if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- queue_push(q, p2);
- lastp2 = p2;
- }
- }
- if (!s->obsoletes)
- return;
- obsp = s->repo->idarraydata + s->obsoletes;
- while ((obs = *obsp++) != 0)
- FOR_PROVIDES(p2, pp2, obs)
- {
- Solvable *ps = pool->solvables + p2;
- if (ps->repo != installed)
- continue;
- if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
- continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- if (p2 == lastp2)
- continue;
- queue_push(q, p2);
- lastp2 = p2;
- }
-}
-
-/*
- * Call add_obsoletes and intersect the result with the
- * elements in Queue q starting at qstart.
- * Assumes that it's the first call if qstart == q->count.
- * May use auxillary map m for the intersection process, all
- * elements of q starting at qstart must have their bit cleared.
- * (This is also true after the function returns.)
- */
-static void
-intersect_obsoletes(Solver *solv, Id p, Queue *q, int qstart, Map *m)
-{
- int i, j;
- int qcount = q->count;
-
- add_obsoletes(solv, p, q);
- if (qcount == qstart)
- return; /* first call */
- if (qcount == q->count)
- j = qstart;
- else if (qcount == qstart + 1)
- {
- /* easy if there's just one element */
- j = qstart;
- for (i = qcount; i < q->count; i++)
- if (q->elements[i] == q->elements[qstart])
- {
- j++; /* keep the element */
- break;
- }
- }
- else if (!m->size && q->count - qstart <= 8)
- {
- /* faster than a map most of the time */
- int k;
- for (i = j = qstart; i < qcount; i++)
- {
- Id ip = q->elements[i];
- for (k = qcount; k < q->count; k++)
- if (q->elements[k] == ip)
- {
- q->elements[j++] = ip;
- break;
- }
- }
- }
- else
- {
- /* for the really pathologic cases we use the map */
- Repo *installed = solv->installed;
- if (!m->size)
- map_init(m, installed->end - installed->start);
- for (i = qcount; i < q->count; i++)
- MAPSET(m, q->elements[i] - installed->start);
- for (i = j = qstart; i < qcount; i++)
- if (MAPTST(m, q->elements[i] - installed->start))
- {
- MAPCLR(m, q->elements[i] - installed->start);
- q->elements[j++] = q->elements[i];
- }
- }
- queue_truncate(q, j);
-}
-
static void
jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
{
qstart = q->count;
FOR_JOB_SELECT(p, pp, select, what)
{
- intersect_obsoletes(solv, p, q, qstart, &omap);
+ solver_intersect_obsoleted(solv, p, q, qstart, &omap);
if (q->count == qstart)
break;
}
}
}
else
- intersect_obsoletes(solv, p, &iq, iqstart, &om);
+ solver_intersect_obsoleted(solv, p, &iq, iqstart, &om);
if (iq.count == iqstart)
break;
}
continue;
supp = s->repo->idarraydata + s->supplements;
while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &im))
+ if (solver_dep_possible(solv, sup, &im))
break;
if (!sup)
{
supp = s->repo->idarraydata + s->supplements;
while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
+ if (solver_dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
{
/* no longer supplemented, also erase */
int iqcount = iq.count;
continue;
supp = s->repo->idarraydata + s->supplements;
while ((sup = *supp++) != 0)
- if (dep_possible(solv, sup, &im))
+ if (solver_dep_possible(solv, sup, &im))
break;
if (sup)
{
Id *dp;
int k;
for (dp = s->repo->idarraydata + s->supplements; *dp; dp++)
- if (dep_possible(solv, *dp, &installedm))
+ if (solver_dep_possible(solv, *dp, &installedm))
{
Queue iq;
Id iqbuf[16];
#define RULES_BLOCK 63
-/********************************************************************
- *
- * dependency check helpers
- *
- */
-
-/*-------------------------------------------------------------------
- * handle split provides
- *
- * a splitprovides dep looks like
- * namespace:splitprovides(pkg REL_WITH path)
- * and is only true if pkg is installed and contains the specified path.
- * we also make sure that pkg is selected for an update, otherwise the
- * update would always be forced onto the user.
- * Map m is the map used when called from dep_possible.
- */
-
-static int
-solver_is_updating(Solver *solv, Id p)
-{
- /* check if the update rule is true */
- Pool *pool = solv->pool;
- Rule *r;
- Id l, pp;
- if (solv->decisionmap[p] >= 0)
- return 0; /* old package stayed */
- r = solv->rules + solv->updaterules + (p - solv->installed->start);
- FOR_RULELITERALS(l, pp, r)
- if (l > 0 && l != p && solv->decisionmap[l] > 0)
- return 1;
- return 0;
-}
-
-int
-solver_splitprovides(Solver *solv, Id dep, Map *m)
-{
- Pool *pool = solv->pool;
- Id p, pp;
- Reldep *rd;
- Solvable *s;
-
- if (!solv->dosplitprovides || !solv->installed)
- return 0;
- if (!ISRELDEP(dep))
- return 0;
- rd = GETRELDEP(pool, dep);
- if (rd->flags != REL_WITH)
- return 0;
- /*
- * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
- * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
- * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
- * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
- * we filter the package name further down anyway).
- */
- if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
- pp = pool_searchlazywhatprovidesq(pool, rd->evr);
- else
- pp = pool_whatprovides(pool, dep);
- while ((p = pool->whatprovidesdata[pp++]) != 0)
- {
- /* here we have packages that provide the correct name and contain the path,
- * now do extra filtering */
- s = pool->solvables + p;
- if (s->repo != solv->installed || s->name != rd->name)
- continue;
- /* check if the package is updated. if m is set, we're called from dep_possible */
- if (m || solver_is_updating(solv, p))
- return 1;
- }
- return 0;
-}
-
-int
-solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
-{
- Pool *pool = solv->pool;
- if (rd->flags == REL_COND)
- {
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- if (solver_dep_fulfilled(solv, rd2->name))
- return solver_dep_fulfilled(solv, rd->name);
- return solver_dep_fulfilled(solv, rd2->evr);
- }
- }
- if (solver_dep_fulfilled(solv, rd->name))
- return 1;
- return !solver_dep_fulfilled(solv, rd->evr);
- }
- if (rd->flags == REL_UNLESS)
- {
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- if (!solver_dep_fulfilled(solv, rd2->name))
- return solver_dep_fulfilled(solv, rd->name);
- return solver_dep_fulfilled(solv, rd2->evr);
- }
- }
- if (!solver_dep_fulfilled(solv, rd->name))
- return 0;
- return !solver_dep_fulfilled(solv, rd->evr);
- }
- if (rd->flags == REL_AND)
- {
- if (!solver_dep_fulfilled(solv, rd->name))
- return 0;
- return solver_dep_fulfilled(solv, rd->evr);
- }
- if (rd->flags == REL_OR)
- {
- if (solver_dep_fulfilled(solv, rd->name))
- return 1;
- return solver_dep_fulfilled(solv, rd->evr);
- }
- return 0;
-}
-
-
-/* mirrors solver_dep_fulfilled, but returns 2 if a new package
- * was involved */
-static int
-solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
-{
- Pool *pool = solv->pool;
- Id p, pp;
- int r;
-
- if (ISRELDEP(dep))
- {
- Reldep *rd = GETRELDEP(pool, dep);
- if (rd->flags == REL_COND)
- {
- int r1, r2;
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
- if (r1)
- {
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- return r2 && r1 == 2 ? 2 : r2;
- }
- return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
- }
- }
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r1 && !r2)
- return 0;
- return r1 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_UNLESS)
- {
- int r1, r2;
- if (ISRELDEP(rd->evr))
- {
- Reldep *rd2 = GETRELDEP(pool, rd->evr);
- if (rd2->flags == REL_ELSE)
- {
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
- if (r1)
- {
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
- return r2 && r1 == 2 ? 2 : r2;
- }
- return solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- }
- }
- /* A AND NOT(B) */
- r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r1 || !r2)
- return 0;
- return r1 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_AND)
- {
- int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- if (!r1)
- return 0;
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r2)
- return 0;
- return r1 == 2 || r2 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_OR)
- {
- int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
- r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
- if (!r1 && !r2)
- return 0;
- return r1 == 2 || r2 == 2 ? 2 : 1;
- }
- if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
- return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
- if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
- {
- Queue *q = solv->installsuppdepq;
- int i;
- for (i = 0; i < q->count; i++)
- if (q->elements[i] == dep || q->elements[i] == rd->name)
- return 2;
- }
- }
- r = 0;
- FOR_PROVIDES(p, pp, dep)
- if (solv->decisionmap[p] > 0)
- {
- Solvable *s = pool->solvables + p;
- if (s->repo && s->repo != solv->installed)
- return 2;
- r = 1;
- }
- return r;
-}
-
-static int
-solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
-{
- Id sup, *supp;
- supp = s->repo->idarraydata + s->supplements;
- while ((sup = *supp++) != 0)
- if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
- return 1;
- return 0;
-}
-
static Id
autouninstall(Solver *solv, Id *problem)
{
extern void solver_reset(Solver *solv);
extern int solver_splitprovides(Solver *solv, Id dep, Map *m);
+extern int solver_dep_possible_slow(Solver *solv, Id dep, Map *m);
extern int solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd);
+extern int solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s);
+extern void solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m);
+
+
+#define ISSIMPLEDEP(pool, dep) (!ISRELDEP(dep) || GETRELDEP(pool, dep)->flags < 8)
+
+static inline int
+solver_dep_possible(Solver *solv, Id dep, Map *m)
+{
+ Pool *pool = solv->pool;
+ Id p, pp;
+
+ if (!ISSIMPLEDEP(pool, dep))
+ return solver_dep_possible_slow(solv, dep, m);
+ FOR_PROVIDES(p, pp, dep)
+ {
+ if (MAPTST(m, p))
+ return 1;
+ }
+ return 0;
+}
static inline int
solver_dep_fulfilled(Solver *solv, Id dep)
--- /dev/null
+/*
+ * Copyright (c) 2017, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * solver_util.c
+ *
+ * Dependency solver helper functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "poolarch.h"
+#include "util.h"
+
+
+/*-------------------------------------------------------------------
+ * check if a installed package p is being updated
+ */
+static int
+solver_is_updating(Solver *solv, Id p)
+{
+ /* check if the update rule is true */
+ Pool *pool = solv->pool;
+ Rule *r;
+ Id l, pp;
+ if (solv->decisionmap[p] >= 0)
+ return 0; /* old package stayed */
+ r = solv->rules + solv->updaterules + (p - solv->installed->start);
+ FOR_RULELITERALS(l, pp, r)
+ if (l > 0 && l != p && solv->decisionmap[l] > 0)
+ return 1;
+ return 0;
+}
+
+/*-------------------------------------------------------------------
+ * handle split provides
+ *
+ * a splitprovides dep looks like
+ * namespace:splitprovides(pkg REL_WITH path)
+ * and is only true if pkg is installed and contains the specified path.
+ * we also make sure that pkg is selected for an update, otherwise the
+ * update would always be forced onto the user.
+ * Map m is the map used when called from dep_possible.
+ */
+int
+solver_splitprovides(Solver *solv, Id dep, Map *m)
+{
+ Pool *pool = solv->pool;
+ Id p, pp;
+ Reldep *rd;
+ Solvable *s;
+
+ if (!solv->dosplitprovides || !solv->installed)
+ return 0;
+ if (!ISRELDEP(dep))
+ return 0;
+ rd = GETRELDEP(pool, dep);
+ if (rd->flags != REL_WITH)
+ return 0;
+ /*
+ * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
+ * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
+ * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
+ * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
+ * we filter the package name further down anyway).
+ */
+ if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
+ pp = pool_searchlazywhatprovidesq(pool, rd->evr);
+ else
+ pp = pool_whatprovides(pool, dep);
+ while ((p = pool->whatprovidesdata[pp++]) != 0)
+ {
+ /* here we have packages that provide the correct name and contain the path,
+ * now do extra filtering */
+ s = pool->solvables + p;
+ if (s->repo != solv->installed || s->name != rd->name)
+ continue;
+ /* check if the package is updated. if m is set, we're called from dep_possible */
+ if (m || solver_is_updating(solv, p))
+ return 1;
+ }
+ return 0;
+}
+
+int
+solver_dep_possible_slow(Solver *solv, Id dep, Map *m)
+{
+ Pool *pool = solv->pool;
+ Id p, pp;
+
+ if (ISRELDEP(dep))
+ {
+ Reldep *rd = GETRELDEP(pool, dep);
+ if (rd->flags >= 8)
+ {
+ if (rd->flags == REL_COND || rd->flags == REL_UNLESS)
+ return 1;
+ if (rd->flags == REL_AND)
+ {
+ if (!solver_dep_possible_slow(solv, rd->name, m))
+ return 0;
+ return solver_dep_possible_slow(solv, rd->evr, m);
+ }
+ if (rd->flags == REL_OR)
+ {
+ if (solver_dep_possible_slow(solv, rd->name, m))
+ return 1;
+ return solver_dep_possible_slow(solv, rd->evr, m);
+ }
+ if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+ return solver_splitprovides(solv, rd->evr, m);
+ }
+ }
+ FOR_PROVIDES(p, pp, dep)
+ {
+ if (MAPTST(m, p))
+ return 1;
+ }
+ return 0;
+}
+
+int
+solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
+{
+ Pool *pool = solv->pool;
+ if (rd->flags == REL_COND)
+ {
+ if (ISRELDEP(rd->evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, rd->evr);
+ if (rd2->flags == REL_ELSE)
+ {
+ if (solver_dep_fulfilled(solv, rd2->name))
+ return solver_dep_fulfilled(solv, rd->name);
+ return solver_dep_fulfilled(solv, rd2->evr);
+ }
+ }
+ if (solver_dep_fulfilled(solv, rd->name))
+ return 1;
+ return !solver_dep_fulfilled(solv, rd->evr);
+ }
+ if (rd->flags == REL_UNLESS)
+ {
+ if (ISRELDEP(rd->evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, rd->evr);
+ if (rd2->flags == REL_ELSE)
+ {
+ if (!solver_dep_fulfilled(solv, rd2->name))
+ return solver_dep_fulfilled(solv, rd->name);
+ return solver_dep_fulfilled(solv, rd2->evr);
+ }
+ }
+ if (!solver_dep_fulfilled(solv, rd->name))
+ return 0;
+ return !solver_dep_fulfilled(solv, rd->evr);
+ }
+ if (rd->flags == REL_AND)
+ {
+ if (!solver_dep_fulfilled(solv, rd->name))
+ return 0;
+ return solver_dep_fulfilled(solv, rd->evr);
+ }
+ if (rd->flags == REL_OR)
+ {
+ if (solver_dep_fulfilled(solv, rd->name))
+ return 1;
+ return solver_dep_fulfilled(solv, rd->evr);
+ }
+ return 0;
+}
+
+
+/* mirrors solver_dep_fulfilled, but returns 2 if a new package
+ * was involved */
+static int
+solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
+{
+ Pool *pool = solv->pool;
+ Id p, pp;
+ int r;
+
+ if (ISRELDEP(dep))
+ {
+ Reldep *rd = GETRELDEP(pool, dep);
+ if (rd->flags == REL_COND)
+ {
+ int r1, r2;
+ if (ISRELDEP(rd->evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, rd->evr);
+ if (rd2->flags == REL_ELSE)
+ {
+ r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
+ if (r1)
+ {
+ r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+ return r2 && r1 == 2 ? 2 : r2;
+ }
+ return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
+ }
+ }
+ r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+ r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+ if (!r1 && !r2)
+ return 0;
+ return r1 == 2 ? 2 : 1;
+ }
+ if (rd->flags == REL_UNLESS)
+ {
+ int r1, r2;
+ if (ISRELDEP(rd->evr))
+ {
+ Reldep *rd2 = GETRELDEP(pool, rd->evr);
+ if (rd2->flags == REL_ELSE)
+ {
+ r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
+ if (r1)
+ {
+ r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
+ return r2 && r1 == 2 ? 2 : r2;
+ }
+ return solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+ }
+ }
+ /* A AND NOT(B) */
+ r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+ r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+ if (!r1 || !r2)
+ return 0;
+ return r1 == 2 ? 2 : 1;
+ }
+ if (rd->flags == REL_AND)
+ {
+ int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+ if (!r1)
+ return 0;
+ r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+ if (!r2)
+ return 0;
+ return r1 == 2 || r2 == 2 ? 2 : 1;
+ }
+ if (rd->flags == REL_OR)
+ {
+ int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+ r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
+ if (!r1 && !r2)
+ return 0;
+ return r1 == 2 || r2 == 2 ? 2 : 1;
+ }
+ if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+ return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
+ if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
+ {
+ Queue *q = solv->installsuppdepq;
+ int i;
+ for (i = 0; i < q->count; i++)
+ if (q->elements[i] == dep || q->elements[i] == rd->name)
+ return 2;
+ }
+ }
+ r = 0;
+ FOR_PROVIDES(p, pp, dep)
+ if (solv->decisionmap[p] > 0)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo && s->repo != solv->installed)
+ return 2;
+ r = 1;
+ }
+ return r;
+}
+
+int
+solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
+{
+ Id sup, *supp;
+ supp = s->repo->idarraydata + s->supplements;
+ while ((sup = *supp++) != 0)
+ if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
+ return 1;
+ return 0;
+}
+/*
+ * add all installed packages that package p obsoletes to Queue q.
+ * Package p is not installed. Also, we know that if
+ * solv->keepexplicitobsoletes is not set, p is not in the multiversion map.
+ * Entries may get added multiple times.
+ */
+static void
+solver_add_obsoleted(Solver *solv, Id p, Queue *q)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ Id p2, pp2;
+ Solvable *s = pool->solvables + p;
+ Id obs, *obsp;
+ Id lastp2 = 0;
+
+ if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
+ {
+ FOR_PROVIDES(p2, pp2, s->name)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (ps->repo != installed)
+ continue;
+ if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
+ continue;
+ if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ queue_push(q, p2);
+ lastp2 = p2;
+ }
+ }
+ if (!s->obsoletes)
+ return;
+ obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ FOR_PROVIDES(p2, pp2, obs)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (ps->repo != installed)
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ if (p2 == lastp2)
+ continue;
+ queue_push(q, p2);
+ lastp2 = p2;
+ }
+}
+
+/*
+ * Call solver_add_obsoleted and intersect the result with the
+ * elements in Queue q starting at qstart.
+ * Assumes that it's the first call if qstart == q->count.
+ * May use auxillary map m for the intersection process, all
+ * elements of q starting at qstart must have their bit cleared.
+ * (This is also true after the function returns.)
+ * (See solver_add_obsoleted for limitations of the package p)
+ */
+void
+solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m)
+{
+ int i, j;
+ int qcount = q->count;
+
+ solver_add_obsoleted(solv, p, q);
+ if (qcount == qstart)
+ return; /* first call */
+ if (qcount == q->count)
+ j = qstart;
+ else if (qcount == qstart + 1)
+ {
+ /* easy if there's just one element */
+ j = qstart;
+ for (i = qcount; i < q->count; i++)
+ if (q->elements[i] == q->elements[qstart])
+ {
+ j++; /* keep the element */
+ break;
+ }
+ }
+ else if (!m->size && q->count - qstart <= 8)
+ {
+ /* faster than a map most of the time */
+ int k;
+ for (i = j = qstart; i < qcount; i++)
+ {
+ Id ip = q->elements[i];
+ for (k = qcount; k < q->count; k++)
+ if (q->elements[k] == ip)
+ {
+ q->elements[j++] = ip;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* for the really pathologic cases we use the map */
+ Repo *installed = solv->installed;
+ if (!m->size)
+ map_init(m, installed->end - installed->start);
+ for (i = qcount; i < q->count; i++)
+ MAPSET(m, q->elements[i] - installed->start);
+ for (i = j = qstart; i < qcount; i++)
+ if (MAPTST(m, q->elements[i] - installed->start))
+ {
+ MAPCLR(m, q->elements[i] - installed->start);
+ q->elements[j++] = q->elements[i];
+ }
+ }
+ queue_truncate(q, j);
+}
+