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