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