+ /* end result has same size as oldoffset -> no new entries */
+ queue_free(&q);
+ pool->whatprovides[d] = oldoffset;
+ return oldoffset;
+ }
+ }
+ pool->whatprovides[d] = pool_queuetowhatprovides(pool, &q);
+ }
+ queue_free(&q);
+ return pool->whatprovides[d];
+}
+
+
+static inline int
+pool_is_kind(Pool *pool, Id name, Id kind)
+{
+ const char *n;
+ if (!kind)
+ return 1;
+ n = pool_id2str(pool, name);
+ if (kind != 1)
+ {
+ const char *kn = pool_id2str(pool, kind);
+ int knl = strlen(kn);
+ return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
+ }
+ else
+ {
+ if (*n == ':')
+ return 1;
+ while(*n >= 'a' && *n <= 'z')
+ n++;
+ return *n == ':' ? 0 : 1;
+ }
+}
+
+/*
+ * addrelproviders
+ *
+ * add packages fulfilling the relation to whatprovides array
+ *
+ * some words about REL_AND and REL_IF: we assume the best case
+ * here, so that you get a "potential" result if you ask for a match.
+ * E.g. if you ask for "whatrequires A" and package X contains
+ * "Requires: A & B", you'll get "X" as an answer.
+ */
+Id
+pool_addrelproviders(Pool *pool, Id d)
+{
+ Reldep *rd;
+ Reldep *prd;
+ Queue plist;
+ Id buf[16];
+ Id name, evr, flags;
+ Id pid, *pidp;
+ Id p, *pp;
+
+ if (!ISRELDEP(d))
+ return pool_addstdproviders(pool, d);
+ rd = GETRELDEP(pool, d);
+ name = rd->name;
+ evr = rd->evr;
+ flags = rd->flags;
+ d = GETRELID(d);
+ queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
+
+ if (flags >= 8)
+ {
+ /* special relation */
+ Id wp = 0;
+ Id *pp2, *pp3;
+
+ switch (flags)
+ {
+ case REL_WITH:
+ wp = pool_whatprovides(pool, name);
+ pp2 = pool_whatprovides_ptr(pool, evr);
+ pp = pool->whatprovidesdata + wp;
+ while ((p = *pp++) != 0)
+ {
+ for (pp3 = pp2; *pp3; pp3++)
+ if (*pp3 == p)
+ break;
+ if (*pp3)
+ queue_push(&plist, p); /* found it */
+ else
+ wp = 0;
+ }
+ break;
+
+ case REL_AND:
+ case REL_OR:
+ wp = pool_whatprovides(pool, name);
+ if (!pool->whatprovidesdata[wp])
+ wp = pool_whatprovides(pool, evr);
+ else
+ {
+ /* sorted merge */
+ pp2 = pool_whatprovides_ptr(pool, evr);
+ pp = pool->whatprovidesdata + wp;
+ while (*pp && *pp2)
+ {
+ if (*pp < *pp2)
+ queue_push(&plist, *pp++);
+ else
+ {
+ if (*pp == *pp2)
+ pp++;
+ queue_push(&plist, *pp2++);
+ }
+ }
+ while (*pp)
+ queue_push(&plist, *pp++);
+ while (*pp2)
+ queue_push(&plist, *pp2++);
+ /* if the number of elements did not change, we can reuse wp */
+ if (pp - (pool->whatprovidesdata + wp) != plist.count)
+ wp = 0;
+ }
+ break;
+
+ case REL_COND:
+ /* assume the condition is true */
+ wp = pool_whatprovides(pool, name);
+ break;
+
+ case REL_NAMESPACE:
+ if (name == NAMESPACE_OTHERPROVIDERS)
+ {
+ wp = pool_whatprovides(pool, evr);
+ break;
+ }
+ if (pool->nscallback)
+ {
+ /* ask callback which packages provide the dependency
+ * 0: none
+ * 1: the system (aka SYSTEMSOLVABLE)
+ * >1: set of packages, stored as offset on whatprovidesdata
+ */
+ p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
+ if (p > 1)
+ wp = p;
+ if (p == 1)
+ queue_push(&plist, SYSTEMSOLVABLE);
+ }
+ break;
+ case REL_ARCH:
+ /* small hack: make it possible to match <pkg>.src
+ * we have to iterate over the solvables as src packages do not
+ * provide anything, thus they are not indexed in our
+ * whatprovides hash */
+ if (evr == ARCH_SRC || evr == ARCH_NOSRC)
+ {
+ Solvable *s;
+ for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
+ {
+ if (!s->repo)
+ continue;
+ if (s->arch != evr && s->arch != ARCH_NOSRC)
+ continue;
+ if (pool_disabled_solvable(pool, s))
+ continue;
+ if (!name || pool_match_nevr(pool, s, name))
+ queue_push(&plist, p);
+ }
+ break;
+ }
+ if (!name)
+ {
+ FOR_POOL_SOLVABLES(p)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo != pool->installed && !pool_installable(pool, s))
+ continue;
+ if (s->arch == evr)
+ queue_push(&plist, p);
+ }
+ break;
+ }
+ wp = pool_whatprovides(pool, name);
+ pp = pool->whatprovidesdata + wp;
+ while ((p = *pp++) != 0)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->arch == evr)
+ queue_push(&plist, p);
+ else
+ wp = 0;
+ }
+ break;
+ case REL_MULTIARCH:
+ if (evr != ARCH_ANY)
+ break;
+ /* XXX : need to check for Multi-Arch: allowed! */
+ wp = pool_whatprovides(pool, name);
+ break;
+ case REL_KIND:
+ /* package kind filtering */
+ if (!name)
+ {
+ FOR_POOL_SOLVABLES(p)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo != pool->installed && !pool_installable(pool, s))
+ continue;
+ if (pool_is_kind(pool, s->name, evr))
+ queue_push(&plist, p);
+ }
+ break;
+ }
+ wp = pool_whatprovides(pool, name);
+ pp = pool->whatprovidesdata + wp;
+ while ((p = *pp++) != 0)
+ {
+ Solvable *s = pool->solvables + p;
+ if (pool_is_kind(pool, s->name, evr))
+ queue_push(&plist, p);
+ else
+ wp = 0;
+ }
+ break;
+ case REL_FILECONFLICT:
+ pp = pool_whatprovides_ptr(pool, name);
+ while ((p = *pp++) != 0)
+ {
+ Id origd = MAKERELDEP(d);
+ Solvable *s = pool->solvables + p;
+ if (!s->provides)
+ continue;
+ pidp = s->repo->idarraydata + s->provides;
+ while ((pid = *pidp++) != 0)
+ if (pid == origd)
+ break;
+ if (pid)
+ queue_push(&plist, p);
+ }
+ break;
+ default:
+ break;
+ }
+ if (wp)
+ {
+ /* we can reuse an existing entry */
+ queue_free(&plist);
+ pool->whatprovides_rel[d] = wp;
+ return wp;
+ }
+ }
+ else if (flags)
+ {
+ /* simple version comparison relation */
+#if 0
+ POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name));
+#endif
+ pp = pool_whatprovides_ptr(pool, name);
+ while (ISRELDEP(name))
+ {
+ rd = GETRELDEP(pool, name);
+ name = rd->name;
+ }
+ while ((p = *pp++) != 0)
+ {
+ Solvable *s = pool->solvables + p;
+ if (!s->provides)
+ {
+ /* no provides - check nevr */
+ if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
+ queue_push(&plist, p);
+ continue;
+ }
+ /* solvable p provides name in some rels */
+ pidp = s->repo->idarraydata + s->provides;
+ while ((pid = *pidp++) != 0)
+ {
+ if (!ISRELDEP(pid))
+ {
+ if (pid != name)
+ continue; /* wrong provides name */
+ if (pool->disttype == DISTTYPE_DEB)
+ continue; /* unversioned provides can never match versioned deps */
+ break;
+ }
+ prd = GETRELDEP(pool, pid);
+ if (prd->name != name)
+ continue; /* wrong provides name */
+ /* right package, both deps are rels. check flags/evr */
+ if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
+ break; /* matches */
+ }
+ if (!pid)
+ continue; /* none of the providers matched */
+ queue_push(&plist, p);
+ }
+ /* make our system solvable provide all unknown rpmlib() stuff */
+ if (plist.count == 0 && !strncmp(pool_id2str(pool, name), "rpmlib(", 7))
+ queue_push(&plist, SYSTEMSOLVABLE);
+ }
+ /* add providers to whatprovides */
+#if 0
+ POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
+#endif
+ pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
+ queue_free(&plist);
+
+ return pool->whatprovides_rel[d];
+}
+
+void
+pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr)
+{
+ int nrels = pool->nrels;
+ Id d;
+ Reldep *rd;
+
+ if (!pool->whatprovides_rel)
+ return;
+ for (d = 1, rd = pool->rels + d; d < nrels; d++, rd++)
+ {
+ if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS)
+ continue;
+ if (ns && rd->name != ns)
+ continue;
+ if (evr && rd->evr != evr)
+ continue;
+ pool->whatprovides_rel[d] = 0;
+ }
+}
+
+/* intersect dependencies in keyname with dep, return list of matching packages */
+void
+pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
+{
+ Id p;
+
+ queue_empty(q);
+ FOR_POOL_SOLVABLES(p)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo->disabled)
+ continue;
+ if (s->repo != pool->installed && !pool_installable(pool, s))
+ continue;
+ if (solvable_matchesdep(s, keyname, dep, marker))
+ queue_push(q, p);
+ }
+}
+
+/*************************************************************************/
+
+void
+pool_debug(Pool *pool, int type, const char *format, ...)
+{
+ va_list args;
+ char buf[1024];
+
+ if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0)
+ {
+ if ((pool->debugmask & type) == 0)
+ return;
+ }
+ va_start(args, format);
+ if (!pool->debugcallback)
+ {
+ if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0 && !(pool->debugmask & SOLV_DEBUG_TO_STDERR))
+ vprintf(format, args);
+ else
+ vfprintf(stderr, format, args);
+ return;
+ }
+ vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+ pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
+}
+
+int
+pool_error(Pool *pool, int ret, const char *format, ...)
+{
+ va_list args;
+ int l;
+ va_start(args, format);
+ if (!pool->errstr)
+ {
+ pool->errstra = 1024;
+ pool->errstr = solv_malloc(pool->errstra);
+ }
+ if (!*format)
+ {
+ *pool->errstr = 0;
+ l = 0;
+ }
+ else
+ l = vsnprintf(pool->errstr, pool->errstra, format, args);
+ va_end(args);
+ if (l >= 0 && l + 1 > pool->errstra)
+ {
+ pool->errstra = l + 256;
+ pool->errstr = solv_realloc(pool->errstr, pool->errstra);
+ va_start(args, format);
+ l = vsnprintf(pool->errstr, pool->errstra, format, args);
+ va_end(args);
+ }
+ if (l < 0)
+ strcpy(pool->errstr, "unknown error");
+ if (pool->debugmask & SOLV_ERROR)
+ pool_debug(pool, SOLV_ERROR, "%s\n", pool->errstr);
+ return ret;
+}
+
+char *
+pool_errstr(Pool *pool)
+{
+ return pool->errstr ? pool->errstr : "no error";
+}
+
+void
+pool_setdebuglevel(Pool *pool, int level)
+{
+ int mask = SOLV_DEBUG_RESULT;
+ if (level > 0)
+ mask |= SOLV_DEBUG_STATS|SOLV_DEBUG_ANALYZE|SOLV_DEBUG_UNSOLVABLE|SOLV_DEBUG_SOLVER|SOLV_DEBUG_TRANSACTION|SOLV_ERROR;
+ if (level > 1)
+ mask |= SOLV_DEBUG_JOB|SOLV_DEBUG_SOLUTIONS|SOLV_DEBUG_POLICY;
+ if (level > 2)
+ mask |= SOLV_DEBUG_PROPAGATE;
+ if (level > 3)
+ mask |= SOLV_DEBUG_RULE_CREATION;
+ mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR; /* keep bit */
+ pool->debugmask = mask;
+}
+
+void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata)
+{
+ pool->debugcallback = debugcallback;
+ pool->debugcallbackdata = debugcallbackdata;
+}
+
+void pool_setdebugmask(Pool *pool, int mask)
+{
+ pool->debugmask = mask;
+}
+
+void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata)
+{
+ pool->loadcallback = cb;
+ pool->loadcallbackdata = loadcbdata;
+}
+
+void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata)
+{
+ pool->nscallback = cb;
+ pool->nscallbackdata = nscbdata;
+}
+
+/*************************************************************************/
+
+struct searchfiles {
+ Id *ids;
+ int nfiles;
+ Map seen;
+};
+
+#define SEARCHFILES_BLOCK 127
+
+static void
+pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
+{
+ Id dep, sid;
+ const char *s;
+ struct searchfiles *csf;
+
+ while ((dep = *ida++) != 0)
+ {
+ csf = sf;
+ while (ISRELDEP(dep))
+ {
+ Reldep *rd;
+ sid = pool->ss.nstrings + GETRELID(dep);
+ if (MAPTST(&csf->seen, sid))
+ {
+ dep = 0;
+ break;
+ }
+ MAPSET(&csf->seen, sid);
+ rd = GETRELDEP(pool, dep);
+ if (rd->flags < 8)
+ dep = rd->name;
+ else if (rd->flags == REL_NAMESPACE)
+ {
+ if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
+ {
+ csf = isf;
+ if (!csf || MAPTST(&csf->seen, sid))
+ {
+ dep = 0;
+ break;
+ }
+ MAPSET(&csf->seen, sid);