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