- frontport solver_trivial_installable() change
[platform/upstream/libsolv.git] / src / pool.c
1 /*
2  * Copyright (c) 2007-2009, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * pool.c
10  * 
11  * The pool contains information about solvables
12  * stored optimized for memory consumption and fast retrieval.
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <unistd.h>
19 #include <string.h>
20
21 #include "pool.h"
22 #include "repo.h"
23 #include "poolid.h"
24 #include "poolid_private.h"
25 #include "poolarch.h"
26 #include "util.h"
27 #include "bitmap.h"
28 #include "evr.h"
29
30 #define SOLVABLE_BLOCK  255
31
32 #define KNOWNID_INITIALIZE
33 #include "knownid.h"
34 #undef KNOWNID_INITIALIZE
35
36 /* create pool */
37 Pool *
38 pool_create(void)
39 {
40   Pool *pool;
41   Solvable *s;
42
43   pool = (Pool *)sat_calloc(1, sizeof(*pool));
44
45   stringpool_init (&pool->ss, initpool_data);
46
47   /* alloc space for RelDep 0 */
48   pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
49   pool->nrels = 1;
50   memset(pool->rels, 0, sizeof(Reldep));
51
52   /* alloc space for Solvable 0 and system solvable */
53   pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
54   pool->nsolvables = 2;
55   memset(pool->solvables, 0, 2 * sizeof(Solvable));
56   s = pool->solvables + SYSTEMSOLVABLE;
57   s->name = SYSTEM_SYSTEM;
58   s->arch = ARCH_NOARCH;
59   s->evr = ID_EMPTY;
60
61   queue_init(&pool->vendormap);
62
63   pool->debugmask = SAT_DEBUG_RESULT;   /* FIXME */
64   return pool;
65 }
66
67
68 /* free all the resources of our pool */
69 void
70 pool_free(Pool *pool)
71 {
72   int i;
73
74   pool_freewhatprovides(pool);
75   pool_freeidhashes(pool);
76   repo_freeallrepos(pool, 1);
77   sat_free(pool->id2arch);
78   sat_free(pool->solvables);
79   stringpool_free(&pool->ss);
80   sat_free(pool->rels);
81   queue_free(&pool->vendormap);
82   for (i = 0; i < POOL_TMPSPACEBUF; i++)
83     sat_free(pool->tmpspacebuf[i]);
84   for (i = 0; i < pool->nlanguages; i++)
85     free((char *)pool->languages[i]);
86   sat_free(pool->languages);
87   sat_free(pool->languagecache);
88   sat_free(pool);
89 }
90
91 Id
92 pool_add_solvable(Pool *pool)
93 {
94   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
95   memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
96   return pool->nsolvables++;
97 }
98
99 Id
100 pool_add_solvable_block(Pool *pool, int count)
101 {
102   Id nsolvables = pool->nsolvables;
103   if (!count)
104     return nsolvables;
105   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
106   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
107   pool->nsolvables += count;
108   return nsolvables;
109 }
110
111 void
112 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
113 {
114   if (!count)
115     return;
116   if (reuseids && start + count == pool->nsolvables)
117     {
118       /* might want to shrink solvable array */
119       pool->nsolvables = start;
120       return;
121     }
122   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
123 }
124
125
126 void
127 pool_set_installed(Pool *pool, Repo *installed)
128 {
129   if (pool->installed == installed)
130     return;
131   pool->installed = installed;
132   pool_freewhatprovides(pool);
133 }
134
135 static Pool *pool_shrink_whatprovides_sortcmp_data;
136
137 static int
138 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp)
139 {
140   int r;
141   Pool *pool = pool_shrink_whatprovides_sortcmp_data;
142   Id oa, ob, *da, *db;
143   oa = pool->whatprovides[*(Id *)ap];
144   ob = pool->whatprovides[*(Id *)bp];
145   if (oa == ob)
146     return *(Id *)ap - *(Id *)bp;
147   if (!oa)
148     return -1;
149   if (!ob)
150     return 1;
151   da = pool->whatprovidesdata + oa;
152   db = pool->whatprovidesdata + ob;
153   while (*db)
154     if ((r = (*da++ - *db++)) != 0)
155       return r;
156   if (*da)
157     return *da;
158   return *(Id *)ap - *(Id *)bp;
159 }
160
161 /*
162  * pool_shrink_whatprovides  - unify whatprovides data
163  *
164  * whatprovides_rel must be empty for this to work!
165  *
166  */
167 static void
168 pool_shrink_whatprovides(Pool *pool)
169 {
170   Id i, id;
171   Id *sorted;
172   Id lastid, *last, *dp, *lp;
173   Offset o;
174   int r;
175
176   if (pool->ss.nstrings < 3)
177     return;
178   sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id));
179   for (id = 0; id < pool->ss.nstrings; id++)
180     sorted[id] = id;
181   pool_shrink_whatprovides_sortcmp_data = pool;
182   qsort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp);
183   last = 0;
184   lastid = 0;
185   for (i = 1; i < pool->ss.nstrings; i++)
186     {
187       id = sorted[i];
188       o = pool->whatprovides[id];
189       if (o == 0 || o == 1)
190         continue;
191       dp = pool->whatprovidesdata + o;
192       if (last)
193         {
194           lp = last;
195           while (*dp)   
196             if (*dp++ != *lp++)
197               {
198                 last = 0;
199                 break;
200               }
201           if (last && *lp)
202             last = 0;
203           if (last)
204             {
205               pool->whatprovides[id] = -lastid;
206               continue;
207             }
208         }
209       last = pool->whatprovidesdata + o;
210       lastid = id;
211     }
212   sat_free(sorted);
213   dp = pool->whatprovidesdata + 2;
214   for (id = 1; id < pool->ss.nstrings; id++)
215     {
216       o = pool->whatprovides[id];
217       if (o == 0 || o == 1)
218         continue;
219       if ((Id)o < 0)
220         {
221           i = -(Id)o;
222           if (i >= id)
223             abort();
224           pool->whatprovides[id] = pool->whatprovides[i];
225           continue;
226         }
227       lp = pool->whatprovidesdata + o;
228       if (lp < dp)
229         abort();
230       pool->whatprovides[id] = dp - pool->whatprovidesdata;
231       while ((*dp++ = *lp++) != 0)
232         ;
233     }
234   o = dp - pool->whatprovidesdata;
235   POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
236   if (pool->whatprovidesdataoff == o)
237     return;
238   r = pool->whatprovidesdataoff - o;
239   pool->whatprovidesdataoff = o;
240   pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
241   if (r > pool->whatprovidesdataleft)
242     r = pool->whatprovidesdataleft;
243   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
244 }
245
246
247 /*
248  * pool_createwhatprovides()
249  * 
250  * create hashes over pool of solvables to ease provide lookups
251  * 
252  */
253 void
254 pool_createwhatprovides(Pool *pool)
255 {
256   int i, num, np, extra;
257   Offset off;
258   Solvable *s;
259   Id id;
260   Offset *idp, n;
261   Offset *whatprovides;
262   Id *whatprovidesdata, *d;
263   Repo *installed = pool->installed;
264   unsigned int now;
265
266   now = sat_timems(0);
267   POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables);
268   POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
269
270   pool_freeidhashes(pool);      /* XXX: should not be here! */
271   pool_freewhatprovides(pool);
272   num = pool->ss.nstrings;
273   pool->whatprovides = whatprovides = sat_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
274   pool->whatprovides_rel = sat_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
275
276   /* count providers for each name */
277   for (i = 1; i < pool->nsolvables; i++)
278     {
279       Id *pp;
280       s = pool->solvables + i;
281       if (!s->provides)
282         continue;
283       /* we always need the installed solvable in the whatprovides data,
284          otherwise obsoletes/conflicts on them won't work */
285       if (s->repo != installed && !pool_installable(pool, s))
286         continue;
287       pp = s->repo->idarraydata + s->provides;
288       while ((id = *pp++) != ID_NULL)
289         {
290           while (ISRELDEP(id))
291             {
292               Reldep *rd = GETRELDEP(pool, id);
293               id = rd->name;
294             }
295           whatprovides[id]++;          /* inc count of providers */
296         }
297     }
298
299   off = 2;      /* first entry is undef, second is empty list */
300   idp = whatprovides;
301   np = 0;                              /* number of names provided */
302   for (i = 0; i < num; i++, idp++)
303     {
304       n = *idp;
305       if (!n)                          /* no providers */
306         continue;
307       *idp = off;                      /* move from counts to offsets into whatprovidesdata */
308       off += n + 1;                    /* make space for all providers + terminating ID_NULL */
309       np++;                            /* inc # of provider 'slots' */
310     }
311
312   POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
313
314   /* reserve some space for relation data */
315   extra = 2 * pool->nrels;
316   if (extra < 256)
317     extra = 256;
318
319   POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
320
321   /* alloc space for all providers + extra */
322   whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
323
324   /* now fill data for all provides */
325   for (i = 1; i < pool->nsolvables; i++)
326     {
327       Id *pp;
328       s = pool->solvables + i;
329       if (!s->provides)
330         continue;
331       if (s->repo != installed && !pool_installable(pool, s))
332         continue;
333
334       /* for all provides of this solvable */
335       pp = s->repo->idarraydata + s->provides;
336       while ((id = *pp++) != 0)
337         {
338           while (ISRELDEP(id))
339             {
340               Reldep *rd = GETRELDEP(pool, id);
341               id = rd->name;
342             }
343           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
344           if (*d)
345             {
346               d++;
347               while (*d)               /* find free slot */
348                 d++;
349               if (d[-1] == i)          /* solvable already tacked at end ? */
350                 continue;              /* Y: skip, on to next provides */
351             }
352           *d = i;                      /* put solvable Id into data */
353         }
354     }
355   pool->whatprovidesdata = whatprovidesdata;
356   pool->whatprovidesdataoff = off;
357   pool->whatprovidesdataleft = extra;
358   pool_shrink_whatprovides(pool);
359   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)));
360   POOL_DEBUG(SAT_DEBUG_STATS, "createwhatprovides took %d ms\n", sat_timems(now));
361 }
362
363 /*
364  * free all of our whatprovides data
365  * be careful, everything internalized with pool_queuetowhatprovides is gone, too
366  */
367 void
368 pool_freewhatprovides(Pool *pool)
369 {
370   pool->whatprovides = sat_free(pool->whatprovides);
371   pool->whatprovides_rel = sat_free(pool->whatprovides_rel);
372   pool->whatprovidesdata = sat_free(pool->whatprovidesdata);
373   pool->whatprovidesdataoff = 0;
374   pool->whatprovidesdataleft = 0;
375 }
376
377
378 /******************************************************************************/
379
380 /*
381  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
382  * 
383  * on-demand filling of provider information
384  * move queue data into whatprovidesdata
385  * q: queue of Ids
386  * returns: Offset into whatprovides
387  *
388  */
389 Id
390 pool_queuetowhatprovides(Pool *pool, Queue *q)
391 {
392   Offset off;
393   int count = q->count;
394
395   if (count == 0)                      /* queue empty -> 1 */
396     return 1;
397
398   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
399   if (pool->whatprovidesdataleft < count + 1)
400     {
401       POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n");
402       pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
403       pool->whatprovidesdataleft = count + 4096;
404     }
405
406   /* copy queue to next free slot */
407   off = pool->whatprovidesdataoff;
408   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
409
410   /* adapt count and ID_NULL-terminate */
411   pool->whatprovidesdataoff += count;
412   pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
413   pool->whatprovidesdataleft -= count + 1;
414
415   return (Id)off;
416 }
417
418
419 /*************************************************************************/
420
421 /* check if a package's nevr matches a dependency */
422
423 int
424 pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
425 {
426   Reldep *rd = GETRELDEP(pool, d);
427   Id name = rd->name;
428   Id evr = rd->evr;
429   int flags = rd->flags;
430
431   if (flags > 7)
432     {
433       switch (flags)
434         {
435         case REL_ARCH:
436           if (s->arch != evr)
437             return 0;
438           return pool_match_nevr(pool, s, name);
439         case REL_OR:
440           if (pool_match_nevr(pool, s, name))
441             return 1;
442           return pool_match_nevr(pool, s, evr);
443         case REL_AND:
444         case REL_WITH:
445           if (!pool_match_nevr(pool, s, name))
446             return 0;
447           return pool_match_nevr(pool, s, evr);
448         default:
449           return 0;
450         }
451     }
452   if (!pool_match_nevr(pool, s, name))
453     return 0;
454   if (evr == s->evr)
455     return flags & 2 ? 1 : 0;
456   if (!flags)
457     return 0;
458   if (flags == 7)
459     return 1;
460   if (flags != 2 && flags != 5)
461     flags ^= 5;
462   if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
463     return 1;
464   return 0;
465 }
466
467 /*
468  * addrelproviders
469  * 
470  * add packages fulfilling the relation to whatprovides array
471  * no exact providers, do range match
472  * 
473  */
474
475 Id
476 pool_addrelproviders(Pool *pool, Id d)
477 {
478   Reldep *rd = GETRELDEP(pool, d);
479   Reldep *prd;
480   Queue plist;
481   Id buf[16];
482   Id name = rd->name;
483   Id evr = rd->evr;
484   int flags = rd->flags;
485   Id pid, *pidp;
486   Id p, wp, *pp, *pp2, *pp3;
487
488   d = GETRELID(d);
489   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
490   switch (flags)
491     {
492     case REL_AND:
493     case REL_WITH:
494       pp = pool_whatprovides_ptr(pool, name);
495       pp2 = pool_whatprovides_ptr(pool, evr);
496       while ((p = *pp++) != 0)
497         {
498           for (pp3 = pp2; *pp3;)
499             if (*pp3++ == p)
500               {
501                 queue_push(&plist, p);
502                 break;
503               }
504         }
505       break;
506     case REL_OR:
507       pp = pool_whatprovides_ptr(pool, name);
508       while ((p = *pp++) != 0)
509         queue_push(&plist, p);
510       pp = pool_whatprovides_ptr(pool, evr);
511       while ((p = *pp++) != 0)
512         queue_pushunique(&plist, p);
513       break;
514     case REL_NAMESPACE:
515       if (name == NAMESPACE_OTHERPROVIDERS)
516         {
517           wp = pool_whatprovides(pool, evr);
518           pool->whatprovides_rel[d] = wp;
519           return wp;
520         }
521       if (pool->nscallback)
522         {
523           /* ask callback which packages provide the dependency
524            * 0:  none
525            * 1:  the system (aka SYSTEMSOLVABLE)
526            * >1: a set of packages, stored as offset on whatprovidesdata
527            */
528           p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
529           if (p > 1)
530             {
531               queue_free(&plist);
532               pool->whatprovides_rel[d] = p;
533               return p;
534             }
535           if (p == 1)
536             queue_push(&plist, SYSTEMSOLVABLE);
537         }
538       break;
539     case REL_ARCH:
540       /* small hack: make it possible to match <pkg>.src
541        * we have to iterate over the solvables as src packages do not
542        * provide anything, thus they are not indexed in our
543        * whatprovides hash */
544       if (evr == ARCH_SRC)
545         {
546           Solvable *s;
547           for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
548             {
549               if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
550                 continue;
551               if (pool_match_nevr(pool, s, name))
552                 queue_push(&plist, p);
553             }
554           break;
555         }
556       wp = pool_whatprovides(pool, name);
557       pp = pool->whatprovidesdata + wp;
558       while ((p = *pp++) != 0)
559         {
560           Solvable *s = pool->solvables + p;
561           if (s->arch == evr)
562             queue_push(&plist, p);
563           else
564             wp = 0;
565         }
566       if (wp)
567         {
568           pool->whatprovides_rel[d] = wp;
569           return wp;
570         }
571       break;
572     default:
573       break;
574     }
575
576   /* convert to whatprovides id */
577 #if 0
578   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
579 #endif
580   if (flags && flags < 8)
581     {
582       pp = pool_whatprovides_ptr(pool, name);
583       while (ISRELDEP(name))
584         {
585           rd = GETRELDEP(pool, name);
586           name = rd->name;
587         }
588       while ((p = *pp++) != 0)
589         {
590           Solvable *s = pool->solvables + p;
591 #if 0
592           POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, s->name));
593 #endif
594           if (!s->provides)
595             {
596               /* no provides - check nevr */
597               if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
598                 queue_push(&plist, p);
599               continue;
600             }
601           /* solvable p provides name in some rels */
602           pidp = s->repo->idarraydata + s->provides;
603           while ((pid = *pidp++) != 0)
604             {
605               int pflags;
606               Id pevr;
607
608               if (pid == name)
609                 {
610 #ifdef DEBIAN_SEMANTICS
611                   continue;             /* unversioned provides can
612                                          * never match versioned deps */
613 #else
614                   break;                /* yes, provides all versions */
615 #endif
616                 }
617               if (!ISRELDEP(pid))
618                 continue;               /* wrong provides name */
619               prd = GETRELDEP(pool, pid);
620               if (prd->name != name)
621                 continue;               /* wrong provides name */
622               /* right package, both deps are rels */
623               pflags = prd->flags;
624               if (!pflags)
625                 continue;
626               if (flags == 7 || pflags == 7)
627                 break; /* included */
628               if ((pflags & flags & 5) != 0)
629                 break; /* same direction, match */
630               pevr = prd->evr;
631               if (pevr == evr)
632                 {
633                   if ((pflags & flags & 2) != 0)
634                     break; /* both have =, match */
635                 }
636               else
637                 {
638                   int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
639 #ifdef DEBIAN_SEMANTICS
640                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_COMPARE)))) != 0)
641                     break;
642 #else
643                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
644                     break;
645 #endif
646                 }
647             }
648           if (!pid)
649             continue;   /* no rel match */
650           queue_push(&plist, p);
651         }
652       /* make our system solvable provide all unknown rpmlib() stuff */
653       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
654         queue_push(&plist, SYSTEMSOLVABLE);
655     }
656   /* add providers to whatprovides */
657 #if 0
658   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
659 #endif
660   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
661   queue_free(&plist);
662
663   return pool->whatprovides_rel[d];
664 }
665
666 /*************************************************************************/
667
668 void
669 pool_debug(Pool *pool, int type, const char *format, ...)
670 {
671   va_list args;
672   char buf[1024];
673
674   if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
675     {
676       if ((pool->debugmask & type) == 0)
677         return;
678     }
679   va_start(args, format);
680   if (!pool->debugcallback)
681     {
682       if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
683         vprintf(format, args);
684       else
685         vfprintf(stderr, format, args);
686       return;
687     }
688   vsnprintf(buf, sizeof(buf), format, args);
689   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
690 }
691
692 void
693 pool_setdebuglevel(Pool *pool, int level)
694 {
695   int mask = SAT_DEBUG_RESULT;
696   if (level > 0)
697     mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE;
698   if (level > 1)
699     mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
700   if (level > 2)
701     mask |= SAT_DEBUG_PROPAGATE;
702   if (level > 3)
703     mask |= SAT_DEBUG_RULE_CREATION;
704   if (level > 4)
705     mask |= SAT_DEBUG_SCHUBI;
706   pool->debugmask = mask;
707 }
708
709 /*************************************************************************/
710
711 struct searchfiles {
712   Id *ids;
713   char **dirs;
714   char **names;
715   int nfiles;
716   Map seen;
717 };
718
719 #define SEARCHFILES_BLOCK 127
720
721 static void
722 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
723 {
724   Id dep, sid;
725   const char *s, *sr;
726   struct searchfiles *csf;
727
728   while ((dep = *ida++) != 0)
729     {
730       csf = sf;
731       while (ISRELDEP(dep))
732         {
733           Reldep *rd;
734           sid = pool->ss.nstrings + GETRELID(dep);
735           if (MAPTST(&csf->seen, sid))
736             {
737               dep = 0;
738               break;
739             }
740           MAPSET(&csf->seen, sid);
741           rd = GETRELDEP(pool, dep);
742           if (rd->flags < 8)
743             dep = rd->name;
744           else if (rd->flags == REL_NAMESPACE)
745             {
746               if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
747                 {
748                   csf = isf;
749                   if (!csf || MAPTST(&csf->seen, sid))
750                     {
751                       dep = 0;
752                       break;
753                     }
754                   MAPSET(&csf->seen, sid);
755                 }
756               dep = rd->evr;
757             }
758           else
759             {
760               Id ids[2];
761               ids[0] = rd->name;
762               ids[1] = 0;
763               pool_addfileprovides_dep(pool, ids, csf, isf);
764               dep = rd->evr;
765             }
766         }
767       if (!dep)
768         continue;
769       if (MAPTST(&csf->seen, dep))
770         continue;
771       MAPSET(&csf->seen, dep);
772       s = id2str(pool, dep);
773       if (*s != '/')
774         continue;
775       csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
776       csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
777       csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
778       csf->ids[csf->nfiles] = dep;
779       sr = strrchr(s, '/');
780       csf->names[csf->nfiles] = strdup(sr + 1);
781       csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1);
782       if (sr != s)
783         strncpy(csf->dirs[csf->nfiles], s, sr - s);
784       csf->dirs[csf->nfiles][sr - s] = 0;
785       csf->nfiles++;
786     }
787 }
788
789 struct addfileprovides_cbdata {
790   int nfiles;
791   Id *ids;
792   char **dirs;
793   char **names;
794
795   Repodata *olddata;
796   Id *dids;
797   Map useddirs;
798 };
799
800 static int
801 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
802 {
803   struct addfileprovides_cbdata *cbd = cbdata;
804   int i;
805
806   if (data != cbd->olddata)
807     {
808       map_free(&cbd->useddirs);
809       map_init(&cbd->useddirs, data->dirpool.ndirs);
810       for (i = 0; i < cbd->nfiles; i++)
811         {
812           Id did = repodata_str2dir(data, cbd->dirs[i], 0);
813           cbd->dids[i] = did;
814           if (did)
815             MAPSET(&cbd->useddirs, did);
816         }
817       cbd->olddata = data;
818     }
819   if (!MAPTST(&cbd->useddirs, value->id))
820     return 0;
821   for (i = 0; i < cbd->nfiles; i++)
822     {
823       if (cbd->dids[i] != value->id)
824         continue;
825       if (!strcmp(cbd->names[i], value->str))
826         break;
827     }
828   if (i == cbd->nfiles)
829     return 0;
830   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
831   return 0;
832 }
833
834 static int
835 addfileprovides_setid_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
836 {
837   Map *provideids = cbdata;
838   if (key->type != REPOKEY_TYPE_IDARRAY)
839     return 0;
840   MAPSET(provideids, kv->id);
841   return kv->eof ? SEARCH_NEXT_SOLVABLE : 0;
842 }
843
844
845 static void
846 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
847 {
848   Id p, start, end;
849   Solvable *s;
850   Repodata *data = 0, *nextdata;
851   Repo *oldrepo = 0;
852   int dataincludes = 0;
853   int i, j;
854   Map providedids;
855
856   cbd->nfiles = sf->nfiles;
857   cbd->ids = sf->ids;
858   cbd->dirs = sf->dirs;
859   cbd->names = sf->names;
860   cbd->olddata = 0;
861   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
862   if (repoonly)
863     {
864       start = repoonly->start;
865       end = repoonly->end;
866     }
867   else
868     {
869       start = 2;        /* skip system solvable */
870       end = pool->nsolvables;
871     }
872   for (p = start, s = pool->solvables + p; p < end; p++, s++)
873     {
874       if (!s->repo || (repoonly && s->repo != repoonly))
875         continue;
876       /* check if p is in (oldrepo,data) */
877       if (s->repo != oldrepo || (data && p >= data->end))
878         {
879           data = 0;
880           oldrepo = 0;
881         }
882       if (oldrepo == 0)
883         {
884           /* nope, find new repo/repodata */
885           /* if we don't find a match, set data to the next repodata */
886           nextdata = 0;
887           for (i = 0, data = s->repo->repodata; i < s->repo->nrepodata; i++, data++)
888             {
889               if (p >= data->end)
890                 continue;
891               if (data->state != REPODATA_AVAILABLE)
892                 continue;
893               for (j = 1; j < data->nkeys; j++)
894                 if (data->keys[j].name == REPOSITORY_ADDEDFILEPROVIDES && data->keys[j].type == REPOKEY_TYPE_IDARRAY)
895                   break;
896               if (j == data->nkeys)
897                 continue;
898               /* great, this repodata contains addedfileprovides */
899               if (!nextdata || nextdata->start > data->start)
900                 nextdata = data;
901               if (p >= data->start)
902                 break;
903             }
904           if (i == s->repo->nrepodata)
905             data = nextdata;    /* no direct hit, use next repodata */
906           if (data)
907             {
908               map_init(&providedids, pool->ss.nstrings);
909               repodata_search(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, 0, addfileprovides_setid_cb, &providedids);
910               for (i = 0; i < cbd->nfiles; i++)
911                 if (!MAPTST(&providedids, cbd->ids[i]))
912                   break;
913               map_free(&providedids);
914               dataincludes = i == cbd->nfiles;
915             }
916           oldrepo = s->repo;
917         }
918       if (data && p >= data->start && dataincludes)
919         continue;
920       repo_search(s->repo, p, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, cbd);
921     }
922 }
923
924 void
925 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
926 {
927   Solvable *s;
928   Repo *repo;
929   struct searchfiles sf, isf, *isfp;
930   struct addfileprovides_cbdata cbd;
931   int i;
932
933   memset(&sf, 0, sizeof(sf));
934   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
935   memset(&isf, 0, sizeof(isf));
936   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
937
938   isfp = installed ? &isf : 0;
939   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
940     {
941       repo = s->repo;
942       if (!repo)
943         continue;
944       if (s->obsoletes)
945         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
946       if (s->conflicts)
947         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
948       if (s->requires)
949         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
950       if (s->recommends)
951         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
952       if (s->suggests)
953         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
954       if (s->supplements)
955         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
956       if (s->enhances)
957         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
958     }
959   map_free(&sf.seen);
960   map_free(&isf.seen);
961   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
962   POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
963   cbd.dids = 0;
964   map_init(&cbd.useddirs, 1);
965   if (idp)
966     *idp = 0;
967   if (sf.nfiles)
968     {
969 #if 0
970       for (i = 0; i < sf.nfiles; i++)
971         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
972 #endif
973       pool_addfileprovides_search(pool, &cbd, &sf, 0);
974       if (idp)
975         {
976           sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
977           sf.ids[sf.nfiles] = 0;
978           *idp = sf.ids;
979           sf.ids = 0;
980         }
981       sat_free(sf.ids);
982       for (i = 0; i < sf.nfiles; i++)
983         {
984           sat_free(sf.dirs[i]);
985           sat_free(sf.names[i]);
986         }
987       sat_free(sf.dirs);
988       sat_free(sf.names);
989     }
990   if (isf.nfiles)
991     {
992 #if 0
993       for (i = 0; i < isf.nfiles; i++)
994         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
995 #endif
996       if (installed)
997         pool_addfileprovides_search(pool, &cbd, &isf, installed);
998       sat_free(isf.ids);
999       for (i = 0; i < isf.nfiles; i++)
1000         {
1001           sat_free(isf.dirs[i]);
1002           sat_free(isf.names[i]);
1003         }
1004       sat_free(isf.dirs);
1005       sat_free(isf.names);
1006     }
1007   map_free(&cbd.useddirs);
1008   sat_free(cbd.dids);
1009   pool_freewhatprovides(pool);  /* as we have added provides */
1010 }
1011
1012 void
1013 pool_addfileprovides(Pool *pool)
1014 {
1015   pool_addfileprovides_ids(pool, pool->installed, 0);
1016 }
1017
1018 void
1019 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)
1020 {
1021   if (p)
1022     {
1023       if (pool->solvables[p].repo)
1024         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1025       return;
1026     }
1027   /* FIXME: obey callback return value! */
1028   for (p = 1; p < pool->nsolvables; p++)
1029     if (pool->solvables[p].repo)
1030       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1031 }
1032
1033 void
1034 pool_clear_pos(Pool *pool)
1035 {
1036   memset(&pool->pos, 0, sizeof(pool->pos));
1037 }
1038
1039
1040 void
1041 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
1042 {
1043   int i;
1044
1045   pool->languagecache = sat_free(pool->languagecache);
1046   pool->languagecacheother = 0;
1047   if (pool->nlanguages)
1048     {
1049       for (i = 0; i < pool->nlanguages; i++)
1050         free((char *)pool->languages[i]);
1051       free(pool->languages);
1052     }
1053   pool->nlanguages = nlanguages;
1054   if (!nlanguages)
1055     return;
1056   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
1057   for (i = 0; i < pool->nlanguages; i++)
1058     pool->languages[i] = strdup(languages[i]);
1059 }
1060
1061 Id
1062 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1063 {
1064   const char *n;
1065   char buf[256], *p;
1066   int l;
1067
1068   if (!lang)
1069     return id;
1070   n = id2str(pool, id);
1071   l = strlen(n) + strlen(lang) + 2;
1072   if (l > sizeof(buf))
1073     p = sat_malloc(strlen(n) + strlen(lang) + 2);
1074   else
1075     p = buf;
1076   sprintf(p, "%s:%s", n, lang);
1077   id = str2id(pool, p, create);
1078   if (p != buf)
1079     free(p);
1080   return id;
1081 }
1082
1083 char *
1084 pool_alloctmpspace(Pool *pool, int len)
1085 {
1086   int n = pool->tmpspacen;
1087   if (!len)
1088     return 0;
1089   if (len > pool->tmpspacelen[n])
1090     {
1091       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
1092       pool->tmpspacelen[n] = len + 32;
1093     }
1094   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
1095   return pool->tmpspacebuf[n];
1096 }
1097
1098 /*******************************************************************/
1099
1100 struct mptree {
1101   Id sibling;
1102   Id child;
1103   const char *comp;
1104   int compl;
1105   Id mountpoint;
1106 };
1107
1108 struct ducbdata {
1109   DUChanges *mps;
1110   struct mptree *mptree;
1111   int addsub;
1112   int hasdu;
1113
1114   Id *dirmap;
1115   int nmap;
1116   Repodata *olddata;
1117 };
1118
1119
1120 static int
1121 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1122 {
1123   struct ducbdata *cbd = cbdata;
1124   Id mp;
1125
1126   if (data != cbd->olddata)
1127     {
1128       Id dn, mp, comp, *dirmap, *dirs;
1129       int i, compl;
1130       const char *compstr;
1131       struct mptree *mptree;
1132
1133       /* create map from dir to mptree */
1134       cbd->dirmap = sat_free(cbd->dirmap);
1135       cbd->nmap = 0;
1136       dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
1137       mptree = cbd->mptree;
1138       mp = 0;
1139       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1140         {
1141           comp = *dirs++;
1142           if (comp <= 0)
1143             {
1144               mp = dirmap[-comp];
1145               continue;
1146             }
1147           if (mp < 0)
1148             {
1149               /* unconnected */
1150               dirmap[dn] = mp;
1151               continue;
1152             }
1153           if (!mptree[mp].child)
1154             {
1155               dirmap[dn] = -mp;
1156               continue;
1157             }
1158           if (data->localpool)
1159             compstr = stringpool_id2str(&data->spool, comp);
1160           else
1161             compstr = id2str(data->repo->pool, comp);
1162           compl = strlen(compstr);
1163           for (i = mptree[mp].child; i; i = mptree[i].sibling)
1164             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1165               break;
1166           dirmap[dn] = i ? i : -mp;
1167         }
1168       /* change dirmap to point to mountpoint instead of mptree */
1169       for (dn = 0; dn < data->dirpool.ndirs; dn++)
1170         {
1171           mp = dirmap[dn];
1172           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1173         }
1174       cbd->dirmap = dirmap;
1175       cbd->nmap = data->dirpool.ndirs;
1176       cbd->olddata = data;
1177     }
1178   cbd->hasdu = 1;
1179   if (value->id < 0 || value->id >= cbd->nmap)
1180     return 0;
1181   mp = cbd->dirmap[value->id];
1182   if (mp < 0)
1183     return 0;
1184   if (cbd->addsub > 0)
1185     {
1186       cbd->mps[mp].kbytes += value->num;
1187       cbd->mps[mp].files += value->num2;
1188     }
1189   else
1190     {
1191       cbd->mps[mp].kbytes -= value->num;
1192       cbd->mps[mp].files -= value->num2;
1193     }
1194   return 0;
1195 }
1196
1197 static void
1198 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
1199 {
1200   int i;
1201   if (mptree[pos].mountpoint == -1)
1202     mptree[pos].mountpoint = mountpoint;
1203   else
1204     mountpoint = mptree[pos].mountpoint;
1205   for (i = mptree[pos].child; i; i = mptree[i].sibling)
1206     propagate_mountpoints(mptree, i, mountpoint);
1207 }
1208
1209 #define MPTREE_BLOCK 15
1210
1211 void
1212 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
1213 {
1214   char *p;
1215   const char *path, *compstr;
1216   struct mptree *mptree;
1217   int i, nmptree;
1218   int pos, compl;
1219   int mp;
1220   struct ducbdata cbd;
1221   Solvable *s;
1222   Id sp;
1223   Map ignoredu;
1224   Repo *oldinstalled = pool->installed;
1225
1226   memset(&ignoredu, 0, sizeof(ignoredu));
1227   cbd.mps = mps;
1228   cbd.addsub = 0;
1229   cbd.dirmap = 0;
1230   cbd.nmap = 0;
1231   cbd.olddata = 0;
1232
1233   mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1234
1235   /* our root node */
1236   mptree[0].sibling = 0;
1237   mptree[0].child = 0;
1238   mptree[0].comp = 0;
1239   mptree[0].compl = 0;
1240   mptree[0].mountpoint = -1;
1241   nmptree = 1;
1242   
1243   /* create component tree */
1244   for (mp = 0; mp < nmps; mp++)
1245     {
1246       mps[mp].kbytes = 0;
1247       mps[mp].files = 0;
1248       pos = 0;
1249       path = mps[mp].path;
1250       while(*path == '/')
1251         path++;
1252       while (*path)
1253         {
1254           if ((p = strchr(path, '/')) == 0)
1255             {
1256               compstr = path;
1257               compl = strlen(compstr);
1258               path += compl;
1259             }
1260           else
1261             {
1262               compstr = path;
1263               compl = p - path;
1264               path = p + 1;
1265               while(*path == '/')
1266                 path++;
1267             }
1268           for (i = mptree[pos].child; i; i = mptree[i].sibling)
1269             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1270               break;
1271           if (!i)
1272             {
1273               /* create new node */
1274               mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1275               i = nmptree++;
1276               mptree[i].sibling = mptree[pos].child;
1277               mptree[i].child = 0;
1278               mptree[i].comp = compstr;
1279               mptree[i].compl = compl;
1280               mptree[i].mountpoint = -1;
1281               mptree[pos].child = i;
1282             }
1283           pos = i;
1284         }
1285       mptree[pos].mountpoint = mp;
1286     }
1287
1288   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
1289
1290 #if 0
1291   for (i = 0; i < nmptree; i++)
1292     {
1293       printf("#%d sibling: %d\n", i, mptree[i].sibling);
1294       printf("#%d child: %d\n", i, mptree[i].child);
1295       printf("#%d comp: %s\n", i, mptree[i].comp);
1296       printf("#%d compl: %d\n", i, mptree[i].compl);
1297       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
1298     }
1299 #endif
1300
1301   cbd.mptree = mptree;
1302   cbd.addsub = 1;
1303   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1304     {
1305       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1306         continue;
1307       if (!MAPTST(installedmap, sp))
1308         continue;
1309       cbd.hasdu = 0;
1310       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1311       if (!cbd.hasdu && oldinstalled)
1312         {
1313           Id op, opp;
1314           /* no du data available, ignore data of all installed solvables we obsolete */
1315           if (!ignoredu.map)
1316             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
1317           if (s->obsoletes)
1318             {
1319               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
1320               while ((obs = *obsp++) != 0)
1321                 FOR_PROVIDES(op, opp, obs)
1322                   if (op >= oldinstalled->start && op < oldinstalled->end)
1323                     MAPSET(&ignoredu, op - oldinstalled->start);
1324             }
1325           FOR_PROVIDES(op, opp, s->name)
1326             if (pool->solvables[op].name == s->name)
1327               if (op >= oldinstalled->start && op < oldinstalled->end)
1328                 MAPSET(&ignoredu, op - oldinstalled->start);
1329         }
1330     }
1331   cbd.addsub = -1;
1332   if (oldinstalled)
1333     {
1334       /* assumes we allways have du data for installed solvables */
1335       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1336         {
1337           if (MAPTST(installedmap, sp))
1338             continue;
1339           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
1340             continue;
1341           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1342         }
1343     }
1344   if (ignoredu.map)
1345     map_free(&ignoredu);
1346   sat_free(cbd.dirmap);
1347   sat_free(mptree);
1348 }
1349
1350 int
1351 pool_calc_installsizechange(Pool *pool, Map *installedmap)
1352 {
1353   Id sp;
1354   Solvable *s;
1355   int change = 0;
1356   Repo *oldinstalled = pool->installed;
1357
1358   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1359     {
1360       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1361         continue;
1362       if (!MAPTST(installedmap, sp))
1363         continue;
1364       change += solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1365     }
1366   if (oldinstalled)
1367     {
1368       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1369         {
1370           if (MAPTST(installedmap, sp))
1371             continue;
1372           change -= solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1373         }
1374     }
1375   return change;
1376 }
1377
1378 /* map:
1379  *  1: installed
1380  *  2: conflicts with installed
1381  *  8: interesting (only true if installed)
1382  * 16: undecided
1383  */
1384  
1385 static inline Id dep2name(Pool *pool, Id dep)
1386 {
1387   while (ISRELDEP(dep))
1388     {
1389       Reldep *rd = rd = GETRELDEP(pool, dep);
1390       dep = rd->name;
1391     }
1392   return dep;
1393 }
1394
1395 static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id dep) 
1396 {
1397   Id p, pp;
1398   Solvable *sn = pool->solvables + n; 
1399
1400   FOR_PROVIDES(p, pp, sn->name)
1401     {    
1402       Solvable *s = pool->solvables + p; 
1403       if (s->name != sn->name || s->arch != sn->arch)
1404         continue;
1405       if ((map[p] & 9) == 9)
1406         return 1;
1407     }    
1408   return 0;
1409 }
1410
1411 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *noobsoletesmap)
1412 {
1413   Id p, pp;
1414   int r = 0;
1415   FOR_PROVIDES(p, pp, dep)
1416     {
1417       if (p == SYSTEMSOLVABLE)
1418         return 1;       /* always boring, as never constraining */
1419       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
1420         continue;
1421       if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep))
1422         if (providedbyinstalled_multiversion(pool, map, p, dep))
1423           continue;
1424       if ((map[p] & 9) == 9)
1425         return 9;
1426       r |= map[p] & 17;
1427     }
1428   return r;
1429 }
1430
1431 /*
1432  * pool_trivial_installable - calculate if a set of solvables is
1433  * trivial installable without any other installs/deinstalls of
1434  * packages not belonging to the set.
1435  *
1436  * the state is returned in the result queue:
1437  * 1:  solvable is installable without any other package changes
1438  * 0:  solvable is not installable
1439  * -1: solvable is installable, but doesn't constrain any installed packages
1440  */
1441
1442 void
1443 pool_trivial_installable_noobsoletesmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *noobsoletesmap)
1444 {
1445   int i, r, m, did;
1446   Id p, *dp, con, *conp, req, *reqp;
1447   unsigned char *map;
1448   Solvable *s;
1449
1450   map = sat_calloc(pool->nsolvables, 1);
1451   for (p = 1; p < pool->nsolvables; p++)
1452     {
1453       if (!MAPTST(installedmap, p))
1454         continue;
1455       map[p] |= 9;
1456       s = pool->solvables + p;
1457       if (!s->conflicts)
1458         continue;
1459       conp = s->repo->idarraydata + s->conflicts;
1460       while ((con = *conp++) != 0)
1461         {
1462           dp = pool_whatprovides_ptr(pool, con);
1463           for (; *dp; dp++)
1464             map[p] |= 2;        /* XXX: self conflict ? */
1465         }
1466     }
1467   for (i = 0; i < pkgs->count; i++)
1468     map[pkgs->elements[i]] = 16;
1469
1470   for (i = 0, did = 0; did < pkgs->count; i++, did++)
1471     {
1472       if (i == pkgs->count)
1473         i = 0;
1474       p = pkgs->elements[i];
1475       if ((map[p] & 16) == 0)
1476         continue;
1477       if ((map[p] & 2) != 0)
1478         {
1479           map[p] = 2;
1480           continue;
1481         }
1482       s = pool->solvables + p;
1483       m = 1;
1484       if (s->requires)
1485         {
1486           reqp = s->repo->idarraydata + s->requires;
1487           while ((req = *reqp++) != 0)
1488             {
1489               if (req == SOLVABLE_PREREQMARKER)
1490                 continue;
1491               r = providedbyinstalled(pool, map, req, 0, 0);
1492               if (!r)
1493                 {
1494                   /* decided and miss */
1495                   map[p] = 2;
1496                   break;
1497                 }
1498               m |= r;   /* 1 | 9 | 16 | 17 */
1499             }
1500           if (req)
1501             continue;
1502           if ((m & 9) == 9)
1503             m = 9;
1504         }
1505       if (s->conflicts)
1506         {
1507           int ispatch = 0;      /* see solver.c patch handling */
1508
1509           if (!strncmp("patch:", id2str(pool, s->name), 6))
1510             ispatch = 1;
1511           conp = s->repo->idarraydata + s->conflicts;
1512           while ((con = *conp++) != 0)
1513             {
1514               if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
1515                 {
1516                   map[p] = 2;
1517                   break;
1518                 }
1519               if ((m == 1 || m == 17) && ISRELDEP(con))
1520                 {
1521                   con = dep2name(pool, con);
1522                   if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
1523                     m = 9;
1524                 }
1525             }
1526           if (con)
1527             continue;   /* found a conflict */
1528         }
1529 #if 0
1530       if (s->repo && s->repo != oldinstalled)
1531         {
1532           Id p2, obs, *obsp, *pp;
1533           Solvable *s2;
1534           if (s->obsoletes)
1535             {
1536               obsp = s->repo->idarraydata + s->obsoletes;
1537               while ((obs = *obsp++) != 0)
1538                 {
1539                   if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
1540                     {
1541                       map[p] = 2;
1542                       break;
1543                     }
1544                 }
1545               if (obs)
1546                 continue;
1547             }
1548           FOR_PROVIDES(p2, pp, s->name)
1549             {
1550               s2 = pool->solvables + p2;
1551               if (s2->name == s->name && (map[p2] & 1) != 0)
1552                 {
1553                   map[p] = 2;
1554                   break;
1555                 }
1556             }
1557           if (p2)
1558             continue;
1559         }
1560 #endif
1561       if (m != map[p])
1562         {
1563           map[p] = m;
1564           did = 0;
1565         }
1566     }
1567   queue_free(res);
1568   queue_clone(res, pkgs);
1569   for (i = 0; i < pkgs->count; i++)
1570     {
1571       m = map[pkgs->elements[i]];
1572       if ((m & 9) == 9)
1573         r = 1;
1574       else if (m & 1)
1575         r = -1;
1576       else
1577         r = 0;
1578       res->elements[i] = r;
1579     }
1580   free(map);
1581 }
1582
1583 void
1584 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
1585 {
1586   pool_trivial_installable_noobsoletesmap(pool, installedmap, pkgs, res, 0);
1587 }
1588
1589 // EOF