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