support "pooljobs", fixed jobs set in the pool
[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   queue_free(&pool->pooljobs);
107   for (i = 0; i < POOL_TMPSPACEBUF; i++)
108     solv_free(pool->tmpspace.buf[i]);
109   for (i = 0; i < pool->nlanguages; i++)
110     free((char *)pool->languages[i]);
111   solv_free(pool->languages);
112   solv_free(pool->languagecache);
113   solv_free(pool->errstr);
114   solv_free(pool->rootdir);
115   solv_free(pool);
116 }
117
118 void
119 pool_freeallrepos(Pool *pool, int reuseids)
120 {
121   int i;
122
123   pool_freewhatprovides(pool);
124   for (i = 1; i < pool->nrepos; i++) 
125     if (pool->repos[i])
126       repo_freedata(pool->repos[i]);
127   pool->repos = solv_free(pool->repos);
128   pool->nrepos = 0; 
129   pool->urepos = 0; 
130   /* the first two solvables don't belong to a repo */
131   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
132 }
133
134 #ifdef MULTI_SEMANTICS
135 void
136 pool_setdisttype(Pool *pool, int disttype)
137 {
138   pool->disttype = disttype;
139   if (disttype == DISTTYPE_RPM)
140     pool->noarchid = ARCH_NOARCH;
141   if (disttype == DISTTYPE_DEB)
142     pool->noarchid = ARCH_ALL;
143   if (disttype == DISTTYPE_ARCH)
144     pool->noarchid = ARCH_ANY;
145   pool->solvables[SYSTEMSOLVABLE].arch = pool->noarchid;
146 }
147 #endif
148
149 int
150 pool_get_flag(Pool *pool, int flag)
151 {
152   switch (flag)
153     {
154     case POOL_FLAG_PROMOTEEPOCH:
155       return pool->promoteepoch;
156     case POOL_FLAG_FORBIDSELFCONFLICTS:
157       return pool->forbidselfconflicts;
158     case POOL_FLAG_OBSOLETEUSESPROVIDES:
159       return pool->obsoleteusesprovides;
160     case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
161       return pool->implicitobsoleteusesprovides;
162     case POOL_FLAG_OBSOLETEUSESCOLORS:
163       return pool->obsoleteusescolors;
164     case POOL_FLAG_NOINSTALLEDOBSOLETES:
165       return pool->noinstalledobsoletes;
166     case POOL_FLAG_HAVEDISTEPOCH:
167       return pool->havedistepoch;
168     default:
169       break;
170     }
171   return -1;
172 }
173
174 int
175 pool_set_flag(Pool *pool, int flag, int value)
176 {
177   int old = pool_get_flag(pool, flag);
178   switch (flag)
179     {
180     case POOL_FLAG_PROMOTEEPOCH:
181       pool->promoteepoch = value;
182       break;
183     case POOL_FLAG_FORBIDSELFCONFLICTS:
184       pool->forbidselfconflicts = value;
185       break;
186     case POOL_FLAG_OBSOLETEUSESPROVIDES:
187       pool->obsoleteusesprovides = value;
188       break;
189     case POOL_FLAG_IMPLICITOBSOLETEUSESPROVIDES:
190       pool->implicitobsoleteusesprovides = value;
191       break;
192     case POOL_FLAG_OBSOLETEUSESCOLORS:
193       pool->obsoleteusescolors = value;
194       break;
195     case POOL_FLAG_NOINSTALLEDOBSOLETES:
196       pool->noinstalledobsoletes = value;
197       break;
198     case POOL_FLAG_HAVEDISTEPOCH:
199       pool->havedistepoch = value;
200       break;
201     default:
202       break;
203     }
204   return old;
205 }
206
207
208 Id
209 pool_add_solvable(Pool *pool)
210 {
211   pool->solvables = solv_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
212   memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
213   return pool->nsolvables++;
214 }
215
216 Id
217 pool_add_solvable_block(Pool *pool, int count)
218 {
219   Id nsolvables = pool->nsolvables;
220   if (!count)
221     return nsolvables;
222   pool->solvables = solv_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
223   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
224   pool->nsolvables += count;
225   return nsolvables;
226 }
227
228 void
229 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
230 {
231   if (!count)
232     return;
233   if (reuseids && start + count == pool->nsolvables)
234     {
235       /* might want to shrink solvable array */
236       pool->nsolvables = start;
237       return;
238     }
239   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
240 }
241
242
243 void
244 pool_set_installed(Pool *pool, Repo *installed)
245 {
246   if (pool->installed == installed)
247     return;
248   pool->installed = installed;
249   pool_freewhatprovides(pool);
250 }
251
252 static int
253 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp, void *dp)
254 {
255   int r;
256   Pool *pool = dp;
257   Id oa, ob, *da, *db;
258   oa = pool->whatprovides[*(Id *)ap];
259   ob = pool->whatprovides[*(Id *)bp];
260   if (oa == ob)
261     return *(Id *)ap - *(Id *)bp;
262   da = pool->whatprovidesdata + oa;
263   db = pool->whatprovidesdata + ob;
264   while (*db)
265     if ((r = (*da++ - *db++)) != 0)
266       return r;
267   if (*da)
268     return *da;
269   return *(Id *)ap - *(Id *)bp;
270 }
271
272 /*
273  * pool_shrink_whatprovides  - unify whatprovides data
274  *
275  * whatprovides_rel must be empty for this to work!
276  *
277  */
278 static void
279 pool_shrink_whatprovides(Pool *pool)
280 {
281   Id i, n, id;
282   Id *sorted;
283   Id lastid, *last, *dp, *lp;
284   Offset o;
285   int r;
286
287   if (pool->ss.nstrings < 3)
288     return;
289   sorted = solv_malloc2(pool->ss.nstrings, sizeof(Id));
290   for (i = id = 0; id < pool->ss.nstrings; id++)
291     if (pool->whatprovides[id] >= 4)
292       sorted[i++] = id;
293   n = i;
294   solv_sort(sorted, n, sizeof(Id), pool_shrink_whatprovides_sortcmp, pool);
295   last = 0;
296   lastid = 0;
297   for (i = 0; i < n; i++)
298     {
299       id = sorted[i];
300       o = pool->whatprovides[id];
301       dp = pool->whatprovidesdata + o;
302       if (last)
303         {
304           lp = last;
305           while (*dp)   
306             if (*dp++ != *lp++)
307               {
308                 last = 0;
309                 break;
310               }
311           if (last && *lp)
312             last = 0;
313           if (last)
314             {
315               pool->whatprovides[id] = -lastid;
316               continue;
317             }
318         }
319       last = pool->whatprovidesdata + o;
320       lastid = id;
321     }
322   solv_free(sorted);
323   dp = pool->whatprovidesdata + 4;
324   for (id = 1; id < pool->ss.nstrings; id++)
325     {
326       o = pool->whatprovides[id];
327       if (!o)
328         continue;
329       if ((Id)o < 0)
330         {
331           i = -(Id)o;
332           if (i >= id)
333             abort();
334           pool->whatprovides[id] = pool->whatprovides[i];
335           continue;
336         }
337       if (o < 4)
338         continue;
339       lp = pool->whatprovidesdata + o;
340       if (lp < dp)
341         abort();
342       pool->whatprovides[id] = dp - pool->whatprovidesdata;
343       while ((*dp++ = *lp++) != 0)
344         ;
345     }
346   o = dp - pool->whatprovidesdata;
347   POOL_DEBUG(SOLV_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
348   if (pool->whatprovidesdataoff == o)
349     return;
350   r = pool->whatprovidesdataoff - o;
351   pool->whatprovidesdataoff = o;
352   pool->whatprovidesdata = solv_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
353   if (r > pool->whatprovidesdataleft)
354     r = pool->whatprovidesdataleft;
355   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
356 }
357
358
359 /*
360  * pool_createwhatprovides()
361  * 
362  * create hashes over pool of solvables to ease provide lookups
363  * 
364  */
365 void
366 pool_createwhatprovides(Pool *pool)
367 {
368   int i, num, np, extra;
369   Offset off;
370   Solvable *s;
371   Id id;
372   Offset *idp, n;
373   Offset *whatprovides;
374   Id *whatprovidesdata, *d;
375   Repo *installed = pool->installed;
376   unsigned int now;
377
378   now = solv_timems(0);
379   POOL_DEBUG(SOLV_DEBUG_STATS, "number of solvables: %d, memory used: %d K\n", pool->nsolvables, pool->nsolvables * (int)sizeof(Solvable) / 1024);
380   POOL_DEBUG(SOLV_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
381   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);
382   if (pool->ss.stringhashmask || pool->relhashmask)
383     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)));
384
385   pool_freeidhashes(pool);      /* XXX: should not be here! */
386   pool_freewhatprovides(pool);
387   num = pool->ss.nstrings;
388   pool->whatprovides = whatprovides = solv_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
389   pool->whatprovides_rel = solv_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
390
391   /* count providers for each name */
392   for (i = pool->nsolvables - 1; i > 0; i--)
393     {
394       Id *pp;
395       s = pool->solvables + i;
396       if (!s->provides || !s->repo || s->repo->disabled)
397         continue;
398       /* we always need the installed solvable in the whatprovides data,
399          otherwise obsoletes/conflicts on them won't work */
400       if (s->repo != installed && !pool_installable(pool, s))
401         continue;
402       pp = s->repo->idarraydata + s->provides;
403       while ((id = *pp++) != 0)
404         {
405           while (ISRELDEP(id))
406             {
407               Reldep *rd = GETRELDEP(pool, id);
408               id = rd->name;
409             }
410           whatprovides[id]++;          /* inc count of providers */
411         }
412     }
413
414   off = 4;      /* first entry is undef, second is empty list, third is system solvable  */
415   np = 0;                              /* number of names provided */
416   for (i = 0, idp = whatprovides; i < num; i++, idp++)
417     {
418       n = *idp;
419       if (!n)                          /* no providers */
420         continue;
421       off += n;                        /* make space for all providers */
422       *idp = off++;                    /* now idp points to terminating zero */
423       np++;                            /* inc # of provider 'slots' for stats */
424     }
425
426   POOL_DEBUG(SOLV_DEBUG_STATS, "provide ids: %d\n", np);
427
428   /* reserve some space for relation data */
429   extra = 2 * pool->nrels;
430   if (extra < 256)
431     extra = 256;
432
433   POOL_DEBUG(SOLV_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
434
435   /* alloc space for all providers + extra */
436   whatprovidesdata = solv_calloc(off + extra, sizeof(Id));
437   whatprovidesdata[2] = SYSTEMSOLVABLE;
438
439   /* now fill data for all provides */
440   for (i = pool->nsolvables - 1; i > 0; i--)
441     {
442       Id *pp;
443       s = pool->solvables + i;
444       if (!s->provides || !s->repo || s->repo->disabled)
445         continue;
446       if (s->repo != installed && !pool_installable(pool, s))
447         continue;
448
449       /* for all provides of this solvable */
450       pp = s->repo->idarraydata + s->provides;
451       while ((id = *pp++) != 0)
452         {
453           while (ISRELDEP(id))
454             {
455               Reldep *rd = GETRELDEP(pool, id);
456               id = rd->name;
457             }
458           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
459           if (*d != i)          /* don't add same solvable twice */
460             {
461               d[-1] = i;
462               whatprovides[id]--;
463             }
464         }
465     }
466   pool->whatprovidesdata = whatprovidesdata;
467   pool->whatprovidesdataoff = off;
468   pool->whatprovidesdataleft = extra;
469   pool_shrink_whatprovides(pool);
470   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)));
471   POOL_DEBUG(SOLV_DEBUG_STATS, "createwhatprovides took %d ms\n", solv_timems(now));
472 }
473
474 /*
475  * free all of our whatprovides data
476  * be careful, everything internalized with pool_queuetowhatprovides is
477  * gone, too
478  */
479 void
480 pool_freewhatprovides(Pool *pool)
481 {
482   pool->whatprovides = solv_free(pool->whatprovides);
483   pool->whatprovides_rel = solv_free(pool->whatprovides_rel);
484   pool->whatprovidesdata = solv_free(pool->whatprovidesdata);
485   pool->whatprovidesdataoff = 0;
486   pool->whatprovidesdataleft = 0;
487 }
488
489
490 /******************************************************************************/
491
492 /*
493  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
494  * 
495  * used for whatprovides, jobs, learnt rules, selections
496  * input: q: queue of Ids
497  * returns: Offset into whatprovidesdata
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 0-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 0-terminate */
524   pool->whatprovidesdataoff += count;
525   pool->whatprovidesdata[pool->whatprovidesdataoff++] = 0;
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                   did = 0;
1916                   break;
1917                 }
1918               if (r == 16)
1919                 break;  /* undecided */
1920               m |= r;   /* 1 | 9 | 17 */
1921             }
1922           if (req)
1923             continue;
1924           if ((m & 9) == 9)
1925             m = 9;
1926         }
1927       if (s->conflicts)
1928         {
1929           int ispatch = 0;      /* see solver.c patch handling */
1930
1931           if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
1932             ispatch = 1;
1933           conp = s->repo->idarraydata + s->conflicts;
1934           while ((con = *conp++) != 0)
1935             {
1936               if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
1937                 {
1938                   map[p] = 2;
1939                   did = 0;
1940                   break;
1941                 }
1942               if ((m == 1 || m == 17) && ISRELDEP(con))
1943                 {
1944                   con = dep2name(pool, con);
1945                   if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
1946                     m = 9;
1947                 }
1948             }
1949           if (con)
1950             continue;   /* found a conflict */
1951         }
1952 #if 0
1953       if (s->repo && s->repo != oldinstalled)
1954         {
1955           Id p2, obs, *obsp, *pp;
1956           Solvable *s2;
1957           if (s->obsoletes)
1958             {
1959               obsp = s->repo->idarraydata + s->obsoletes;
1960               while ((obs = *obsp++) != 0)
1961                 {
1962                   if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
1963                     {
1964                       map[p] = 2;
1965                       break;
1966                     }
1967                 }
1968               if (obs)
1969                 continue;
1970             }
1971           FOR_PROVIDES(p2, pp, s->name)
1972             {
1973               s2 = pool->solvables + p2;
1974               if (s2->name == s->name && (map[p2] & 1) != 0)
1975                 {
1976                   map[p] = 2;
1977                   break;
1978                 }
1979             }
1980           if (p2)
1981             continue;
1982         }
1983 #endif
1984       if (m != map[p])
1985         {
1986           map[p] = m;
1987           did = 0;
1988         }
1989     }
1990   queue_free(res);
1991   queue_init_clone(res, pkgs);
1992   for (i = 0; i < pkgs->count; i++)
1993     {
1994       m = map[pkgs->elements[i]];
1995       if ((m & 9) == 9)
1996         r = 1;
1997       else if (m & 1)
1998         r = -1;
1999       else
2000         r = 0;
2001       res->elements[i] = r;
2002     }
2003   free(map);
2004 }
2005
2006 void
2007 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
2008 {
2009   pool_trivial_installable_noobsoletesmap(pool, installedmap, pkgs, res, 0);
2010 }
2011
2012 const char *
2013 pool_lookup_str(Pool *pool, Id entry, Id keyname)
2014 {
2015   if (entry == SOLVID_POS && pool->pos.repo)
2016     return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
2017   if (entry <= 0)
2018     return 0;
2019   return solvable_lookup_str(pool->solvables + entry, keyname);
2020 }
2021
2022 Id
2023 pool_lookup_id(Pool *pool, Id entry, Id keyname)
2024 {
2025   if (entry == SOLVID_POS && pool->pos.repo)
2026     {
2027       Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
2028       Id id = repodata_lookup_id(data, SOLVID_POS, keyname);
2029       return data->localpool ? repodata_globalize_id(data, id, 1) : id;
2030     }
2031   if (entry <= 0)
2032     return 0;
2033   return solvable_lookup_id(pool->solvables + entry, keyname);
2034 }
2035
2036 unsigned long long
2037 pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned long long notfound)
2038 {
2039   if (entry == SOLVID_POS && pool->pos.repo)
2040     {
2041       unsigned long long value;
2042       if (repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, &value))
2043         return value;
2044       return notfound;
2045     }
2046   if (entry <= 0)
2047     return notfound;
2048   return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
2049 }
2050
2051 int
2052 pool_lookup_void(Pool *pool, Id entry, Id keyname)
2053 {
2054   if (entry == SOLVID_POS && pool->pos.repo)
2055     return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
2056   if (entry <= 0)
2057     return 0;
2058   return solvable_lookup_void(pool->solvables + entry, keyname);
2059 }
2060
2061 const unsigned char *
2062 pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
2063 {
2064   if (entry == SOLVID_POS && pool->pos.repo)
2065     return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
2066   if (entry <= 0)
2067     return 0;
2068   return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
2069 }
2070
2071 const char *
2072 pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
2073 {
2074   if (entry == SOLVID_POS && pool->pos.repo)
2075     {
2076       const unsigned char *chk = repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
2077       return chk ? repodata_chk2str(pool->pos.repo->repodata + pool->pos.repodataid, *typep, chk) : 0;
2078     }
2079   if (entry <= 0)
2080     return 0;
2081   return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
2082 }
2083
2084 const char *
2085 pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *medianrp)
2086 {
2087   const char *loc;
2088   if (medianrp)
2089     *medianrp = 0;
2090   if (entry != SOLVID_POS)
2091     return 0;
2092   loc = pool_lookup_str(pool, entry, DELTA_LOCATION_DIR);
2093   loc = pool_tmpjoin(pool, loc, loc ? "/" : 0, pool_lookup_str(pool, entry, DELTA_LOCATION_NAME));
2094   loc = pool_tmpappend(pool, loc, "-", pool_lookup_str(pool, entry, DELTA_LOCATION_EVR));
2095   loc = pool_tmpappend(pool, loc, ".", pool_lookup_str(pool, entry, DELTA_LOCATION_SUFFIX));
2096   return loc;
2097 }
2098
2099 void
2100 pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts)
2101 {
2102   int hadhashes = pool->relhashtbl ? 1 : 0;
2103   Solvable *s;
2104   Id fn, p, q, md5;
2105   Id id;
2106   int i;
2107
2108   if (!conflicts->count)
2109     return;
2110   pool_freewhatprovides(pool);
2111   for (i = 0; i < conflicts->count; i += 5)
2112     {
2113       fn = conflicts->elements[i];
2114       p = conflicts->elements[i + 1];
2115       md5 = conflicts->elements[i + 2];
2116       q = conflicts->elements[i + 3];
2117       id = pool_rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
2118       s = pool->solvables + p;
2119       if (!s->repo)
2120         continue;
2121       s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
2122       s = pool->solvables + q;
2123       if (!s->repo)
2124         continue;
2125       s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
2126     }
2127   if (!hadhashes)
2128     pool_freeidhashes(pool);
2129 }
2130
2131 char *
2132 pool_prepend_rootdir(Pool *pool, const char *path)
2133 {
2134   if (!path)
2135     return 0;
2136   if (!pool->rootdir)
2137     return solv_strdup(path);
2138   return solv_dupjoin(pool->rootdir, "/", *path == '/' ? path + 1 : path);
2139 }
2140
2141 const char *
2142 pool_prepend_rootdir_tmp(Pool *pool, const char *path)
2143 {
2144   if (!path)
2145     return 0;
2146   if (!pool->rootdir)
2147     return path;
2148   return pool_tmpjoin(pool, pool->rootdir, "/", *path == '/' ? path + 1 : path);
2149 }
2150
2151 void
2152 pool_set_rootdir(Pool *pool, const char *rootdir)
2153 {
2154   solv_free(pool->rootdir);
2155   pool->rootdir = solv_strdup(rootdir);
2156 }
2157
2158 const char *
2159 pool_get_rootdir(Pool *pool)
2160 {
2161   return pool->rootdir;
2162 }
2163
2164 /* EOF */