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