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