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, wp, *pp, *pp2, *pp3;
00558 
00559   d = GETRELID(d);
00560   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
00561   switch (flags)
00562     {
00563     case REL_AND:
00564     case REL_WITH:
00565       wp = pool_whatprovides(pool, name);
00566       pp2 = pool_whatprovides_ptr(pool, evr);
00567       pp = pool->whatprovidesdata + wp;
00568       while ((p = *pp++) != 0)
00569         {
00570           for (pp3 = pp2; *pp3;)
00571             if (*pp3++ == p)
00572               {
00573                 queue_push(&plist, p);
00574                 break;
00575               }
00576         }
00577       break;
00578     case REL_OR:
00579       pp = pool_whatprovides_ptr(pool, name);
00580       while ((p = *pp++) != 0)
00581         queue_push(&plist, p);
00582       pp = pool_whatprovides_ptr(pool, evr);
00583       while ((p = *pp++) != 0)
00584         queue_pushunique(&plist, p);
00585       break;
00586     case REL_NAMESPACE:
00587       if (name == NAMESPACE_OTHERPROVIDERS)
00588         {
00589           wp = pool_whatprovides(pool, evr);
00590           pool->whatprovides_rel[d] = wp;
00591           return wp;
00592         }
00593       if (pool->nscallback)
00594         {
00595           /* ask callback which packages provide the dependency
00596            * 0:  none
00597            * 1:  the system (aka SYSTEMSOLVABLE)
00598            * >1: a set of packages, stored as offset on whatprovidesdata
00599            */
00600           p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
00601           if (p > 1)
00602             {
00603               queue_free(&plist);
00604               pool->whatprovides_rel[d] = p;
00605               return p;
00606             }
00607           if (p == 1)
00608             queue_push(&plist, SYSTEMSOLVABLE);
00609         }
00610       break;
00611     case REL_ARCH:
00612       /* small hack: make it possible to match <pkg>.src
00613        * we have to iterate over the solvables as src packages do not
00614        * provide anything, thus they are not indexed in our
00615        * whatprovides hash */
00616       if (evr == ARCH_SRC)
00617         {
00618           Solvable *s;
00619           for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
00620             {
00621               if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
00622                 continue;
00623               if (pool_match_nevr(pool, s, name))
00624                 queue_push(&plist, p);
00625             }
00626           break;
00627         }
00628       wp = pool_whatprovides(pool, name);
00629       pp = pool->whatprovidesdata + wp;
00630       while ((p = *pp++) != 0)
00631         {
00632           Solvable *s = pool->solvables + p;
00633           if (s->arch == evr)
00634             queue_push(&plist, p);
00635           else
00636             wp = 0;
00637         }
00638       if (wp)
00639         {
00640           /* all solvables match, no need to create a new list */
00641           queue_free(&plist);
00642           pool->whatprovides_rel[d] = wp;
00643           return wp;
00644         }
00645       break;
00646     case REL_FILECONFLICT:
00647       pp = pool_whatprovides_ptr(pool, name);
00648       while ((p = *pp++) != 0)
00649         {
00650           Id origd = MAKERELDEP(d);
00651           Solvable *s = pool->solvables + p;
00652           if (!s->provides)
00653             continue;
00654           pidp = s->repo->idarraydata + s->provides;
00655           while ((pid = *pidp++) != 0)
00656             if (pid == origd)
00657               break;
00658           if (pid)
00659             queue_push(&plist, p);
00660         }
00661       break;
00662     default:
00663       break;
00664     }
00665 
00666   /* convert to whatprovides id */
00667 #if 0
00668   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
00669 #endif
00670   if (flags && flags < 8)
00671     {
00672       pp = pool_whatprovides_ptr(pool, name);
00673       while (ISRELDEP(name))
00674         {
00675           rd = GETRELDEP(pool, name);
00676           name = rd->name;
00677         }
00678       while ((p = *pp++) != 0)
00679         {
00680           Solvable *s = pool->solvables + p;
00681 #if 0
00682           POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, s->name));
00683 #endif
00684           if (!s->provides)
00685             {
00686               /* no provides - check nevr */
00687               if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
00688                 queue_push(&plist, p);
00689               continue;
00690             }
00691           /* solvable p provides name in some rels */
00692           pidp = s->repo->idarraydata + s->provides;
00693           while ((pid = *pidp++) != 0)
00694             {
00695               if (pid == name)
00696                 {
00697 #if defined(MULTI_SEMANTICS)
00698                   if (pool->disttype == DISTTYPE_DEB)
00699                     continue;
00700                   else
00701                     break;
00702 #elif defined(DEBIAN_SEMANTICS)
00703                   continue;             /* unversioned provides can
00704                                          * never match versioned deps */
00705 #else
00706                   break;                /* yes, provides all versions */
00707 #endif
00708                 }
00709               if (!ISRELDEP(pid))
00710                 continue;               /* wrong provides name */
00711               prd = GETRELDEP(pool, pid);
00712               if (prd->name != name)
00713                 continue;               /* wrong provides name */
00714               /* right package, both deps are rels. check flags/evr */
00715               if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
00716                 break;  /* matches */
00717             }
00718           if (!pid)
00719             continue;   /* none of the providers matched */
00720           queue_push(&plist, p);
00721         }
00722       /* make our system solvable provide all unknown rpmlib() stuff */
00723       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
00724         queue_push(&plist, SYSTEMSOLVABLE);
00725     }
00726   /* add providers to whatprovides */
00727 #if 0
00728   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
00729 #endif
00730   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
00731   queue_free(&plist);
00732 
00733   return pool->whatprovides_rel[d];
00734 }
00735 
00736 /*************************************************************************/
00737 
00738 void
00739 pool_debug(Pool *pool, int type, const char *format, ...)
00740 {
00741   va_list args;
00742   char buf[1024];
00743 
00744   if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
00745     {
00746       if ((pool->debugmask & type) == 0)
00747         return;
00748     }
00749   va_start(args, format);
00750   if (!pool->debugcallback)
00751     {
00752       if ((type & (SAT_FATAL|SAT_ERROR)) == 0 && !(pool->debugmask & SAT_DEBUG_TO_STDERR))
00753         vprintf(format, args);
00754       else
00755         vfprintf(stderr, format, args);
00756       return;
00757     }
00758   vsnprintf(buf, sizeof(buf), format, args);
00759   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
00760 }
00761 
00762 void
00763 pool_setdebuglevel(Pool *pool, int level)
00764 {
00765   int mask = SAT_DEBUG_RESULT;
00766   if (level > 0)
00767     mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE|SAT_DEBUG_SOLVER|SAT_DEBUG_TRANSACTION;
00768   if (level > 1)
00769     mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
00770   if (level > 2)
00771     mask |= SAT_DEBUG_PROPAGATE;
00772   if (level > 3)
00773     mask |= SAT_DEBUG_RULE_CREATION;
00774   if (level > 4)
00775     mask |= SAT_DEBUG_SCHUBI;
00776   mask |= pool->debugmask & SAT_DEBUG_TO_STDERR;        /* keep bit */
00777   pool->debugmask = mask;
00778 }
00779 
00780 /*************************************************************************/
00781 
00782 struct searchfiles {
00783   Id *ids;
00784   char **dirs;
00785   char **names;
00786   int nfiles;
00787   Map seen;
00788 };
00789 
00790 #define SEARCHFILES_BLOCK 127
00791 
00792 static void
00793 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
00794 {
00795   Id dep, sid;
00796   const char *s, *sr;
00797   struct searchfiles *csf;
00798 
00799   while ((dep = *ida++) != 0)
00800     {
00801       csf = sf;
00802       while (ISRELDEP(dep))
00803         {
00804           Reldep *rd;
00805           sid = pool->ss.nstrings + GETRELID(dep);
00806           if (MAPTST(&csf->seen, sid))
00807             {
00808               dep = 0;
00809               break;
00810             }
00811           MAPSET(&csf->seen, sid);
00812           rd = GETRELDEP(pool, dep);
00813           if (rd->flags < 8)
00814             dep = rd->name;
00815           else if (rd->flags == REL_NAMESPACE)
00816             {
00817               if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
00818                 {
00819                   csf = isf;
00820                   if (!csf || MAPTST(&csf->seen, sid))
00821                     {
00822                       dep = 0;
00823                       break;
00824                     }
00825                   MAPSET(&csf->seen, sid);
00826                 }
00827               dep = rd->evr;
00828             }
00829           else if (rd->flags == REL_FILECONFLICT)
00830             {
00831               dep = 0;
00832               break;
00833             }
00834           else
00835             {
00836               Id ids[2];
00837               ids[0] = rd->name;
00838               ids[1] = 0;
00839               pool_addfileprovides_dep(pool, ids, csf, isf);
00840               dep = rd->evr;
00841             }
00842         }
00843       if (!dep)
00844         continue;
00845       if (MAPTST(&csf->seen, dep))
00846         continue;
00847       MAPSET(&csf->seen, dep);
00848       s = id2str(pool, dep);
00849       if (*s != '/')
00850         continue;
00851       csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
00852       csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
00853       csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
00854       csf->ids[csf->nfiles] = dep;
00855       sr = strrchr(s, '/');
00856       csf->names[csf->nfiles] = strdup(sr + 1);
00857       csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1);
00858       if (sr != s)
00859         strncpy(csf->dirs[csf->nfiles], s, sr - s);
00860       csf->dirs[csf->nfiles][sr - s] = 0;
00861       csf->nfiles++;
00862     }
00863 }
00864 
00865 struct addfileprovides_cbdata {
00866   int nfiles;
00867   Id *ids;
00868   char **dirs;
00869   char **names;
00870 
00871   Id *dids;
00872 
00873   Map providedids;
00874 
00875   Map useddirs;
00876 };
00877 
00878 static int
00879 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
00880 {
00881   struct addfileprovides_cbdata *cbd = cbdata;
00882   int i;
00883 
00884   if (!cbd->useddirs.size)
00885     {
00886       map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
00887       for (i = 0; i < cbd->nfiles; i++)
00888         {
00889           Id did;
00890           if (MAPTST(&cbd->providedids, cbd->ids[i]))
00891             {
00892               cbd->dids[i] = 0;
00893               continue;
00894             }
00895           did = repodata_str2dir(data, cbd->dirs[i], 0);
00896           cbd->dids[i] = did;
00897           if (did)
00898             MAPSET(&cbd->useddirs, did);
00899         }
00900     }
00901   if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
00902     return 0;
00903   for (i = 0; i < cbd->nfiles; i++)
00904     {
00905       if (cbd->dids[i] != value->id)
00906         continue;
00907       if (!strcmp(cbd->names[i], value->str))
00908         break;
00909     }
00910   if (i == cbd->nfiles)
00911     return 0;
00912   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
00913   return 0;
00914 }
00915 
00916 static void
00917 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
00918 {
00919   Id p;
00920   Repodata *data;
00921   Repo *repo;
00922   Queue fileprovidesq;
00923   int i, j, repoid, repodataid;
00924   int provstart, provend;
00925   Map donemap;
00926   int ndone, incomplete;
00927 
00928   if (!pool->nrepos)
00929     return;
00930 
00931   cbd->nfiles = sf->nfiles;
00932   cbd->ids = sf->ids;
00933   cbd->dirs = sf->dirs;
00934   cbd->names = sf->names;
00935   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
00936   map_init(&cbd->providedids, pool->ss.nstrings);
00937 
00938   repoid = 0;
00939   repo = repoonly ? repoonly : pool->repos[0];
00940   map_init(&donemap, pool->nsolvables);
00941   queue_init(&fileprovidesq);
00942   provstart = provend = 0;
00943   for (;;)
00944     {
00945       if (repo->disabled)
00946         {
00947           if (repoonly || ++repoid == pool->nrepos)
00948             break;
00949           repo = pool->repos[repoid];
00950           continue;
00951         }
00952       ndone = 0;
00953       for (data = repo->repodata, repodataid = 0; repodataid < repo->nrepodata; repodataid++, data++)
00954         {
00955           if (ndone >= repo->nsolvables)
00956             break;
00957 
00958           if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
00959             {
00960               map_empty(&cbd->providedids);
00961               for (i = 0; i < fileprovidesq.count; i++)
00962                 MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
00963               provstart = data->start;
00964               provend = data->end;
00965               for (i = 0; i < cbd->nfiles; i++)
00966                 if (!MAPTST(&cbd->providedids, cbd->ids[i]))
00967                   break;
00968               if (i == cbd->nfiles)
00969                 {
00970                   /* great! no need to search files */
00971                   for (p = data->start; p < data->end; p++)
00972                     if (pool->solvables[p].repo == repo)
00973                       {
00974                         if (MAPTST(&donemap, p))
00975                           continue;
00976                         MAPSET(&donemap, p);
00977                         ndone++;
00978                       }
00979                   continue;
00980                 }
00981             }
00982 
00983           if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
00984             continue;
00985 
00986           if (data->start < provstart || data->end > provend)
00987             {
00988               map_empty(&cbd->providedids);
00989               provstart = provend = 0;
00990             }
00991 
00992           /* check if the data is incomplete */
00993           incomplete = 0;
00994           if (data->state == REPODATA_AVAILABLE)
00995             {
00996               for (j = 1; j < data->nkeys; j++)
00997                 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
00998                   break;
00999               if (j < data->nkeys)
01000                 {
01001 #if 0
01002                   for (i = 0; i < cbd->nfiles; i++)
01003                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
01004                       printf("need complete filelist because of %s\n", id2str(pool, cbd->ids[i]));
01005 #endif
01006                   for (i = 0; i < cbd->nfiles; i++)
01007                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
01008                       break;
01009                   if (i < cbd->nfiles)
01010                     incomplete = 1;
01011                 }
01012             }
01013 
01014           /* do the search */
01015           map_init(&cbd->useddirs, 0);
01016           for (p = data->start; p < data->end; p++)
01017             if (pool->solvables[p].repo == repo)
01018               {
01019                 if (MAPTST(&donemap, p))
01020                   continue;
01021                 repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
01022                 if (!incomplete)
01023                   {
01024                     MAPSET(&donemap, p);
01025                     ndone++;
01026                   }
01027               }
01028           map_free(&cbd->useddirs);
01029         }
01030 
01031       if (repoonly || ++repoid == pool->nrepos)
01032         break;
01033       repo = pool->repos[repoid];
01034     }
01035   map_free(&donemap);
01036   queue_free(&fileprovidesq);
01037   map_free(&cbd->providedids);
01038 }
01039 
01040 void
01041 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
01042 {
01043   Solvable *s;
01044   Repo *repo;
01045   struct searchfiles sf, isf, *isfp;
01046   struct addfileprovides_cbdata cbd;
01047   int i;
01048   unsigned int now;
01049 
01050   now = sat_timems(0);
01051   memset(&sf, 0, sizeof(sf));
01052   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
01053   memset(&isf, 0, sizeof(isf));
01054   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
01055 
01056   isfp = installed ? &isf : 0;
01057   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
01058     {
01059       repo = s->repo;
01060       if (!repo)
01061         continue;
01062       if (s->obsoletes)
01063         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
01064       if (s->conflicts)
01065         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
01066       if (s->requires)
01067         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
01068       if (s->recommends)
01069         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
01070       if (s->suggests)
01071         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
01072       if (s->supplements)
01073         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
01074       if (s->enhances)
01075         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
01076     }
01077   map_free(&sf.seen);
01078   map_free(&isf.seen);
01079   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
01080   cbd.dids = 0;
01081   if (idp)
01082     *idp = 0;
01083   if (sf.nfiles)
01084     {
01085 #if 0
01086       for (i = 0; i < sf.nfiles; i++)
01087         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
01088 #endif
01089       pool_addfileprovides_search(pool, &cbd, &sf, 0);
01090       if (idp)
01091         {
01092           sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
01093           sf.ids[sf.nfiles] = 0;
01094           *idp = sf.ids;
01095           sf.ids = 0;
01096         }
01097       sat_free(sf.ids);
01098       for (i = 0; i < sf.nfiles; i++)
01099         {
01100           sat_free(sf.dirs[i]);
01101           sat_free(sf.names[i]);
01102         }
01103       sat_free(sf.dirs);
01104       sat_free(sf.names);
01105     }
01106   if (isf.nfiles)
01107     {
01108 #if 0
01109       for (i = 0; i < isf.nfiles; i++)
01110         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
01111 #endif
01112       if (installed)
01113         pool_addfileprovides_search(pool, &cbd, &isf, installed);
01114       sat_free(isf.ids);
01115       for (i = 0; i < isf.nfiles; i++)
01116         {
01117           sat_free(isf.dirs[i]);
01118           sat_free(isf.names[i]);
01119         }
01120       sat_free(isf.dirs);
01121       sat_free(isf.names);
01122     }
01123   sat_free(cbd.dids);
01124   pool_freewhatprovides(pool);  /* as we have added provides */
01125   POOL_DEBUG(SAT_DEBUG_STATS, "addfileprovides took %d ms\n", sat_timems(now));
01126 }
01127 
01128 void
01129 pool_addfileprovides(Pool *pool)
01130 {
01131   pool_addfileprovides_ids(pool, pool->installed, 0);
01132 }
01133 
01134 void
01135 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)
01136 {
01137   if (p)
01138     {
01139       if (pool->solvables[p].repo)
01140         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
01141       return;
01142     }
01143   /* FIXME: obey callback return value! */
01144   for (p = 1; p < pool->nsolvables; p++)
01145     if (pool->solvables[p].repo)
01146       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
01147 }
01148 
01149 void
01150 pool_clear_pos(Pool *pool)
01151 {
01152   memset(&pool->pos, 0, sizeof(pool->pos));
01153 }
01154 
01155 
01156 void
01157 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
01158 {
01159   int i;
01160 
01161   pool->languagecache = sat_free(pool->languagecache);
01162   pool->languagecacheother = 0;
01163   if (pool->nlanguages)
01164     {
01165       for (i = 0; i < pool->nlanguages; i++)
01166         free((char *)pool->languages[i]);
01167       free(pool->languages);
01168     }
01169   pool->nlanguages = nlanguages;
01170   if (!nlanguages)
01171     return;
01172   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
01173   for (i = 0; i < pool->nlanguages; i++)
01174     pool->languages[i] = strdup(languages[i]);
01175 }
01176 
01177 Id
01178 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
01179 {
01180   const char *n;
01181   char buf[256], *p;
01182   int l;
01183 
01184   if (!lang)
01185     return id;
01186   n = id2str(pool, id);
01187   l = strlen(n) + strlen(lang) + 2;
01188   if (l > sizeof(buf))
01189     p = sat_malloc(strlen(n) + strlen(lang) + 2);
01190   else
01191     p = buf;
01192   sprintf(p, "%s:%s", n, lang);
01193   id = str2id(pool, p, create);
01194   if (p != buf)
01195     free(p);
01196   return id;
01197 }
01198 
01199 char *
01200 pool_alloctmpspace(Pool *pool, int len)
01201 {
01202   int n = pool->tmpspacen;
01203   if (!len)
01204     return 0;
01205   if (len > pool->tmpspacelen[n])
01206     {
01207       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
01208       pool->tmpspacelen[n] = len + 32;
01209     }
01210   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
01211   return pool->tmpspacebuf[n];
01212 }
01213 
01214 char *
01215 pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3)
01216 {
01217   int l1, l2, l3;
01218   char *s, *str;
01219   l1 = str1 ? strlen(str1) : 0;
01220   l2 = str2 ? strlen(str2) : 0;
01221   l3 = str3 ? strlen(str3) : 0;
01222   s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
01223   if (l1)
01224     {
01225       strcpy(s, str1);
01226       s += l1;
01227     }
01228   if (l2)
01229     {
01230       strcpy(s, str2);
01231       s += l2;
01232     }
01233   if (l3)
01234     {
01235       strcpy(s, str3);
01236       s += l3;
01237     }
01238   *s = 0;
01239   return str;
01240 }
01241 
01242 
01243 /*******************************************************************/
01244 
01245 struct mptree {
01246   Id sibling;
01247   Id child;
01248   const char *comp;
01249   int compl;
01250   Id mountpoint;
01251 };
01252 
01253 struct ducbdata {
01254   DUChanges *mps;
01255   struct mptree *mptree;
01256   int addsub;
01257   int hasdu;
01258 
01259   Id *dirmap;
01260   int nmap;
01261   Repodata *olddata;
01262 };
01263 
01264 
01265 static int
01266 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
01267 {
01268   struct ducbdata *cbd = cbdata;
01269   Id mp;
01270 
01271   if (data != cbd->olddata)
01272     {
01273       Id dn, mp, comp, *dirmap, *dirs;
01274       int i, compl;
01275       const char *compstr;
01276       struct mptree *mptree;
01277 
01278       /* create map from dir to mptree */
01279       cbd->dirmap = sat_free(cbd->dirmap);
01280       cbd->nmap = 0;
01281       dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
01282       mptree = cbd->mptree;
01283       mp = 0;
01284       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
01285         {
01286           comp = *dirs++;
01287           if (comp <= 0)
01288             {
01289               mp = dirmap[-comp];
01290               continue;
01291             }
01292           if (mp < 0)
01293             {
01294               /* unconnected */
01295               dirmap[dn] = mp;
01296               continue;
01297             }
01298           if (!mptree[mp].child)
01299             {
01300               dirmap[dn] = -mp;
01301               continue;
01302             }
01303           if (data->localpool)
01304             compstr = stringpool_id2str(&data->spool, comp);
01305           else
01306             compstr = id2str(data->repo->pool, comp);
01307           compl = strlen(compstr);
01308           for (i = mptree[mp].child; i; i = mptree[i].sibling)
01309             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
01310               break;
01311           dirmap[dn] = i ? i : -mp;
01312         }
01313       /* change dirmap to point to mountpoint instead of mptree */
01314       for (dn = 0; dn < data->dirpool.ndirs; dn++)
01315         {
01316           mp = dirmap[dn];
01317           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
01318         }
01319       cbd->dirmap = dirmap;
01320       cbd->nmap = data->dirpool.ndirs;
01321       cbd->olddata = data;
01322     }
01323   cbd->hasdu = 1;
01324   if (value->id < 0 || value->id >= cbd->nmap)
01325     return 0;
01326   mp = cbd->dirmap[value->id];
01327   if (mp < 0)
01328     return 0;
01329   if (cbd->addsub > 0)
01330     {
01331       cbd->mps[mp].kbytes += value->num;
01332       cbd->mps[mp].files += value->num2;
01333     }
01334   else
01335     {
01336       cbd->mps[mp].kbytes -= value->num;
01337       cbd->mps[mp].files -= value->num2;
01338     }
01339   return 0;
01340 }
01341 
01342 static void
01343 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
01344 {
01345   int i;
01346   if (mptree[pos].mountpoint == -1)
01347     mptree[pos].mountpoint = mountpoint;
01348   else
01349     mountpoint = mptree[pos].mountpoint;
01350   for (i = mptree[pos].child; i; i = mptree[i].sibling)
01351     propagate_mountpoints(mptree, i, mountpoint);
01352 }
01353 
01354 #define MPTREE_BLOCK 15
01355 
01356 void
01357 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
01358 {
01359   char *p;
01360   const char *path, *compstr;
01361   struct mptree *mptree;
01362   int i, nmptree;
01363   int pos, compl;
01364   int mp;
01365   struct ducbdata cbd;
01366   Solvable *s;
01367   Id sp;
01368   Map ignoredu;
01369   Repo *oldinstalled = pool->installed;
01370 
01371   memset(&ignoredu, 0, sizeof(ignoredu));
01372   cbd.mps = mps;
01373   cbd.addsub = 0;
01374   cbd.dirmap = 0;
01375   cbd.nmap = 0;
01376   cbd.olddata = 0;
01377 
01378   mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
01379 
01380   /* our root node */
01381   mptree[0].sibling = 0;
01382   mptree[0].child = 0;
01383   mptree[0].comp = 0;
01384   mptree[0].compl = 0;
01385   mptree[0].mountpoint = -1;
01386   nmptree = 1;
01387   
01388   /* create component tree */
01389   for (mp = 0; mp < nmps; mp++)
01390     {
01391       mps[mp].kbytes = 0;
01392       mps[mp].files = 0;
01393       pos = 0;
01394       path = mps[mp].path;
01395       while(*path == '/')
01396         path++;
01397       while (*path)
01398         {
01399           if ((p = strchr(path, '/')) == 0)
01400             {
01401               compstr = path;
01402               compl = strlen(compstr);
01403               path += compl;
01404             }
01405           else
01406             {
01407               compstr = path;
01408               compl = p - path;
01409               path = p + 1;
01410               while(*path == '/')
01411                 path++;
01412             }
01413           for (i = mptree[pos].child; i; i = mptree[i].sibling)
01414             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
01415               break;
01416           if (!i)
01417             {
01418               /* create new node */
01419               mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
01420               i = nmptree++;
01421               mptree[i].sibling = mptree[pos].child;
01422               mptree[i].child = 0;
01423               mptree[i].comp = compstr;
01424               mptree[i].compl = compl;
01425               mptree[i].mountpoint = -1;
01426               mptree[pos].child = i;
01427             }
01428           pos = i;
01429         }
01430       mptree[pos].mountpoint = mp;
01431     }
01432 
01433   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
01434 
01435 #if 0
01436   for (i = 0; i < nmptree; i++)
01437     {
01438       printf("#%d sibling: %d\n", i, mptree[i].sibling);
01439       printf("#%d child: %d\n", i, mptree[i].child);
01440       printf("#%d comp: %s\n", i, mptree[i].comp);
01441       printf("#%d compl: %d\n", i, mptree[i].compl);
01442       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
01443     }
01444 #endif
01445 
01446   cbd.mptree = mptree;
01447   cbd.addsub = 1;
01448   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
01449     {
01450       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
01451         continue;
01452       if (!MAPTST(installedmap, sp))
01453         continue;
01454       cbd.hasdu = 0;
01455       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
01456       if (!cbd.hasdu && oldinstalled)
01457         {
01458           Id op, opp;
01459           /* no du data available, ignore data of all installed solvables we obsolete */
01460           if (!ignoredu.map)
01461             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
01462           if (s->obsoletes)
01463             {
01464               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
01465               while ((obs = *obsp++) != 0)
01466                 FOR_PROVIDES(op, opp, obs)
01467                   if (op >= oldinstalled->start && op < oldinstalled->end)
01468                     MAPSET(&ignoredu, op - oldinstalled->start);
01469             }
01470           FOR_PROVIDES(op, opp, s->name)
01471             if (pool->solvables[op].name == s->name)
01472               if (op >= oldinstalled->start && op < oldinstalled->end)
01473                 MAPSET(&ignoredu, op - oldinstalled->start);
01474         }
01475     }
01476   cbd.addsub = -1;
01477   if (oldinstalled)
01478     {
01479       /* assumes we allways have du data for installed solvables */
01480       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
01481         {
01482           if (MAPTST(installedmap, sp))
01483             continue;
01484           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
01485             continue;
01486           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
01487         }
01488     }
01489   if (ignoredu.map)
01490     map_free(&ignoredu);
01491   sat_free(cbd.dirmap);
01492   sat_free(mptree);
01493 }
01494 
01495 int
01496 pool_calc_installsizechange(Pool *pool, Map *installedmap)
01497 {
01498   Id sp;
01499   Solvable *s;
01500   int change = 0;
01501   Repo *oldinstalled = pool->installed;
01502 
01503   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
01504     {
01505       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
01506         continue;
01507       if (!MAPTST(installedmap, sp))
01508         continue;
01509       change += solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
01510     }
01511   if (oldinstalled)
01512     {
01513       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
01514         {
01515           if (MAPTST(installedmap, sp))
01516             continue;
01517           change -= solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
01518         }
01519     }
01520   return change;
01521 }
01522 
01523 /* map:
01524  *  1: installed
01525  *  2: conflicts with installed
01526  *  8: interesting (only true if installed)
01527  * 16: undecided
01528  */
01529  
01530 static inline Id dep2name(Pool *pool, Id dep)
01531 {
01532   while (ISRELDEP(dep))
01533     {
01534       Reldep *rd = rd = GETRELDEP(pool, dep);
01535       dep = rd->name;
01536     }
01537   return dep;
01538 }
01539 
01540 static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con) 
01541 {
01542   Id p, pp;
01543   Solvable *sn = pool->solvables + n; 
01544 
01545   FOR_PROVIDES(p, pp, sn->name)
01546     {    
01547       Solvable *s = pool->solvables + p; 
01548       if (s->name != sn->name || s->arch != sn->arch)
01549         continue;
01550       if ((map[p] & 9) != 9)
01551         continue;
01552       if (pool_match_nevr(pool, pool->solvables + p, con))
01553         continue;
01554       return 1;         /* found installed package that doesn't conflict */
01555     }
01556   return 0;
01557 }
01558 
01559 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *noobsoletesmap)
01560 {
01561   Id p, pp;
01562   int r = 0;
01563   FOR_PROVIDES(p, pp, dep)
01564     {
01565       if (p == SYSTEMSOLVABLE)
01566         return 1;       /* always boring, as never constraining */
01567       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
01568         continue;
01569       if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep))
01570         if (providedbyinstalled_multiversion(pool, map, p, dep))
01571           continue;
01572       if ((map[p] & 9) == 9)
01573         return 9;
01574       r |= map[p] & 17;
01575     }
01576   return r;
01577 }
01578 
01579 /*
01580  * pool_trivial_installable - calculate if a set of solvables is
01581  * trivial installable without any other installs/deinstalls of
01582  * packages not belonging to the set.
01583  *
01584  * the state is returned in the result queue:
01585  * 1:  solvable is installable without any other package changes
01586  * 0:  solvable is not installable
01587  * -1: solvable is installable, but doesn't constrain any installed packages
01588  */
01589 
01590 void
01591 pool_trivial_installable_noobsoletesmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *noobsoletesmap)
01592 {
01593   int i, r, m, did;
01594   Id p, *dp, con, *conp, req, *reqp;
01595   unsigned char *map;
01596   Solvable *s;
01597 
01598   map = sat_calloc(pool->nsolvables, 1);
01599   for (p = 1; p < pool->nsolvables; p++)
01600     {
01601       if (!MAPTST(installedmap, p))
01602         continue;
01603       map[p] |= 9;
01604       s = pool->solvables + p;
01605       if (!s->conflicts)
01606         continue;
01607       conp = s->repo->idarraydata + s->conflicts;
01608       while ((con = *conp++) != 0)
01609         {
01610           dp = pool_whatprovides_ptr(pool, con);
01611           for (; *dp; dp++)
01612             map[p] |= 2;        /* XXX: self conflict ? */
01613         }
01614     }
01615   for (i = 0; i < pkgs->count; i++)
01616     map[pkgs->elements[i]] = 16;
01617 
01618   for (i = 0, did = 0; did < pkgs->count; i++, did++)
01619     {
01620       if (i == pkgs->count)
01621         i = 0;
01622       p = pkgs->elements[i];
01623       if ((map[p] & 16) == 0)
01624         continue;
01625       if ((map[p] & 2) != 0)
01626         {
01627           map[p] = 2;
01628           continue;
01629         }
01630       s = pool->solvables + p;
01631       m = 1;
01632       if (s->requires)
01633         {
01634           reqp = s->repo->idarraydata + s->requires;
01635           while ((req = *reqp++) != 0)
01636             {
01637               if (req == SOLVABLE_PREREQMARKER)
01638                 continue;
01639               r = providedbyinstalled(pool, map, req, 0, 0);
01640               if (!r)
01641                 {
01642                   /* decided and miss */
01643                   map[p] = 2;
01644                   break;
01645                 }
01646               m |= r;   /* 1 | 9 | 16 | 17 */
01647             }
01648           if (req)
01649             continue;
01650           if ((m & 9) == 9)
01651             m = 9;
01652         }
01653       if (s->conflicts)
01654         {
01655           int ispatch = 0;      /* see solver.c patch handling */
01656 
01657           if (!strncmp("patch:", id2str(pool, s->name), 6))
01658             ispatch = 1;
01659           conp = s->repo->idarraydata + s->conflicts;
01660           while ((con = *conp++) != 0)
01661             {
01662               if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
01663                 {
01664                   map[p] = 2;
01665                   break;
01666                 }
01667               if ((m == 1 || m == 17) && ISRELDEP(con))
01668                 {
01669                   con = dep2name(pool, con);
01670                   if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
01671                     m = 9;
01672                 }
01673             }
01674           if (con)
01675             continue;   /* found a conflict */
01676         }
01677 #if 0
01678       if (s->repo && s->repo != oldinstalled)
01679         {
01680           Id p2, obs, *obsp, *pp;
01681           Solvable *s2;
01682           if (s->obsoletes)
01683             {
01684               obsp = s->repo->idarraydata + s->obsoletes;
01685               while ((obs = *obsp++) != 0)
01686                 {
01687                   if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
01688                     {
01689                       map[p] = 2;
01690                       break;
01691                     }
01692                 }
01693               if (obs)
01694                 continue;
01695             }
01696           FOR_PROVIDES(p2, pp, s->name)
01697             {
01698               s2 = pool->solvables + p2;
01699               if (s2->name == s->name && (map[p2] & 1) != 0)
01700                 {
01701                   map[p] = 2;
01702                   break;
01703                 }
01704             }
01705           if (p2)
01706             continue;
01707         }
01708 #endif
01709       if (m != map[p])
01710         {
01711           map[p] = m;
01712           did = 0;
01713         }
01714     }
01715   queue_free(res);
01716   queue_init_clone(res, pkgs);
01717   for (i = 0; i < pkgs->count; i++)
01718     {
01719       m = map[pkgs->elements[i]];
01720       if ((m & 9) == 9)
01721         r = 1;
01722       else if (m & 1)
01723         r = -1;
01724       else
01725         r = 0;
01726       res->elements[i] = r;
01727     }
01728   free(map);
01729 }
01730 
01731 void
01732 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
01733 {
01734   pool_trivial_installable_noobsoletesmap(pool, installedmap, pkgs, res, 0);
01735 }
01736 
01737 const char *
01738 pool_lookup_str(Pool *pool, Id entry, Id keyname)
01739 {
01740   if (entry == SOLVID_POS && pool->pos.repo)
01741     return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
01742   if (entry <= 0)
01743     return 0;
01744   return solvable_lookup_str(pool->solvables + entry, keyname);
01745 }
01746 
01747 Id
01748 pool_lookup_id(Pool *pool, Id entry, Id keyname)
01749 {
01750   if (entry == SOLVID_POS && pool->pos.repo)
01751     {
01752       Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
01753       Id id = repodata_lookup_id(data, SOLVID_POS, keyname);
01754       return data->localpool ? repodata_globalize_id(data, id, 1) : id;
01755     }
01756   if (entry <= 0)
01757     return 0;
01758   return solvable_lookup_id(pool->solvables + entry, keyname);
01759 }
01760 
01761 unsigned int
01762 pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned int notfound)
01763 {
01764   if (entry == SOLVID_POS && pool->pos.repo)
01765     {
01766       unsigned int value;
01767       if (repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, &value))
01768         return value;
01769       return notfound;
01770     }
01771   if (entry <= 0)
01772     return notfound;
01773   return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
01774 }
01775 
01776 int
01777 pool_lookup_void(Pool *pool, Id entry, Id keyname)
01778 {
01779   if (entry == SOLVID_POS && pool->pos.repo)
01780     return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
01781   if (entry <= 0)
01782     return 0;
01783   return solvable_lookup_void(pool->solvables + entry, keyname);
01784 }
01785 
01786 const unsigned char *
01787 pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
01788 {
01789   if (entry == SOLVID_POS && pool->pos.repo)
01790     return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
01791   if (entry <= 0)
01792     return 0;
01793   return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
01794 }
01795 
01796 const char *
01797 pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
01798 {
01799   if (entry == SOLVID_POS && pool->pos.repo)
01800     {
01801       const unsigned char *chk = repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
01802       return chk ? repodata_chk2str(pool->pos.repo->repodata + pool->pos.repodataid, *typep, chk) : 0;
01803     }
01804   if (entry <= 0)
01805     return 0;
01806   return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
01807 }
01808 
01809 void
01810 pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
01811 {
01812   int hadhashes = pool->relhashtbl ? 1 : 0;
01813   Solvable *s;
01814   Id fn, p, q, md5;
01815   Id id;
01816   int i;
01817 
01818   if (!conflicts->count)
01819     return;
01820   pool_freewhatprovides(pool);
01821   for (i = 0; i < conflicts->count; i += 5)
01822     {
01823       fn = conflicts->elements[i];
01824       p = conflicts->elements[i + 1];
01825       md5 = conflicts->elements[i + 2];
01826       q = conflicts->elements[i + 3];
01827       id = rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
01828       s = pool->solvables + p;
01829       if (!s->repo)
01830         continue;
01831       s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
01832       s = pool->solvables + q;
01833       if (!s->repo)
01834         continue;
01835       s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
01836     }
01837   if (!hadhashes)
01838     pool_freeidhashes(pool);
01839 }
01840 
01841 /* EOF */
Generated on Mon Dec 12 11:44:12 2011 for satsolver by  doxygen 1.6.3