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