X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fpool.c;h=d14c27fb9fddede0dafc0e3ba74eb26cc2f02877;hb=ba9e3357e853bea6ff2b3fc0547e89ecc2cf770b;hp=9e728947ebfa28d3751c6d335f3bbe476a807a3b;hpb=555a08b276116a939f9343445e1c0939c7da4db2;p=platform%2Fupstream%2Flibsolv.git diff --git a/src/pool.c b/src/pool.c index 9e72894..d14c27f 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1,4 +1,11 @@ /* + * Copyright (c) 2007, Novell Inc. + * + * This program is licensed under the BSD license, read LICENSE.BSD + * for further information + */ + +/* * pool.c * * The pool contains information about solvables @@ -7,129 +14,113 @@ #include #include +#include #include #include #include "pool.h" +#include "repo.h" #include "poolid.h" #include "poolid_private.h" #include "poolarch.h" #include "util.h" +#include "bitmap.h" #include "evr.h" +#define SOLVABLE_BLOCK 255 -// reset all whatprovides -// -void -pool_freewhatprovides(Pool *pool) -{ - pool->whatprovides = xfree(pool->whatprovides); - pool->whatprovidesdata = xfree(pool->whatprovidesdata); - pool->whatprovidesdataoff = 0; - pool->whatprovidesdataleft = 0; -} - - -// list of string constants, so we can do pointer/Id instead of string comparison -// index into array matches ID_xxx constants in pool.h - -static char *initpool_data[] = { - "", // ID_NULL - "", // ID_EMPTY - "solvable:name", - "solvable:arch", - "solvable:evr", - "solvable:vendor", - "solvable:provides", - "solvable:obsoletes", - "solvable:conflicts", - "solvable:requires", - "solvable:recommends", - "solvable:suggests", - "solvable:supplements", - "solvable:enhances", - "solvable:freshens", - "rpm:dbid", /* direct key into rpmdb */ - "solvable:prereqmarker", - "solvable:filemarker", - "namespace:installed", - "namespace:modalias", - "system:system", - "src", - "nosrc", - "noarch" -}; +#define KNOWNID_INITIALIZE +#include "knownid.h" +#undef KNOWNID_INITIALIZE -// create pool -// +/* create pool */ Pool * pool_create(void) { - int count, totalsize = 0; Pool *pool; Solvable *s; - pool = (Pool *)xcalloc(1, sizeof(*pool)); + pool = (Pool *)sat_calloc(1, sizeof(*pool)); - // count number and total size of predefined strings - for (count = 0; count < sizeof(initpool_data)/sizeof(*initpool_data); count++) - totalsize += strlen(initpool_data[count]) + 1; + stringpool_init (&pool->ss, initpool_data); - // alloc appropriate space - pool->stringspace = (char *)xmalloc((totalsize + STRINGSPACE_BLOCK) & ~STRINGSPACE_BLOCK); - pool->strings = (Offset *)xmalloc(((count + STRING_BLOCK) & ~STRING_BLOCK) * sizeof(Offset)); - - // now copy predefined strings into allocated space - pool->sstrings = 0; - for (count = 0; count < sizeof(initpool_data)/sizeof(*initpool_data); count++) - { - strcpy(pool->stringspace + pool->sstrings, initpool_data[count]); - pool->strings[count] = pool->sstrings; - pool->sstrings += strlen(initpool_data[count]) + 1; - } - pool->nstrings = count; - - // pre-alloc space for a RelDep - pool->rels = (Reldep *)xcalloc(1 + REL_BLOCK, sizeof(Reldep)); + /* alloc space for RelDep 0 */ + pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK); pool->nrels = 1; + memset(pool->rels, 0, sizeof(Reldep)); - // pre-alloc space for a Solvable - pool->solvables = (Solvable *)xcalloc(2, sizeof(Solvable)); + /* alloc space for Solvable 0 and system solvable */ + pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK); pool->nsolvables = 2; + memset(pool->solvables, 0, 2 * sizeof(Solvable)); s = pool->solvables + SYSTEMSOLVABLE; s->name = SYSTEM_SYSTEM; s->arch = ARCH_NOARCH; s->evr = ID_EMPTY; + + queue_init(&pool->vendormap); + + pool->debugmask = SAT_DEBUG_RESULT; /* FIXME */ return pool; } -// empty the pool -// +/* free all the resources of our pool */ void pool_free(Pool *pool) { int i; - Repo *repo; pool_freewhatprovides(pool); pool_freeidhashes(pool); - for (i = 0; i < pool->nrepos; i++) - { - repo = pool->repos[i]; - xfree(repo->idarraydata); - xfree(repo->rpmdbid); - xfree(repo); - } - xfree(pool->id2arch); - xfree(pool->solvables); - xfree(pool->repos); - xfree(pool->stringspace); - xfree(pool->strings); - xfree(pool->rels); - for (i = 0; i < DEP2STRBUF; i++) - xfree(pool->dep2strbuf[i]); - xfree(pool); + repo_freeallrepos(pool, 1); + sat_free(pool->id2arch); + sat_free(pool->solvables); + sat_free(pool->ss.stringspace); + sat_free(pool->ss.strings); + sat_free(pool->rels); + queue_free(&pool->vendormap); + for (i = 0; i < POOL_TMPSPACEBUF; i++) + sat_free(pool->tmpspacebuf[i]); + for (i = 0; i < pool->nlanguages; i++) + free((char *)pool->languages[i]); + sat_free(pool->languages); + sat_free(pool->languagecache); + sat_free(pool); +} + +Id +pool_add_solvable(Pool *pool) +{ + pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK); + memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable)); + return pool->nsolvables++; +} + +Id +pool_add_solvable_block(Pool *pool, int count) +{ + Id nsolvables = pool->nsolvables; + if (!count) + return nsolvables; + pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK); + memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count); + pool->nsolvables += count; + return nsolvables; +} + +void +pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids) +{ + if (!count) + return; + if (reuseids && start + count == pool->nsolvables) + { + /* might want to shrink solvable array */ + pool->nsolvables = start; + return; + } + memset(pool->solvables + start, 0, sizeof(Solvable) * count); } @@ -159,6 +150,12 @@ pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp) return *(Id *)ap - *(Id *)bp; } +/* + * pool_shrink_whatprovides - unify whatprovides data + * + * whatprovides_rel must be empty for this to work! + * + */ static void pool_shrink_whatprovides(Pool *pool) { @@ -168,16 +165,16 @@ pool_shrink_whatprovides(Pool *pool) Offset o; int r; - if (pool->nstrings < 3) + if (pool->ss.nstrings < 3) return; - sorted = xmalloc2(pool->nstrings, sizeof(Id)); - for (id = 0; id < pool->nstrings; id++) + sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id)); + for (id = 0; id < pool->ss.nstrings; id++) sorted[id] = id; pool_shrink_whatprovides_sortcmp_data = pool; - qsort(sorted + 1, pool->nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp); + qsort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp); last = 0; lastid = 0; - for (i = 1; i < pool->nstrings; i++) + for (i = 1; i < pool->ss.nstrings; i++) { id = sorted[i]; o = pool->whatprovides[id]; @@ -204,9 +201,9 @@ pool_shrink_whatprovides(Pool *pool) last = pool->whatprovidesdata + o; lastid = id; } - xfree(sorted); + sat_free(sorted); dp = pool->whatprovidesdata + 2; - for (id = 1; id < pool->nstrings; id++) + for (id = 1; id < pool->ss.nstrings; id++) { o = pool->whatprovides[id]; if (o == 0 || o == 1) @@ -227,13 +224,12 @@ pool_shrink_whatprovides(Pool *pool) ; } o = dp - pool->whatprovidesdata; - if (pool->verbose) - printf("shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o); + POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o); if (pool->whatprovidesdataoff == o) return; r = pool->whatprovidesdataoff - o; pool->whatprovidesdataoff = o; - pool->whatprovidesdata = xrealloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id)); + pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id)); if (r > pool->whatprovidesdataleft) r = pool->whatprovidesdataleft; memset(pool->whatprovidesdata + o, 0, r * sizeof(Id)); @@ -241,14 +237,13 @@ pool_shrink_whatprovides(Pool *pool) /* - * pool_prepare() + * pool_createwhatprovides() * - * create hashes over complete pool to ease lookups + * create hashes over pool of solvables to ease provide lookups * */ - void -pool_prepare(Pool *pool) +pool_createwhatprovides(Pool *pool) { int i, num, np, extra; Offset off; @@ -258,15 +253,14 @@ pool_prepare(Pool *pool) Offset *whatprovides; Id *whatprovidesdata, *d; - if (pool->verbose) - printf("number of solvables: %d\n", pool->nsolvables); - if (pool->verbose) - printf("number of ids: %d + %d\n", pool->nstrings, pool->nrels); + POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables); + POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels); - pool_freeidhashes(pool); + pool_freeidhashes(pool); /* XXX: should not be here! */ pool_freewhatprovides(pool); - num = pool->nstrings + pool->nrels; - whatprovides = (Offset *)xcalloc(num, sizeof(Offset)); + num = pool->ss.nstrings; + pool->whatprovides = whatprovides = sat_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK); + pool->whatprovides_rel = sat_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK); /* count providers for each name */ for (i = 1; i < pool->nsolvables; i++) @@ -280,7 +274,7 @@ pool_prepare(Pool *pool) pp = s->repo->idarraydata + s->provides; while ((id = *pp++) != ID_NULL) { - if (ISRELDEP(id)) + while (ISRELDEP(id)) { Reldep *rd = GETRELDEP(pool, id); id = rd->name; @@ -302,18 +296,17 @@ pool_prepare(Pool *pool) np++; /* inc # of provider 'slots' */ } - if (pool->verbose) - printf("provide ids: %d\n", np); - extra = 2 * pool->nrels; + POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np); + /* reserve some space for relation data */ + extra = 2 * pool->nrels; if (extra < 256) extra = 256; - if (pool->verbose) - printf("provide space needed: %d + %d\n", off, extra); + POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra); /* alloc space for all providers + extra */ - whatprovidesdata = (Id *)xcalloc(off + extra, sizeof(Id)); + whatprovidesdata = sat_calloc(off + extra, sizeof(Id)); /* now fill data for all provides */ for (i = 1; i < pool->nsolvables; i++) @@ -329,7 +322,7 @@ pool_prepare(Pool *pool) pp = s->repo->idarraydata + s->provides; while ((id = *pp++) != 0) { - if (ISRELDEP(id)) + while (ISRELDEP(id)) { Reldep *rd = GETRELDEP(pool, id); id = rd->name; @@ -340,36 +333,44 @@ pool_prepare(Pool *pool) d++; while (*d) /* find free slot */ d++; - if (d[-1] == i) - { -#if 0 - if (pool->verbose) printf("duplicate entry for %s in package %s.%s\n", id2str(pool, id), id2str(pool, s->name), id2str(pool, s->arch)); -#endif - continue; - } + if (d[-1] == i) /* solvable already tacked at end ? */ + continue; /* Y: skip, on to next provides */ } *d = i; /* put solvable Id into data */ } } - pool->whatprovides = whatprovides; pool->whatprovidesdata = whatprovidesdata; pool->whatprovidesdataoff = off; pool->whatprovidesdataleft = extra; pool_shrink_whatprovides(pool); } +/* + * free all of our whatprovides data + * be careful, everything internalized with pool_queuetowhatprovides is gone, too + */ +void +pool_freewhatprovides(Pool *pool) +{ + pool->whatprovides = sat_free(pool->whatprovides); + pool->whatprovides_rel = sat_free(pool->whatprovides_rel); + pool->whatprovidesdata = sat_free(pool->whatprovidesdata); + pool->whatprovidesdataoff = 0; + pool->whatprovidesdataleft = 0; +} + /******************************************************************************/ /* - * pool_queuetowhatprovides + * pool_queuetowhatprovides - add queue contents to whatprovidesdata * * on-demand filling of provider information * move queue data into whatprovidesdata * q: queue of Ids * returns: Offset into whatprovides + * */ - Id pool_queuetowhatprovides(Pool *pool, Queue *q) { @@ -382,9 +383,8 @@ pool_queuetowhatprovides(Pool *pool, Queue *q) /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */ if (pool->whatprovidesdataleft < count + 1) { - if (pool->verbose) - printf("growing provides hash data...\n"); - pool->whatprovidesdata = (Id *)xrealloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id)); + POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n"); + pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id)); pool->whatprovidesdataleft = count + 4096; } @@ -401,7 +401,53 @@ pool_queuetowhatprovides(Pool *pool, Queue *q) } -/******************************************************************************/ +/*************************************************************************/ + +/* check if a package's nevr matches a dependency */ + +int +pool_match_nevr_rel(Pool *pool, Solvable *s, Id d) +{ + Reldep *rd = GETRELDEP(pool, d); + Id name = rd->name; + Id evr = rd->evr; + int flags = rd->flags; + + if (flags > 7) + { + switch (flags) + { + case REL_ARCH: + if (s->arch != evr) + return 0; + return pool_match_nevr(pool, s, name); + case REL_OR: + if (pool_match_nevr(pool, s, name)) + return 1; + return pool_match_nevr(pool, s, evr); + case REL_AND: + case REL_WITH: + if (!pool_match_nevr(pool, s, name)) + return 0; + return pool_match_nevr(pool, s, evr); + default: + return 0; + } + } + if (!pool_match_nevr(pool, s, name)) + return 0; + if (evr == s->evr) + return flags & 2 ? 1 : 0; + if (!flags) + return 0; + if (flags == 7) + return 1; + if (flags != 2 && flags != 5) + flags ^= 5; + if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_MATCH_RELEASE)))) != 0) + return 1; + return 0; +} /* * addrelproviders @@ -424,14 +470,14 @@ pool_addrelproviders(Pool *pool, Id d) Id pid, *pidp; Id p, *pp, *pp2, *pp3; - d = GETRELID(pool, d); + d = GETRELID(d); queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf)); switch (flags) { case REL_AND: case REL_WITH: - pp = GET_PROVIDESP(name, p); - pp2 = GET_PROVIDESP(evr, p); + pp = pool_whatprovides(pool, name); + pp2 = pool_whatprovides(pool, evr); while ((p = *pp++) != 0) { for (pp3 = pp2; *pp3;) @@ -443,53 +489,106 @@ pool_addrelproviders(Pool *pool, Id d) } break; case REL_OR: - pp = GET_PROVIDESP(name, p); + pp = pool_whatprovides(pool, name); while ((p = *pp++) != 0) queue_push(&plist, p); - pp = GET_PROVIDESP(evr, p); + pp = pool_whatprovides(pool, evr); while ((p = *pp++) != 0) queue_pushunique(&plist, p); break; case REL_NAMESPACE: if (pool->nscallback) { + /* ask callback which packages provide the dependency + * 0: none + * 1: the system (aka SYSTEMSOLVABLE) + * >1: a set of packages, stored as offset on whatprovidesdata + */ p = pool->nscallback(pool, pool->nscallbackdata, name, evr); if (p > 1) { queue_free(&plist); - pool->whatprovides[d] = p; + pool->whatprovides_rel[d] = p; return pool->whatprovidesdata + p; } if (p == 1) queue_push(&plist, SYSTEMSOLVABLE); } break; + case REL_ARCH: + /* small hack: make it possible to match .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) + { + Solvable *s; + for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++) + { + if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) + continue; + if (pool_match_nevr(pool, s, name)) + queue_push(&plist, p); + } + break; + } + pp = pp2 = pool_whatprovides(pool, name); + while ((p = *pp++) != 0) + { + Solvable *s = pool->solvables + p; + if (s->arch == evr) + queue_push(&plist, p); + else + pp2 = 0; + } + if (pp2) + return pp2; + break; default: break; } /* convert to whatprovides id */ #if 0 - if (pool->verbose) - printf("addrelproviders: what provides %s?\n", id2str(pool, name)); + POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name)); #endif if (flags && flags < 8) { - FOR_PROVIDES(p, pp, name) + pp = pool_whatprovides(pool, name); + while (ISRELDEP(name)) + { + rd = GETRELDEP(pool, name); + name = rd->name; + } + while ((p = *pp++) != 0) { + Solvable *s = pool->solvables + p; #if 0 - if (pool->verbose) - printf("addrelproviders: checking package %s\n", id2str(pool, pool->p[p].name)); + POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, s->name)); #endif + 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 = pool->solvables[p].repo->idarraydata + pool->solvables[p].provides; + pidp = s->repo->idarraydata + s->provides; while ((pid = *pidp++) != 0) { int pflags; Id pevr; if (pid == name) - break; /* yes, provides all versions */ + { +#ifdef DEBIAN_SEMANTICS + continue; /* unversioned provides can + * never match versioned deps */ +#else + break; /* yes, provides all versions */ +#endif + } if (!ISRELDEP(pid)) continue; /* wrong provides name */ prd = GETRELDEP(pool, pid); @@ -512,7 +611,7 @@ pool_addrelproviders(Pool *pool, Id d) else { int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5); - if ((f & (1 << (1 + evrcmp(pool, pevr, evr)))) != 0) + if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0) break; } } @@ -526,12 +625,878 @@ pool_addrelproviders(Pool *pool, Id d) } /* add providers to whatprovides */ #if 0 - if (pool->verbose) printf("addrelproviders: adding %d packages to %d\n", plist.count, d); + POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d); #endif - pool->whatprovides[d] = pool_queuetowhatprovides(pool, &plist); + pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist); queue_free(&plist); - return pool->whatprovidesdata + pool->whatprovides[d]; + return pool->whatprovidesdata + pool->whatprovides_rel[d]; +} + +/*************************************************************************/ + +void +pool_debug(Pool *pool, int type, const char *format, ...) +{ + va_list args; + char buf[1024]; + + if ((type & (SAT_FATAL|SAT_ERROR)) == 0) + { + if ((pool->debugmask & type) == 0) + return; + } + va_start(args, format); + if (!pool->debugcallback) + { + if ((type & (SAT_FATAL|SAT_ERROR)) == 0) + vprintf(format, args); + else + vfprintf(stderr, format, args); + return; + } + vsnprintf(buf, sizeof(buf), format, args); + pool->debugcallback(pool, pool->debugcallbackdata, type, buf); +} + +void +pool_setdebuglevel(Pool *pool, int level) +{ + int mask = SAT_DEBUG_RESULT; + if (level > 0) + mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE; + if (level > 1) + mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY; + if (level > 2) + mask |= SAT_DEBUG_PROPAGATE; + if (level > 3) + mask |= SAT_DEBUG_RULE_CREATION; + if (level > 4) + mask |= SAT_DEBUG_SCHUBI; + pool->debugmask = mask; +} + +/*************************************************************************/ + +struct searchfiles { + Id *ids; + char **dirs; + char **names; + 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, *sr; + 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); + } + dep = rd->evr; + } + else + { + Id ids[2]; + ids[0] = rd->name; + ids[1] = 0; + pool_addfileprovides_dep(pool, ids, csf, isf); + dep = rd->evr; + } + } + if (!dep) + continue; + if (MAPTST(&csf->seen, dep)) + continue; + MAPSET(&csf->seen, dep); + s = id2str(pool, dep); + if (*s != '/') + continue; + csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); + csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK); + csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK); + csf->ids[csf->nfiles] = dep; + sr = strrchr(s, '/'); + csf->names[csf->nfiles] = strdup(sr + 1); + csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1); + if (sr != s) + strncpy(csf->dirs[csf->nfiles], s, sr - s); + csf->dirs[csf->nfiles][sr - s] = 0; + csf->nfiles++; + } +} + +struct addfileprovides_cbdata { + int nfiles; + Id *ids; + char **dirs; + char **names; + + Repodata *olddata; + Id *dids; + Map useddirs; +}; + +static int +addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) +{ + struct addfileprovides_cbdata *cbd = cbdata; + int i; + + if (data != cbd->olddata) + { + map_free(&cbd->useddirs); + map_init(&cbd->useddirs, data->dirpool.ndirs); + for (i = 0; i < cbd->nfiles; i++) + { + Id did = repodata_str2dir(data, cbd->dirs[i], 0); + cbd->dids[i] = did; + if (did) + MAPSET(&cbd->useddirs, did); + } + cbd->olddata = data; + } + if (!MAPTST(&cbd->useddirs, value->id)) + return 0; + for (i = 0; i < cbd->nfiles; i++) + { + if (cbd->dids[i] != value->id) + continue; + if (!strcmp(cbd->names[i], value->str)) + break; + } + if (i == cbd->nfiles) + return 0; + s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); + return 0; +} + + +static void +pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly) +{ + Id p, start, end, *idp; + Solvable *s; + Repodata *data = 0, *nextdata; + Repo *oldrepo = 0; + int dataincludes = 0; + int i; + Map providedids; + + cbd->nfiles = sf->nfiles; + cbd->ids = sf->ids; + cbd->dirs = sf->dirs; + cbd->names = sf->names; + cbd->olddata = 0; + cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); + if (repoonly) + { + start = repoonly->start; + end = repoonly->end; + } + else + { + start = 2; /* skip system solvable */ + end = pool->nsolvables; + } + for (p = start, s = pool->solvables + p; p < end; p++, s++) + { + if (!s->repo || (repoonly && s->repo != repoonly)) + continue; + if (s->repo != oldrepo || (data && p >= data->end)) + { + data = 0; + oldrepo = 0; + } + if (oldrepo == 0) + { + nextdata = 0; + for (i = 0, data = s->repo->repodata; i < s->repo->nrepodata; i++, data++) + { + if (!data->addedfileprovides || p >= data->end) + continue; + if (!nextdata || nextdata->start > data->start) + nextdata = data; + if (p >= data->start) + break; + } + if (i == s->repo->nrepodata) + data = nextdata; + if (data) + { + map_init(&providedids, pool->ss.nstrings); + for (idp = data->addedfileprovides; *idp; idp++) + MAPSET(&providedids, *idp); + for (i = 0; i < cbd->nfiles; i++) + if (!MAPTST(&providedids, cbd->ids[i])) + { + break; + } + map_free(&providedids); + dataincludes = i == cbd->nfiles; + } + oldrepo = s->repo; + } + if (data && p >= data->start && dataincludes) + continue; + repo_search(s->repo, p, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, cbd); + } +} + +void +pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp) +{ + Solvable *s; + Repo *repo; + struct searchfiles sf, isf, *isfp; + struct addfileprovides_cbdata cbd; + int i; + + memset(&sf, 0, sizeof(sf)); + map_init(&sf.seen, pool->ss.nstrings + pool->nrels); + memset(&isf, 0, sizeof(isf)); + map_init(&isf.seen, pool->ss.nstrings + pool->nrels); + + isfp = installed ? &isf : 0; + for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) + { + repo = s->repo; + if (!repo) + continue; + if (s->obsoletes) + pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); + if (s->conflicts) + pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); + if (s->requires) + pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); + if (s->recommends) + pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); + if (s->suggests) + pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); + if (s->supplements) + pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); + if (s->enhances) + pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); + } + map_free(&sf.seen); + map_free(&isf.seen); + POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles); + POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles); + cbd.dids = 0; + map_init(&cbd.useddirs, 1); + if (idp) + *idp = 0; + if (sf.nfiles) + { +#if 0 + for (i = 0; i < sf.nfiles; i++) + POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i])); +#endif + pool_addfileprovides_search(pool, &cbd, &sf, 0); + if (idp) + { + sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); + sf.ids[sf.nfiles] = 0; + *idp = sf.ids; + sf.ids = 0; + } + sat_free(sf.ids); + for (i = 0; i < sf.nfiles; i++) + { + sat_free(sf.dirs[i]); + sat_free(sf.names[i]); + } + sat_free(sf.dirs); + sat_free(sf.names); + } + if (isf.nfiles) + { +#if 0 + for (i = 0; i < isf.nfiles; i++) + POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i])); +#endif + if (installed) + pool_addfileprovides_search(pool, &cbd, &isf, installed); + sat_free(isf.ids); + for (i = 0; i < isf.nfiles; i++) + { + sat_free(isf.dirs[i]); + sat_free(isf.names[i]); + } + sat_free(isf.dirs); + sat_free(isf.names); + } + map_free(&cbd.useddirs); + sat_free(cbd.dids); + pool_freewhatprovides(pool); /* as we have added provides */ +} + +void +pool_addfileprovides(Pool *pool, Repo *installed) +{ + pool_addfileprovides_ids(pool, installed, 0); +} + +void +pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata) +{ + if (p) + { + if (pool->solvables[p].repo) + repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata); + return; + } + /* FIXME: obey callback return value! */ + for (p = 1; p < pool->nsolvables; p++) + if (pool->solvables[p].repo) + repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata); +} + + +void +pool_set_languages(Pool *pool, const char **languages, int nlanguages) +{ + int i; + + pool->languagecache = sat_free(pool->languagecache); + pool->languagecacheother = 0; + if (pool->nlanguages) + { + for (i = 0; i < pool->nlanguages; i++) + free((char *)pool->languages[i]); + free(pool->languages); + } + pool->nlanguages = nlanguages; + if (!nlanguages) + return; + pool->languages = sat_calloc(nlanguages, sizeof(const char **)); + for (i = 0; i < pool->nlanguages; i++) + pool->languages[i] = strdup(languages[i]); +} + +Id +pool_id2langid(Pool *pool, Id id, const char *lang, int create) +{ + const char *n; + char buf[256], *p; + int l; + + if (!lang) + return id; + n = id2str(pool, id); + l = strlen(n) + strlen(lang) + 2; + if (l > sizeof(buf)) + p = sat_malloc(strlen(n) + strlen(lang) + 2); + else + p = buf; + sprintf(p, "%s:%s", n, lang); + id = str2id(pool, p, create); + if (p != buf) + free(p); + return id; +} + +char * +pool_alloctmpspace(Pool *pool, int len) +{ + int n = pool->tmpspacen; + if (!len) + return 0; + if (len > pool->tmpspacelen[n]) + { + pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32); + pool->tmpspacelen[n] = len + 32; + } + pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF; + return pool->tmpspacebuf[n]; +} + +/*******************************************************************/ + +struct mptree { + Id sibling; + Id child; + const char *comp; + int compl; + Id mountpoint; +}; + +struct ducbdata { + DUChanges *mps; + struct mptree *mptree; + int addsub; + int hasdu; + + Id *dirmap; + int nmap; + Repodata *olddata; +}; + + +static int +solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) +{ + struct ducbdata *cbd = cbdata; + Id mp; + + if (data != cbd->olddata) + { + Id dn, mp, comp, *dirmap, *dirs; + int i, compl; + const char *compstr; + struct mptree *mptree; + + /* create map from dir to mptree */ + cbd->dirmap = sat_free(cbd->dirmap); + cbd->nmap = 0; + dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id)); + mptree = cbd->mptree; + mp = 0; + for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) + { + comp = *dirs++; + if (comp <= 0) + { + mp = dirmap[-comp]; + continue; + } + if (mp < 0) + { + /* unconnected */ + dirmap[dn] = mp; + continue; + } + if (!mptree[mp].child) + { + dirmap[dn] = -mp; + continue; + } + if (data->localpool) + compstr = stringpool_id2str(&data->spool, comp); + else + compstr = id2str(data->repo->pool, comp); + compl = strlen(compstr); + for (i = mptree[mp].child; i; i = mptree[i].sibling) + if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) + break; + dirmap[dn] = i ? i : -mp; + } + /* change dirmap to point to mountpoint instead of mptree */ + for (dn = 0; dn < data->dirpool.ndirs; dn++) + { + mp = dirmap[dn]; + dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; + } + cbd->dirmap = dirmap; + cbd->nmap = data->dirpool.ndirs; + cbd->olddata = data; + } + cbd->hasdu = 1; + if (value->id < 0 || value->id >= cbd->nmap) + return 0; + mp = cbd->dirmap[value->id]; + if (mp < 0) + return 0; + if (cbd->addsub > 0) + { + cbd->mps[mp].kbytes += value->num; + cbd->mps[mp].files += value->num2; + } + else + { + cbd->mps[mp].kbytes -= value->num; + cbd->mps[mp].files -= value->num2; + } + return 0; +} + +static void +propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) +{ + int i; + if (mptree[pos].mountpoint == -1) + mptree[pos].mountpoint = mountpoint; + else + mountpoint = mptree[pos].mountpoint; + for (i = mptree[pos].child; i; i = mptree[i].sibling) + propagate_mountpoints(mptree, i, mountpoint); +} + +#define MPTREE_BLOCK 15 + +void +pool_calc_duchanges(Pool *pool, Repo *oldinstalled, Map *installedmap, DUChanges *mps, int nmps) +{ + char *p; + const char *path, *compstr; + struct mptree *mptree; + int i, nmptree; + int pos, compl; + int mp; + struct ducbdata cbd; + Solvable *s; + Id sp; + Map ignoredu; + + memset(&ignoredu, 0, sizeof(ignoredu)); + cbd.mps = mps; + cbd.addsub = 0; + cbd.dirmap = 0; + cbd.nmap = 0; + cbd.olddata = 0; + + mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); + + /* our root node */ + mptree[0].sibling = 0; + mptree[0].child = 0; + mptree[0].comp = 0; + mptree[0].compl = 0; + mptree[0].mountpoint = -1; + nmptree = 1; + + /* create component tree */ + for (mp = 0; mp < nmps; mp++) + { + mps[mp].kbytes = 0; + mps[mp].files = 0; + pos = 0; + path = mps[mp].path; + while(*path == '/') + path++; + while (*path) + { + if ((p = strchr(path, '/')) == 0) + { + compstr = path; + compl = strlen(compstr); + path += compl; + } + else + { + compstr = path; + compl = p - path; + path = p + 1; + while(*path == '/') + path++; + } + for (i = mptree[pos].child; i; i = mptree[i].sibling) + if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) + break; + if (!i) + { + /* create new node */ + mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); + i = nmptree++; + mptree[i].sibling = mptree[pos].child; + mptree[i].child = 0; + mptree[i].comp = compstr; + mptree[i].compl = compl; + mptree[i].mountpoint = -1; + mptree[pos].child = i; + } + pos = i; + } + mptree[pos].mountpoint = mp; + } + + propagate_mountpoints(mptree, 0, mptree[0].mountpoint); + +#if 0 + for (i = 0; i < nmptree; i++) + { + printf("#%d sibling: %d\n", i, mptree[i].sibling); + printf("#%d child: %d\n", i, mptree[i].child); + printf("#%d comp: %s\n", i, mptree[i].comp); + printf("#%d compl: %d\n", i, mptree[i].compl); + printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); + } +#endif + + cbd.mptree = mptree; + cbd.addsub = 1; + for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) + { + if (!s->repo || (oldinstalled && s->repo == oldinstalled)) + continue; + if (!MAPTST(installedmap, sp)) + continue; + cbd.hasdu = 0; + repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + if (!cbd.hasdu && oldinstalled) + { + Id op, *opp; + /* no du data available, ignore data of all installed solvables we obsolete */ + if (!ignoredu.map) + map_init(&ignoredu, oldinstalled->end - oldinstalled->start); + if (s->obsoletes) + { + Id obs, *obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + FOR_PROVIDES(op, opp, obs) + if (op >= oldinstalled->start && op < oldinstalled->end) + MAPSET(&ignoredu, op - oldinstalled->start); + } + FOR_PROVIDES(op, opp, s->name) + if (pool->solvables[op].name == s->name) + if (op >= oldinstalled->start && op < oldinstalled->end) + MAPSET(&ignoredu, op - oldinstalled->start); + } + } + cbd.addsub = -1; + if (oldinstalled) + { + /* assumes we allways have du data for installed solvables */ + FOR_REPO_SOLVABLES(oldinstalled, sp, s) + { + if (MAPTST(installedmap, sp)) + continue; + if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start)) + continue; + repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); + } + } + if (ignoredu.map) + map_free(&ignoredu); + sat_free(cbd.dirmap); + sat_free(mptree); +} + +int +pool_calc_installsizechange(Pool *pool, Repo *oldinstalled, Map *installedmap) +{ + Id sp; + Solvable *s; + int change = 0; + + for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) + { + if (!s->repo || (oldinstalled && s->repo == oldinstalled)) + continue; + if (!MAPTST(installedmap, sp)) + continue; + change += repo_lookup_num(s, SOLVABLE_INSTALLSIZE); + } + if (oldinstalled) + { + FOR_REPO_SOLVABLES(oldinstalled, sp, s) + { + if (MAPTST(installedmap, sp)) + continue; + change -= repo_lookup_num(s, SOLVABLE_INSTALLSIZE); + } + } + return change; +} + +/* map: + * 1: installed + * 2: conflicts with installed + * 8: interesting (only true if installed) + * 16: undecided + */ + +static inline Id dep2name(Pool *pool, Id dep) +{ + while (ISRELDEP(dep)) + { + Reldep *rd = rd = GETRELDEP(pool, dep); + dep = rd->name; + } + return dep; +} + +static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep) +{ + Id p, *pp; + int r = 0; + FOR_PROVIDES(p, pp, dep) + { + if (p == SYSTEMSOLVABLE) + return 1; /* always boring, as never constraining */ + if ((map[p] & 9) == 9) + return 9; + r |= map[p] & 17; + } + return r; +} + +/* + * pool_trivial_installable - calculate if a set of solvables is + * trivial installable without any other installs/deinstalls of + * packages not belonging to the set. + * + * the state is returned in the result queue: + * 1: solvable is installable without any other package changes + * 0: solvable is not installable + * -1: solvable is installable, but doesn't constrain any installed packages + */ + +void +pool_trivial_installable(Pool *pool, Repo *oldinstalled, Map *installedmap, Queue *pkgs, Queue *res) +{ + int i, r, m, did; + Id p, *dp, con, *conp, req, *reqp; + unsigned char *map; + Solvable *s; + + map = sat_calloc(pool->nsolvables, 1); + for (p = 1; p < pool->nsolvables; p++) + { + if (!MAPTST(installedmap, p)) + continue; + map[p] |= 9; + s = pool->solvables + p; + if (!s->conflicts) + continue; + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + dp = pool_whatprovides(pool, con); + for (; *dp; dp++) + map[p] |= 2; /* XXX: self conflict ? */ + } + } + for (i = 0; i < pkgs->count; i++) + map[pkgs->elements[i]] = 16; + + for (i = 0, did = 0; did < pkgs->count; i++, did++) + { + if (i == pkgs->count) + i = 0; + p = pkgs->elements[i]; + if ((map[p] & 16) == 0) + continue; + if ((map[p] & 2) != 0) + { + map[p] = 2; + continue; + } + s = pool->solvables + p; + m = 1; + if (s->requires) + { + reqp = s->repo->idarraydata + s->requires; + while ((req = *reqp++) != 0) + { + if (req == SOLVABLE_PREREQMARKER) + continue; + r = providedbyinstalled(pool, map, req); + if (!r) + { + /* decided and miss */ + map[p] = 2; + break; + } + m |= r; /* 1 | 9 | 16 | 17 */ + } + if (req) + continue; + if ((m & 9) == 9) + m = 9; + } + if (s->conflicts) + { + conp = s->repo->idarraydata + s->conflicts; + while ((con = *conp++) != 0) + { + if ((providedbyinstalled(pool, map, con) & 1) != 0) + { + map[p] = 2; + break; + } + if ((m == 1 || m == 17) && ISRELDEP(con)) + { + con = dep2name(pool, con); + if ((providedbyinstalled(pool, map, con) & 1) != 0) + m = 9; + } + } + if (con) + continue; /* found a conflict */ + } +#if 0 + if (s->repo && s->repo != oldinstalled) + { + Id p2, obs, *obsp, *pp; + Solvable *s2; + if (s->obsoletes) + { + obsp = s->repo->idarraydata + s->obsoletes; + while ((obs = *obsp++) != 0) + { + if ((providedbyinstalled(pool, map, obs) & 1) != 0) + { + map[p] = 2; + break; + } + } + if (obs) + continue; + } + FOR_PROVIDES(p2, pp, s->name) + { + s2 = pool->solvables + p2; + if (s2->name == s->name && (map[p2] & 1) != 0) + { + map[p] = 2; + break; + } + } + if (p2) + continue; + } +#endif + if (m != map[p]) + { + map[p] = m; + did = 0; + } + } + queue_free(res); + queue_clone(res, pkgs); + for (i = 0; i < pkgs->count; i++) + { + m = map[pkgs->elements[i]]; + if ((m & 9) == 9) + r = 1; + else if (m & 1) + r = -1; + else + r = 0; + res->elements[i] = r; + } + free(map); } // EOF