- clean up tmp space management
[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 /*
33  * list of string constants, so we can do pointer/Id instead of string comparison
34  * index into array matches ID_xxx constants in pool.h
35  */
36   
37 static const char *initpool_data[] = {
38   "<NULL>",                   // ID_NULL
39   "",                         // ID_EMPTY
40   "solvable:name",
41   "solvable:arch",
42   "solvable:evr",
43   "solvable:vendor",
44   "solvable:provides",
45   "solvable:obsoletes",
46   "solvable:conflicts",
47   "solvable:requires",
48   "solvable:recommends",
49   "solvable:suggests",
50   "solvable:supplements",
51   "solvable:enhances",
52   "solvable:freshens",
53   "rpm:dbid",                          /* direct key into rpmdb */
54   "solvable:prereqmarker",
55   "solvable:filemarker",
56   "namespace:installed",
57   "namespace:modalias",
58   "namespace:splitprovides",
59   "namespace:language",
60   "system:system",
61   "src",
62   "nosrc",
63   "noarch",
64   "repodata:external",
65   "repodata:keys",
66   "repodata:location",
67   "repokey:type:void",
68   "repokey:type:constant",
69   "repokey:type:constantid",
70   "repokey:type:id",
71   "repokey:type:num",
72   "repokey:type:num32",
73   "repokey:type:dir",
74   "repokey:type:str",
75   "repokey:type:idarray",
76   "repokey:type:relidarray",
77   "repokey:type:dirstrarray",
78   "repokey:type:dirnumnumarray",
79
80   "solvable:summary",
81   "solvable:description",
82   "solvable:authors",
83   "solvable:group",
84   "solvable:keywords",
85   "solvable:license",
86   "solvable:buildtime",
87
88   "solvable:eula",
89   "solvable:messageins",
90   "solvable:messagedel",
91
92   "solvable:installsize",
93   "solvable:diskusage",
94   "solvable:filelist",
95
96   "solvable:installtime",
97
98   "solvable:mediadir",
99   "solvable:mediafile",
100   "solvable:medianr",
101   "solvable:downloadsize",
102
103   "solvable:sourcearch",
104   "solvable:sourcename",
105   "solvable:sourceevr",
106
107   "solvable:isvisible",                 /* from susetags */
108
109   "solvable:patchcategory",
110
111   0
112 };
113
114 /* create pool */
115 Pool *
116 pool_create(void)
117 {
118   Pool *pool;
119   Solvable *s;
120
121   pool = (Pool *)sat_calloc(1, sizeof(*pool));
122
123   stringpool_init (&pool->ss, initpool_data);
124
125   /* alloc space for ReDep 0 */
126   pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
127   pool->nrels = 1;
128   memset(pool->rels, 0, sizeof(Reldep));
129
130   /* alloc space for Solvable 0 and system solvable */
131   pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK);
132   pool->nsolvables = 2;
133   memset(pool->solvables, 0, 2 * sizeof(Solvable));
134   s = pool->solvables + SYSTEMSOLVABLE;
135   s->name = SYSTEM_SYSTEM;
136   s->arch = ARCH_NOARCH;
137   s->evr = ID_EMPTY;
138
139   queue_init(&pool->vendormap);
140
141   pool->debugmask = SAT_DEBUG_RESULT;   /* FIXME */
142   return pool;
143 }
144
145
146 /* free all the resources of our pool */
147 void
148 pool_free(Pool *pool)
149 {
150   int i;
151
152   pool_freewhatprovides(pool);
153   pool_freeidhashes(pool);
154   repo_freeallrepos(pool, 1);
155   sat_free(pool->id2arch);
156   sat_free(pool->solvables);
157   sat_free(pool->ss.stringspace);
158   sat_free(pool->ss.strings);
159   sat_free(pool->rels);
160   queue_free(&pool->vendormap);
161   for (i = 0; i < POOL_TMPSPACEBUF; i++)
162     sat_free(pool->tmpspacebuf[i]);
163   for (i = 0; i < pool->nlanguages; i++)
164     free((char *)pool->languages[i]);
165   sat_free(pool->languages);
166   sat_free(pool->languagecache);
167   sat_free(pool);
168 }
169
170 Id
171 pool_add_solvable(Pool *pool)
172 {
173   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
174   memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
175   return pool->nsolvables++;
176 }
177
178 Id
179 pool_add_solvable_block(Pool *pool, int count)
180 {
181   Id nsolvables = pool->nsolvables;
182   if (!count)
183     return nsolvables;
184   pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
185   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
186   pool->nsolvables += count;
187   return nsolvables;
188 }
189
190 void
191 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
192 {
193   if (!count)
194     return;
195   if (reuseids && start + count == pool->nsolvables)
196     {
197       /* might want to shrink solvable array */
198       pool->nsolvables = start;
199       return;
200     }
201   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
202 }
203
204
205 static Pool *pool_shrink_whatprovides_sortcmp_data;
206
207 static int
208 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp)
209 {
210   int r;
211   Pool *pool = pool_shrink_whatprovides_sortcmp_data;
212   Id oa, ob, *da, *db;
213   oa = pool->whatprovides[*(Id *)ap];
214   ob = pool->whatprovides[*(Id *)bp];
215   if (oa == ob)
216     return *(Id *)ap - *(Id *)bp;
217   if (!oa)
218     return -1;
219   if (!ob)
220     return 1;
221   da = pool->whatprovidesdata + oa;
222   db = pool->whatprovidesdata + ob;
223   while (*db)
224     if ((r = (*da++ - *db++)) != 0)
225       return r;
226   if (*da)
227     return *da;
228   return *(Id *)ap - *(Id *)bp;
229 }
230
231 /*
232  * pool_shrink_whatprovides  - unify whatprovides data
233  *
234  * whatprovides_rel must be empty for this to work!
235  *
236  */
237 static void
238 pool_shrink_whatprovides(Pool *pool)
239 {
240   Id i, id;
241   Id *sorted;
242   Id lastid, *last, *dp, *lp;
243   Offset o;
244   int r;
245
246   if (pool->ss.nstrings < 3)
247     return;
248   sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id));
249   for (id = 0; id < pool->ss.nstrings; id++)
250     sorted[id] = id;
251   pool_shrink_whatprovides_sortcmp_data = pool;
252   qsort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp);
253   last = 0;
254   lastid = 0;
255   for (i = 1; i < pool->ss.nstrings; i++)
256     {
257       id = sorted[i];
258       o = pool->whatprovides[id];
259       if (o == 0 || o == 1)
260         continue;
261       dp = pool->whatprovidesdata + o;
262       if (last)
263         {
264           lp = last;
265           while (*dp)   
266             if (*dp++ != *lp++)
267               {
268                 last = 0;
269                 break;
270               }
271           if (last && *lp)
272             last = 0;
273           if (last)
274             {
275               pool->whatprovides[id] = -lastid;
276               continue;
277             }
278         }
279       last = pool->whatprovidesdata + o;
280       lastid = id;
281     }
282   sat_free(sorted);
283   dp = pool->whatprovidesdata + 2;
284   for (id = 1; id < pool->ss.nstrings; id++)
285     {
286       o = pool->whatprovides[id];
287       if (o == 0 || o == 1)
288         continue;
289       if ((Id)o < 0)
290         {
291           i = -(Id)o;
292           if (i >= id)
293             abort();
294           pool->whatprovides[id] = pool->whatprovides[i];
295           continue;
296         }
297       lp = pool->whatprovidesdata + o;
298       if (lp < dp)
299         abort();
300       pool->whatprovides[id] = dp - pool->whatprovidesdata;
301       while ((*dp++ = *lp++) != 0)
302         ;
303     }
304   o = dp - pool->whatprovidesdata;
305   POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
306   if (pool->whatprovidesdataoff == o)
307     return;
308   r = pool->whatprovidesdataoff - o;
309   pool->whatprovidesdataoff = o;
310   pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
311   if (r > pool->whatprovidesdataleft)
312     r = pool->whatprovidesdataleft;
313   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
314 }
315
316
317 /*
318  * pool_createwhatprovides()
319  * 
320  * create hashes over pool of solvables to ease provide lookups
321  * 
322  */
323 void
324 pool_createwhatprovides(Pool *pool)
325 {
326   int i, num, np, extra;
327   Offset off;
328   Solvable *s;
329   Id id;
330   Offset *idp, n;
331   Offset *whatprovides;
332   Id *whatprovidesdata, *d;
333
334   POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables);
335   POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
336
337   pool_freeidhashes(pool);      /* XXX: should not be here! */
338   pool_freewhatprovides(pool);
339   num = pool->ss.nstrings;
340   pool->whatprovides = whatprovides = sat_extend_resize(0, num, sizeof(Offset), WHATPROVIDES_BLOCK);
341   memset(whatprovides, 0, num * sizeof(Offset));
342   pool->whatprovides_rel = sat_extend_resize(0, pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
343   memset(pool->whatprovides_rel, 0, pool->nrels * sizeof(Offset));
344
345   /* count providers for each name */
346   for (i = 1; i < pool->nsolvables; i++)
347     {
348       Id *pp;
349       s = pool->solvables + i;
350       if (!s->provides)
351         continue;
352       if (!pool_installable(pool, s))
353         continue;
354       pp = s->repo->idarraydata + s->provides;
355       while ((id = *pp++) != ID_NULL)
356         {
357           while (ISRELDEP(id))
358             {
359               Reldep *rd = GETRELDEP(pool, id);
360               id = rd->name;
361             }
362           whatprovides[id]++;          /* inc count of providers */
363         }
364     }
365
366   off = 2;      /* first entry is undef, second is empty list */
367   idp = whatprovides;
368   np = 0;                              /* number of names provided */
369   for (i = 0; i < num; i++, idp++)
370     {
371       n = *idp;
372       if (!n)                          /* no providers */
373         continue;
374       *idp = off;                      /* move from counts to offsets into whatprovidesdata */
375       off += n + 1;                    /* make space for all providers + terminating ID_NULL */
376       np++;                            /* inc # of provider 'slots' */
377     }
378
379   POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
380
381   /* reserve some space for relation data */
382   extra = 2 * pool->nrels;
383   if (extra < 256)
384     extra = 256;
385
386   POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
387
388   /* alloc space for all providers + extra */
389   whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
390
391   /* now fill data for all provides */
392   for (i = 1; i < pool->nsolvables; i++)
393     {
394       Id *pp;
395       s = pool->solvables + i;
396       if (!s->provides)
397         continue;
398       if (!pool_installable(pool, s))
399         continue;
400
401       /* for all provides of this solvable */
402       pp = s->repo->idarraydata + s->provides;
403       while ((id = *pp++) != 0)
404         {
405           while (ISRELDEP(id))
406             {
407               Reldep *rd = GETRELDEP(pool, id);
408               id = rd->name;
409             }
410           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
411           if (*d)
412             {
413               d++;
414               while (*d)               /* find free slot */
415                 d++;
416               if (d[-1] == i)
417                 continue;
418             }
419           *d = i;                      /* put solvable Id into data */
420         }
421     }
422   pool->whatprovidesdata = whatprovidesdata;
423   pool->whatprovidesdataoff = off;
424   pool->whatprovidesdataleft = extra;
425   pool_shrink_whatprovides(pool);
426 }
427
428 /*
429  * free all of our whatprovides data
430  * be careful, everything internalized with pool_queuetowhatprovides is gone, too
431  */
432 void
433 pool_freewhatprovides(Pool *pool)
434 {
435   pool->whatprovides = sat_free(pool->whatprovides);
436   pool->whatprovides_rel = sat_free(pool->whatprovides_rel);
437   pool->whatprovidesdata = sat_free(pool->whatprovidesdata);
438   pool->whatprovidesdataoff = 0;
439   pool->whatprovidesdataleft = 0;
440 }
441
442
443 /******************************************************************************/
444
445 /*
446  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
447  * 
448  * on-demand filling of provider information
449  * move queue data into whatprovidesdata
450  * q: queue of Ids
451  * returns: Offset into whatprovides
452  *
453  */
454 Id
455 pool_queuetowhatprovides(Pool *pool, Queue *q)
456 {
457   Offset off;
458   int count = q->count;
459
460   if (count == 0)                      /* queue empty -> ID_EMPTY */
461     return ID_EMPTY;
462
463   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
464   if (pool->whatprovidesdataleft < count + 1)
465     {
466       POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n");
467       pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
468       pool->whatprovidesdataleft = count + 4096;
469     }
470
471   /* copy queue to next free slot */
472   off = pool->whatprovidesdataoff;
473   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
474
475   /* adapt count and ID_NULL-terminate */
476   pool->whatprovidesdataoff += count;
477   pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
478   pool->whatprovidesdataleft -= count + 1;
479
480   return (Id)off;
481 }
482
483
484 /*************************************************************************/
485
486 /*
487  * addrelproviders
488  * 
489  * add packages fulfilling the relation to whatprovides array
490  * no exact providers, do range match
491  * 
492  */
493
494 Id *
495 pool_addrelproviders(Pool *pool, Id d)
496 {
497   Reldep *rd = GETRELDEP(pool, d);
498   Reldep *prd;
499   Queue plist;
500   Id buf[16];
501   Id name = rd->name;
502   Id evr = rd->evr;
503   int flags = rd->flags;
504   Id pid, *pidp;
505   Id p, *pp, *pp2, *pp3;
506
507   d = GETRELID(d);
508   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
509   switch (flags)
510     {
511     case REL_AND:
512     case REL_WITH:
513       pp = pool_whatprovides(pool, name);
514       pp2 = pool_whatprovides(pool, evr);
515       while ((p = *pp++) != 0)
516         {
517           for (pp3 = pp2; *pp3;)
518             if (*pp3++ == p)
519               {
520                 queue_push(&plist, p);
521                 break;
522               }
523         }
524       break;
525     case REL_OR:
526       pp = pool_whatprovides(pool, name);
527       while ((p = *pp++) != 0)
528         queue_push(&plist, p);
529       pp = pool_whatprovides(pool, evr);
530       while ((p = *pp++) != 0)
531         queue_pushunique(&plist, p);
532       break;
533     case REL_NAMESPACE:
534       if (pool->nscallback)
535         {
536           p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
537           if (p > 1)
538             {
539               queue_free(&plist);
540               pool->whatprovides_rel[d] = p;
541               return pool->whatprovidesdata + p;
542             }
543           if (p == 1)
544             queue_push(&plist, SYSTEMSOLVABLE);
545         }
546       break;
547     default:
548       break;
549     }
550
551   /* convert to whatprovides id */
552 #if 0
553   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
554 #endif
555   if (flags && flags < 8)
556     {
557       FOR_PROVIDES(p, pp, name)
558         {
559 #if 0
560           POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, pool->p[p].name));
561 #endif
562           /* solvable p provides name in some rels */
563           pidp = pool->solvables[p].repo->idarraydata + pool->solvables[p].provides;
564           while ((pid = *pidp++) != 0)
565             {
566               int pflags;
567               Id pevr;
568
569               if (pid == name)
570                 {
571 #ifdef DEBIAN_SEMANTICS
572                   continue;             /* unversioned provides can
573                                          * never match versioned deps */
574 #else
575                   break;                /* yes, provides all versions */
576 #endif
577                 }
578               if (!ISRELDEP(pid))
579                 continue;               /* wrong provides name */
580               prd = GETRELDEP(pool, pid);
581               if (prd->name != name)
582                 continue;               /* wrong provides name */
583               /* right package, both deps are rels */
584               pflags = prd->flags;
585               if (!pflags)
586                 continue;
587               if (flags == 7 || pflags == 7)
588                 break; /* included */
589               if ((pflags & flags & 5) != 0)
590                 break; /* same direction, match */
591               pevr = prd->evr;
592               if (pevr == evr)
593                 {
594                   if ((pflags & flags & 2) != 0)
595                     break; /* both have =, match */
596                 }
597               else
598                 {
599                   int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
600                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
601                     break;
602                 }
603             }
604           if (!pid)
605             continue;   /* no rel match */
606           queue_push(&plist, p);
607         }
608       /* make our system solvable provide all unknown rpmlib() stuff */
609       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
610         queue_push(&plist, SYSTEMSOLVABLE);
611     }
612   /* add providers to whatprovides */
613 #if 0
614   POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
615 #endif
616   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
617   queue_free(&plist);
618
619   return pool->whatprovidesdata + pool->whatprovides_rel[d];
620 }
621
622 /*************************************************************************/
623
624 void
625 pool_debug(Pool *pool, int type, const char *format, ...)
626 {
627   va_list args;
628   char buf[1024];
629
630   if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
631     {
632       if ((pool->debugmask & type) == 0)
633         return;
634     }
635   va_start(args, format);
636   if (!pool->debugcallback)
637     {
638       if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
639         vprintf(format, args);
640       else
641         vfprintf(stderr, format, args);
642       return;
643     }
644   vsnprintf(buf, sizeof(buf), format, args);
645   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
646 }
647
648 void
649 pool_setdebuglevel(Pool *pool, int level)
650 {
651   int mask = SAT_DEBUG_RESULT;
652   if (level > 0)
653     mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE;
654   if (level > 1)
655     mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
656   if (level > 2)
657     mask |= SAT_DEBUG_PROPAGATE;
658   if (level > 3)
659     mask |= SAT_DEBUG_RULE_CREATION;
660   if (level > 4)
661     mask |= SAT_DEBUG_SCHUBI;
662   pool->debugmask = mask;
663 }
664
665 /*************************************************************************/
666
667 struct searchfiles {
668   Id *ids;
669   char **dirs;
670   char **names;
671   int nfiles;
672   Map seen;
673 };
674
675 #define SEARCHFILES_BLOCK 127
676
677 static void
678 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
679 {
680   Id dep, sid;
681   const char *s, *sr;
682
683   while ((dep = *ida++) != 0)
684     {
685       while (ISRELDEP(dep))
686         {
687           Reldep *rd;
688           sid = pool->ss.nstrings + GETRELID(dep);
689           if (MAPTST(&sf->seen, sid))
690             {
691               dep = 0;
692               break;
693             }
694           MAPSET(&sf->seen, sid);
695           rd = GETRELDEP(pool, dep);
696           if (rd->flags < 8)
697             dep = rd->name;
698           else if (rd->flags == REL_NAMESPACE)
699             {
700               if (isf && (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES))
701                 {
702                   sf = isf;
703                   isf = 0;
704                   if (MAPTST(&sf->seen, sid))
705                     {
706                       dep = 0;
707                       break;
708                     }
709                   MAPSET(&sf->seen, sid);
710                 }
711               dep = rd->evr;
712             }
713           else
714             {
715               Id ids[2];
716               ids[0] = rd->name;
717               ids[1] = 0;
718               pool_addfileprovides_dep(pool, ids, sf, isf);
719               dep = rd->evr;
720             }
721         }
722       if (!dep)
723         continue;
724       if (MAPTST(&sf->seen, dep))
725         continue;
726       MAPSET(&sf->seen, dep);
727       s = id2str(pool, dep);
728       if (*s != '/')
729         continue;
730       sf->ids = sat_extend(sf->ids, sf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
731       sf->dirs = sat_extend(sf->dirs, sf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
732       sf->names = sat_extend(sf->names, sf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
733       sf->ids[sf->nfiles] = dep;
734       sr = strrchr(s, '/');
735       sf->names[sf->nfiles] = strdup(sr + 1);
736       sf->dirs[sf->nfiles] = sat_malloc(sr - s + 1);
737       if (sr != s)
738         strncpy(sf->dirs[sf->nfiles], s, sr - s);
739       sf->dirs[sf->nfiles][sr - s] = 0;
740       sf->nfiles++;
741     }
742 }
743
744 struct addfileprovides_cbdata {
745   int nfiles;
746   Id *ids;
747   char **dirs;
748   char **names;
749
750   Repodata *olddata;
751   Id *dids;
752   Map useddirs;
753 };
754
755 static int
756 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
757 {
758   struct addfileprovides_cbdata *cbd = cbdata;
759   int i;
760
761   if (data != cbd->olddata)
762     {
763       map_free(&cbd->useddirs);
764       map_init(&cbd->useddirs, data->dirpool.ndirs);
765       for (i = 0; i < cbd->nfiles; i++)
766         {
767           Id did = repodata_str2dir(data, cbd->dirs[i], 0);
768           cbd->dids[i] = did;
769           if (did)
770             MAPSET(&cbd->useddirs, did);
771         }
772       cbd->olddata = data;
773     }
774   if (!MAPTST(&cbd->useddirs, value->id))
775     return 0;
776   for (i = 0; i < cbd->nfiles; i++)
777     {
778       if (cbd->dids[i] != value->id)
779         continue;
780       if (!strcmp(cbd->names[i], value->str))
781         break;
782     }
783   if (i == cbd->nfiles)
784     return 0;
785   s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
786   return 0;
787 }
788
789 void
790 pool_addfileprovides(Pool *pool, Repo *installed)
791 {
792   Solvable *s;
793   Repo *repo;
794   struct searchfiles sf, isf;
795   struct addfileprovides_cbdata cbd;
796   int i;
797
798   memset(&sf, 0, sizeof(sf));
799   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
800   memset(&isf, 0, sizeof(isf));
801   map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
802
803   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
804     {
805       repo = s->repo;
806       if (!repo)
807         continue;
808       if (s->obsoletes)
809         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, &isf);
810       if (s->conflicts)
811         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, &isf);
812       if (s->requires)
813         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, &isf);
814       if (s->recommends)
815         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, &isf);
816       if (s->suggests)
817         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, &isf);
818       if (s->supplements)
819         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, &isf);
820       if (s->enhances)
821         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, &isf);
822       if (s->freshens)
823         pool_addfileprovides_dep(pool, repo->idarraydata + s->freshens, &sf, &isf);
824     }
825   map_free(&sf.seen);
826   map_free(&isf.seen);
827   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
828   POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
829   cbd.dids = 0;
830   map_init(&cbd.useddirs, 1);
831   if (sf.nfiles)
832     {
833 #if 0
834       for (i = 0; i < sf.nfiles; i++)
835         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
836 #endif
837       cbd.nfiles = sf.nfiles;
838       cbd.ids = sf.ids;
839       cbd.dirs = sf.dirs;
840       cbd.names = sf.names;
841       cbd.olddata = 0;
842       cbd.dids = sat_realloc2(cbd.dids, sf.nfiles, sizeof(Id));
843       pool_search(pool, 0, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, &cbd);
844       sat_free(sf.ids);
845       for (i = 0; i < sf.nfiles; i++)
846         {
847           sat_free(sf.dirs[i]);
848           sat_free(sf.names[i]);
849         }
850       sat_free(sf.dirs);
851       sat_free(sf.names);
852     }
853   if (isf.nfiles && installed)
854     {
855 #if 0
856       for (i = 0; i < isf.nfiles; i++)
857         POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
858 #endif
859       cbd.nfiles = isf.nfiles;
860       cbd.ids = isf.ids;
861       cbd.dirs = isf.dirs;
862       cbd.names = isf.names;
863       cbd.olddata = 0;
864       cbd.dids = sat_realloc2(cbd.dids, isf.nfiles, sizeof(Id));
865       repo_search(installed, 0, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, &cbd);
866       sat_free(isf.ids);
867       for (i = 0; i < isf.nfiles; i++)
868         {
869           sat_free(isf.dirs[i]);
870           sat_free(isf.names[i]);
871         }
872       sat_free(isf.dirs);
873       sat_free(isf.names);
874     }
875   map_free(&cbd.useddirs);
876   sat_free(cbd.dids);
877   pool_freewhatprovides(pool);  /* as we have added provides */
878 }
879
880 void
881 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)
882 {
883   if (p)
884     {
885       if (pool->solvables[p].repo)
886         repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
887       return;
888     }
889   /* FIXME: obey callback return value! */
890   for (p = 1; p < pool->nsolvables; p++)
891     if (pool->solvables[p].repo)
892       repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
893 }
894
895
896 void
897 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
898 {
899   int i;
900
901   pool->languagecache = sat_free(pool->languagecache);
902   pool->languagecacheother = 0;
903   if (pool->nlanguages)
904     {
905       for (i = 0; i < pool->nlanguages; i++)
906         free((char *)pool->languages[i]);
907       free(pool->languages);
908     }
909   pool->nlanguages = nlanguages;
910   if (!nlanguages)
911     return;
912   pool->languages = sat_calloc(nlanguages, sizeof(const char **));
913   for (i = 0; i < pool->nlanguages; i++)
914     pool->languages[i] = strdup(languages[i]);
915 }
916
917 char *
918 pool_alloctmpspace(Pool *pool, int len)
919 {
920   int n = pool->tmpspacen;
921   if (!len)
922     return 0;
923   if (len > pool->tmpspacelen[n])
924     {
925       pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32);
926       pool->tmpspacelen[n] = len + 32;
927     }
928   pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF;
929   return pool->tmpspacebuf[n];
930 }
931
932
933 // EOF