rename selection_make_deps to selection_make_matchdeps, add marker support
[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 /*
850  * addrelproviders
851  * 
852  * add packages fulfilling the relation to whatprovides array
853  * 
854  */
855 Id
856 pool_addrelproviders(Pool *pool, Id d)
857 {
858   Reldep *rd;
859   Reldep *prd;
860   Queue plist;
861   Id buf[16];
862   Id name, evr, flags;
863   Id pid, *pidp;
864   Id p, *pp;
865
866   if (!ISRELDEP(d))
867     return pool_addstdproviders(pool, d);
868   rd = GETRELDEP(pool, d);
869   name = rd->name;
870   evr = rd->evr;
871   flags = rd->flags;
872   d = GETRELID(d);
873   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
874
875   if (flags >= 8)
876     {
877       /* special relation */
878       Id wp = 0;
879       Id *pp2, *pp3;
880
881       switch (flags)
882         {
883         case REL_AND:
884         case REL_WITH:
885           wp = pool_whatprovides(pool, name);
886           pp2 = pool_whatprovides_ptr(pool, evr);
887           pp = pool->whatprovidesdata + wp;
888           while ((p = *pp++) != 0)
889             {
890               for (pp3 = pp2; *pp3; pp3++)
891                 if (*pp3 == p)
892                   break;
893               if (*pp3)
894                 queue_push(&plist, p);  /* found it */
895               else
896                 wp = 0;
897             }
898           break;
899         case REL_OR:
900           wp = pool_whatprovides(pool, name);
901           pp = pool->whatprovidesdata + wp;
902           if (!*pp)
903             wp = pool_whatprovides(pool, evr);
904           else
905             {
906               int cnt;
907               while ((p = *pp++) != 0)
908                 queue_push(&plist, p);
909               cnt = plist.count;
910               pp = pool_whatprovides_ptr(pool, evr);
911               while ((p = *pp++) != 0)
912                 queue_pushunique(&plist, p);
913               if (plist.count != cnt)
914                 wp = 0;
915             }
916           break;
917         case REL_NAMESPACE:
918           if (name == NAMESPACE_OTHERPROVIDERS)
919             {
920               wp = pool_whatprovides(pool, evr);
921               break;
922             }
923           if (pool->nscallback)
924             {
925               /* ask callback which packages provide the dependency
926                * 0:  none
927                * 1:  the system (aka SYSTEMSOLVABLE)
928                * >1: set of packages, stored as offset on whatprovidesdata
929                */
930               p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
931               if (p > 1)
932                 wp = p;
933               if (p == 1)
934                 queue_push(&plist, SYSTEMSOLVABLE);
935             }
936           break;
937         case REL_ARCH:
938           /* small hack: make it possible to match <pkg>.src
939            * we have to iterate over the solvables as src packages do not
940            * provide anything, thus they are not indexed in our
941            * whatprovides hash */
942           if (evr == ARCH_SRC || evr == ARCH_NOSRC)
943             {
944               Solvable *s;
945               for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
946                 {
947                   if (!s->repo)
948                     continue;
949                   if (s->arch != evr && s->arch != ARCH_NOSRC)
950                     continue;
951                   if (pool_disabled_solvable(pool, s))
952                     continue;
953                   if (pool_match_nevr(pool, s, name))
954                     queue_push(&plist, p);
955                 }
956               break;
957             }
958           wp = pool_whatprovides(pool, name);
959           pp = pool->whatprovidesdata + wp;
960           while ((p = *pp++) != 0)
961             {
962               Solvable *s = pool->solvables + p;
963               if (s->arch == evr)
964                 queue_push(&plist, p);
965               else
966                 wp = 0;
967             }
968           break;
969         case REL_FILECONFLICT:
970           pp = pool_whatprovides_ptr(pool, name);
971           while ((p = *pp++) != 0)
972             {
973               Id origd = MAKERELDEP(d);
974               Solvable *s = pool->solvables + p;
975               if (!s->provides)
976                 continue;
977               pidp = s->repo->idarraydata + s->provides;
978               while ((pid = *pidp++) != 0)
979                 if (pid == origd)
980                   break;
981               if (pid)
982                 queue_push(&plist, p);
983             }
984           break;
985         default:
986           break;
987         }
988       if (wp)
989         {
990           /* we can reuse an existing entry */
991           queue_free(&plist);
992           pool->whatprovides_rel[d] = wp;
993           return wp;
994         }
995     }
996   else if (flags)
997     {
998       /* simple version comparison relation */
999 #if 0
1000       POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: what provides %s?\n", pool_dep2str(pool, name));
1001 #endif
1002       pp = pool_whatprovides_ptr(pool, name);
1003       while (ISRELDEP(name))
1004         {
1005           rd = GETRELDEP(pool, name);
1006           name = rd->name;
1007         }
1008       while ((p = *pp++) != 0)
1009         {
1010           Solvable *s = pool->solvables + p;
1011           if (!s->provides)
1012             {
1013               /* no provides - check nevr */
1014               if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
1015                 queue_push(&plist, p);
1016               continue;
1017             }
1018           /* solvable p provides name in some rels */
1019           pidp = s->repo->idarraydata + s->provides;
1020           while ((pid = *pidp++) != 0)
1021             {
1022               if (!ISRELDEP(pid))
1023                 {
1024                   if (pid != name)
1025                     continue;           /* wrong provides name */
1026                   if (pool->disttype == DISTTYPE_DEB)
1027                     continue;           /* unversioned provides can never match versioned deps */
1028                   break;
1029                 }
1030               prd = GETRELDEP(pool, pid);
1031               if (prd->name != name)
1032                 continue;               /* wrong provides name */
1033               /* right package, both deps are rels. check flags/evr */
1034               if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
1035                 break;  /* matches */
1036             }
1037           if (!pid)
1038             continue;   /* none of the providers matched */
1039           queue_push(&plist, p);
1040         }
1041       /* make our system solvable provide all unknown rpmlib() stuff */
1042       if (plist.count == 0 && !strncmp(pool_id2str(pool, name), "rpmlib(", 7))
1043         queue_push(&plist, SYSTEMSOLVABLE);
1044     }
1045   /* add providers to whatprovides */
1046 #if 0
1047   POOL_DEBUG(SOLV_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
1048 #endif
1049   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
1050   queue_free(&plist);
1051
1052   return pool->whatprovides_rel[d];
1053 }
1054
1055 void
1056 pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr)
1057 {
1058   int nrels = pool->nrels;
1059   Id d;
1060   Reldep *rd;
1061
1062   if (!pool->whatprovides_rel)
1063     return;
1064   for (d = 1, rd = pool->rels + d; d < nrels; d++, rd++)
1065     {
1066       if (rd->flags != REL_NAMESPACE || rd->name == NAMESPACE_OTHERPROVIDERS)
1067         continue;
1068       if (ns && rd->name != ns)
1069         continue;
1070       if (evr && rd->evr != evr)
1071         continue;
1072       pool->whatprovides_rel[d] = 0;
1073     }
1074 }
1075
1076 /* intersect dependencies in keyname with dep, return list of matching packages */
1077 void
1078 pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
1079 {
1080   Id p;
1081
1082   queue_empty(q);
1083   FOR_POOL_SOLVABLES(p)
1084     {
1085       Solvable *s = pool->solvables + p;
1086       if (s->repo->disabled)
1087         continue;
1088       if (s->repo != pool->installed && !pool_installable(pool, s))
1089         continue;
1090       if (solvable_matchesdep(s, keyname, dep, marker))
1091         queue_push(q, p);
1092     }
1093 }
1094
1095 /*************************************************************************/
1096
1097 void
1098 pool_debug(Pool *pool, int type, const char *format, ...)
1099 {
1100   va_list args;
1101   char buf[1024];
1102
1103   if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0)
1104     {
1105       if ((pool->debugmask & type) == 0)
1106         return;
1107     }
1108   va_start(args, format);
1109   if (!pool->debugcallback)
1110     {
1111       if ((type & (SOLV_FATAL|SOLV_ERROR)) == 0 && !(pool->debugmask & SOLV_DEBUG_TO_STDERR))
1112         vprintf(format, args);
1113       else
1114         vfprintf(stderr, format, args);
1115       return;
1116     }
1117   vsnprintf(buf, sizeof(buf), format, args);
1118   va_end(args);
1119   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
1120 }
1121
1122 int
1123 pool_error(Pool *pool, int ret, const char *format, ...)
1124 {
1125   va_list args;
1126   int l;
1127   va_start(args, format);
1128   if (!pool->errstr)
1129     {
1130       pool->errstra = 1024;
1131       pool->errstr = solv_malloc(pool->errstra);
1132     }
1133   if (!*format)
1134     {
1135       *pool->errstr = 0;
1136       l = 0;
1137     }
1138   else
1139     l = vsnprintf(pool->errstr, pool->errstra, format, args);
1140   va_end(args);
1141   if (l >= 0 && l + 1 > pool->errstra)
1142     {
1143       pool->errstra = l + 256;
1144       pool->errstr = solv_realloc(pool->errstr, pool->errstra);
1145       va_start(args, format);
1146       l = vsnprintf(pool->errstr, pool->errstra, format, args);
1147       va_end(args);
1148     }
1149   if (l < 0)
1150     strcpy(pool->errstr, "unknown error");
1151   if (pool->debugmask & SOLV_ERROR)
1152     pool_debug(pool, SOLV_ERROR, "%s\n", pool->errstr);
1153   return ret;
1154 }
1155
1156 char *
1157 pool_errstr(Pool *pool)
1158 {
1159   return pool->errstr ? pool->errstr : "no error";
1160 }
1161
1162 void
1163 pool_setdebuglevel(Pool *pool, int level)
1164 {
1165   int mask = SOLV_DEBUG_RESULT;
1166   if (level > 0)
1167     mask |= SOLV_DEBUG_STATS|SOLV_DEBUG_ANALYZE|SOLV_DEBUG_UNSOLVABLE|SOLV_DEBUG_SOLVER|SOLV_DEBUG_TRANSACTION|SOLV_ERROR;
1168   if (level > 1)
1169     mask |= SOLV_DEBUG_JOB|SOLV_DEBUG_SOLUTIONS|SOLV_DEBUG_POLICY;
1170   if (level > 2)
1171     mask |= SOLV_DEBUG_PROPAGATE;
1172   if (level > 3)
1173     mask |= SOLV_DEBUG_RULE_CREATION;
1174   mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR;       /* keep bit */
1175   pool->debugmask = mask;
1176 }
1177
1178 void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata)
1179 {
1180   pool->debugcallback = debugcallback;
1181   pool->debugcallbackdata = debugcallbackdata;
1182 }
1183
1184 void pool_setdebugmask(Pool *pool, int mask)
1185 {
1186   pool->debugmask = mask;
1187 }
1188
1189 void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata)
1190 {
1191   pool->loadcallback = cb;
1192   pool->loadcallbackdata = loadcbdata;
1193 }
1194
1195 void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata)
1196 {
1197   pool->nscallback = cb;
1198   pool->nscallbackdata = nscbdata;
1199 }
1200
1201 /*************************************************************************/
1202
1203 struct searchfiles {
1204   Id *ids;
1205   char **dirs;
1206   char **names;
1207   int nfiles;
1208   Map seen;
1209 };
1210
1211 #define SEARCHFILES_BLOCK 127
1212
1213 static void
1214 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
1215 {
1216   Id dep, sid;
1217   const char *s, *sr;
1218   struct searchfiles *csf;
1219
1220   while ((dep = *ida++) != 0)
1221     {
1222       csf = sf;
1223       while (ISRELDEP(dep))
1224         {
1225           Reldep *rd;
1226           sid = pool->ss.nstrings + GETRELID(dep);
1227           if (MAPTST(&csf->seen, sid))
1228             {
1229               dep = 0;
1230               break;
1231             }
1232           MAPSET(&csf->seen, sid);
1233           rd = GETRELDEP(pool, dep);
1234           if (rd->flags < 8)
1235             dep = rd->name;
1236           else if (rd->flags == REL_NAMESPACE)
1237             {
1238               if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
1239                 {
1240                   csf = isf;
1241                   if (!csf || MAPTST(&csf->seen, sid))
1242                     {
1243                       dep = 0;
1244                       break;
1245                     }
1246                   MAPSET(&csf->seen, sid);
1247                 }
1248               dep = rd->evr;
1249             }
1250           else if (rd->flags == REL_FILECONFLICT)
1251             {
1252               dep = 0;
1253               break;
1254             }
1255           else
1256             {
1257               Id ids[2];
1258               ids[0] = rd->name;
1259               ids[1] = 0;
1260               pool_addfileprovides_dep(pool, ids, csf, isf);
1261               dep = rd->evr;
1262             }
1263         }
1264       if (!dep)
1265         continue;
1266       if (MAPTST(&csf->seen, dep))
1267         continue;
1268       MAPSET(&csf->seen, dep);
1269       s = pool_id2str(pool, dep);
1270       if (*s != '/')
1271         continue;
1272       if (csf != isf && pool->addedfileprovides == 1 && !repodata_filelistfilter_matches(0, s))
1273         continue;       /* skip non-standard locations csf == isf: installed case */
1274       csf->ids = solv_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
1275       csf->dirs = solv_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
1276       csf->names = solv_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
1277       csf->ids[csf->nfiles] = dep;
1278       sr = strrchr(s, '/');
1279       csf->names[csf->nfiles] = solv_strdup(sr + 1);
1280       csf->dirs[csf->nfiles] = solv_malloc(sr - s + 1);
1281       if (sr != s)
1282         strncpy(csf->dirs[csf->nfiles], s, sr - s);
1283       csf->dirs[csf->nfiles][sr - s] = 0;
1284       csf->nfiles++;
1285     }
1286 }
1287
1288 struct addfileprovides_cbdata {
1289   int nfiles;
1290   Id *ids;
1291   char **dirs;
1292   char **names;
1293
1294   Id *dids;
1295
1296   Map providedids;
1297
1298   Map useddirs;
1299 };
1300
1301 static int
1302 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1303 {
1304   struct addfileprovides_cbdata *cbd = cbdata;
1305   int i;
1306
1307   if (!cbd->useddirs.size)
1308     {
1309       map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
1310       for (i = 0; i < cbd->nfiles; i++)
1311         {
1312           Id did;
1313           if (MAPTST(&cbd->providedids, cbd->ids[i]))
1314             {
1315               cbd->dids[i] = 0;
1316               continue;
1317             }
1318           did = repodata_str2dir(data, cbd->dirs[i], 0);
1319           cbd->dids[i] = did;
1320           if (did)
1321             MAPSET(&cbd->useddirs, did);
1322         }
1323       repodata_free_dircache(data);
1324     }
1325   if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
1326     return 0;
1327   for (i = 0; i < cbd->nfiles; i++)
1328     {
1329       if (cbd->dids[i] != value->id)
1330         continue;
1331       if (!strcmp(cbd->names[i], value->str))
1332         break;
1333     }
1334   if (i == cbd->nfiles)
1335     return 0;
1336   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
1337   return 0;
1338 }
1339
1340 static void
1341 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
1342 {
1343   Id p;
1344   Repodata *data;
1345   Repo *repo;
1346   Queue fileprovidesq;
1347   int i, j, repoid, repodataid;
1348   int provstart, provend;
1349   Map donemap;
1350   int ndone, incomplete;
1351
1352   if (!pool->urepos)
1353     return;
1354
1355   cbd->nfiles = sf->nfiles;
1356   cbd->ids = sf->ids;
1357   cbd->dirs = sf->dirs;
1358   cbd->names = sf->names;
1359   cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
1360   map_init(&cbd->providedids, pool->ss.nstrings);
1361
1362   repoid = 1;
1363   repo = repoonly ? repoonly : pool->repos[repoid];
1364   map_init(&donemap, pool->nsolvables);
1365   queue_init(&fileprovidesq);
1366   provstart = provend = 0;
1367   for (;;)
1368     {
1369       if (!repo || repo->disabled)
1370         {
1371           if (repoonly || ++repoid == pool->nrepos)
1372             break;
1373           repo = pool->repos[repoid];
1374           continue;
1375         }
1376       ndone = 0;
1377       FOR_REPODATAS(repo, repodataid, data)
1378         {
1379           if (ndone >= repo->nsolvables)
1380             break;
1381
1382           if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
1383             {
1384               map_empty(&cbd->providedids);
1385               for (i = 0; i < fileprovidesq.count; i++)
1386                 MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
1387               provstart = data->start;
1388               provend = data->end;
1389               for (i = 0; i < cbd->nfiles; i++)
1390                 if (!MAPTST(&cbd->providedids, cbd->ids[i]))
1391                   break;
1392               if (i == cbd->nfiles)
1393                 {
1394                   /* great! no need to search files */
1395                   for (p = data->start; p < data->end; p++)
1396                     if (pool->solvables[p].repo == repo)
1397                       {
1398                         if (MAPTST(&donemap, p))
1399                           continue;
1400                         MAPSET(&donemap, p);
1401                         ndone++;
1402                       }
1403                   continue;
1404                 }
1405             }
1406
1407           if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
1408             continue;
1409
1410           if (data->start < provstart || data->end > provend)
1411             {
1412               map_empty(&cbd->providedids);
1413               provstart = provend = 0;
1414             }
1415
1416           /* check if the data is incomplete */
1417           incomplete = 0;
1418           if (data->state == REPODATA_AVAILABLE)
1419             {
1420               for (j = 1; j < data->nkeys; j++)
1421                 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1422                   break;
1423               if (j < data->nkeys)
1424                 {
1425 #if 0
1426                   for (i = 0; i < cbd->nfiles; i++)
1427                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
1428                       printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i]));
1429 #endif
1430                   for (i = 0; i < cbd->nfiles; i++)
1431                     if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
1432                       break;
1433                   if (i < cbd->nfiles)
1434                     incomplete = 1;
1435                 }
1436             }
1437
1438           /* do the search */
1439           map_init(&cbd->useddirs, 0);
1440           for (p = data->start; p < data->end; p++)
1441             if (pool->solvables[p].repo == repo)
1442               {
1443                 if (MAPTST(&donemap, p))
1444                   continue;
1445                 repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
1446                 if (!incomplete)
1447                   {
1448                     MAPSET(&donemap, p);
1449                     ndone++;
1450                   }
1451               }
1452           map_free(&cbd->useddirs);
1453         }
1454
1455       if (repoonly || ++repoid == pool->nrepos)
1456         break;
1457       repo = pool->repos[repoid];
1458     }
1459   map_free(&donemap);
1460   queue_free(&fileprovidesq);
1461   map_free(&cbd->providedids);
1462 }
1463
1464 void
1465 pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
1466 {
1467   Solvable *s;
1468   Repo *installed, *repo;
1469   struct searchfiles sf, isf, *isfp;
1470   struct addfileprovides_cbdata cbd;
1471   int i;
1472   unsigned int now;
1473
1474   installed = pool->installed;
1475   now = solv_timems(0);
1476   memset(&sf, 0, sizeof(sf));
1477   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
1478   memset(&isf, 0, sizeof(isf));
1479   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
1480   pool->addedfileprovides = pool->addfileprovidesfiltered ? 1 : 2;
1481
1482   if (idq)
1483     queue_empty(idq);
1484   if (idqinst)
1485     queue_empty(idqinst);
1486   isfp = installed ? &isf : 0;
1487   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
1488     {
1489       repo = s->repo;
1490       if (!repo)
1491         continue;
1492       if (s->obsoletes)
1493         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
1494       if (s->conflicts)
1495         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
1496       if (s->requires)
1497         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
1498       if (s->recommends)
1499         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
1500       if (s->suggests)
1501         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
1502       if (s->supplements)
1503         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
1504       if (s->enhances)
1505         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
1506     }
1507   map_free(&sf.seen);
1508   map_free(&isf.seen);
1509   POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
1510   cbd.dids = 0;
1511   if (sf.nfiles)
1512     {
1513 #if 0
1514       for (i = 0; i < sf.nfiles; i++)
1515         POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i]));
1516 #endif
1517       pool_addfileprovides_search(pool, &cbd, &sf, 0);
1518       if (idq)
1519         for (i = 0; i < sf.nfiles; i++)
1520           queue_push(idq, sf.ids[i]);
1521       if (idqinst)
1522         for (i = 0; i < sf.nfiles; i++)
1523           queue_push(idqinst, sf.ids[i]);
1524       solv_free(sf.ids);
1525       for (i = 0; i < sf.nfiles; i++)
1526         {
1527           solv_free(sf.dirs[i]);
1528           solv_free(sf.names[i]);
1529         }
1530       solv_free(sf.dirs);
1531       solv_free(sf.names);
1532     }
1533   if (isf.nfiles)
1534     {
1535 #if 0
1536       for (i = 0; i < isf.nfiles; i++)
1537         POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i]));
1538 #endif
1539       if (installed)
1540         pool_addfileprovides_search(pool, &cbd, &isf, installed);
1541       if (installed && idqinst)
1542         for (i = 0; i < isf.nfiles; i++)
1543           queue_pushunique(idqinst, isf.ids[i]);
1544       solv_free(isf.ids);
1545       for (i = 0; i < isf.nfiles; i++)
1546         {
1547           solv_free(isf.dirs[i]);
1548           solv_free(isf.names[i]);
1549         }
1550       solv_free(isf.dirs);
1551       solv_free(isf.names);
1552     }
1553   solv_free(cbd.dids);
1554   pool_freewhatprovides(pool);  /* as we have added provides */
1555   POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now));
1556 }
1557
1558 void
1559 pool_addfileprovides(Pool *pool)
1560 {
1561   pool_addfileprovides_queue(pool, 0, 0);
1562 }
1563
1564 void
1565 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)
1566 {
1567   if (p)
1568     {
1569       if (pool->solvables[p].repo)
1570         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1571       return;
1572     }
1573   /* FIXME: obey callback return value! */
1574   for (p = 1; p < pool->nsolvables; p++)
1575     if (pool->solvables[p].repo)
1576       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1577 }
1578
1579 void
1580 pool_clear_pos(Pool *pool)
1581 {
1582   memset(&pool->pos, 0, sizeof(pool->pos));
1583 }
1584
1585
1586 void
1587 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
1588 {
1589   int i;
1590
1591   pool->languagecache = solv_free(pool->languagecache);
1592   pool->languagecacheother = 0;
1593   if (pool->nlanguages)
1594     {
1595       for (i = 0; i < pool->nlanguages; i++)
1596         free((char *)pool->languages[i]);
1597       free(pool->languages);
1598     }
1599   pool->nlanguages = nlanguages;
1600   if (!nlanguages)
1601     return;
1602   pool->languages = solv_calloc(nlanguages, sizeof(const char **));
1603   for (i = 0; i < pool->nlanguages; i++)
1604     pool->languages[i] = solv_strdup(languages[i]);
1605 }
1606
1607 Id
1608 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1609 {
1610   const char *n;
1611   char buf[256], *p;
1612   int l;
1613
1614   if (!lang || !*lang)
1615     return id;
1616   n = pool_id2str(pool, id);
1617   l = strlen(n) + strlen(lang) + 2;
1618   if (l > sizeof(buf))
1619     p = solv_malloc(strlen(n) + strlen(lang) + 2);
1620   else
1621     p = buf;
1622   sprintf(p, "%s:%s", n, lang);
1623   id = pool_str2id(pool, p, create);
1624   if (p != buf)
1625     free(p);
1626   return id;
1627 }
1628
1629 char *
1630 pool_alloctmpspace(Pool *pool, int len)
1631 {
1632   int n = pool->tmpspace.n;
1633   if (!len)
1634     return 0;
1635   if (len > pool->tmpspace.len[n])
1636     {
1637       pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
1638       pool->tmpspace.len[n] = len + 32;
1639     }
1640   pool->tmpspace.n = (n + 1) % POOL_TMPSPACEBUF;
1641   return pool->tmpspace.buf[n];
1642 }
1643
1644 static char *
1645 pool_alloctmpspace_free(Pool *pool, const char *space, int len)
1646 {
1647   if (space)
1648     {
1649       int n, oldn;
1650       n = oldn = pool->tmpspace.n;
1651       for (;;)
1652         {
1653           if (!n--)
1654             n = POOL_TMPSPACEBUF - 1;
1655           if (n == oldn)
1656             break;
1657           if (pool->tmpspace.buf[n] != space)
1658             continue;
1659           if (len > pool->tmpspace.len[n])
1660             {
1661               pool->tmpspace.buf[n] = solv_realloc(pool->tmpspace.buf[n], len + 32);
1662               pool->tmpspace.len[n] = len + 32;
1663             }
1664           return pool->tmpspace.buf[n];
1665         }
1666     }
1667   return 0;
1668 }
1669
1670 void
1671 pool_freetmpspace(Pool *pool, const char *space)
1672 {
1673   int n = pool->tmpspace.n;
1674   if (!space)
1675     return;
1676   n = (n + (POOL_TMPSPACEBUF - 1)) % POOL_TMPSPACEBUF;
1677   if (pool->tmpspace.buf[n] == space)
1678     pool->tmpspace.n = n;
1679 }
1680
1681 char *
1682 pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3)
1683 {
1684   int l1, l2, l3;
1685   char *s, *str;
1686   l1 = str1 ? strlen(str1) : 0;
1687   l2 = str2 ? strlen(str2) : 0;
1688   l3 = str3 ? strlen(str3) : 0;
1689   s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
1690   if (l1)
1691     {
1692       strcpy(s, str1);
1693       s += l1;
1694     }
1695   if (l2)
1696     {
1697       strcpy(s, str2);
1698       s += l2;
1699     }
1700   if (l3)
1701     {
1702       strcpy(s, str3);
1703       s += l3;
1704     }
1705   *s = 0;
1706   return str;
1707 }
1708
1709 char *
1710 pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3)
1711 {
1712   int l1, l2, l3;
1713   char *s, *str;
1714
1715   l1 = str1 ? strlen(str1) : 0;
1716   l2 = str2 ? strlen(str2) : 0;
1717   l3 = str3 ? strlen(str3) : 0;
1718   str = pool_alloctmpspace_free(pool, str1, l1 + l2 + l3 + 1);
1719   if (str)
1720     str1 = str;
1721   else
1722     str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
1723   s = str;
1724   if (l1)
1725     {
1726       if (s != str1)
1727         strcpy(s, str1);
1728       s += l1;
1729     }
1730   if (l2)
1731     {
1732       strcpy(s, str2);
1733       s += l2;
1734     }
1735   if (l3)
1736     {
1737       strcpy(s, str3);
1738       s += l3;
1739     }
1740   *s = 0;
1741   return str;
1742 }
1743
1744 const char *
1745 pool_bin2hex(Pool *pool, const unsigned char *buf, int len)
1746 {
1747   char *s;
1748   if (!len)
1749     return "";
1750   s = pool_alloctmpspace(pool, 2 * len + 1);
1751   solv_bin2hex(buf, len, s);
1752   return s;
1753 }
1754
1755 /*******************************************************************/
1756
1757 struct mptree {
1758   Id sibling;
1759   Id child;
1760   const char *comp;
1761   int compl;
1762   Id mountpoint;
1763 };
1764
1765 struct ducbdata {
1766   DUChanges *mps;
1767   struct mptree *mptree;
1768   int addsub;
1769   int hasdu;
1770
1771   Id *dirmap;
1772   int nmap;
1773   Repodata *olddata;
1774 };
1775
1776
1777 static int
1778 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1779 {
1780   struct ducbdata *cbd = cbdata;
1781   Id mp;
1782
1783   if (data != cbd->olddata)
1784     {
1785       Id dn, mp, comp, *dirmap, *dirs;
1786       int i, compl;
1787       const char *compstr;
1788       struct mptree *mptree;
1789
1790       /* create map from dir to mptree */
1791       cbd->dirmap = solv_free(cbd->dirmap);
1792       cbd->nmap = 0;
1793       dirmap = solv_calloc(data->dirpool.ndirs, sizeof(Id));
1794       mptree = cbd->mptree;
1795       mp = 0;
1796       for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1797         {
1798           comp = *dirs++;
1799           if (comp <= 0)
1800             {
1801               mp = dirmap[-comp];
1802               continue;
1803             }
1804           if (mp < 0)
1805             {
1806               /* unconnected */
1807               dirmap[dn] = mp;
1808               continue;
1809             }
1810           if (!mptree[mp].child)
1811             {
1812               dirmap[dn] = -mp;
1813               continue;
1814             }
1815           if (data->localpool)
1816             compstr = stringpool_id2str(&data->spool, comp);
1817           else
1818             compstr = pool_id2str(data->repo->pool, comp);
1819           compl = strlen(compstr);
1820           for (i = mptree[mp].child; i; i = mptree[i].sibling)
1821             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1822               break;
1823           dirmap[dn] = i ? i : -mp;
1824         }
1825       /* change dirmap to point to mountpoint instead of mptree */
1826       for (dn = 0; dn < data->dirpool.ndirs; dn++)
1827         {
1828           mp = dirmap[dn];
1829           dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1830         }
1831       cbd->dirmap = dirmap;
1832       cbd->nmap = data->dirpool.ndirs;
1833       cbd->olddata = data;
1834     }
1835   cbd->hasdu = 1;
1836   if (value->id < 0 || value->id >= cbd->nmap)
1837     return 0;
1838   mp = cbd->dirmap[value->id];
1839   if (mp < 0)
1840     return 0;
1841   if (cbd->addsub > 0)
1842     {
1843       cbd->mps[mp].kbytes += value->num;
1844       cbd->mps[mp].files += value->num2;
1845     }
1846   else
1847     {
1848       cbd->mps[mp].kbytes -= value->num;
1849       cbd->mps[mp].files -= value->num2;
1850     }
1851   return 0;
1852 }
1853
1854 static void
1855 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint)
1856 {
1857   int i;
1858   if (mptree[pos].mountpoint == -1)
1859     mptree[pos].mountpoint = mountpoint;
1860   else
1861     mountpoint = mptree[pos].mountpoint;
1862   for (i = mptree[pos].child; i; i = mptree[i].sibling)
1863     propagate_mountpoints(mptree, i, mountpoint);
1864 }
1865
1866 #define MPTREE_BLOCK 15
1867
1868 void
1869 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
1870 {
1871   char *p;
1872   const char *path, *compstr;
1873   struct mptree *mptree;
1874   int i, nmptree;
1875   int pos, compl;
1876   int mp;
1877   struct ducbdata cbd;
1878   Solvable *s;
1879   Id sp;
1880   Map ignoredu;
1881   Repo *oldinstalled = pool->installed;
1882
1883   memset(&ignoredu, 0, sizeof(ignoredu));
1884   cbd.mps = mps;
1885   cbd.addsub = 0;
1886   cbd.dirmap = 0;
1887   cbd.nmap = 0;
1888   cbd.olddata = 0;
1889
1890   mptree = solv_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1891
1892   /* our root node */
1893   mptree[0].sibling = 0;
1894   mptree[0].child = 0;
1895   mptree[0].comp = 0;
1896   mptree[0].compl = 0;
1897   mptree[0].mountpoint = -1;
1898   nmptree = 1;
1899   
1900   /* create component tree */
1901   for (mp = 0; mp < nmps; mp++)
1902     {
1903       mps[mp].kbytes = 0;
1904       mps[mp].files = 0;
1905       pos = 0;
1906       path = mps[mp].path;
1907       while(*path == '/')
1908         path++;
1909       while (*path)
1910         {
1911           if ((p = strchr(path, '/')) == 0)
1912             {
1913               compstr = path;
1914               compl = strlen(compstr);
1915               path += compl;
1916             }
1917           else
1918             {
1919               compstr = path;
1920               compl = p - path;
1921               path = p + 1;
1922               while(*path == '/')
1923                 path++;
1924             }
1925           for (i = mptree[pos].child; i; i = mptree[i].sibling)
1926             if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1927               break;
1928           if (!i)
1929             {
1930               /* create new node */
1931               mptree = solv_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1932               i = nmptree++;
1933               mptree[i].sibling = mptree[pos].child;
1934               mptree[i].child = 0;
1935               mptree[i].comp = compstr;
1936               mptree[i].compl = compl;
1937               mptree[i].mountpoint = -1;
1938               mptree[pos].child = i;
1939             }
1940           pos = i;
1941         }
1942       mptree[pos].mountpoint = mp;
1943     }
1944
1945   propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
1946
1947 #if 0
1948   for (i = 0; i < nmptree; i++)
1949     {
1950       printf("#%d sibling: %d\n", i, mptree[i].sibling);
1951       printf("#%d child: %d\n", i, mptree[i].child);
1952       printf("#%d comp: %s\n", i, mptree[i].comp);
1953       printf("#%d compl: %d\n", i, mptree[i].compl);
1954       printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
1955     }
1956 #endif
1957
1958   cbd.mptree = mptree;
1959   cbd.addsub = 1;
1960   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1961     {
1962       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1963         continue;
1964       if (!MAPTST(installedmap, sp))
1965         continue;
1966       cbd.hasdu = 0;
1967       repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1968       if (!cbd.hasdu && oldinstalled)
1969         {
1970           Id op, opp;
1971           /* no du data available, ignore data of all installed solvables we obsolete */
1972           if (!ignoredu.map)
1973             map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
1974           if (s->obsoletes)
1975             {
1976               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
1977               while ((obs = *obsp++) != 0)
1978                 FOR_PROVIDES(op, opp, obs)
1979                   if (op >= oldinstalled->start && op < oldinstalled->end)
1980                     MAPSET(&ignoredu, op - oldinstalled->start);
1981             }
1982           FOR_PROVIDES(op, opp, s->name)
1983             if (pool->solvables[op].name == s->name)
1984               if (op >= oldinstalled->start && op < oldinstalled->end)
1985                 MAPSET(&ignoredu, op - oldinstalled->start);
1986         }
1987     }
1988   cbd.addsub = -1;
1989   if (oldinstalled)
1990     {
1991       /* assumes we allways have du data for installed solvables */
1992       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1993         {
1994           if (MAPTST(installedmap, sp))
1995             continue;
1996           if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
1997             continue;
1998           repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1999         }
2000     }
2001   if (ignoredu.map)
2002     map_free(&ignoredu);
2003   solv_free(cbd.dirmap);
2004   solv_free(mptree);
2005 }
2006
2007 int
2008 pool_calc_installsizechange(Pool *pool, Map *installedmap)
2009 {
2010   Id sp;
2011   Solvable *s;
2012   int change = 0;
2013   Repo *oldinstalled = pool->installed;
2014
2015   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
2016     {
2017       if (!s->repo || (oldinstalled && s->repo == oldinstalled))
2018         continue;
2019       if (!MAPTST(installedmap, sp))
2020         continue;
2021       change += solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
2022     }
2023   if (oldinstalled)
2024     {
2025       FOR_REPO_SOLVABLES(oldinstalled, sp, s)
2026         {
2027           if (MAPTST(installedmap, sp))
2028             continue;
2029           change -= solvable_lookup_sizek(s, SOLVABLE_INSTALLSIZE, 0);
2030         }
2031     }
2032   return change;
2033 }
2034
2035 /* map:
2036  *  1: installed
2037  *  2: conflicts with installed
2038  *  8: interesting (only true if installed)
2039  * 16: undecided
2040  */
2041  
2042 static inline Id dep2name(Pool *pool, Id dep)
2043 {
2044   while (ISRELDEP(dep))
2045     {
2046       Reldep *rd = rd = GETRELDEP(pool, dep);
2047       dep = rd->name;
2048     }
2049   return dep;
2050 }
2051
2052 static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con) 
2053 {
2054   Id p, pp;
2055   Solvable *sn = pool->solvables + n; 
2056
2057   FOR_PROVIDES(p, pp, sn->name)
2058     {    
2059       Solvable *s = pool->solvables + p; 
2060       if (s->name != sn->name || s->arch != sn->arch)
2061         continue;
2062       if ((map[p] & 9) != 9)
2063         continue;
2064       if (pool_match_nevr(pool, pool->solvables + p, con))
2065         continue;
2066       return 1;         /* found installed package that doesn't conflict */
2067     }
2068   return 0;
2069 }
2070
2071 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *multiversionmap)
2072 {
2073   Id p, pp;
2074   int r = 0;
2075   FOR_PROVIDES(p, pp, dep)
2076     {
2077       if (p == SYSTEMSOLVABLE)
2078         return 1;       /* always boring, as never constraining */
2079       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
2080         continue;
2081       if (ispatch && multiversionmap && multiversionmap->size && MAPTST(multiversionmap, p) && ISRELDEP(dep))
2082         if (providedbyinstalled_multiversion(pool, map, p, dep))
2083           continue;
2084       if ((map[p] & 9) == 9)
2085         return 9;
2086       r |= map[p] & 17;
2087     }
2088   return r;
2089 }
2090
2091 /*
2092  * pool_trivial_installable - calculate if a set of solvables is
2093  * trivial installable without any other installs/deinstalls of
2094  * packages not belonging to the set.
2095  *
2096  * the state is returned in the result queue:
2097  * 1:  solvable is installable without any other package changes
2098  * 0:  solvable is not installable
2099  * -1: solvable is installable, but doesn't constrain any installed packages
2100  */
2101
2102 void
2103 pool_trivial_installable_multiversionmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *multiversionmap)
2104 {
2105   int i, r, m, did;
2106   Id p, *dp, con, *conp, req, *reqp;
2107   unsigned char *map;
2108   Solvable *s;
2109
2110   map = solv_calloc(pool->nsolvables, 1);
2111   for (p = 1; p < pool->nsolvables; p++)
2112     {
2113       if (!MAPTST(installedmap, p))
2114         continue;
2115       map[p] |= 9;
2116       s = pool->solvables + p;
2117       if (!s->conflicts)
2118         continue;
2119       conp = s->repo->idarraydata + s->conflicts;
2120       while ((con = *conp++) != 0)
2121         {
2122           dp = pool_whatprovides_ptr(pool, con);
2123           for (; *dp; dp++)
2124             map[p] |= 2;        /* XXX: self conflict ? */
2125         }
2126     }
2127   for (i = 0; i < pkgs->count; i++)
2128     map[pkgs->elements[i]] = 16;
2129
2130   for (i = 0, did = 0; did < pkgs->count; i++, did++)
2131     {
2132       if (i == pkgs->count)
2133         i = 0;
2134       p = pkgs->elements[i];
2135       if ((map[p] & 16) == 0)
2136         continue;
2137       if ((map[p] & 2) != 0)
2138         {
2139           map[p] = 2;
2140           continue;
2141         }
2142       s = pool->solvables + p;
2143       m = 1;
2144       if (s->requires)
2145         {
2146           reqp = s->repo->idarraydata + s->requires;
2147           while ((req = *reqp++) != 0)
2148             {
2149               if (req == SOLVABLE_PREREQMARKER)
2150                 continue;
2151               r = providedbyinstalled(pool, map, req, 0, 0);
2152               if (!r)
2153                 {
2154                   /* decided and miss */
2155                   map[p] = 2;
2156                   did = 0;
2157                   break;
2158                 }
2159               if (r == 16)
2160                 break;  /* undecided */
2161               m |= r;   /* 1 | 9 | 17 */
2162             }
2163           if (req)
2164             continue;
2165           if ((m & 9) == 9)
2166             m = 9;
2167         }
2168       if (s->conflicts)
2169         {
2170           int ispatch = 0;      /* see solver.c patch handling */
2171
2172           if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
2173             ispatch = 1;
2174           conp = s->repo->idarraydata + s->conflicts;
2175           while ((con = *conp++) != 0)
2176             {
2177               if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0)
2178                 {
2179                   map[p] = 2;
2180                   did = 0;
2181                   break;
2182                 }
2183               if ((m == 1 || m == 17) && ISRELDEP(con))
2184                 {
2185                   con = dep2name(pool, con);
2186                   if ((providedbyinstalled(pool, map, con, ispatch, multiversionmap) & 1) != 0)
2187                     m = 9;
2188                 }
2189             }
2190           if (con)
2191             continue;   /* found a conflict */
2192         }
2193 #if 0
2194       if (s->repo && s->repo != oldinstalled)
2195         {
2196           Id p2, obs, *obsp, *pp;
2197           Solvable *s2;
2198           if (s->obsoletes)
2199             {
2200               obsp = s->repo->idarraydata + s->obsoletes;
2201               while ((obs = *obsp++) != 0)
2202                 {
2203                   if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
2204                     {
2205                       map[p] = 2;
2206                       break;
2207                     }
2208                 }
2209               if (obs)
2210                 continue;
2211             }
2212           FOR_PROVIDES(p2, pp, s->name)
2213             {
2214               s2 = pool->solvables + p2;
2215               if (s2->name == s->name && (map[p2] & 1) != 0)
2216                 {
2217                   map[p] = 2;
2218                   break;
2219                 }
2220             }
2221           if (p2)
2222             continue;
2223         }
2224 #endif
2225       if (m != map[p])
2226         {
2227           map[p] = m;
2228           did = 0;
2229         }
2230     }
2231   queue_free(res);
2232   queue_init_clone(res, pkgs);
2233   for (i = 0; i < pkgs->count; i++)
2234     {
2235       m = map[pkgs->elements[i]];
2236       if ((m & 9) == 9)
2237         r = 1;
2238       else if (m & 1)
2239         r = -1;
2240       else
2241         r = 0;
2242       res->elements[i] = r;
2243     }
2244   free(map);
2245 }
2246
2247 void
2248 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
2249 {
2250   pool_trivial_installable_multiversionmap(pool, installedmap, pkgs, res, 0);
2251 }
2252
2253 const char *
2254 pool_lookup_str(Pool *pool, Id entry, Id keyname)
2255 {
2256   if (entry == SOLVID_POS && pool->pos.repo)
2257     return repo_lookup_str(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
2258   if (entry <= 0)
2259     return 0;
2260   return solvable_lookup_str(pool->solvables + entry, keyname);
2261 }
2262
2263 Id
2264 pool_lookup_id(Pool *pool, Id entry, Id keyname)
2265 {
2266   if (entry == SOLVID_POS && pool->pos.repo)
2267     return repo_lookup_id(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
2268   if (entry <= 0)
2269     return 0;
2270   return solvable_lookup_id(pool->solvables + entry, keyname);
2271 }
2272
2273 unsigned long long
2274 pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound)
2275 {
2276   if (entry == SOLVID_POS && pool->pos.repo)
2277     return repo_lookup_num(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, notfound);
2278   if (entry <= 0)
2279     return notfound;
2280   return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
2281 }
2282
2283 int
2284 pool_lookup_void(Pool *pool, Id entry, Id keyname)
2285 {
2286   if (entry == SOLVID_POS && pool->pos.repo)
2287     return repo_lookup_void(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname);
2288   if (entry <= 0)
2289     return 0;
2290   return solvable_lookup_void(pool->solvables + entry, keyname);
2291 }
2292
2293 const unsigned char *
2294 pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
2295 {
2296   if (entry == SOLVID_POS && pool->pos.repo)
2297     return repo_lookup_bin_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
2298   if (entry <= 0)
2299     return 0;
2300   return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
2301 }
2302
2303 const char *
2304 pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
2305 {
2306   if (entry == SOLVID_POS && pool->pos.repo)
2307     return repo_lookup_checksum(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, typep);
2308   if (entry <= 0)
2309     return 0;
2310   return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
2311 }
2312
2313 int
2314 pool_lookup_idarray(Pool *pool, Id entry, Id keyname, Queue *q)
2315 {
2316   if (entry == SOLVID_POS && pool->pos.repo)
2317     return repo_lookup_idarray(pool->pos.repo, pool->pos.repodataid ? entry : pool->pos.solvid, keyname, q);
2318   if (entry <= 0)
2319     return 0;
2320   return solvable_lookup_idarray(pool->solvables + entry, keyname, q);
2321 }
2322
2323 const char *
2324 pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp)
2325 {
2326   const char *loc;
2327   if (medianrp)
2328     *medianrp = 0;
2329   if (entry != SOLVID_POS)
2330     return 0;
2331   loc = pool_lookup_str(pool, entry, DELTA_LOCATION_DIR);
2332   loc = pool_tmpjoin(pool, loc, loc ? "/" : 0, pool_lookup_str(pool, entry, DELTA_LOCATION_NAME));
2333   loc = pool_tmpappend(pool, loc, "-", pool_lookup_str(pool, entry, DELTA_LOCATION_EVR));
2334   loc = pool_tmpappend(pool, loc, ".", pool_lookup_str(pool, entry, DELTA_LOCATION_SUFFIX));
2335   return loc;
2336 }
2337
2338 static void
2339 add_new_provider(Pool *pool, Id id, Id p)
2340 {
2341   Queue q;
2342   Id *pp;
2343
2344   while (ISRELDEP(id))
2345     {
2346       Reldep *rd = GETRELDEP(pool, id);
2347       id = rd->name;
2348     }
2349
2350   queue_init(&q);
2351   for (pp = pool->whatprovidesdata + pool->whatprovides[id]; *pp; pp++)
2352     {
2353       if (*pp == p)
2354         {
2355           queue_free(&q);
2356           return;
2357         }
2358       if (*pp > p)
2359         {
2360           queue_push(&q, p);
2361           p = 0;
2362         }
2363       queue_push(&q, *pp);
2364     }
2365   if (p)
2366     queue_push(&q, p);
2367   pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
2368   queue_free(&q);
2369 }
2370
2371 void
2372 pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
2373 {
2374   int hadhashes = pool->relhashtbl ? 1 : 0;
2375   Solvable *s;
2376   Id fn, p, q, md5;
2377   Id id;
2378   int i;
2379
2380   if (!conflicts->count)
2381     return;
2382   for (i = 0; i < conflicts->count; i += 6)
2383     {
2384       fn = conflicts->elements[i];
2385       p = conflicts->elements[i + 1];
2386       md5 = conflicts->elements[i + 2];
2387       q = conflicts->elements[i + 4];
2388       id = pool_rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
2389       s = pool->solvables + p;
2390       if (!s->repo)
2391         continue;
2392       s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
2393       if (pool->whatprovides)
2394         add_new_provider(pool, fn, p);
2395       if (pool->whatprovides_rel)
2396         pool->whatprovides_rel[GETRELID(id)] = 0;       /* clear cache */
2397       s = pool->solvables + q;
2398       if (!s->repo)
2399         continue;
2400       s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
2401     }
2402   if (!hadhashes)
2403     pool_freeidhashes(pool);
2404 }
2405
2406 char *
2407 pool_prepend_rootdir(Pool *pool, const char *path)
2408 {
2409   if (!path)
2410     return 0;
2411   if (!pool->rootdir)
2412     return solv_strdup(path);
2413   return solv_dupjoin(pool->rootdir, "/", *path == '/' ? path + 1 : path);
2414 }
2415
2416 const char *
2417 pool_prepend_rootdir_tmp(Pool *pool, const char *path)
2418 {
2419   if (!path)
2420     return 0;
2421   if (!pool->rootdir)
2422     return path;
2423   return pool_tmpjoin(pool, pool->rootdir, "/", *path == '/' ? path + 1 : path);
2424 }
2425
2426 void
2427 pool_set_rootdir(Pool *pool, const char *rootdir)
2428 {
2429   solv_free(pool->rootdir);
2430   pool->rootdir = solv_strdup(rootdir);
2431 }
2432
2433 const char *
2434 pool_get_rootdir(Pool *pool)
2435 {
2436   return pool->rootdir;
2437 }
2438
2439 /* only used in libzypp */
2440 void
2441 pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, Solvable *))
2442 {
2443   pool->custom_vendorcheck = vendorcheck;
2444 }
2445
2446 /* EOF */