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