satsolver 0.16.3

pool.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007-2009, Novell Inc.
00003  *
00004  * This program is licensed under the BSD license, read LICENSE.BSD
00005  * for further information
00006  */
00007 
00008 /*
00009  * pool.c
00010  * 
00011  * The pool contains information about solvables
00012  * stored optimized for memory consumption and fast retrieval.
00013  */
00014 
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <stdarg.h>
00018 #include <unistd.h>
00019 #include <string.h>
00020 
00021 #include "pool.h"
00022 #include "repo.h"
00023 #include "poolid.h"
00024 #include "poolid_private.h"
00025 #include "poolarch.h"
00026 #include "util.h"
00027 #include "bitmap.h"
00028 #include "evr.h"
00029 
00030 #define SOLVABLE_BLOCK  255
00031 
00032 #define KNOWNID_INITIALIZE
00033 #include "knownid.h"
00034 #undef KNOWNID_INITIALIZE
00035 
00036 /* create pool */
00037 Pool *
00038 pool_create(void)
00039 {
00040   Pool *pool;
00041   Solvable *s;
00042 
00043   pool = (Pool *)sat_calloc(1, sizeof(*pool));
00044 
00045   stringpool_init (&pool->ss, initpool_data);
00046 
00047   /* alloc space for RelDep 0 */
00048   pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
00049   pool->nrels = 1;
00050   memset(pool->rels, 0, sizeof(Reldep));
00051 
00052   /* alloc space for Solvable 0 and system solvable */
00053   pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
00054   pool->nsolvables = 2;
00055   memset(pool->solvables, 0, 2 * sizeof(Solvable));
00056   s = pool->solvables + SYSTEMSOLVABLE;
00057   s->name = SYSTEM_SYSTEM;
00058   s->arch = ARCH_NOARCH;
00059   s->evr = ID_EMPTY;
00060 
00061   queue_init(&pool->vendormap);
00062 
00063   pool->debugmask = SAT_DEBUG_RESULT;   /* FIXME */
00064 #ifdef FEDORA
00065   pool->obsoleteusescolors = 1;
00066 #endif
00067 #ifdef DEBIAN 
00068   pool->allowselfconflicts = 1;
00069 # ifdef MULTI_SEMANTICS
00070   pool->disttype = DISTTYPE_DEB;
00071 # endif
00072 #endif
00073   return pool;
00074 }
00075 
00076 
00077 /* free all the resources of our pool */
00078 void
00079 pool_free(Pool *pool)
00080 {
00081   int i;
00082 
00083   pool_freewhatprovides(pool);
00084   pool_freeidhashes(pool);
00085   repo_freeallrepos(pool, 1);
00086   sat_free(pool->id2arch);
00087   sat_free(pool->solvables);
00088   stringpool_free(&pool->ss);
00089   sat_free(pool->rels);
00090   queue_free(&pool->vendormap);
00091   for (i = 0; i < POOL_TMPSPACEBUF; i++)
00092     sat_free(pool->tmpspacebuf[i]);
00093   for (i = 0; i < pool->nlanguages; i++)
00094     free((char *)pool->languages[i]);
00095   sat_free(pool->languages);
00096   sat_free(pool->languagecache);
00097   sat_free(pool);
00098 }
00099 
00100 #ifdef MULTI_SEMANTICS
00101 void
00102 pool_setdisttype(Pool *pool, int disttype)
00103 {
00104   pool->disttype = disttype;
00105 }
00106 #endif
00107 
00108 Id
00109 pool_add_solvable(Pool *pool)
00110 {
00111   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
00112   memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
00113   return pool->nsolvables++;
00114 }
00115 
00116 Id
00117 pool_add_solvable_block(Pool *pool, int count)
00118 {
00119   Id nsolvables = pool->nsolvables;
00120   if (!count)
00121     return nsolvables;
00122   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
00123   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
00124   pool->nsolvables += count;
00125   return nsolvables;
00126 }
00127 
00128 void
00129 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
00130 {
00131   if (!count)
00132     return;
00133   if (reuseids && start + count == pool->nsolvables)
00134     {
00135       /* might want to shrink solvable array */
00136       pool->nsolvables = start;
00137       return;
00138     }
00139   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
00140 }
00141 
00142 
00143 void
00144 pool_set_installed(Pool *pool, Repo *installed)
00145 {
00146   if (pool->installed == installed)
00147     return;
00148   pool->installed = installed;
00149   pool_freewhatprovides(pool);
00150 }
00151 
00152 static int
00153 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp, void *dp)
00154 {
00155   int r;
00156   Pool *pool = dp;
00157   Id oa, ob, *da, *db;
00158   oa = pool->whatprovides[*(Id *)ap];
00159   ob = pool->whatprovides[*(Id *)bp];
00160   if (oa == ob)
00161     return *(Id *)ap - *(Id *)bp;
00162   if (!oa)
00163     return -1;
00164   if (!ob)
00165     return 1;
00166   da = pool->whatprovidesdata + oa;
00167   db = pool->whatprovidesdata + ob;
00168   while (*db)
00169     if ((r = (*da++ - *db++)) != 0)
00170       return r;
00171   if (*da)
00172     return *da;
00173   return *(Id *)ap - *(Id *)bp;
00174 }
00175 
00176 /*
00177  * pool_shrink_whatprovides  - unify whatprovides data
00178  *
00179  * whatprovides_rel must be empty for this to work!
00180  *
00181  */
00182 static void
00183 pool_shrink_whatprovides(Pool *pool)
00184 {
00185   Id i, id;
00186   Id *sorted;
00187   Id lastid, *last, *dp, *lp;
00188   Offset o;
00189   int r;
00190 
00191   if (pool->ss.nstrings < 3)
00192     return;
00193   sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id));
00194   for (id = 0; id < pool->ss.nstrings; id++)
00195     sorted[id] = id;
00196   sat_sort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp, pool);
00197   last = 0;
00198   lastid = 0;
00199   for (i = 1; i < pool->ss.nstrings; i++)
00200     {
00201       id = sorted[i];
00202       o = pool->whatprovides[id];
00203       if (o == 0 || o == 1)
00204         continue;
00205       dp = pool->whatprovidesdata + o;
00206       if (last)
00207         {
00208           lp = last;
00209           while (*dp)   
00210             if (*dp++ != *lp++)
00211               {
00212                 last = 0;
00213                 break;
00214               }
00215           if (last && *lp)
00216             last = 0;
00217           if (last)
00218             {
00219               pool->whatprovides[id] = -lastid;
00220               continue;
00221             }
00222         }
00223       last = pool->whatprovidesdata + o;
00224       lastid = id;
00225     }
00226   sat_free(sorted);
00227   dp = pool->whatprovidesdata + 2;
00228   for (id = 1; id < pool->ss.nstrings; id++)
00229     {
00230       o = pool->whatprovides[id];
00231       if (o == 0 || o == 1)
00232         continue;
00233       if ((Id)o < 0)
00234         {
00235           i = -(Id)o;
00236           if (i >= id)
00237             abort();
00238           pool->whatprovides[id] = pool->whatprovides[i];
00239           continue;
00240         }
00241       lp = pool->whatprovidesdata + o;
00242       if (lp < dp)
00243         abort();
00244       pool->whatprovides[id] = dp - pool->whatprovidesdata;
00245       while ((*dp++ = *lp++) != 0)
00246         ;
00247     }
00248   o = dp - pool->whatprovidesdata;
00249   POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
00250   if (pool->whatprovidesdataoff == o)
00251     return;
00252   r = pool->whatprovidesdataoff - o;
00253   pool->whatprovidesdataoff = o;
00254   pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
00255   if (r > pool->whatprovidesdataleft)
00256     r = pool->whatprovidesdataleft;
00257   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
00258 }
00259 
00260 
00261 /*
00262  * pool_createwhatprovides()
00263  * 
00264  * create hashes over pool of solvables to ease provide lookups
00265  * 
00266  */
00267 void
00268 pool_createwhatprovides(Pool *pool)
00269 {
00270   int i, num, np, extra;
00271   Offset off;
00272   Solvable *s;
00273   Id id;
00274   Offset *idp, n;
00275   Offset *whatprovides;
00276   Id *whatprovidesdata, *d;
00277   Repo *installed = pool->installed;
00278   unsigned int now;
00279 
00280   now = sat_timems(0);
00281   POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables);
00282   POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
00283 
00284   pool_freeidhashes(pool);      /* XXX: should not be here! */
00285   pool_freewhatprovides(pool);
00286   num = pool->ss.nstrings;
00287   pool->whatprovides = whatprovides = sat_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
00288   pool->whatprovides_rel = sat_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
00289 
00290   /* count providers for each name */
00291   for (i = pool->nsolvables - 1; i > 0; i--)
00292     {
00293       Id *pp;
00294       s = pool->solvables + i;
00295       if (!s->provides || !s->repo || s->repo->disabled)
00296         continue;
00297       /* we always need the installed solvable in the whatprovides data,
00298          otherwise obsoletes/conflicts on them won't work */
00299       if (s->repo != installed && !pool_installable(pool, s))
00300         continue;
00301       pp = s->repo->idarraydata + s->provides;
00302       while ((id = *pp++) != 0)
00303         {
00304           while (ISRELDEP(id))
00305             {
00306               Reldep *rd = GETRELDEP(pool, id);
00307               id = rd->name;
00308             }
00309           whatprovides[id]++;          /* inc count of providers */
00310         }
00311     }
00312 
00313   off = 2;      /* first entry is undef, second is empty list */
00314   np = 0;                              /* number of names provided */
00315   for (i = 0, idp = whatprovides; i < num; i++, idp++)
00316     {
00317       n = *idp;
00318       if (!n)                          /* no providers */
00319         continue;
00320       off += n;                        /* make space for all providers */
00321       *idp = off++;                    /* now idp points to terminating zero */
00322       np++;                            /* inc # of provider 'slots' for stats */
00323     }
00324 
00325   POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
00326 
00327   /* reserve some space for relation data */
00328   extra = 2 * pool->nrels;
00329   if (extra < 256)
00330     extra = 256;
00331 
00332   POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
00333 
00334   /* alloc space for all providers + extra */
00335   whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
00336 
00337   /* now fill data for all provides */
00338   for (i = pool->nsolvables - 1; i > 0; i--)
00339     {
00340       Id *pp;
00341       s = pool->solvables + i;
00342       if (!s->provides || !s->repo || s->repo->disabled)
00343         continue;
00344       if (s->repo != installed && !pool_installable(pool, s))
00345         continue;
00346 
00347       /* for all provides of this solvable */
00348       pp = s->repo->idarraydata + s->provides;
00349       while ((id = *pp++) != 0)
00350         {
00351           while (ISRELDEP(id))
00352             {
00353               Reldep *rd = GETRELDEP(pool, id);
00354               id = rd->name;
00355             }
00356           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
00357           if (*d != i)          /* don't add same solvable twice */
00358             {
00359               d[-1] = i;
00360               whatprovides[id]--;
00361             }
00362         }
00363     }
00364   pool->whatprovidesdata = whatprovidesdata;
00365   pool->whatprovidesdataoff = off;
00366   pool->whatprovidesdataleft = extra;
00367   pool_shrink_whatprovides(pool);
00368   POOL_DEBUG(SAT_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id)));
00369   POOL_DEBUG(SAT_DEBUG_STATS, "createwhatprovides took %d ms\n", sat_timems(now));
00370 }
00371 
00372 /*
00373  * free all of our whatprovides data
00374  * be careful, everything internalized with pool_queuetowhatprovides is
00375  * gone, too
00376  */
00377 void
00378 pool_freewhatprovides(Pool *pool)
00379 {
00380   pool->whatprovides = sat_free(pool->whatprovides);
00381   pool->whatprovides_rel = sat_free(pool->whatprovides_rel);
00382   pool->whatprovidesdata = sat_free(pool->whatprovidesdata);
00383   pool->whatprovidesdataoff = 0;
00384   pool->whatprovidesdataleft = 0;
00385 }
00386 
00387 
00388 /******************************************************************************/
00389 
00390 /*
00391  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
00392  * 
00393  * on-demand filling of provider information
00394  * move queue data into whatprovidesdata
00395  * q: queue of Ids
00396  * returns: Offset into whatprovides
00397  *
00398  */
00399 Id
00400 pool_queuetowhatprovides(Pool *pool, Queue *q)
00401 {
00402   Offset off;
00403   int count = q->count;
00404 
00405   if (count == 0)                      /* queue empty -> 1 */
00406     return 1;
00407 
00408   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
00409   if (pool->whatprovidesdataleft < count + 1)
00410     {
00411       POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n");
00412       pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
00413       pool->whatprovidesdataleft = count + 4096;
00414     }
00415 
00416   /* copy queue to next free slot */
00417   off = pool->whatprovidesdataoff;
00418   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
00419 
00420   /* adapt count and ID_NULL-terminate */
00421   pool->whatprovidesdataoff += count;
00422   pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
00423   pool->whatprovidesdataleft -= count + 1;
00424 
00425   return (Id)off;
00426 }
00427 
00428 
00429 /*************************************************************************/
00430 
00431 #if defined(MULTI_SEMANTICS)
00432 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
00433 #elif defined(DEBIAN_SEMANTICS)
00434 # define EVRCMP_DEPCMP EVRCMP_COMPARE
00435 #else
00436 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
00437 #endif
00438 
00439 /* check if a package's nevr matches a dependency */
00440 
00441 int
00442 pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
00443 {
00444   Reldep *rd = GETRELDEP(pool, d);
00445   Id name = rd->name;
00446   Id evr = rd->evr;
00447   int flags = rd->flags;
00448 
00449   if (flags > 7)
00450     {
00451       switch (flags)
00452         {
00453         case REL_ARCH:
00454           if (s->arch != evr)
00455             return 0;
00456           return pool_match_nevr(pool, s, name);
00457         case REL_OR:
00458           if (pool_match_nevr(pool, s, name))
00459             return 1;
00460           return pool_match_nevr(pool, s, evr);
00461         case REL_AND:
00462         case REL_WITH:
00463           if (!pool_match_nevr(pool, s, name))
00464             return 0;
00465           return pool_match_nevr(pool, s, evr);
00466         default:
00467           return 0;
00468         }
00469     }
00470   if (!pool_match_nevr(pool, s, name))
00471     return 0;
00472   if (evr == s->evr)
00473     return flags & 2 ? 1 : 0;
00474   if (!flags)
00475     return 0;
00476   if (flags == 7)
00477     return 1;
00478   if (flags != 2 && flags != 5)
00479     flags ^= 5;
00480   if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP)))) != 0)
00481     return 1;
00482   return 0;
00483 }
00484 
00485 /* match (flags, evr) against provider (pflags, pevr) */
00486 static inline int
00487 pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr)
00488 {
00489   if (!pflags || !flags || pflags >= 8 || flags >= 8)
00490     return 0;
00491   if (flags == 7 || pflags == 7)
00492     return 1;           /* rel provides every version */
00493   if ((pflags & flags & 5) != 0)
00494     return 1;           /* both rels show in the same direction */
00495   if (pevr == evr)
00496     {
00497       if ((pflags & flags & 2) != 0)
00498         return 1;       /* both have '=', match */
00499     }
00500   else
00501     {
00502       int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
00503       if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)))) != 0)
00504         return 1;
00505     }
00506   return 0;
00507 }
00508 
00509 /* match two dependencies (d1 = provider) */
00510 
00511 int
00512 pool_match_dep(Pool *pool, Id d1, Id d2)
00513 {
00514   Reldep *rd1, *rd2;
00515 
00516   if (d1 == d2)
00517     return 1;
00518   if (!ISRELDEP(d1))
00519     {
00520       if (!ISRELDEP(d2))
00521         return 0;
00522       rd2 = GETRELDEP(pool, d2);
00523       return pool_match_dep(pool, d1, rd2->name);
00524     }
00525   rd1 = GETRELDEP(pool, d1);
00526   if (!ISRELDEP(d2))
00527     {
00528       return pool_match_dep(pool, rd1->name, d2);
00529     }
00530   rd2 = GETRELDEP(pool, d2);
00531   /* first match name */
00532   if (!pool_match_dep(pool, rd1->name, rd2->name))
00533     return 0;
00534   /* name matches, check flags and evr */
00535   return pool_match_flags_evr(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
00536 }
00537 
00538 /*
00539  * addrelproviders
00540  * 
00541  * add packages fulfilling the relation to whatprovides array
00542  * no exact providers, do range match
00543  * 
00544  */
00545 
00546 Id
00547 pool_addrelproviders(Pool *pool, Id d)
00548 {
00549   Reldep *rd = GETRELDEP(pool, d);
00550   Reldep *prd;
00551   Queue plist;
00552   Id buf[16];
00553   Id name = rd->name;
00554   Id evr = rd->evr;
00555   int flags = rd->flags;
00556   Id pid, *pidp;
00557   Id p, *pp;
00558 
00559   d = GETRELID(d);
00560   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
00561 
00562   if (flags >= 8)
00563     {
00564       /* special relation */
00565       Id wp = 0;
00566       Id *pp2, *pp3;
00567 
00568       switch (flags)
00569         {
00570         case REL_AND:
00571         case REL_WITH:
00572           wp = pool_whatprovides(pool, name);
00573           pp2 = pool_whatprovides_ptr(pool, evr);
00574           pp = pool->whatprovidesdata + wp;
00575           while ((p = *pp++) != 0)
00576             {
00577               for (pp3 = pp2; *pp3; pp3++)
00578                 if (*pp3 == p)
00579                   break;
00580               if (*pp3)
00581                 queue_push(&plist, p);  /* found it */
00582               else
00583                 wp = 0;
00584             }
00585           break;
00586         case REL_OR:
00587           wp = pool_whatprovides(pool, name);
00588           pp = pool->whatprovidesdata + wp;
00589           if (!*pp)
00590             wp = pool_whatprovides(pool, evr);
00591           else
00592             {
00593               int cnt;
00594               while ((p = *pp++) != 0)
00595                 queue_push(&plist, p);
00596               cnt = plist.count;
00597               pp = pool_whatprovides_ptr(pool, evr);
00598               while ((p = *pp++) != 0)
00599                 queue_pushunique(&plist, p);
00600               if (plist.count != cnt)
00601                 wp = 0;
00602             }
00603           break;
00604         case REL_NAMESPACE:
00605           if (name == NAMESPACE_OTHERPROVIDERS)
00606             {
00607               wp = pool_whatprovides(pool, evr);
00608               break;
00609             }
00610           if (pool->nscallback)
00611             {
00612               /* ask callback which packages provide the dependency
00613                * 0:  none
00614                * 1:  the system (aka SYSTEMSOLVABLE)
00615                * >1: set of packages, stored as offset on whatprovidesdata
00616                */
00617               p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
00618               if (p > 1)
00619                 wp = p;
00620               if (p == 1)
00621                 queue_push(&plist, SYSTEMSOLVABLE);
00622             }
00623           break;
00624         case REL_ARCH:
00625           /* small hack: make it possible to match <pkg>.src
00626            * we have to iterate over the solvables as src packages do not
00627            * provide anything, thus they are not indexed in our
00628            * whatprovides hash */
00629           if (evr == ARCH_SRC)
00630             {
00631               Solvable *s;
00632               for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
00633                 {
00634                   if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
00635                     continue;
00636                   if (pool_match_nevr(pool, s, name))
00637                     queue_push(&plist, p);
00638                 }
00639               break;
00640             }
00641           wp = pool_whatprovides(pool, name);
00642           pp = pool->whatprovidesdata + wp;
00643           while ((p = *pp++) != 0)
00644             {
00645               Solvable *s = pool->solvables + p;
00646               if (s->arch == evr)
00647                 queue_push(&plist, p);
00648               else
00649                 wp = 0;
00650             }
00651           break;
00652         case REL_FILECONFLICT:
00653           pp = pool_whatprovides_ptr(pool, name);
00654           while ((p = *pp++) != 0)
00655             {
00656               Id origd = MAKERELDEP(d);
00657               Solvable *s = pool->solvables + p;
00658               if (!s->provides)
00659                 continue;
00660               pidp = s->repo->idarraydata + s->provides;
00661               while ((pid = *pidp++) != 0)
00662                 if (pid == origd)
00663                   break;
00664               if (pid)
00665                 queue_push(&plist, p);
00666             }
00667           break;
00668         default:
00669           break;
00670         }
00671       if (wp)
00672         {
00673           /* we can reuse an existing entry */
00674           queue_free(&plist);
00675           pool->whatprovides_rel[d] = wp;
00676           return wp;
00677         }
00678     }
00679   else if (flags)
00680     {
00681       /* simple version comparison relation */
00682 #if 0
00683       POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
00684 #endif
00685       pp = pool_whatprovides_ptr(pool, name);
00686       while (ISRELDEP(name))
00687         {
00688           rd = GETRELDEP(pool, name);
00689           name = rd->name;
00690         }
00691       while ((p = *pp++) != 0)
00692         {
00693           Solvable *s = pool->solvables + p;
00694           if (!s->provides)
00695             {
00696               /* no provides - check nevr */
00697               if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
00698                 queue_push(&plist, p);
00699               continue;
00700             }
00701           /* solvable p provides name in some rels */
00702           pidp = s->repo->idarraydata + s->provides;
00703           while ((pid = *pidp++) != 0)
00704             {
00705               if (pid == name)
00706                 {
00707 #if defined(MULTI_SEMANTICS)
00708                   if (pool->disttype == DISTTYPE_DEB)
00709                     continue;
00710                   else
00711                     break;
00712 #elif defined(DEBIAN_SEMANTICS)
00713                   continue;             /* unversioned provides can
00714                                          * never match versioned deps */
00715 #else
00716                   break;                /* yes, provides all versions */
00717 #endif
00718                 }
00719               if (!ISRELDEP(pid))
00720                 continue;               /* wrong provides name */
00721               prd = GETRELDEP(pool, pid);
00722               if (prd->name != name)
00723                 continue;               /* wrong provides name */
00724               /* right package, both deps are rels. check flags/evr */
00725               if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
00726                 break;  /* matches */
00727             }
00728           if (!pid)
00729             continue;   /* none of the providers matched */
00730           queue_push(&plist, p);
00731         }
00732       /* make our system solvable provide all unknown rpmlib() stuff */
00733       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
00734         queue_push(&plist, SYSTEMSOLVABLE);
00735     }
00736   /* add providers to whatprovides */
00737 #if 0
00738   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
00739 #endif
00740   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
00741   queue_free(&plist);
00742 
00743   return pool->whatprovides_rel[d];
00744 }
00745 
00746 /*************************************************************************/
00747 
00748 void
00749 pool_debug(Pool *pool, int type, const char *format, ...)
00750 {
00751   va_list args;
00752   char buf[1024];
00753 
00754   if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
00755     {
00756       if ((pool->debugmask & type) == 0)
00757         return;
00758     }
00759   va_start(args, format);
00760   if (!pool->debugcallback)
00761     {
00762       if ((type & (SAT_FATAL|SAT_ERROR)) == 0 && !(pool->debugmask & SAT_DEBUG_TO_STDERR))
00763         vprintf(format, args);
00764       else
00765         vfprintf(stderr, format, args);
00766       return;
00767     }
00768   vsnprintf(buf, sizeof(buf), format, args);
00769   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
00770 }
00771 
00772 void
00773 pool_setdebuglevel(Pool *pool, int level)
00774 {
00775   int mask = SAT_DEBUG_RESULT;
00776   if (level > 0)
00777     mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE|SAT_DEBUG_SOLVER|SAT_DEBUG_TRANSACTION;
00778   if (level > 1)
00779     mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
00780   if (level > 2)
00781     mask |= SAT_DEBUG_PROPAGATE;
00782   if (level > 3)
00783     mask |= SAT_DEBUG_RULE_CREATION;
00784   if (level > 4)
00785     mask |= SAT_DEBUG_SCHUBI;
00786   mask |= pool->debugmask & SAT_DEBUG_TO_STDERR;        /* keep bit */
00787   pool->debugmask = mask;
00788 }
00789 
00790 /*************************************************************************/
00791 
00792 struct searchfiles {
00793   Id *ids;
00794   char **dirs;
00795   char **names;
00796   int nfiles;
00797   Map seen;
00798 };
00799 
00800 #define SEARCHFILES_BLOCK 127
00801 
00802 static void
00803 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
00804 {
00805   Id dep, sid;
00806   const char *s, *sr;
00807   struct searchfiles *csf;
00808 
00809   while ((dep = *ida++) != 0)
00810     {
00811       csf = sf;
00812       while (ISRELDEP(dep))
00813         {
00814           Reldep *rd;
00815           sid = pool->ss.nstrings + GETRELID(dep);
00816           if (MAPTST(&csf->seen, sid))
00817             {
00818               dep = 0;
00819               break;
00820             }
00821           MAPSET(&csf->seen, sid);
00822           rd = GETRELDEP(pool, dep);
00823           if (rd->flags < 8)
00824             dep = rd->name;
00825           else if (rd->flags == REL_NAMESPACE)
00826             {
00827               if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
00828                 {
00829                   csf = isf;
00830                   if (!csf || MAPTST(&csf->seen, sid))
00831                     {
00832                       dep = 0;
00833                       break;
00834                     }
00835                   MAPSET(&csf->seen, sid);
00836                 }
00837               dep = rd->evr;
00838             }
00839           else if (rd->flags == REL_FILECONFLICT)
00840             {
00841               dep = 0;
00842               break;
00843             }
00844           else
00845             {
00846               Id ids[2];
00847               ids[0] = rd->name;
00848               ids[1] = 0;
00849               pool_addfileprovides_dep(pool, ids, csf, isf);
00850               dep = rd->evr;
00851             }
00852         }
00853       if (!dep)
00854         continue;
00855       if (MAPTST(&csf->seen, dep))
00856         continue;
00857       MAPSET(&csf->seen, dep);
00858       s = id2str(pool, dep);
00859       if (*s != '/')
00860         continue;
00861       csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
00862       csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
00863       csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
00864       csf->ids[csf->nfiles] = dep;
00865       sr = strrchr(s, '/');
00866       csf->names[csf->nfiles] = strdup(sr + 1);
00867       csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1);
00868       if (sr != s)
00869         strncpy(csf->dirs[csf->nfiles], s, sr - s);
00870       csf->dirs[csf->nfiles][sr - s] = 0;
00871       csf->nfiles++;
00872     }
00873 }
00874 
00875 struct addfileprovides_cbdata {
00876   int nfiles;
00877   Id *ids;
00878   char **dirs;
00879   char **names;
00880 
00881   Id *dids;
00882 
00883   Map providedids;
00884 
00885   Map useddirs;
00886 };
00887 
00888 static int
00889 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
00890 {
00891   struct addfileprovides_cbdata *cbd = cbdata;
00892   int i;
00893 
00894   if (!cbd->useddirs.size)
00895     {
00896       map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
00897       for (i = 0; i < cbd->nfiles; i++)
00898         {
00899           Id did;
00900           if (MAPTST(&cbd->providedids, cbd->ids[i]))
00901             {
00902               cbd->dids[i] = 0;
00903               continue;
00904             }
00905           did = repodata_str2dir(data, cbd->dirs[i], 0);
00906           cbd->dids[i] = did;
00907           if (did)
00908             MAPSET(&cbd->useddirs, did);
00909         }
00910     }
00911   if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
00912     return 0;
00913   for (i = 0; i < cbd->nfiles; i++)
00914     {
00915       if (cbd->dids[i] != value->id)
00916         continue;
00917       if (!strcmp(cbd->names[i], value->str))
00918         break;
00919     }
00920   if (i == cbd->nfiles)
00921     return 0;
00922   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
00923   return 0;
00924 }
00925 
00926 static void
00927 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
00928 {
00929   Id p;
00930   Repodata *data;
00931   Repo *repo;
00932   Queue fileprovidesq;
00933   int i, j, repoid, repodataid;
00934   int provstart, provend;
00935   Map donemap;
00936   int ndone, incomplete;
00937 
00938   if (!pool->nrepos)
00939     return;
00940 
00941   cbd->nfiles = sf->nfiles;
00942   cbd->ids = sf->ids;
00943   cbd->dirs = sf->dirs;
00944   cbd->names = sf->names;
00945   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
00946   map_init(&cbd->providedids, pool->ss.nstrings);
00947 
00948   repoid = 0;
00949   repo = repoonly ? repoonly : pool->repos[0];
00950   map_init(&donemap, pool->nsolvables);
00951   queue_init(&fileprovidesq);
00952   provstart = provend = 0;
00953   for (;;)
00954     {
00955       if (repo->disabled)
00956         {
00957           if (repoonly || ++repoid == pool->nrepos)
00958             break;
00959           repo = pool->repos[repoid];
00960           continue;
00961         }
00962       ndone = 0;
00963       for (data = repo->repodata, repodataid = 0; repodataid < repo->nrepodata; repodataid++, data++)
00964         {
00965           if (ndone >= repo->nsolvables)
00966             break;
00967 
00968           if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
00969             {
00970               map_empty(&cbd->providedids);
00971               for (i = 0; i < fileprovidesq.count; i++)
00972                 MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
00973               provstart = data->start;
00974               provend = data->end;
00975               for (i = 0; i < cbd->nfiles; i++)
00976                 if (!MAPTST(&cbd->providedids, cbd->ids[i]))
00977                   break;
00978               if (i == cbd->nfiles)
00979                 {
00980                   /* great! no need to search files */
00981                   for (p = data->start; p < data->end; p++)
00982                     if (pool->solvables[p].repo == repo)
00983                       {
00984                         if (MAPTST(&donemap, p))
00985                           continue;
00986                         MAPSET(&donemap, p);
00987                         ndone++;
00988                       }
00989                   continue;
00990                 }
00991             }
00992 
00993           if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
00994             continue;
00995 
00996           if (data->start < provstart || data->end > provend)
00997             {
00998               map_empty(&cbd->providedids);
00999               provstart = provend = 0;
01000             }
01001 
01002           /* check if the data is incomplete */
01003           incomplete = 0;
01004           if (data->state == REPODATA_AVAILABLE)
01005             {
01006               for (j = 1; j < data->nkeys; j++)
01007                 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
01008                   break;
01009               if (j < data->nkeys)
01010                 {
01011 #if 0
01012                   for (i = 0; i < cbd->nfiles; i++)
01013                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
01014                       printf("need complete filelist because of %s\n", id2str(pool, cbd->ids[i]));
01015 #endif
01016                   for (i = 0; i < cbd->nfiles; i++)
01017                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
01018                       break;
01019                   if (i < cbd->nfiles)
01020                     incomplete = 1;
01021                 }
01022             }
01023 
01024           /* do the search */
01025           map_init(&cbd->useddirs, 0);
01026           for (p = data->start; p < data->end; p++)
01027             if (pool->solvables[p].repo == repo)
01028               {
01029                 if (MAPTST(&donemap, p))
01030                   continue;
01031                 repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
01032                 if (!incomplete)
01033                   {
01034                     MAPSET(&donemap, p);
01035                     ndone++;
01036                   }
01037               }
01038           map_free(&cbd->useddirs);
01039         }
01040 
01041       if (repoonly || ++repoid == pool->nrepos)
01042         break;
01043       repo = pool->repos[repoid];
01044     }
01045   map_free(&donemap);
01046   queue_free(&fileprovidesq);
01047   map_free(&cbd->providedids);
01048 }
01049 
01050 void
01051 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
01052 {
01053   Solvable *s;
01054   Repo *repo;
01055   struct searchfiles sf, isf, *isfp;
01056   struct addfileprovides_cbdata cbd;
01057   int i;
01058   unsigned int now;
01059 
01060   now = sat_timems(0);
01061   memset(&sf, 0, sizeof(sf));
01062   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
01063   memset(&isf, 0, sizeof(isf));
01064   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
01065 
01066   isfp = installed ? &isf : 0;
01067   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
01068     {
01069       repo = s->repo;
01070       if (!repo)
01071         continue;
01072       if (s->obsoletes)
01073         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
01074       if (s->conflicts)
01075         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
01076       if (s->requires)
01077         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
01078       if (s->recommends)
01079         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
01080       if (s->suggests)
01081         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
01082       if (s->supplements)
01083         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
01084       if (s->enhances)
01085         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
01086     }
01087   map_free(&sf.seen);
01088   map_free(&isf.seen);
01089   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
01090   cbd.dids = 0;
01091   if (idp)
01092     *idp = 0;
01093   if (sf.nfiles)
01094     {
01095 #if 0
01096       for (i = 0; i < sf.nfiles; i++)
01097         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
01098 #endif
01099       pool_addfileprovides_search(pool, &cbd, &sf, 0);
01100       if (idp)
01101         {
01102           sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
01103           sf.ids[sf.nfiles] = 0;
01104           *idp = sf.ids;
01105           sf.ids = 0;
01106         }
01107       sat_free(sf.ids);
01108       for (i = 0; i < sf.nfiles; i++)
01109         {
01110           sat_free(sf.dirs[i]);
01111           sat_free(sf.names[i]);
01112         }
01113       sat_free(sf.dirs);
01114       sat_free(sf.names);
01115     }
01116   if (isf.nfiles)
01117     {
01118 #if 0
01119       for (i = 0; i < isf.nfiles; i++)
01120         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
01121 #endif
01122       if (installed)
01123         pool_addfileprovides_search(pool, &cbd, &isf, installed);
01124       sat_free(isf.ids);
01125       for (i = 0; i < isf.nfiles; i++)
01126         {
01127           sat_free(isf.dirs[i]);
01128           sat_free(isf.names[i]);
01129         }
01130       sat_free(isf.dirs);
01131       sat_free(isf.names);
01132     }
01133   sat_free(cbd.dids);
01134   pool_freewhatprovides(pool);  /* as we have added provides */
01135   POOL_DEBUG(SAT_DEBUG_STATS, "addfileprovides took %d ms\n", sat_timems(now));
01136 }
01137 
01138 void
01139 pool_addfileprovides(Pool *pool)
01140 {
01141   pool_addfileprovides_ids(pool, pool->installed, 0);
01142 }
01143 
01144 void
01145 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)
01146 {
01147   if (p)
01148     {
01149       if (pool->solvables[p].repo)
01150         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
01151       return;
01152     }
01153   /* FIXME: obey callback return value! */
01154   for (p = 1; p < pool->nsolvables; p++)
01155     if (pool->solvables[p].repo)
01156       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
01157 }
01158 
01159 void
01160 pool_clear_pos(Pool *pool)
01161 {
01162   memset(&pool->pos, 0, sizeof(pool->pos));
01163 }
01164 
01165 
01166 void
01167 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
01168 {
01169   int i;
01170 
01171   pool->languagecache = sat_free(pool->languagecache);
01172   pool->languagecacheother = 0;
01173   if (pool->nlanguages)
01174     {
01175       for (i = 0; i < pool->nlanguages; i++)
01176         free((char *)pool->languages[i]);
01177       free(pool->languages);
01178     }
01179   pool->nlanguages = nlanguages;
01180   if (!nlanguages)
01181     return;
01182   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
01183   for (i = 0; i < pool->nlanguages; i++)
01184     pool->languages[i] = strdup(languages[i]);
01185 }
01186 
01187 Id
01188 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
01189 {
01190   const char *n;
01191   char buf[256], *p;
01192   int l;
01193 
01194   if (!lang)
01195     return id;
01196   n = id2str(pool, id);
01197   l = strlen(n) + strlen(lang) + 2;
01198   if (l > sizeof(buf))
01199     p = sat_malloc(strlen(n) + strlen(lang) + 2);
01200   else
01201     p = buf;
01202   sprintf(p, "%s:%s", n, lang);
01203   id = str2id(pool, p, create);
01204   if (p != buf)
01205     free(p);
01206   return id;
01207 }
01208 
01209 char *
01210 pool_alloctmpspace(Pool *pool, int len)
01211 {
01212   int n = pool->tmpspacen;
01213   if (!len)
01214     return 0;
01215   if (len > pool->tmpspacelen[n])
01216     {
01217       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
01218       pool->tmpspacelen[n] = len + 32;
01219     }
01220   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
01221   return pool->tmpspacebuf[n];
01222 }
01223 
01224 char *
01225 pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3)
01226 {
01227   int l1, l2, l3;
01228   char *s, *str;
01229   l1 = str1 ? strlen(str1) : 0;
01230   l2 = str2 ? strlen(str2) : 0;
01231   l3 = str3 ? strlen(str3) : 0;
01232   s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
01233   if (l1)
01234     {
01235       strcpy(s, str1);
01236       s += l1;
01237     }
01238   if (l2)
01239     {
01240       strcpy(s, str2);
01241       s += l2;
01242     }
01243   if (l3)
01244     {
01245       strcpy(s, str3);
01246       s += l3;
01247     }
01248   *s = 0;
01249   return str;
01250 }
01251 
01252 
01253 /*******************************************************************/
01254 
01255 struct mptree {
01256   Id sibling;
01257   Id child;
01258   const char *comp;
01259   int compl;
01260   Id mountpoint;
01261 };
01262 
01263 struct ducbdata {
01264   DUChanges *mps;
01265   struct mptree *mptree;
01266   int addsub;
01267   int hasdu;
01268 
01269   Id *dirmap;
01270   int nmap;
01271   Repodata *olddata;
01272 };
01273 
01274 
01275 static int
01276 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
01277 {
01278   struct ducbdata *cbd = cbdata;
01279   Id mp;
01280 
01281   if (data != cbd->olddata)
01282     {
01283       Id dn, mp, comp, *dirmap, *dirs;
01284       int i, compl;
01285       const char *compstr;
01286       struct mptree *mptree;
01287 
01288       /* create map from dir to mptree */
01289       cbd->dirmap = sat_free(cbd->dirmap);
01290       cbd->nmap = 0;
01291       dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
01292       mptree = cbd->mptree;
01293       mp = 0;
01294       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
01295         {
01296           comp = *dirs++;
01297           if (comp <= 0)
01298             {
01299               mp = dirmap[-comp];
01300               continue;
01301             }
01302           if (mp < 0)
01303             {
01304               /* unconnected */
01305               dirmap[dn] = mp;
01306               continue;
01307             }
01308           if (!mptree[mp].child)
01309             {
01310               dirmap[dn] = -mp;
01311               continue;
01312             }
01313           if (data->localpool)
01314             compstr = stringpool_id2str(&data->spool, comp);
01315           else
01316             compstr = id2str(data->repo->pool, comp);
01317           compl = strlen(compstr);
01318           for (i = mptree[mp].child; i; i = mptree[i].sibling)
01319             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
01320               break;
01321           dirmap[dn] = i ? i : -mp;
01322         }
01323       /* change dirmap to point to mountpoint instead of mptree */
01324       for (dn = 0; dn < data->dirpool.ndirs; dn++)
01325         {
01326           mp = dirmap[dn];
01327           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
01328         }
01329       cbd->dirmap = dirmap;
01330       cbd->nmap = data->dirpool.ndirs;
01331       cbd->olddata = data;
01332     }
01333   cbd->hasdu = 1;
01334   if (value->id < 0 || value->id >= cbd->nmap)
01335     return 0;
01336   mp = cbd->dirmap[value->id];
01337   if (mp < 0)
01338     return 0;
01339   if (cbd->addsub > 0)
01340     {
01341       cbd->mps[mp].kbytes += value->num;
01342       cbd->mps[mp].files += value->num2;
01343     }
01344   else
01345     {
01346       cbd->mps[mp].kbytes -= value->num;
01347       cbd->mps[mp].files -= value->num2;
01348     }
01349   return 0;
01350 }
01351 
01352 static void
01353 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
01354 {
01355   int i;
01356   if (mptree[pos].mountpoint == -1)
01357     mptree[pos].mountpoint = mountpoint;
01358   else
01359     mountpoint = mptree[pos].mountpoint;
01360   for (i = mptree[pos].child; i; i = mptree[i].sibling)
01361     propagate_mountpoints(mptree, i, mountpoint);
01362 }
01363 
01364 #define MPTREE_BLOCK 15
01365 
01366 void
01367 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
01368 {
01369   char *p;
01370   const char *path, *compstr;
01371   struct mptree *mptree;
01372   int i, nmptree;
01373   int pos, compl;
01374   int mp;
01375   struct ducbdata cbd;
01376   Solvable *s;
01377   Id sp;
01378   Map ignoredu;
01379   Repo *oldinstalled = pool->installed;
01380 
01381   memset(&ignoredu, 0, sizeof(ignoredu));
01382   cbd.mps = mps;
01383   cbd.addsub = 0;
01384   cbd.dirmap = 0;
01385   cbd.nmap = 0;
01386   cbd.olddata = 0;
01387 
01388   mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
01389 
01390   /* our root node */
01391   mptree[0].sibling = 0;
01392   mptree[0].child = 0;
01393   mptree[0].comp = 0;
01394   mptree[0].compl = 0;
01395   mptree[0].mountpoint = -1;
01396   nmptree = 1;
01397   
01398   /* create component tree */
01399   for (mp = 0; mp < nmps; mp++)
01400     {
01401       mps[mp].kbytes = 0;
01402       mps[mp].files = 0;
01403       pos = 0;
01404       path = mps[mp].path;
01405       while(*path == '/')
01406         path++;
01407       while (*path)
01408         {
01409           if ((p = strchr(path, '/')) == 0)
01410             {
01411               compstr = path;
01412               compl = strlen(compstr);
01413               path += compl;
01414             }
01415           else
01416             {
01417               compstr = path;
01418               compl = p - path;
01419               path = p + 1;
01420               while(*path == '/')
01421                 path++;
01422             }
01423           for (i = mptree[pos].child; i; i = mptree[i].sibling)
01424             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
01425               break;
01426           if (!i)
01427             {
01428               /* create new node */
01429               mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
01430               i = nmptree++;
01431               mptree[i].sibling = mptree[pos].child;
01432               mptree[i].child = 0;
01433               mptree[i].comp = compstr;
01434               mptree[i].compl = compl;
01435               mptree[i].mountpoint = -1;
01436               mptree[pos].child = i;
01437             }
01438           pos = i;
01439         }
01440       mptree[pos].mountpoint = mp;
01441     }
01442 
01443   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
01444 
01445 #if 0
01446   for (i = 0; i < nmptree; i++)
01447     {
01448       printf("#%d sibling: %d\n", i, mptree[i].sibling);
01449       printf("#%d child: %d\n", i, mptree[i].child);
01450       printf("#%d comp: %s\n", i, mptree[i].comp);
01451       printf("#%d compl: %d\n", i, mptree[i].compl);
01452       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
01453     }
01454 #endif
01455 
01456   cbd.mptree = mptree;
01457   cbd.addsub = 1;
01458   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
01459     {
01460       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
01461         continue;
01462       if (!MAPTST(installedmap, sp))
01463         continue;
01464       cbd.hasdu = 0;
01465       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
01466       if (!cbd.hasdu && oldinstalled)
01467         {
01468           Id op, opp;
01469           /* no du data available, ignore data of all installed solvables we obsolete */
01470           if (!ignoredu.map)
01471             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
01472           if (s->obsoletes)
01473             {
01474               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
01475               while ((obs = *obsp++) != 0)
01476                 FOR_PROVIDES(op, opp, obs)
01477                   if (op >= oldinstalled->start && op < oldinstalled->end)
01478                     MAPSET(&ignoredu, op - oldinstalled->start);
01479             }
01480           FOR_PROVIDES(op, opp, s->name)
01481             if (pool->solvables[op].name == s->name)
01482               if (op >= oldinstalled->start && op < oldinstalled->end)
01483                 MAPSET(&ignoredu, op - oldinstalled->start);
01484         }
01485     }
01486   cbd.addsub = -1;
01487   if (oldinstalled)
01488     {
01489       /* assumes we allways have du data for installed solvables */
01490       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
01491         {
01492           if (MAPTST(installedmap, sp))
01493             continue;
01494           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
01495             continue;
01496           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
01497         }
01498     }
01499   if (ignoredu.map)
01500     map_free(&ignoredu);
01501   sat_free(cbd.dirmap);
01502   sat_free(mptree);
01503 }
01504 
01505 int
01506 pool_calc_installsizechange(Pool *pool, Map *installedmap)
01507 {
01508   Id sp;
01509   Solvable *s;
01510   int change = 0;
01511   Repo *oldinstalled = pool->installed;
01512 
01513   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
01514     {
01515       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
01516         continue;
01517       if (!MAPTST(installedmap, sp))
01518         continue;
01519       change += solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
01520     }
01521   if (oldinstalled)
01522     {
01523       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
01524         {
01525           if (MAPTST(installedmap, sp))
01526             continue;
01527           change -= solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
01528         }
01529     }
01530   return change;
01531 }
01532 
01533 /* map:
01534  *  1: installed
01535  *  2: conflicts with installed
01536  *  8: interesting (only true if installed)
01537  * 16: undecided
01538  */
01539  
01540 static inline Id dep2name(Pool *pool, Id dep)
01541 {
01542   while (ISRELDEP(dep))
01543     {
01544       Reldep *rd = rd = GETRELDEP(pool, dep);
01545       dep = rd->name;
01546     }
01547   return dep;
01548 }
01549 
01550 static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con) 
01551 {
01552   Id p, pp;
01553   Solvable *sn = pool->solvables + n; 
01554 
01555   FOR_PROVIDES(p, pp, sn->name)
01556     {    
01557       Solvable *s = pool->solvables + p; 
01558       if (s->name != sn->name || s->arch != sn->arch)
01559         continue;
01560       if ((map[p] & 9) != 9)
01561         continue;
01562       if (pool_match_nevr(pool, pool->solvables + p, con))
01563         continue;
01564       return 1;         /* found installed package that doesn't conflict */
01565     }
01566   return 0;
01567 }
01568 
01569 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *noobsoletesmap)
01570 {
01571   Id p, pp;
01572   int r = 0;
01573   FOR_PROVIDES(p, pp, dep)
01574     {
01575       if (p == SYSTEMSOLVABLE)
01576         return 1;       /* always boring, as never constraining */
01577       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
01578         continue;
01579       if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep))
01580         if (providedbyinstalled_multiversion(pool, map, p, dep))
01581           continue;
01582       if ((map[p] & 9) == 9)
01583         return 9;
01584       r |= map[p] & 17;
01585     }
01586   return r;
01587 }
01588 
01589 /*
01590  * pool_trivial_installable - calculate if a set of solvables is
01591  * trivial installable without any other installs/deinstalls of
01592  * packages not belonging to the set.
01593  *
01594  * the state is returned in the result queue:
01595  * 1:  solvable is installable without any other package changes
01596  * 0:  solvable is not installable
01597  * -1: solvable is installable, but doesn't constrain any installed packages
01598  */
01599 
01600 void
01601 pool_trivial_installable_noobsoletesmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *noobsoletesmap)
01602 {
01603   int i, r, m, did;
01604   Id p, *dp, con, *conp, req, *reqp;
01605   unsigned char *map;
01606   Solvable *s;
01607 
01608   map = sat_calloc(pool->nsolvables, 1);
01609   for (p = 1; p < pool->nsolvables; p++)
01610     {
01611       if (!MAPTST(installedmap, p))
01612         continue;
01613       map[p] |= 9;
01614       s = pool->solvables + p;
01615       if (!s->conflicts)
01616         continue;
01617       conp = s->repo->idarraydata + s->conflicts;
01618       while ((con = *conp++) != 0)
01619         {
01620           dp = pool_whatprovides_ptr(pool, con);
01621           for (; *dp; dp++)
01622             map[p] |= 2;        /* XXX: self conflict ? */
01623         }
01624     }
01625   for (i = 0; i < pkgs->count; i++)
01626     map[pkgs->elements[i]] = 16;
01627 
01628   for (i = 0, did = 0; did < pkgs->count; i++, did++)
01629     {
01630       if (i == pkgs->count)
01631         i = 0;
01632       p = pkgs->elements[i];
01633       if ((map[p] & 16) == 0)
01634         continue;
01635       if ((map[p] & 2) != 0)
01636         {
01637           map[p] = 2;
01638           continue;
01639         }
01640       s = pool->solvables + p;
01641       m = 1;
01642       if (s->requires)
01643         {
01644           reqp = s->repo->idarraydata + s->requires;
01645           while ((req = *reqp++) != 0)
01646             {
01647               if (req == SOLVABLE_PREREQMARKER)
01648                 continue;
01649               r = providedbyinstalled(pool, map, req, 0, 0);
01650               if (!r)
01651                 {
01652                   /* decided and miss */
01653                   map[p] = 2;
01654                   break;
01655                 }
01656               m |= r;   /* 1 | 9 | 16 | 17 */
01657             }
01658           if (req)
01659             continue;
01660           if ((m & 9) == 9)
01661             m = 9;
01662         }
01663       if (s->conflicts)
01664         {
01665           int ispatch = 0;      /* see solver.c patch handling */
01666 
01667           if (!strncmp("patch:", id2str(pool, s->name), 6))
01668             ispatch = 1;
01669           conp = s->repo->idarraydata + s->conflicts;
01670           while ((con = *conp++) != 0)
01671             {
01672               if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
01673                 {
01674                   map[p] = 2;
01675                   break;
01676                 }
01677               if ((m == 1 || m == 17) && ISRELDEP(con))
01678                 {
01679                   con = dep2name(pool, con);
01680                   if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
01681                     m = 9;
01682                 }
01683             }
01684           if (con)
01685             continue;   /* found a conflict */
01686         }
01687 #if 0
01688       if (s->repo && s->repo != oldinstalled)
01689         {
01690           Id p2, obs, *obsp, *pp;
01691           Solvable *s2;
01692           if (s->obsoletes)
01693             {
01694               obsp = s->repo->idarraydata + s->obsoletes;
01695               while ((obs = *obsp++) != 0)
01696                 {
01697                   if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
01698                     {
01699                       map[p] = 2;
01700                       break;
01701                     }
01702                 }
01703               if (obs)
01704                 continue;
01705             }
01706           FOR_PROVIDES(p2, pp, s->name)
01707             {
01708               s2 = pool->solvables + p2;
01709               if (s2->name == s->name && (map[p2] & 1) != 0)
01710                 {
01711                   map[p] = 2;
01712                   break;
01713                 }
01714             }
01715           if (p2)
01716             continue;
01717         }
01718 #endif
01719       if (m != map[p])
01720         {
01721           map[p] = m;
01722           did = 0;
01723         }
01724     }
01725   queue_free(res);
01726   queue_init_clone(res, pkgs);
01727   for (i = 0; i < pkgs->count; i++)
01728     {
01729       m = map[pkgs->elements[i]];
01730       if ((m & 9) == 9)
01731         r = 1;
01732       else if (m & 1)
01733         r = -1;
01734       else
01735         r = 0;
01736       res->elements[i] = r;
01737     }
01738   free(map);
01739 }
01740 
01741 void
01742 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
01743 {
01744   pool_trivial_installable_noobsoletesmap(pool, installedmap, pkgs, res, 0);
01745 }
01746 
01747 const char *
01748 pool_lookup_str(Pool *pool, Id entry, Id keyname)
01749 {
01750   if (entry == SOLVID_POS && pool->pos.repo)
01751     return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
01752   if (entry <= 0)
01753     return 0;
01754   return solvable_lookup_str(pool->solvables + entry, keyname);
01755 }
01756 
01757 Id
01758 pool_lookup_id(Pool *pool, Id entry, Id keyname)
01759 {
01760   if (entry == SOLVID_POS && pool->pos.repo)
01761     {
01762       Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
01763       Id id = repodata_lookup_id(data, SOLVID_POS, keyname);
01764       return data->localpool ? repodata_globalize_id(data, id, 1) : id;
01765     }
01766   if (entry <= 0)
01767     return 0;
01768   return solvable_lookup_id(pool->solvables + entry, keyname);
01769 }
01770 
01771 unsigned int
01772 pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned int notfound)
01773 {
01774   if (entry == SOLVID_POS && pool->pos.repo)
01775     {
01776       unsigned int value;
01777       if (repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, &value))
01778         return value;
01779       return notfound;
01780     }
01781   if (entry <= 0)
01782     return notfound;
01783   return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
01784 }
01785 
01786 int
01787 pool_lookup_void(Pool *pool, Id entry, Id keyname)
01788 {
01789   if (entry == SOLVID_POS && pool->pos.repo)
01790     return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
01791   if (entry <= 0)
01792     return 0;
01793   return solvable_lookup_void(pool->solvables + entry, keyname);
01794 }
01795 
01796 const unsigned char *
01797 pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
01798 {
01799   if (entry == SOLVID_POS && pool->pos.repo)
01800     return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
01801   if (entry <= 0)
01802     return 0;
01803   return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
01804 }
01805 
01806 const char *
01807 pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
01808 {
01809   if (entry == SOLVID_POS && pool->pos.repo)
01810     {
01811       const unsigned char *chk = repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
01812       return chk ? repodata_chk2str(pool->pos.repo->repodata + pool->pos.repodataid, *typep, chk) : 0;
01813     }
01814   if (entry <= 0)
01815     return 0;
01816   return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
01817 }
01818 
01819 void
01820 pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
01821 {
01822   int hadhashes = pool->relhashtbl ? 1 : 0;
01823   Solvable *s;
01824   Id fn, p, q, md5;
01825   Id id;
01826   int i;
01827 
01828   if (!conflicts->count)
01829     return;
01830   pool_freewhatprovides(pool);
01831   for (i = 0; i < conflicts->count; i += 5)
01832     {
01833       fn = conflicts->elements[i];
01834       p = conflicts->elements[i + 1];
01835       md5 = conflicts->elements[i + 2];
01836       q = conflicts->elements[i + 3];
01837       id = rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
01838       s = pool->solvables + p;
01839       if (!s->repo)
01840         continue;
01841       s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
01842       s = pool->solvables + q;
01843       if (!s->repo)
01844         continue;
01845       s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
01846     }
01847   if (!hadhashes)
01848     pool_freeidhashes(pool);
01849 }
01850 
01851 /* EOF */