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