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