refactor selection code, add SELECTION_SKIP_KIND, add support for arch/kind filtering
[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 "poolvendor.h"
23 #include "repo.h"
24 #include "poolid.h"
25 #include "poolid_private.h"
26 #include "poolarch.h"
27 #include "util.h"
28 #include "bitmap.h"
29 #include "evr.h"
30
31 #define SOLVABLE_BLOCK  255
32
33 #define KNOWNID_INITIALIZE
34 #include "knownid.h"
35 #undef KNOWNID_INITIALIZE
36
37 /* create pool */
38 Pool *
39 pool_create(void)
40 {
41   Pool *pool;
42   Solvable *s;
43
44   pool = (Pool *)solv_calloc(1, sizeof(*pool));
45
46   stringpool_init (&pool->ss, initpool_data);
47
48   /* alloc space for RelDep 0 */
49   pool->rels = solv_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
50   pool->nrels = 1;
51   memset(pool->rels, 0, sizeof(Reldep));
52
53   /* alloc space for Solvable 0 and system solvable */
54   pool->solvables = solv_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
55   pool->nsolvables = 2;
56   memset(pool->solvables, 0, 2 * sizeof(Solvable));
57
58   queue_init(&pool->vendormap);
59   queue_init(&pool->pooljobs);
60   queue_init(&pool->lazywhatprovidesq);
61
62 #if defined(DEBIAN)
63   pool->disttype = DISTTYPE_DEB;
64   pool->noarchid = ARCH_ALL;
65 #elif defined(ARCHLINUX)
66   pool->disttype = DISTTYPE_ARCH;
67   pool->noarchid = ARCH_ANY;
68 #elif defined(HAIKU)
69   pool->disttype = DISTTYPE_HAIKU;
70   pool->noarchid = ARCH_ANY;
71   pool->obsoleteusesprovides = 1;
72 #else
73   pool->disttype = DISTTYPE_RPM;
74   pool->noarchid = ARCH_NOARCH;
75 #endif
76
77   /* initialize the system solvable */
78   s = pool->solvables + SYSTEMSOLVABLE;
79   s->name = SYSTEM_SYSTEM;
80   s->arch = pool->noarchid;
81   s->evr = ID_EMPTY;
82
83   pool->debugmask = SOLV_DEBUG_RESULT;  /* FIXME */
84 #ifdef FEDORA
85   pool->implicitobsoleteusescolors = 1;
86 #endif
87 #ifdef RPM5
88   pool->noobsoletesmultiversion = 1;
89   pool->forbidselfconflicts = 1;
90   pool->obsoleteusesprovides = 1;
91   pool->implicitobsoleteusesprovides = 1;
92   pool->havedistepoch = 1;
93 #endif
94   return pool;
95 }
96
97
98 /* free all the resources of our pool */
99 void
100 pool_free(Pool *pool)
101 {
102   int i;
103
104   pool_freewhatprovides(pool);
105   pool_freeidhashes(pool);
106   pool_freeallrepos(pool, 1);
107   solv_free(pool->id2arch);
108   solv_free(pool->id2color);
109   solv_free(pool->solvables);
110   stringpool_free(&pool->ss);
111   solv_free(pool->rels);
112   pool_setvendorclasses(pool, 0);
113   queue_free(&pool->vendormap);
114   queue_free(&pool->pooljobs);
115   queue_free(&pool->lazywhatprovidesq);
116   for (i = 0; i < POOL_TMPSPACEBUF; i++)
117     solv_free(pool->tmpspace.buf[i]);
118   for (i = 0; i < pool->nlanguages; i++)
119     free((char *)pool->languages[i]);
120   solv_free(pool->languages);
121   solv_free(pool->languagecache);
122   solv_free(pool->errstr);
123   solv_free(pool->rootdir);
124   solv_free(pool);
125 }
126
127 void
128 pool_freeallrepos(Pool *pool, int reuseids)
129 {
130   int i;
131
132   pool_freewhatprovides(pool);
133   for (i = 1; i < pool->nrepos; i++) 
134     if (pool->repos[i])
135       repo_freedata(pool->repos[i]);
136   pool->repos = solv_free(pool->repos);
137   pool->nrepos = 0; 
138   pool->urepos = 0; 
139   /* the first two solvables don't belong to a repo */
140   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
141 }
142
143 #ifdef MULTI_SEMANTICS
144 void
145 pool_setdisttype(Pool *pool, int disttype)
146 {
147   pool->disttype = disttype;
148   if (disttype == DISTTYPE_RPM)
149     pool->noarchid = ARCH_NOARCH;
150   if (disttype == DISTTYPE_DEB)
151     pool->noarchid = ARCH_ALL;
152   if (disttype == DISTTYPE_ARCH)
153     pool->noarchid = ARCH_ANY;
154   if (disttype == DISTTYPE_HAIKU)
155     pool->noarchid = ARCH_ANY;
156   pool->solvables[SYSTEMSOLVABLE].arch = pool->noarchid;
157 }
158 #endif
159
160 int
161 pool_get_flag(Pool *pool, int flag)
162 {
163   switch (flag)
164     {
165     case POOL_FLAG_PROMOTEEPOCH:
166       return pool->promoteepoch;
167     case POOL_FLAG_FORBIDSELFCONFLICTS:
168       return pool->forbidselfconflicts;
169     case POOL_FLAG_OBSOLETEUSESPROVIDES:
170       return pool->obsoleteusesprovides;
171     case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
172       return pool->implicitobsoleteusesprovides;
173     case POOL_FLAG_OBSOLETEUSESCOLORS:
174       return pool->obsoleteusescolors;
175     case POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS:
176       return pool->implicitobsoleteusescolors;
177     case POOL_FLAG_NOINSTALLEDOBSOLETES:
178       return pool->noinstalledobsoletes;
179     case POOL_FLAG_HAVEDISTEPOCH:
180       return pool->havedistepoch;
181     case POOL_FLAG_NOOBSOLETESMULTIVERSION:
182       return pool->noobsoletesmultiversion;
183     case POOL_FLAG_ADDFILEPROVIDESFILTERED:
184       return pool->addfileprovidesfiltered;
185     default:
186       break;
187     }
188   return -1;
189 }
190
191 int
192 pool_set_flag(Pool *pool, int flag, int value)
193 {
194   int old = pool_get_flag(pool, flag);
195   switch (flag)
196     {
197     case POOL_FLAG_PROMOTEEPOCH:
198       pool->promoteepoch = value;
199       break;
200     case POOL_FLAG_FORBIDSELFCONFLICTS:
201       pool->forbidselfconflicts = value;
202       break;
203     case POOL_FLAG_OBSOLETEUSESPROVIDES:
204       pool->obsoleteusesprovides = value;
205       break;
206     case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
207       pool->implicitobsoleteusesprovides = value;
208       break;
209     case POOL_FLAG_OBSOLETEUSESCOLORS:
210       pool->obsoleteusescolors = value;
211       break;
212     case POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS:
213       pool->implicitobsoleteusescolors = value;
214       break;
215     case POOL_FLAG_NOINSTALLEDOBSOLETES:
216       pool->noinstalledobsoletes = value;
217       break;
218     case POOL_FLAG_HAVEDISTEPOCH:
219       pool->havedistepoch = value;
220       break;
221     case POOL_FLAG_NOOBSOLETESMULTIVERSION:
222       pool->noobsoletesmultiversion = value;
223       break;
224     case POOL_FLAG_ADDFILEPROVIDESFILTERED:
225       pool->addfileprovidesfiltered = value;
226       break;
227     default:
228       break;
229     }
230   return old;
231 }
232
233
234 Id
235 pool_add_solvable(Pool *pool)
236 {
237   pool->solvables = solv_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
238   memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
239   return pool->nsolvables++;
240 }
241
242 Id
243 pool_add_solvable_block(Pool *pool, int count)
244 {
245   Id nsolvables = pool->nsolvables;
246   if (!count)
247     return nsolvables;
248   pool->solvables = solv_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
249   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
250   pool->nsolvables += count;
251   return nsolvables;
252 }
253
254 void
255 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
256 {
257   if (!count)
258     return;
259   if (reuseids && start + count == pool->nsolvables)
260     {
261       /* might want to shrink solvable array */
262       pool->nsolvables = start;
263       return;
264     }
265   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
266 }
267
268
269 void
270 pool_set_installed(Pool *pool, Repo *installed)
271 {
272   if (pool->installed == installed)
273     return;
274   pool->installed = installed;
275   pool_freewhatprovides(pool);
276 }
277
278 static int
279 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp, void *dp)
280 {
281   int r;
282   Pool *pool = dp;
283   Id oa, ob, *da, *db;
284   oa = pool->whatprovides[*(Id *)ap];
285   ob = pool->whatprovides[*(Id *)bp];
286   if (oa == ob)
287     return *(Id *)ap - *(Id *)bp;
288   da = pool->whatprovidesdata + oa;
289   db = pool->whatprovidesdata + ob;
290   while (*db)
291     if ((r = (*da++ - *db++)) != 0)
292       return r;
293   if (*da)
294     return *da;
295   return *(Id *)ap - *(Id *)bp;
296 }
297
298 /*
299  * pool_shrink_whatprovides  - unify whatprovides data
300  *
301  * whatprovides_rel must be empty for this to work!
302  *
303  */
304 static void
305 pool_shrink_whatprovides(Pool *pool)
306 {
307   Id i, n, id;
308   Id *sorted;
309   Id lastid, *last, *dp, *lp;
310   Offset o;
311   int r;
312
313   if (pool->ss.nstrings < 3)
314     return;
315   sorted = solv_malloc2(pool->ss.nstrings, sizeof(Id));
316   for (i = id = 0; id < pool->ss.nstrings; id++)
317     if (pool->whatprovides[id] >= 4)
318       sorted[i++] = id;
319   n = i;
320   solv_sort(sorted, n, sizeof(Id), pool_shrink_whatprovides_sortcmp, pool);
321   last = 0;
322   lastid = 0;
323   for (i = 0; i < n; i++)
324     {
325       id = sorted[i];
326       o = pool->whatprovides[id];
327       dp = pool->whatprovidesdata + o;
328       if (last)
329         {
330           lp = last;
331           while (*dp)   
332             if (*dp++ != *lp++)
333               {
334                 last = 0;
335                 break;
336               }
337           if (last && *lp)
338             last = 0;
339           if (last)
340             {
341               pool->whatprovides[id] = -lastid;
342               continue;
343             }
344         }
345       last = pool->whatprovidesdata + o;
346       lastid = id;
347     }
348   solv_free(sorted);
349   dp = pool->whatprovidesdata + 4;
350   for (id = 1; id < pool->ss.nstrings; id++)
351     {
352       o = pool->whatprovides[id];
353       if (!o)
354         continue;
355       if ((Id)o < 0)
356         {
357           i = -(Id)o;
358           if (i >= id)
359             abort();
360           pool->whatprovides[id] = pool->whatprovides[i];
361           continue;
362         }
363       if (o < 4)
364         continue;
365       lp = pool->whatprovidesdata + o;
366       if (lp < dp)
367         abort();
368       pool->whatprovides[id] = dp - pool->whatprovidesdata;
369       while ((*dp++ = *lp++) != 0)
370         ;
371     }
372   o = dp - pool->whatprovidesdata;
373   POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
374   if (pool->whatprovidesdataoff == o)
375     return;
376   r = pool->whatprovidesdataoff - o;
377   pool->whatprovidesdataoff = o;
378   pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
379   if (r > pool->whatprovidesdataleft)
380     r = pool->whatprovidesdataleft;
381   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
382 }
383
384
385 /*
386  * pool_createwhatprovides()
387  * 
388  * create hashes over pool of solvables to ease provide lookups
389  * 
390  */
391 void
392 pool_createwhatprovides(Pool *pool)
393 {
394   int i, num, np, extra;
395   Offset off;
396   Solvable *s;
397   Id id;
398   Offset *idp, n;
399   Offset *whatprovides;
400   Id *whatprovidesdata, *d;
401   Repo *installed = pool->installed;
402   unsigned int now;
403
404   now = solv_timems(0);
405   POOL_DEBUG(SOLV_DEBUG_STATS, "number of solvables: %d, memory used: %d K\n", pool->nsolvables, pool->nsolvables * (int)sizeof(Solvable) / 1024);
406   POOL_DEBUG(SOLV_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
407   POOL_DEBUG(SOLV_DEBUG_STATS, "string memory used: %d K array + %d K data,  rel memory used: %d K array\n", pool->ss.nstrings / (1024 / (int)sizeof(Id)), pool->ss.sstrings / 1024, pool->nrels * (int)sizeof(Reldep) / 1024);
408   if (pool->ss.stringhashmask || pool->relhashmask)
409     POOL_DEBUG(SOLV_DEBUG_STATS, "string hash memory: %d K, rel hash memory : %d K\n", (pool->ss.stringhashmask + 1) / (int)(1024/sizeof(Id)), (pool->relhashmask + 1) / (int)(1024/sizeof(Id)));
410
411   pool_freeidhashes(pool);      /* XXX: should not be here! */
412   pool_freewhatprovides(pool);
413   num = pool->ss.nstrings;
414   pool->whatprovides = whatprovides = solv_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
415   pool->whatprovides_rel = solv_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
416
417   /* count providers for each name */
418   for (i = pool->nsolvables - 1; i > 0; i--)
419     {
420       Id *pp;
421       s = pool->solvables + i;
422       if (!s->provides || !s->repo || s->repo->disabled)
423         continue;
424       /* we always need the installed solvable in the whatprovides data,
425          otherwise obsoletes/conflicts on them won't work */
426       if (s->repo != installed && !pool_installable(pool, s))
427         continue;
428       pp = s->repo->idarraydata + s->provides;
429       while ((id = *pp++) != 0)
430         {
431           while (ISRELDEP(id))
432             {
433               Reldep *rd = GETRELDEP(pool, id);
434               id = rd->name;
435             }
436           whatprovides[id]++;          /* inc count of providers */
437         }
438     }
439
440   off = 4;      /* first entry is undef, second is empty list, third is system solvable  */
441   np = 0;                              /* number of names provided */
442   for (i = 0, idp = whatprovides; i < num; i++, idp++)
443     {
444       n = *idp;
445       if (!n)                           /* no providers */
446         {
447           *idp = 1;                     /* offset for empty list */
448           continue;
449         }
450       off += n;                         /* make space for all providers */
451       *idp = off++;                     /* now idp points to terminating zero */
452       np++;                             /* inc # of provider 'slots' for stats */
453     }
454
455   POOL_DEBUG(SOLV_DEBUG_STATS, "provide ids: %d\n", np);
456
457   /* reserve some space for relation data */
458   extra = 2 * pool->nrels;
459   if (extra < 256)
460     extra = 256;
461
462   POOL_DEBUG(SOLV_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
463
464   /* alloc space for all providers + extra */
465   whatprovidesdata = solv_calloc(off + extra, sizeof(Id));
466   whatprovidesdata[2] = SYSTEMSOLVABLE;
467
468   /* now fill data for all provides */
469   for (i = pool->nsolvables - 1; i > 0; i--)
470     {
471       Id *pp;
472       s = pool->solvables + i;
473       if (!s->provides || !s->repo || s->repo->disabled)
474         continue;
475       if (s->repo != installed && !pool_installable(pool, s))
476         continue;
477
478       /* for all provides of this solvable */
479       pp = s->repo->idarraydata + s->provides;
480       while ((id = *pp++) != 0)
481         {
482           while (ISRELDEP(id))
483             {
484               Reldep *rd = GETRELDEP(pool, id);
485               id = rd->name;
486             }
487           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
488           if (*d != i)          /* don't add same solvable twice */
489             {
490               d[-1] = i;
491               whatprovides[id]--;
492             }
493         }
494     }
495   pool->whatprovidesdata = whatprovidesdata;
496   pool->whatprovidesdataoff = off;
497   pool->whatprovidesdataleft = extra;
498   pool_shrink_whatprovides(pool);
499   POOL_DEBUG(SOLV_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)));
500
501   queue_empty(&pool->lazywhatprovidesq);
502   if ((!pool->addedfileprovides && pool->disttype == DISTTYPE_RPM) || pool->addedfileprovides == 1)
503     {
504       if (!pool->addedfileprovides)
505         POOL_DEBUG(SOLV_DEBUG_STATS, "WARNING: pool_addfileprovides was not called, this may result in slow operation\n");
506       /* lazyly add file provides */
507       for (i = 1; i < num; i++)
508         {
509           const char *str = pool->ss.stringspace + pool->ss.strings[i];
510           if (str[0] != '/')
511             continue;
512           if (pool->addedfileprovides == 1 && repodata_filelistfilter_matches(0, str))
513             continue;
514           /* setup lazy adding, but remember old value */
515           if (pool->whatprovides[i] > 1)
516             queue_push2(&pool->lazywhatprovidesq, i, pool->whatprovides[i]);
517           pool->whatprovides[i] = 0;
518         }
519       POOL_DEBUG(SOLV_DEBUG_STATS, "lazywhatprovidesq size: %d entries\n", pool->lazywhatprovidesq.count / 2);
520     }
521
522   POOL_DEBUG(SOLV_DEBUG_STATS, "createwhatprovides took %d ms\n", solv_timems(now));
523 }
524
525 /*
526  * free all of our whatprovides data
527  * be careful, everything internalized with pool_queuetowhatprovides is
528  * gone, too
529  */
530 void
531 pool_freewhatprovides(Pool *pool)
532 {
533   pool->whatprovides = solv_free(pool->whatprovides);
534   pool->whatprovides_rel = solv_free(pool->whatprovides_rel);
535   pool->whatprovidesdata = solv_free(pool->whatprovidesdata);
536   pool->whatprovidesdataoff = 0;
537   pool->whatprovidesdataleft = 0;
538 }
539
540
541 /******************************************************************************/
542
543 /*
544  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
545  * 
546  * used for whatprovides, jobs, learnt rules, selections
547  * input: q: queue of Ids
548  * returns: Offset into whatprovidesdata
549  *
550  */
551 Id
552 pool_queuetowhatprovides(Pool *pool, Queue *q)
553 {
554   Offset off;
555   int count = q->count;
556
557   if (count == 0)                      /* queue empty -> 1 */
558     return 1;
559   if (count == 1 && q->elements[0] == SYSTEMSOLVABLE)
560     return 2;
561
562   /* extend whatprovidesdata if needed, +1 for 0-termination */
563   if (pool->whatprovidesdataleft < count + 1)
564     {
565       POOL_DEBUG(SOLV_DEBUG_STATS, "growing provides hash data...\n");
566       pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
567       pool->whatprovidesdataleft = count + 4096;
568     }
569
570   /* copy queue to next free slot */
571   off = pool->whatprovidesdataoff;
572   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
573
574   /* adapt count and 0-terminate */
575   pool->whatprovidesdataoff += count;
576   pool->whatprovidesdata[pool->whatprovidesdataoff++] = 0;
577   pool->whatprovidesdataleft -= count + 1;
578
579   return (Id)off;
580 }
581
582
583 /*************************************************************************/
584
585 #if defined(MULTI_SEMANTICS)
586 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
587 #elif defined(DEBIAN)
588 # define EVRCMP_DEPCMP EVRCMP_COMPARE
589 #else
590 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
591 #endif
592
593 /* check if a package's nevr matches a dependency */
594 /* semi-private, called from public pool_match_nevr */
595
596 int
597 pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
598 {
599   Reldep *rd = GETRELDEP(pool, d);
600   Id name = rd->name;
601   Id evr = rd->evr;
602   int flags = rd->flags;
603
604   if (flags > 7)
605     {
606       switch (flags)
607         {
608         case REL_ARCH:
609           if (s->arch != evr)
610             {
611               if (evr != ARCH_SRC || s->arch != ARCH_NOSRC)
612                 return 0;
613             }
614           return pool_match_nevr(pool, s, name);
615         case REL_OR:
616           if (pool_match_nevr(pool, s, name))
617             return 1;
618           return pool_match_nevr(pool, s, evr);
619         case REL_AND:
620         case REL_WITH:
621           if (!pool_match_nevr(pool, s, name))
622             return 0;
623           return pool_match_nevr(pool, s, evr);
624         default:
625           return 0;
626         }
627     }
628   if (!pool_match_nevr(pool, s, name))
629     return 0;
630   if (evr == s->evr)
631     return (flags & REL_EQ) ? 1 : 0;
632   if (!flags)
633     return 0;
634   if (flags == 7)
635     return 1;
636   switch (pool_evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP))
637     {
638     case -2:
639       return 1;
640     case -1:
641       return (flags & REL_LT) ? 1 : 0;
642     case 0:
643       return (flags & REL_EQ) ? 1 : 0;
644     case 1:
645       return (flags & REL_GT) ? 1 : 0;
646     case 2:
647       return (flags & REL_EQ) ? 1 : 0;
648     default:
649       break;
650     }
651   return 0;
652 }
653
654 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
655 /* forward declaration */
656 static int pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr);
657 #endif
658
659 /* match (flags, evr) against provider (pflags, pevr) */
660 static inline int
661 pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr)
662 {
663   if (!pflags || !flags || pflags >= 8 || flags >= 8)
664     return 0;
665   if (flags == 7 || pflags == 7)
666     return 1;           /* rel provides every version */
667   if ((pflags & flags & (REL_LT | REL_GT)) != 0)
668     return 1;           /* both rels show in the same direction */
669   if (pevr == evr)
670     return (flags & pflags & REL_EQ) ? 1 : 0;
671 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
672   if (ISRELDEP(pevr))
673     {
674       Reldep *rd = GETRELDEP(pool, pevr);
675       if (rd->flags == REL_COMPAT)
676         return pool_match_flags_evr_rel_compat(pool, rd, flags, evr);
677     }
678 #endif
679   switch (pool_evrcmp(pool, pevr, evr, EVRCMP_DEPCMP))
680     {
681     case -2:
682       return (pflags & REL_EQ) ? 1 : 0;
683     case -1:
684       return (flags & REL_LT) || (pflags & REL_GT) ? 1 : 0;
685     case 0:
686       return (flags & pflags & REL_EQ) ? 1 : 0;
687     case 1:
688       return (flags & REL_GT) || (pflags & REL_LT) ? 1 : 0;
689     case 2:
690       return (flags & REL_EQ) ? 1 : 0;
691     default:
692       break;
693     }
694   return 0;
695 }
696
697 #if defined(HAIKU) || defined(MULTI_SEMANTICS)
698 static int
699 pool_match_flags_evr_rel_compat(Pool *pool, Reldep *range, int flags, int evr)
700 {
701   /* range->name is the actual version, range->evr the backwards compatibility
702      version. If flags are '>=' or '>', we match the compatibility version
703      as well, otherwise only the actual version. */
704   if (!(flags & REL_GT) || (flags & REL_LT))
705     return pool_match_flags_evr(pool, REL_EQ, range->name, flags, evr);
706   return pool_match_flags_evr(pool, REL_LT | REL_EQ, range->name, flags, evr) &&
707          pool_match_flags_evr(pool, REL_GT | REL_EQ, range->evr, REL_EQ, evr);
708 }
709 #endif
710
711 /* public (i.e. not inlined) version of pool_match_flags_evr */
712 int
713 pool_intersect_evrs(Pool *pool, int pflags, Id pevr, int flags, int evr)
714 {
715   return pool_match_flags_evr(pool, pflags, pevr, flags, evr);
716 }
717
718 /* match two dependencies (d1 = provider) */
719
720 int
721 pool_match_dep(Pool *pool, Id d1, Id d2)
722 {
723   Reldep *rd1, *rd2;
724
725   if (d1 == d2)
726     return 1;
727   if (!ISRELDEP(d1))
728     {
729       if (!ISRELDEP(d2))
730         return 0;
731       rd2 = GETRELDEP(pool, d2);
732       return pool_match_dep(pool, d1, rd2->name);
733     }
734   rd1 = GETRELDEP(pool, d1);
735   if (!ISRELDEP(d2))
736     {
737       return pool_match_dep(pool, rd1->name, d2);
738     }
739   rd2 = GETRELDEP(pool, d2);
740   /* first match name */
741   if (!pool_match_dep(pool, rd1->name, rd2->name))
742     return 0;
743   /* name matches, check flags and evr */
744   return pool_intersect_evrs(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
745 }
746
747 Id
748 pool_searchlazywhatprovidesq(Pool *pool, Id d)
749 {
750   int start = 0;
751   int end = pool->lazywhatprovidesq.count;
752   Id *elements;
753   if (!end)
754     return 0;
755   elements = pool->lazywhatprovidesq.elements;
756   while (end - start > 16)
757     {
758       int mid = (start + end) / 2 & ~1;
759       if (elements[mid] == d)
760         return elements[mid + 1];
761       if (elements[mid] < d)
762         start = mid + 2;
763       else
764         end = mid;
765     }
766   for (; start < end; start += 2)
767     if (elements[start] == d)
768       return elements[start + 1];
769   return 0;
770 }
771
772 /*
773  * addstdproviders
774  * 
775  * lazy populating of the whatprovides array, non relation case
776  */
777 static Id
778 pool_addstdproviders(Pool *pool, Id d)
779 {
780   const char *str;
781   Queue q;
782   Id qbuf[16];
783   Dataiterator di;
784   Id oldoffset;
785
786   if (pool->addedfileprovides == 2)
787     {
788       pool->whatprovides[d] = 1;
789       return 1;
790     }
791   str =  pool->ss.stringspace + pool->ss.strings[d];
792   if (*str != '/')
793     {
794       pool->whatprovides[d] = 1;
795       return 1;
796     }
797   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
798   dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, str, SEARCH_STRING|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
799   for (; dataiterator_step(&di); dataiterator_skip_solvable(&di))
800     {
801       Solvable *s = pool->solvables + di.solvid;
802       /* XXX: maybe should add a provides dependency to the solvables
803        * OTOH this is only needed for rel deps that filter the provides,
804        * and those should not use filelist entries */
805       if (s->repo->disabled)
806         continue;
807       if (s->repo != pool->installed && !pool_installable(pool, s))
808         continue;
809       queue_push(&q, di.solvid);
810     }
811   dataiterator_free(&di);
812   oldoffset = pool_searchlazywhatprovidesq(pool, d);
813   if (!q.count)
814     pool->whatprovides[d] = oldoffset ? oldoffset : 1;
815   else
816     {
817       if (oldoffset)
818         {
819           Id *oo = pool->whatprovidesdata + oldoffset;
820           int i;
821           /* unify both queues. easy, as we know both are sorted */
822           for (i = 0; i < q.count; i++)
823             {
824               if (*oo > q.elements[i])
825                 continue;
826               if (*oo < q.elements[i])
827                 queue_insert(&q, i, *oo);
828               oo++;
829               if (!*oo)
830                 break;
831             }
832           while (*oo)
833             queue_push(&q, *oo++);
834           if (q.count == oo - (pool->whatprovidesdata + oldoffset))
835             {
836               /* end result has same size as oldoffset -> no new entries */
837               queue_free(&q);
838               pool->whatprovides[d] = oldoffset;
839               return oldoffset;
840             }
841         }
842       pool->whatprovides[d] = pool_queuetowhatprovides(pool, &q);
843     }
844   queue_free(&q);
845   return pool->whatprovides[d];
846 }
847
848
849 static inline int
850 pool_is_kind(Pool *pool, Id name, Id kind)
851 {
852   const char *n;
853   if (!kind)
854     return 1;
855   n = pool_id2str(pool, name);
856   if (kind != 1)
857     {
858       const char *kn = pool_id2str(pool, kind);
859       int knl = strlen(kn);
860       return !strncmp(n, kn, knl) && n[knl] == ':' ? 1 : 0;
861     }
862   else
863     {
864       if (*n == ':')
865         return 1;
866       while(*n >= 'a' && *n <= 'z')
867         n++;
868       return *n == ':' ? 0 : 1;
869     }
870 }
871
872 /*
873  * addrelproviders
874  * 
875  * add packages fulfilling the relation to whatprovides array
876  * 
877  */
878 Id
879 pool_addrelproviders(Pool *pool, Id d)
880 {
881   Reldep *rd;
882   Reldep *prd;
883   Queue plist;
884   Id buf[16];
885   Id name, evr, flags;
886   Id pid, *pidp;
887   Id p, *pp;
888
889   if (!ISRELDEP(d))
890     return pool_addstdproviders(pool, d);
891   rd = GETRELDEP(pool, d);
892   name = rd->name;
893   evr = rd->evr;
894   flags = rd->flags;
895   d = GETRELID(d);
896   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
897
898   if (flags >= 8)
899     {
900       /* special relation */
901       Id wp = 0;
902       Id *pp2, *pp3;
903
904       switch (flags)
905         {
906         case REL_AND:
907         case REL_WITH:
908           wp = pool_whatprovides(pool, name);
909           pp2 = pool_whatprovides_ptr(pool, evr);
910           pp = pool->whatprovidesdata + wp;
911           while ((p = *pp++) != 0)
912             {
913               for (pp3 = pp2; *pp3; pp3++)
914                 if (*pp3 == p)
915                   break;
916               if (*pp3)
917                 queue_push(&plist, p);  /* found it */
918               else
919                 wp = 0;
920             }
921           break;
922         case REL_OR:
923           wp = pool_whatprovides(pool, name);
924           pp = pool->whatprovidesdata + wp;
925           if (!*pp)
926             wp = pool_whatprovides(pool, evr);
927           else
928             {
929               int cnt;
930               while ((p = *pp++) != 0)
931                 queue_push(&plist, p);
932               cnt = plist.count;
933               pp = pool_whatprovides_ptr(pool, evr);
934               while ((p = *pp++) != 0)
935                 queue_pushunique(&plist, p);
936               if (plist.count != cnt)
937                 wp = 0;
938             }
939           break;
940         case REL_NAMESPACE:
941           if (name == NAMESPACE_OTHERPROVIDERS)
942             {
943               wp = pool_whatprovides(pool, evr);
944               break;
945             }
946           if (pool->nscallback)
947             {
948               /* ask callback which packages provide the dependency
949                * 0:  none
950                * 1:  the system (aka SYSTEMSOLVABLE)
951                * >1: set of packages, stored as offset on whatprovidesdata
952                */
953               p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
954               if (p > 1)
955                 wp = p;
956               if (p == 1)
957                 queue_push(&plist, SYSTEMSOLVABLE);
958             }
959           break;
960         case REL_ARCH:
961           /* small hack: make it possible to match <pkg>.src
962            * we have to iterate over the solvables as src packages do not
963            * provide anything, thus they are not indexed in our
964            * whatprovides hash */
965           if (evr == ARCH_SRC || evr == ARCH_NOSRC)
966             {
967               Solvable *s;
968               for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
969                 {
970                   if (!s->repo)
971                     continue;
972                   if (s->arch != evr && s->arch != ARCH_NOSRC)
973                     continue;
974                   if (pool_disabled_solvable(pool, s))
975                     continue;
976                   if (!name || pool_match_nevr(pool, s, name))
977                     queue_push(&plist, p);
978                 }
979               break;
980             }
981           if (!name)
982             {
983               FOR_POOL_SOLVABLES(p)
984                 {
985                   Solvable *s = pool->solvables + p;
986                   if (s->repo != pool->installed && !pool_installable(pool, s))
987                     continue;
988                   if (s->arch == evr)
989                     queue_push(&plist, p);
990                 }
991               break;
992             }
993           wp = pool_whatprovides(pool, name);
994           pp = pool->whatprovidesdata + wp;
995           while ((p = *pp++) != 0)
996             {
997               Solvable *s = pool->solvables + p;
998               if (s->arch == evr)
999                 queue_push(&plist, p);
1000               else
1001                 wp = 0;
1002             }
1003           break;
1004         case REL_KIND:
1005           /* package kind filtering */
1006           if (!name)
1007             {
1008               FOR_POOL_SOLVABLES(p)
1009                 {
1010                   Solvable *s = pool->solvables + p;
1011                   if (s->repo != pool->installed && !pool_installable(pool, s))
1012                     continue;
1013                   if (pool_is_kind(pool, s->name, evr))
1014                     queue_push(&plist, p);
1015                 }
1016               break;
1017             }
1018           wp = pool_whatprovides(pool, name);
1019           pp = pool->whatprovidesdata + wp;
1020           while ((p = *pp++) != 0)
1021             {
1022               Solvable *s = pool->solvables + p;
1023               if (pool_is_kind(pool, s->name, evr))
1024                 queue_push(&plist, p);
1025               else
1026                 wp = 0;
1027             }
1028           break;
1029         case REL_FILECONFLICT:
1030           pp = pool_whatprovides_ptr(pool, name);
1031           while ((p = *pp++) != 0)
1032             {
1033               Id origd = MAKERELDEP(d);
1034               Solvable *s = pool->solvables + p;
1035               if (!s->provides)
1036                 continue;
1037               pidp = s->repo->idarraydata + s->provides;
1038               while ((pid = *pidp++) != 0)
1039                 if (pid == origd)
1040                   break;
1041               if (pid)
1042                 queue_push(&plist, p);
1043             }
1044           break;
1045         default:
1046           break;
1047         }
1048       if (wp)
1049         {
1050           /* we can reuse an existing entry */
1051           queue_free(&plist);
1052           pool->whatprovides_rel[d] = wp;
1053           return wp;
1054         }
1055     }
1056   else if (flags)
1057     {
1058       /* simple version comparison relation */
1059 #if 0
1060       POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name));
1061 #endif
1062       pp = pool_whatprovides_ptr(pool, name);
1063       while (ISRELDEP(name))
1064         {
1065           rd = GETRELDEP(pool, name);
1066           name = rd->name;
1067         }
1068       while ((p = *pp++) != 0)
1069         {
1070           Solvable *s = pool->solvables + p;
1071           if (!s->provides)
1072             {
1073               /* no provides - check nevr */
1074               if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
1075                 queue_push(&plist, p);
1076               continue;
1077             }
1078           /* solvable p provides name in some rels */
1079           pidp = s->repo->idarraydata + s->provides;
1080           while ((pid = *pidp++) != 0)
1081             {
1082               if (!ISRELDEP(pid))
1083                 {
1084                   if (pid != name)
1085                     continue;           /* wrong provides name */
1086                   if (pool->disttype == DISTTYPE_DEB)
1087                     continue;           /* unversioned provides can never match versioned deps */
1088                   break;
1089                 }
1090               prd = GETRELDEP(pool, pid);
1091               if (prd->name != name)
1092                 continue;               /* wrong provides name */
1093               /* right package, both deps are rels. check flags/evr */
1094               if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
1095                 break;  /* matches */
1096             }
1097           if (!pid)
1098             continue;   /* none of the providers matched */
1099           queue_push(&plist, p);
1100         }
1101       /* make our system solvable provide all unknown rpmlib() stuff */
1102       if (plist.count == 0 && !strncmp(pool_id2str(pool, name), "rpmlib(", 7))
1103         queue_push(&plist, SYSTEMSOLVABLE);
1104     }
1105   /* add providers to whatprovides */
1106 #if 0
1107   POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
1108 #endif
1109   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
1110   queue_free(&plist);
1111
1112   return pool->whatprovides_rel[d];
1113 }
1114
1115 void
1116 pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr)
1117 {
1118   int nrels = pool->nrels;
1119   Id d;
1120   Reldep *rd;
1121
1122   if (!pool->whatprovides_rel)
1123     return;
1124   for (d = 1, rd = pool->rels + d; d < nrels; d++, rd++)
1125     {
1126       if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS)
1127         continue;
1128       if (ns && rd->name != ns)
1129         continue;
1130       if (evr && rd->evr != evr)
1131         continue;
1132       pool->whatprovides_rel[d] = 0;
1133     }
1134 }
1135
1136 /* intersect dependencies in keyname with dep, return list of matching packages */
1137 void
1138 pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
1139 {
1140   Id p;
1141
1142   queue_empty(q);
1143   FOR_POOL_SOLVABLES(p)
1144     {
1145       Solvable *s = pool->solvables + p;
1146       if (s->repo->disabled)
1147         continue;
1148       if (s->repo != pool->installed && !pool_installable(pool, s))
1149         continue;
1150       if (solvable_matchesdep(s, keyname, dep, marker))
1151         queue_push(q, p);
1152     }
1153 }
1154
1155 /*************************************************************************/
1156
1157 void
1158 pool_debug(Pool *pool, int type, const char *format, ...)
1159 {
1160   va_list args;
1161   char buf[1024];
1162
1163   if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0)
1164     {
1165       if ((pool->debugmask & type) == 0)
1166         return;
1167     }
1168   va_start(args, format);
1169   if (!pool->debugcallback)
1170     {
1171       if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0 && !(pool->debugmask & SOLV_DEBUG_TO_STDERR))
1172         vprintf(format, args);
1173       else
1174         vfprintf(stderr, format, args);
1175       return;
1176     }
1177   vsnprintf(buf, sizeof(buf), format, args);
1178   va_end(args);
1179   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
1180 }
1181
1182 int
1183 pool_error(Pool *pool, int ret, const char *format, ...)
1184 {
1185   va_list args;
1186   int l;
1187   va_start(args, format);
1188   if (!pool->errstr)
1189     {
1190       pool->errstra = 1024;
1191       pool->errstr = solv_malloc(pool->errstra);
1192     }
1193   if (!*format)
1194     {
1195       *pool->errstr = 0;
1196       l = 0;
1197     }
1198   else
1199     l = vsnprintf(pool->errstr, pool->errstra, format, args);
1200   va_end(args);
1201   if (l >= 0 && l + 1 > pool->errstra)
1202     {
1203       pool->errstra = l + 256;
1204       pool->errstr = solv_realloc(pool->errstr, pool->errstra);
1205       va_start(args, format);
1206       l = vsnprintf(pool->errstr, pool->errstra, format, args);
1207       va_end(args);
1208     }
1209   if (l < 0)
1210     strcpy(pool->errstr, "unknown error");
1211   if (pool->debugmask & SOLV_ERROR)
1212     pool_debug(pool, SOLV_ERROR, "%s\n", pool->errstr);
1213   return ret;
1214 }
1215
1216 char *
1217 pool_errstr(Pool *pool)
1218 {
1219   return pool->errstr ? pool->errstr : "no error";
1220 }
1221
1222 void
1223 pool_setdebuglevel(Pool *pool, int level)
1224 {
1225   int mask = SOLV_DEBUG_RESULT;
1226   if (level > 0)
1227     mask |= SOLV_DEBUG_STATS|SOLV_DEBUG_ANALYZE|SOLV_DEBUG_UNSOLVABLE|SOLV_DEBUG_SOLVER|SOLV_DEBUG_TRANSACTION|SOLV_ERROR;
1228   if (level > 1)
1229     mask |= SOLV_DEBUG_JOB|SOLV_DEBUG_SOLUTIONS|SOLV_DEBUG_POLICY;
1230   if (level > 2)
1231     mask |= SOLV_DEBUG_PROPAGATE;
1232   if (level > 3)
1233     mask |= SOLV_DEBUG_RULE_CREATION;
1234   mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR;       /* keep bit */
1235   pool->debugmask = mask;
1236 }
1237
1238 void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata)
1239 {
1240   pool->debugcallback = debugcallback;
1241   pool->debugcallbackdata = debugcallbackdata;
1242 }
1243
1244 void pool_setdebugmask(Pool *pool, int mask)
1245 {
1246   pool->debugmask = mask;
1247 }
1248
1249 void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata)
1250 {
1251   pool->loadcallback = cb;
1252   pool->loadcallbackdata = loadcbdata;
1253 }
1254
1255 void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata)
1256 {
1257   pool->nscallback = cb;
1258   pool->nscallbackdata = nscbdata;
1259 }
1260
1261 /*************************************************************************/
1262
1263 struct searchfiles {
1264   Id *ids;
1265   char **dirs;
1266   char **names;
1267   int nfiles;
1268   Map seen;
1269 };
1270
1271 #define SEARCHFILES_BLOCK 127
1272
1273 static void
1274 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
1275 {
1276   Id dep, sid;
1277   const char *s, *sr;
1278   struct searchfiles *csf;
1279
1280   while ((dep = *ida++) != 0)
1281     {
1282       csf = sf;
1283       while (ISRELDEP(dep))
1284         {
1285           Reldep *rd;
1286           sid = pool->ss.nstrings + GETRELID(dep);
1287           if (MAPTST(&csf->seen, sid))
1288             {
1289               dep = 0;
1290               break;
1291             }
1292           MAPSET(&csf->seen, sid);
1293           rd = GETRELDEP(pool, dep);
1294           if (rd->flags < 8)
1295             dep = rd->name;
1296           else if (rd->flags == REL_NAMESPACE)
1297             {
1298               if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
1299                 {
1300                   csf = isf;
1301                   if (!csf || MAPTST(&csf->seen, sid))
1302                     {
1303                       dep = 0;
1304                       break;
1305                     }
1306                   MAPSET(&csf->seen, sid);
1307                 }
1308               dep = rd->evr;
1309             }
1310           else if (rd->flags == REL_FILECONFLICT)
1311             {
1312               dep = 0;
1313               break;
1314             }
1315           else
1316             {
1317               Id ids[2];
1318               ids[0] = rd->name;
1319               ids[1] = 0;
1320               pool_addfileprovides_dep(pool, ids, csf, isf);
1321               dep = rd->evr;
1322             }
1323         }
1324       if (!dep)
1325         continue;
1326       if (MAPTST(&csf->seen, dep))
1327         continue;
1328       MAPSET(&csf->seen, dep);
1329       s = pool_id2str(pool, dep);
1330       if (*s != '/')
1331         continue;
1332       if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s))
1333         continue;       /* skip non-standard locations csf == isf: installed case */
1334       csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
1335       csf->dirs = solv_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
1336       csf->names = solv_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
1337       csf->ids[csf->nfiles] = dep;
1338       sr = strrchr(s, '/');
1339       csf->names[csf->nfiles] = solv_strdup(sr + 1);
1340       csf->dirs[csf->nfiles] = solv_malloc(sr - s + 1);
1341       if (sr != s)
1342         strncpy(csf->dirs[csf->nfiles], s, sr - s);
1343       csf->dirs[csf->nfiles][sr - s] = 0;
1344       csf->nfiles++;
1345     }
1346 }
1347
1348 struct addfileprovides_cbdata {
1349   int nfiles;
1350   Id *ids;
1351   char **dirs;
1352   char **names;
1353
1354   Id *dids;
1355
1356   Map providedids;
1357
1358   Map useddirs;
1359 };
1360
1361 static int
1362 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1363 {
1364   struct addfileprovides_cbdata *cbd = cbdata;
1365   int i;
1366
1367   if (!cbd->useddirs.size)
1368     {
1369       map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
1370       for (i = 0; i < cbd->nfiles; i++)
1371         {
1372           Id did;
1373           if (MAPTST(&cbd->providedids, cbd->ids[i]))
1374             {
1375               cbd->dids[i] = 0;
1376               continue;
1377             }
1378           did = repodata_str2dir(data, cbd->dirs[i], 0);
1379           cbd->dids[i] = did;
1380           if (did)
1381             MAPSET(&cbd->useddirs, did);
1382         }
1383       repodata_free_dircache(data);
1384     }
1385   if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
1386     return 0;
1387   for (i = 0; i < cbd->nfiles; i++)
1388     {
1389       if (cbd->dids[i] != value->id)
1390         continue;
1391       if (!strcmp(cbd->names[i], value->str))
1392         break;
1393     }
1394   if (i == cbd->nfiles)
1395     return 0;
1396   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
1397   return 0;
1398 }
1399
1400 static void
1401 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
1402 {
1403   Id p;
1404   Repodata *data;
1405   Repo *repo;
1406   Queue fileprovidesq;
1407   int i, j, repoid, repodataid;
1408   int provstart, provend;
1409   Map donemap;
1410   int ndone, incomplete;
1411
1412   if (!pool->urepos)
1413     return;
1414
1415   cbd->nfiles = sf->nfiles;
1416   cbd->ids = sf->ids;
1417   cbd->dirs = sf->dirs;
1418   cbd->names = sf->names;
1419   cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
1420   map_init(&cbd->providedids, pool->ss.nstrings);
1421
1422   repoid = 1;
1423   repo = repoonly ? repoonly : pool->repos[repoid];
1424   map_init(&donemap, pool->nsolvables);
1425   queue_init(&fileprovidesq);
1426   provstart = provend = 0;
1427   for (;;)
1428     {
1429       if (!repo || repo->disabled)
1430         {
1431           if (repoonly || ++repoid == pool->nrepos)
1432             break;
1433           repo = pool->repos[repoid];
1434           continue;
1435         }
1436       ndone = 0;
1437       FOR_REPODATAS(repo, repodataid, data)
1438         {
1439           if (ndone >= repo->nsolvables)
1440             break;
1441
1442           if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
1443             {
1444               map_empty(&cbd->providedids);
1445               for (i = 0; i < fileprovidesq.count; i++)
1446                 MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
1447               provstart = data->start;
1448               provend = data->end;
1449               for (i = 0; i < cbd->nfiles; i++)
1450                 if (!MAPTST(&cbd->providedids, cbd->ids[i]))
1451                   break;
1452               if (i == cbd->nfiles)
1453                 {
1454                   /* great! no need to search files */
1455                   for (p = data->start; p < data->end; p++)
1456                     if (pool->solvables[p].repo == repo)
1457                       {
1458                         if (MAPTST(&donemap, p))
1459                           continue;
1460                         MAPSET(&donemap, p);
1461                         ndone++;
1462                       }
1463                   continue;
1464                 }
1465             }
1466
1467           if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
1468             continue;
1469
1470           if (data->start < provstart || data->end > provend)
1471             {
1472               map_empty(&cbd->providedids);
1473               provstart = provend = 0;
1474             }
1475
1476           /* check if the data is incomplete */
1477           incomplete = 0;
1478           if (data->state == REPODATA_AVAILABLE)
1479             {
1480               for (j = 1; j < data->nkeys; j++)
1481                 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1482                   break;
1483               if (j < data->nkeys)
1484                 {
1485 #if 0
1486                   for (i = 0; i < cbd->nfiles; i++)
1487                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
1488                       printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i]));
1489 #endif
1490                   for (i = 0; i < cbd->nfiles; i++)
1491                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
1492                       break;
1493                   if (i < cbd->nfiles)
1494                     incomplete = 1;
1495                 }
1496             }
1497
1498           /* do the search */
1499           map_init(&cbd->useddirs, 0);
1500           for (p = data->start; p < data->end; p++)
1501             if (pool->solvables[p].repo == repo)
1502               {
1503                 if (MAPTST(&donemap, p))
1504                   continue;
1505                 repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
1506                 if (!incomplete)
1507                   {
1508                     MAPSET(&donemap, p);
1509                     ndone++;
1510                   }
1511               }
1512           map_free(&cbd->useddirs);
1513         }
1514
1515       if (repoonly || ++repoid == pool->nrepos)
1516         break;
1517       repo = pool->repos[repoid];
1518     }
1519   map_free(&donemap);
1520   queue_free(&fileprovidesq);
1521   map_free(&cbd->providedids);
1522 }
1523
1524 void
1525 pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
1526 {
1527   Solvable *s;
1528   Repo *installed, *repo;
1529   struct searchfiles sf, isf, *isfp;
1530   struct addfileprovides_cbdata cbd;
1531   int i;
1532   unsigned int now;
1533
1534   installed = pool->installed;
1535   now = solv_timems(0);
1536   memset(&sf, 0, sizeof(sf));
1537   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
1538   memset(&isf, 0, sizeof(isf));
1539   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
1540   pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2;
1541
1542   if (idq)
1543     queue_empty(idq);
1544   if (idqinst)
1545     queue_empty(idqinst);
1546   isfp = installed ? &isf : 0;
1547   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
1548     {
1549       repo = s->repo;
1550       if (!repo)
1551         continue;
1552       if (s->obsoletes)
1553         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
1554       if (s->conflicts)
1555         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
1556       if (s->requires)
1557         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
1558       if (s->recommends)
1559         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
1560       if (s->suggests)
1561         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
1562       if (s->supplements)
1563         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
1564       if (s->enhances)
1565         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
1566     }
1567   map_free(&sf.seen);
1568   map_free(&isf.seen);
1569   POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
1570   cbd.dids = 0;
1571   if (sf.nfiles)
1572     {
1573 #if 0
1574       for (i = 0; i < sf.nfiles; i++)
1575         POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i]));
1576 #endif
1577       pool_addfileprovides_search(pool, &cbd, &sf, 0);
1578       if (idq)
1579         for (i = 0; i < sf.nfiles; i++)
1580           queue_push(idq, sf.ids[i]);
1581       if (idqinst)
1582         for (i = 0; i < sf.nfiles; i++)
1583           queue_push(idqinst, sf.ids[i]);
1584       solv_free(sf.ids);
1585       for (i = 0; i < sf.nfiles; i++)
1586         {
1587           solv_free(sf.dirs[i]);
1588           solv_free(sf.names[i]);
1589         }
1590       solv_free(sf.dirs);
1591       solv_free(sf.names);
1592     }
1593   if (isf.nfiles)
1594     {
1595 #if 0
1596       for (i = 0; i < isf.nfiles; i++)
1597         POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i]));
1598 #endif
1599       if (installed)
1600         pool_addfileprovides_search(pool, &cbd, &isf, installed);
1601       if (installed && idqinst)
1602         for (i = 0; i < isf.nfiles; i++)
1603           queue_pushunique(idqinst, isf.ids[i]);
1604       solv_free(isf.ids);
1605       for (i = 0; i < isf.nfiles; i++)
1606         {
1607           solv_free(isf.dirs[i]);
1608           solv_free(isf.names[i]);
1609         }
1610       solv_free(isf.dirs);
1611       solv_free(isf.names);
1612     }
1613   solv_free(cbd.dids);
1614   pool_freewhatprovides(pool);  /* as we have added provides */
1615   POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now));
1616 }
1617
1618 void
1619 pool_addfileprovides(Pool *pool)
1620 {
1621   pool_addfileprovides_queue(pool, 0, 0);
1622 }
1623
1624 void
1625 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)
1626 {
1627   if (p)
1628     {
1629       if (pool->solvables[p].repo)
1630         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1631       return;
1632     }
1633   /* FIXME: obey callback return value! */
1634   for (p = 1; p < pool->nsolvables; p++)
1635     if (pool->solvables[p].repo)
1636       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1637 }
1638
1639 void
1640 pool_clear_pos(Pool *pool)
1641 {
1642   memset(&pool->pos, 0, sizeof(pool->pos));
1643 }
1644
1645
1646 void
1647 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
1648 {
1649   int i;
1650
1651   pool->languagecache = solv_free(pool->languagecache);
1652   pool->languagecacheother = 0;
1653   if (pool->nlanguages)
1654     {
1655       for (i = 0; i < pool->nlanguages; i++)
1656         free((char *)pool->languages[i]);
1657       free(pool->languages);
1658     }
1659   pool->nlanguages = nlanguages;
1660   if (!nlanguages)
1661     return;
1662   pool->languages = solv_calloc(nlanguages, sizeof(const char **));
1663   for (i = 0; i < pool->nlanguages; i++)
1664     pool->languages[i] = solv_strdup(languages[i]);
1665 }
1666
1667 Id
1668 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1669 {
1670   const char *n;
1671   char buf[256], *p;
1672   int l;
1673
1674   if (!lang || !*lang)
1675     return id;
1676   n = pool_id2str(pool, id);
1677   l = strlen(n) + strlen(lang) + 2;
1678   if (l > sizeof(buf))
1679     p = solv_malloc(strlen(n) + strlen(lang) + 2);
1680   else
1681     p = buf;
1682   sprintf(p, "%s:%s", n, lang);
1683   id = pool_str2id(pool, p, create);
1684   if (p != buf)
1685     free(p);
1686   return id;
1687 }
1688
1689 char *
1690 pool_alloctmpspace(Pool *pool, int len)
1691 {
1692   int n = pool->tmpspace.n;
1693   if (!len)
1694     return 0;
1695   if (len > pool->tmpspace.len[n])
1696     {
1697       pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
1698       pool->tmpspace.len[n] = len + 32;
1699     }
1700   pool->tmpspace.n = (n + 1) % POOL_TMPSPACEBUF;
1701   return pool->tmpspace.buf[n];
1702 }
1703
1704 static char *
1705 pool_alloctmpspace_free(Pool *pool, const char *space, int len)
1706 {
1707   if (space)
1708     {
1709       int n, oldn;
1710       n = oldn = pool->tmpspace.n;
1711       for (;;)
1712         {
1713           if (!n--)
1714             n = POOL_TMPSPACEBUF - 1;
1715           if (n == oldn)
1716             break;
1717           if (pool->tmpspace.buf[n] != space)
1718             continue;
1719           if (len > pool->tmpspace.len[n])
1720             {
1721               pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
1722               pool->tmpspace.len[n] = len + 32;
1723             }
1724           return pool->tmpspace.buf[n];
1725         }
1726     }
1727   return 0;
1728 }
1729
1730 void
1731 pool_freetmpspace(Pool *pool, const char *space)
1732 {
1733   int n = pool->tmpspace.n;
1734   if (!space)
1735     return;
1736   n = (n + (POOL_TMPSPACEBUF - 1)) % POOL_TMPSPACEBUF;
1737   if (pool->tmpspace.buf[n] == space)
1738     pool->tmpspace.n = n;
1739 }
1740
1741 char *
1742 pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3)
1743 {
1744   int l1, l2, l3;
1745   char *s, *str;
1746   l1 = str1 ? strlen(str1) : 0;
1747   l2 = str2 ? strlen(str2) : 0;
1748   l3 = str3 ? strlen(str3) : 0;
1749   s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
1750   if (l1)
1751     {
1752       strcpy(s, str1);
1753       s += l1;
1754     }
1755   if (l2)
1756     {
1757       strcpy(s, str2);
1758       s += l2;
1759     }
1760   if (l3)
1761     {
1762       strcpy(s, str3);
1763       s += l3;
1764     }
1765   *s = 0;
1766   return str;
1767 }
1768
1769 char *
1770 pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3)
1771 {
1772   int l1, l2, l3;
1773   char *s, *str;
1774
1775   l1 = str1 ? strlen(str1) : 0;
1776   l2 = str2 ? strlen(str2) : 0;
1777   l3 = str3 ? strlen(str3) : 0;
1778   str = pool_alloctmpspace_free(pool, str1, l1 + l2 + l3 + 1);
1779   if (str)
1780     str1 = str;
1781   else
1782     str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
1783   s = str;
1784   if (l1)
1785     {
1786       if (s != str1)
1787         strcpy(s, str1);
1788       s += l1;
1789     }
1790   if (l2)
1791     {
1792       strcpy(s, str2);
1793       s += l2;
1794     }
1795   if (l3)
1796     {
1797       strcpy(s, str3);
1798       s += l3;
1799     }
1800   *s = 0;
1801   return str;
1802 }
1803
1804 const char *
1805 pool_bin2hex(Pool *pool, const unsigned char *buf, int len)
1806 {
1807   char *s;
1808   if (!len)
1809     return "";
1810   s = pool_alloctmpspace(pool, 2 * len + 1);
1811   solv_bin2hex(buf, len, s);
1812   return s;
1813 }
1814
1815 /*******************************************************************/
1816
1817 struct mptree {
1818   Id sibling;
1819   Id child;
1820   const char *comp;
1821   int compl;
1822   Id mountpoint;
1823 };
1824
1825 struct ducbdata {
1826   DUChanges *mps;
1827   struct mptree *mptree;
1828   int addsub;
1829   int hasdu;
1830
1831   Id *dirmap;
1832   int nmap;
1833   Repodata *olddata;
1834 };
1835
1836
1837 static int
1838 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1839 {
1840   struct ducbdata *cbd = cbdata;
1841   Id mp;
1842
1843   if (data != cbd->olddata)
1844     {
1845       Id dn, mp, comp, *dirmap, *dirs;
1846       int i, compl;
1847       const char *compstr;
1848       struct mptree *mptree;
1849
1850       /* create map from dir to mptree */
1851       cbd->dirmap = solv_free(cbd->dirmap);
1852       cbd->nmap = 0;
1853       dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id));
1854       mptree = cbd->mptree;
1855       mp = 0;
1856       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1857         {
1858           comp = *dirs++;
1859           if (comp <= 0)
1860             {
1861               mp = dirmap[-comp];
1862               continue;
1863             }
1864           if (mp < 0)
1865             {
1866               /* unconnected */
1867               dirmap[dn] = mp;
1868               continue;
1869             }
1870           if (!mptree[mp].child)
1871             {
1872               dirmap[dn] = -mp;
1873               continue;
1874             }
1875           if (data->localpool)
1876             compstr = stringpool_id2str(&data->spool, comp);
1877           else
1878             compstr = pool_id2str(data->repo->pool, comp);
1879           compl = strlen(compstr);
1880           for (i = mptree[mp].child; i; i = mptree[i].sibling)
1881             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1882               break;
1883           dirmap[dn] = i ? i : -mp;
1884         }
1885       /* change dirmap to point to mountpoint instead of mptree */
1886       for (dn = 0; dn < data->dirpool.ndirs; dn++)
1887         {
1888           mp = dirmap[dn];
1889           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1890         }
1891       cbd->dirmap = dirmap;
1892       cbd->nmap = data->dirpool.ndirs;
1893       cbd->olddata = data;
1894     }
1895   cbd->hasdu = 1;
1896   if (value->id < 0 || value->id >= cbd->nmap)
1897     return 0;
1898   mp = cbd->dirmap[value->id];
1899   if (mp < 0)
1900     return 0;
1901   if (cbd->addsub > 0)
1902     {
1903       cbd->mps[mp].kbytes += value->num;
1904       cbd->mps[mp].files += value->num2;
1905     }
1906   else
1907     {
1908       cbd->mps[mp].kbytes -= value->num;
1909       cbd->mps[mp].files -= value->num2;
1910     }
1911   return 0;
1912 }
1913
1914 static void
1915 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
1916 {
1917   int i;
1918   if (mptree[pos].mountpoint == -1)
1919     mptree[pos].mountpoint = mountpoint;
1920   else
1921     mountpoint = mptree[pos].mountpoint;
1922   for (i = mptree[pos].child; i; i = mptree[i].sibling)
1923     propagate_mountpoints(mptree, i, mountpoint);
1924 }
1925
1926 #define MPTREE_BLOCK 15
1927
1928 void
1929 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
1930 {
1931   char *p;
1932   const char *path, *compstr;
1933   struct mptree *mptree;
1934   int i, nmptree;
1935   int pos, compl;
1936   int mp;
1937   struct ducbdata cbd;
1938   Solvable *s;
1939   Id sp;
1940   Map ignoredu;
1941   Repo *oldinstalled = pool->installed;
1942
1943   memset(&ignoredu, 0, sizeof(ignoredu));
1944   cbd.mps = mps;
1945   cbd.addsub = 0;
1946   cbd.dirmap = 0;
1947   cbd.nmap = 0;
1948   cbd.olddata = 0;
1949
1950   mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1951
1952   /* our root node */
1953   mptree[0].sibling = 0;
1954   mptree[0].child = 0;
1955   mptree[0].comp = 0;
1956   mptree[0].compl = 0;
1957   mptree[0].mountpoint = -1;
1958   nmptree = 1;
1959   
1960   /* create component tree */
1961   for (mp = 0; mp < nmps; mp++)
1962     {
1963       mps[mp].kbytes = 0;
1964       mps[mp].files = 0;
1965       pos = 0;
1966       path = mps[mp].path;
1967       while(*path == '/')
1968         path++;
1969       while (*path)
1970         {
1971           if ((p = strchr(path, '/')) == 0)
1972             {
1973               compstr = path;
1974               compl = strlen(compstr);
1975               path += compl;
1976             }
1977           else
1978             {
1979               compstr = path;
1980               compl = p - path;
1981               path = p + 1;
1982               while(*path == '/')
1983                 path++;
1984             }
1985           for (i = mptree[pos].child; i; i = mptree[i].sibling)
1986             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1987               break;
1988           if (!i)
1989             {
1990               /* create new node */
1991               mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1992               i = nmptree++;
1993               mptree[i].sibling = mptree[pos].child;
1994               mptree[i].child = 0;
1995               mptree[i].comp = compstr;
1996               mptree[i].compl = compl;
1997               mptree[i].mountpoint = -1;
1998               mptree[pos].child = i;
1999             }
2000           pos = i;
2001         }
2002       mptree[pos].mountpoint = mp;
2003     }
2004
2005   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
2006
2007 #if 0
2008   for (i = 0; i < nmptree; i++)
2009     {
2010       printf("#%d sibling: %d\n", i, mptree[i].sibling);
2011       printf("#%d child: %d\n", i, mptree[i].child);
2012       printf("#%d comp: %s\n", i, mptree[i].comp);
2013       printf("#%d compl: %d\n", i, mptree[i].compl);
2014       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
2015     }
2016 #endif
2017
2018   cbd.mptree = mptree;
2019   cbd.addsub = 1;
2020   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
2021     {
2022       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
2023         continue;
2024       if (!MAPTST(installedmap, sp))
2025         continue;
2026       cbd.hasdu = 0;
2027       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
2028       if (!cbd.hasdu && oldinstalled)
2029         {
2030           Id op, opp;
2031           /* no du data available, ignore data of all installed solvables we obsolete */
2032           if (!ignoredu.map)
2033             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
2034           if (s->obsoletes)
2035             {
2036               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
2037               while ((obs = *obsp++) != 0)
2038                 FOR_PROVIDES(op, opp, obs)
2039                   if (op >= oldinstalled->start && op < oldinstalled->end)
2040                     MAPSET(&ignoredu, op - oldinstalled->start);
2041             }
2042           FOR_PROVIDES(op, opp, s->name)
2043             if (pool->solvables[op].name == s->name)
2044               if (op >= oldinstalled->start && op < oldinstalled->end)
2045                 MAPSET(&ignoredu, op - oldinstalled->start);
2046         }
2047     }
2048   cbd.addsub = -1;
2049   if (oldinstalled)
2050     {
2051       /* assumes we allways have du data for installed solvables */
2052       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
2053         {
2054           if (MAPTST(installedmap, sp))
2055             continue;
2056           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
2057             continue;
2058           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
2059         }
2060     }
2061   if (ignoredu.map)
2062     map_free(&ignoredu);
2063   solv_free(cbd.dirmap);
2064   solv_free(mptree);
2065 }
2066
2067 int
2068 pool_calc_installsizechange(Pool *pool, Map *installedmap)
2069 {
2070   Id sp;
2071   Solvable *s;
2072   int change = 0;
2073   Repo *oldinstalled = pool->installed;
2074
2075   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
2076     {
2077       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
2078         continue;
2079       if (!MAPTST(installedmap, sp))
2080         continue;
2081       change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
2082     }
2083   if (oldinstalled)
2084     {
2085       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
2086         {
2087           if (MAPTST(installedmap, sp))
2088             continue;
2089           change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
2090         }
2091     }
2092   return change;
2093 }
2094
2095 /* map:
2096  *  1: installed
2097  *  2: conflicts with installed
2098  *  8: interesting (only true if installed)
2099  * 16: undecided
2100  */
2101  
2102 static inline Id dep2name(Pool *pool, Id dep)
2103 {
2104   while (ISRELDEP(dep))
2105     {
2106       Reldep *rd = rd = GETRELDEP(pool, dep);
2107       dep = rd->name;
2108     }
2109   return dep;
2110 }
2111
2112 static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con) 
2113 {
2114   Id p, pp;
2115   Solvable *sn = pool->solvables + n; 
2116
2117   FOR_PROVIDES(p, pp, sn->name)
2118     {    
2119       Solvable *s = pool->solvables + p; 
2120       if (s->name != sn->name || s->arch != sn->arch)
2121         continue;
2122       if ((map[p] & 9) != 9)
2123         continue;
2124       if (pool_match_nevr(pool, pool->solvables + p, con))
2125         continue;
2126       return 1;         /* found installed package that doesn't conflict */
2127     }
2128   return 0;
2129 }
2130
2131 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *multiversionmap)
2132 {
2133   Id p, pp;
2134   int r = 0;
2135   FOR_PROVIDES(p, pp, dep)
2136     {
2137       if (p == SYSTEMSOLVABLE)
2138         return 1;       /* always boring, as never constraining */
2139       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
2140         continue;
2141       if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
2142         if (providedbyinstalled_multiversion(pool, map, p, dep))
2143           continue;
2144       if ((map[p] & 9) == 9)
2145         return 9;
2146       r |= map[p] & 17;
2147     }
2148   return r;
2149 }
2150
2151 /*
2152  * pool_trivial_installable - calculate if a set of solvables is
2153  * trivial installable without any other installs/deinstalls of
2154  * packages not belonging to the set.
2155  *
2156  * the state is returned in the result queue:
2157  * 1:  solvable is installable without any other package changes
2158  * 0:  solvable is not installable
2159  * -1: solvable is installable, but doesn't constrain any installed packages
2160  */
2161
2162 void
2163 pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap)
2164 {
2165   int i, r, m, did;
2166   Id p, *dp, con, *conp, req, *reqp;
2167   unsigned char *map;
2168   Solvable *s;
2169
2170   map = solv_calloc(pool->nsolvables, 1);
2171   for (p = 1; p < pool->nsolvables; p++)
2172     {
2173       if (!MAPTST(installedmap, p))
2174         continue;
2175       map[p] |= 9;
2176       s = pool->solvables + p;
2177       if (!s->conflicts)
2178         continue;
2179       conp = s->repo->idarraydata + s->conflicts;
2180       while ((con = *conp++) != 0)
2181         {
2182           dp = pool_whatprovides_ptr(pool, con);
2183           for (; *dp; dp++)
2184             map[p] |= 2;        /* XXX: self conflict ? */
2185         }
2186     }
2187   for (i = 0; i < pkgs->count; i++)
2188     map[pkgs->elements[i]] = 16;
2189
2190   for (i = 0, did = 0; did < pkgs->count; i++, did++)
2191     {
2192       if (i == pkgs->count)
2193         i = 0;
2194       p = pkgs->elements[i];
2195       if ((map[p] & 16) == 0)
2196         continue;
2197       if ((map[p] & 2) != 0)
2198         {
2199           map[p] = 2;
2200           continue;
2201         }
2202       s = pool->solvables + p;
2203       m = 1;
2204       if (s->requires)
2205         {
2206           reqp = s->repo->idarraydata + s->requires;
2207           while ((req = *reqp++) != 0)
2208             {
2209               if (req == SOLVABLE_PREREQMARKER)
2210                 continue;
2211               r = providedbyinstalled(pool, map, req, 0, 0);
2212               if (!r)
2213                 {
2214                   /* decided and miss */
2215                   map[p] = 2;
2216                   did = 0;
2217                   break;
2218                 }
2219               if (r == 16)
2220                 break;  /* undecided */
2221               m |= r;   /* 1 | 9 | 17 */
2222             }
2223           if (req)
2224             continue;
2225           if ((m & 9) == 9)
2226             m = 9;
2227         }
2228       if (s->conflicts)
2229         {
2230           int ispatch = 0;      /* see solver.c patch handling */
2231
2232           if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
2233             ispatch = 1;
2234           conp = s->repo->idarraydata + s->conflicts;
2235           while ((con = *conp++) != 0)
2236             {
2237               if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0)
2238                 {
2239                   map[p] = 2;
2240                   did = 0;
2241                   break;
2242                 }
2243               if ((m == 1 || m == 17) && ISRELDEP(con))
2244                 {
2245                   con = dep2name(pool, con);
2246                   if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0)
2247                     m = 9;
2248                 }
2249             }
2250           if (con)
2251             continue;   /* found a conflict */
2252         }
2253 #if 0
2254       if (s->repo && s->repo != oldinstalled)
2255         {
2256           Id p2, obs, *obsp, *pp;
2257           Solvable *s2;
2258           if (s->obsoletes)
2259             {
2260               obsp = s->repo->idarraydata + s->obsoletes;
2261               while ((obs = *obsp++) != 0)
2262                 {
2263                   if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
2264                     {
2265                       map[p] = 2;
2266                       break;
2267                     }
2268                 }
2269               if (obs)
2270                 continue;
2271             }
2272           FOR_PROVIDES(p2, pp, s->name)
2273             {
2274               s2 = pool->solvables + p2;
2275               if (s2->name == s->name && (map[p2] & 1) != 0)
2276                 {
2277                   map[p] = 2;
2278                   break;
2279                 }
2280             }
2281           if (p2)
2282             continue;
2283         }
2284 #endif
2285       if (m != map[p])
2286         {
2287           map[p] = m;
2288           did = 0;
2289         }
2290     }
2291   queue_free(res);
2292   queue_init_clone(res, pkgs);
2293   for (i = 0; i < pkgs->count; i++)
2294     {
2295       m = map[pkgs->elements[i]];
2296       if ((m & 9) == 9)
2297         r = 1;
2298       else if (m & 1)
2299         r = -1;
2300       else
2301         r = 0;
2302       res->elements[i] = r;
2303     }
2304   free(map);
2305 }
2306
2307 void
2308 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
2309 {
2310   pool_trivial_installable_multiversionmap(pool, installedmap, pkgs, res, 0);
2311 }
2312
2313 const char *
2314 pool_lookup_str(Pool *pool, Id entry, Id keyname)
2315 {
2316   if (entry == SOLVID_POS && pool->pos.repo)
2317     return repo_lookup_str(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
2318   if (entry <= 0)
2319     return 0;
2320   return solvable_lookup_str(pool->solvables + entry, keyname);
2321 }
2322
2323 Id
2324 pool_lookup_id(Pool *pool, Id entry, Id keyname)
2325 {
2326   if (entry == SOLVID_POS && pool->pos.repo)
2327     return repo_lookup_id(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
2328   if (entry <= 0)
2329     return 0;
2330   return solvable_lookup_id(pool->solvables + entry, keyname);
2331 }
2332
2333 unsigned long long
2334 pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound)
2335 {
2336   if (entry == SOLVID_POS && pool->pos.repo)
2337     return repo_lookup_num(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, notfound);
2338   if (entry <= 0)
2339     return notfound;
2340   return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
2341 }
2342
2343 int
2344 pool_lookup_void(Pool *pool, Id entry, Id keyname)
2345 {
2346   if (entry == SOLVID_POS && pool->pos.repo)
2347     return repo_lookup_void(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
2348   if (entry <= 0)
2349     return 0;
2350   return solvable_lookup_void(pool->solvables + entry, keyname);
2351 }
2352
2353 const unsigned char *
2354 pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
2355 {
2356   if (entry == SOLVID_POS && pool->pos.repo)
2357     return repo_lookup_bin_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
2358   if (entry <= 0)
2359     return 0;
2360   return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
2361 }
2362
2363 const char *
2364 pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
2365 {
2366   if (entry == SOLVID_POS && pool->pos.repo)
2367     return repo_lookup_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
2368   if (entry <= 0)
2369     return 0;
2370   return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
2371 }
2372
2373 int
2374 pool_lookup_idarray(Pool *pool, Id entry, Id keyname, Queue *q)
2375 {
2376   if (entry == SOLVID_POS && pool->pos.repo)
2377     return repo_lookup_idarray(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, q);
2378   if (entry <= 0)
2379     return 0;
2380   return solvable_lookup_idarray(pool->solvables + entry, keyname, q);
2381 }
2382
2383 const char *
2384 pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp)
2385 {
2386   const char *loc;
2387   if (medianrp)
2388     *medianrp = 0;
2389   if (entry != SOLVID_POS)
2390     return 0;
2391   loc = pool_lookup_str(pool, entry, DELTA_LOCATION_DIR);
2392   loc = pool_tmpjoin(pool, loc, loc ? "/" : 0, pool_lookup_str(pool, entry, DELTA_LOCATION_NAME));
2393   loc = pool_tmpappend(pool, loc, "-", pool_lookup_str(pool, entry, DELTA_LOCATION_EVR));
2394   loc = pool_tmpappend(pool, loc, ".", pool_lookup_str(pool, entry, DELTA_LOCATION_SUFFIX));
2395   return loc;
2396 }
2397
2398 static void
2399 add_new_provider(Pool *pool, Id id, Id p)
2400 {
2401   Queue q;
2402   Id *pp;
2403
2404   while (ISRELDEP(id))
2405     {
2406       Reldep *rd = GETRELDEP(pool, id);
2407       id = rd->name;
2408     }
2409
2410   queue_init(&q);
2411   for (pp = pool->whatprovidesdata + pool->whatprovides[id]; *pp; pp++)
2412     {
2413       if (*pp == p)
2414         {
2415           queue_free(&q);
2416           return;
2417         }
2418       if (*pp > p)
2419         {
2420           queue_push(&q, p);
2421           p = 0;
2422         }
2423       queue_push(&q, *pp);
2424     }
2425   if (p)
2426     queue_push(&q, p);
2427   pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
2428   queue_free(&q);
2429 }
2430
2431 void
2432 pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
2433 {
2434   int hadhashes = pool->relhashtbl ? 1 : 0;
2435   Solvable *s;
2436   Id fn, p, q, md5;
2437   Id id;
2438   int i;
2439
2440   if (!conflicts->count)
2441     return;
2442   for (i = 0; i < conflicts->count; i += 6)
2443     {
2444       fn = conflicts->elements[i];
2445       p = conflicts->elements[i + 1];
2446       md5 = conflicts->elements[i + 2];
2447       q = conflicts->elements[i + 4];
2448       id = pool_rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
2449       s = pool->solvables + p;
2450       if (!s->repo)
2451         continue;
2452       s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
2453       if (pool->whatprovides)
2454         add_new_provider(pool, fn, p);
2455       if (pool->whatprovides_rel)
2456         pool->whatprovides_rel[GETRELID(id)] = 0;       /* clear cache */
2457       s = pool->solvables + q;
2458       if (!s->repo)
2459         continue;
2460       s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
2461     }
2462   if (!hadhashes)
2463     pool_freeidhashes(pool);
2464 }
2465
2466 char *
2467 pool_prepend_rootdir(Pool *pool, const char *path)
2468 {
2469   if (!path)
2470     return 0;
2471   if (!pool->rootdir)
2472     return solv_strdup(path);
2473   return solv_dupjoin(pool->rootdir, "/", *path == '/' ? path + 1 : path);
2474 }
2475
2476 const char *
2477 pool_prepend_rootdir_tmp(Pool *pool, const char *path)
2478 {
2479   if (!path)
2480     return 0;
2481   if (!pool->rootdir)
2482     return path;
2483   return pool_tmpjoin(pool, pool->rootdir, "/", *path == '/' ? path + 1 : path);
2484 }
2485
2486 void
2487 pool_set_rootdir(Pool *pool, const char *rootdir)
2488 {
2489   solv_free(pool->rootdir);
2490   pool->rootdir = solv_strdup(rootdir);
2491 }
2492
2493 const char *
2494 pool_get_rootdir(Pool *pool)
2495 {
2496   return pool->rootdir;
2497 }
2498
2499 /* only used in libzypp */
2500 void
2501 pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *))
2502 {
2503   pool->custom_vendorcheck = vendorcheck;
2504 }
2505
2506 /* EOF */