- rename xmalloc/... functions to sat_malloc, as we're a
[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 static const char *initpool_data[] = {
37   "<NULL>",                   // ID_NULL
38   "",                         // ID_EMPTY
39   "solvable:name",
40   "solvable:arch",
41   "solvable:evr",
42   "solvable:vendor",
43   "solvable:provides",
44   "solvable:obsoletes",
45   "solvable:conflicts",
46   "solvable:requires",
47   "solvable:recommends",
48   "solvable:suggests",
49   "solvable:supplements",
50   "solvable:enhances",
51   "solvable:freshens",
52   "rpm:dbid",                          /* direct key into rpmdb */
53   "solvable:prereqmarker",
54   "solvable:filemarker",
55   "namespace:installed",
56   "namespace:modalias",
57   "system:system",
58   "src",
59   "nosrc",
60   "noarch",
61   "repodata:external",
62   "repodata:keys",
63   "repodata:location",
64   0
65 };
66
67 /* create pool */
68 Pool *
69 pool_create(void)
70 {
71   Pool *pool;
72   Solvable *s;
73
74   pool = (Pool *)sat_calloc(1, sizeof(*pool));
75
76   stringpool_init (&pool->ss, initpool_data);
77
78   // pre-alloc space for a RelDep
79   pool->rels = (Reldep *)sat_calloc(1 + REL_BLOCK, sizeof(Reldep));
80   pool->nrels = 1;
81
82   // pre-alloc space for a Solvable
83   pool->solvables = (Solvable *)sat_calloc(SOLVABLE_BLOCK + 1, sizeof(Solvable));
84   pool->nsolvables = 2;
85   queue_init(&pool->vendormap);
86   s = pool->solvables + SYSTEMSOLVABLE;
87   s->name = SYSTEM_SYSTEM;
88   s->arch = ARCH_NOARCH;
89   s->evr = ID_EMPTY;
90
91   pool->debugmask = SAT_DEBUG_RESULT;   /* FIXME */
92   return pool;
93 }
94
95
96 /* free all the resources of our pool */
97 void
98 pool_free(Pool *pool)
99 {
100   int i;
101
102   pool_freewhatprovides(pool);
103   pool_freeidhashes(pool);
104   repo_freeallrepos(pool, 1);
105   sat_free(pool->id2arch);
106   sat_free(pool->solvables);
107   sat_free(pool->ss.stringspace);
108   sat_free(pool->ss.strings);
109   sat_free(pool->rels);
110   queue_free(&pool->vendormap);
111   for (i = 0; i < DEP2STRBUF; i++)
112     sat_free(pool->dep2strbuf[i]);
113   sat_free(pool);
114 }
115
116 Id
117 pool_add_solvable(Pool *pool)
118 {
119   if ((pool->nsolvables & SOLVABLE_BLOCK) == 0)
120     pool->solvables = sat_realloc2(pool->solvables, pool->nsolvables + (SOLVABLE_BLOCK + 1), sizeof(Solvable));
121   memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
122   return pool->nsolvables++;
123 }
124
125 Id
126 pool_add_solvable_block(Pool *pool, int count)
127 {
128   Id nsolvables = pool->nsolvables;
129   if (!count)
130     return nsolvables;
131   if (((nsolvables - 1) | SOLVABLE_BLOCK) != ((nsolvables + count - 1) | SOLVABLE_BLOCK))
132     pool->solvables = sat_realloc2(pool->solvables, (nsolvables + count + SOLVABLE_BLOCK) & ~SOLVABLE_BLOCK, sizeof(Solvable));
133   memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
134   pool->nsolvables += count;
135   return nsolvables;
136 }
137
138 void
139 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
140 {
141   if (!count)
142     return;
143   if (reuseids && start + count == pool->nsolvables)
144     {
145       /* might want to shrink solvable array */
146       pool->nsolvables = start;
147       return;
148     }
149   memset(pool->solvables + start, 0, sizeof(Solvable) * count);
150 }
151
152
153 const char *
154 solvable2str(Pool *pool, Solvable *s)
155 {
156   int l, nn = pool->dep2strn;
157   const char *n, *e, *a;
158   n = id2str(pool, s->name);
159   e = id2str(pool, s->evr);
160   a = id2str(pool, s->arch);
161   l = strlen(n) + strlen(e) + strlen(a) + 3;
162   if (l > pool->dep2strlen[nn])
163     {
164       pool->dep2strbuf[nn] = sat_realloc(pool->dep2strbuf[nn], l + 32);
165       pool->dep2strlen[nn] = l + 32;
166     }
167   sprintf(pool->dep2strbuf[nn], "%s-%s.%s", n, e, a);
168   pool->dep2strn = (nn + 1) % DEP2STRBUF;
169   return pool->dep2strbuf[nn];
170 }
171
172 static Pool *pool_shrink_whatprovides_sortcmp_data;
173
174 static int
175 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp)
176 {
177   int r;
178   Pool *pool = pool_shrink_whatprovides_sortcmp_data;
179   Id oa, ob, *da, *db;
180   oa = pool->whatprovides[*(Id *)ap];
181   ob = pool->whatprovides[*(Id *)bp];
182   if (oa == ob)
183     return *(Id *)ap - *(Id *)bp;
184   if (!oa)
185     return -1;
186   if (!ob)
187     return 1;
188   da = pool->whatprovidesdata + oa;
189   db = pool->whatprovidesdata + ob;
190   while (*db)
191     if ((r = (*da++ - *db++)) != 0)
192       return r;
193   if (*da)
194     return *da;
195   return *(Id *)ap - *(Id *)bp;
196 }
197
198 /*
199  * pool_shrink_whatprovides  - unify whatprovides data
200  *
201  * whatprovides_rel must be empty for this to work!
202  *
203  */
204 static void
205 pool_shrink_whatprovides(Pool *pool)
206 {
207   Id i, id;
208   Id *sorted;
209   Id lastid, *last, *dp, *lp;
210   Offset o;
211   int r;
212
213   if (pool->ss.nstrings < 3)
214     return;
215   sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id));
216   for (id = 0; id < pool->ss.nstrings; id++)
217     sorted[id] = id;
218   pool_shrink_whatprovides_sortcmp_data = pool;
219   qsort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp);
220   last = 0;
221   lastid = 0;
222   for (i = 1; i < pool->ss.nstrings; i++)
223     {
224       id = sorted[i];
225       o = pool->whatprovides[id];
226       if (o == 0 || o == 1)
227         continue;
228       dp = pool->whatprovidesdata + o;
229       if (last)
230         {
231           lp = last;
232           while (*dp)   
233             if (*dp++ != *lp++)
234               {
235                 last = 0;
236                 break;
237               }
238           if (last && *lp)
239             last = 0;
240           if (last)
241             {
242               pool->whatprovides[id] = -lastid;
243               continue;
244             }
245         }
246       last = pool->whatprovidesdata + o;
247       lastid = id;
248     }
249   sat_free(sorted);
250   dp = pool->whatprovidesdata + 2;
251   for (id = 1; id < pool->ss.nstrings; id++)
252     {
253       o = pool->whatprovides[id];
254       if (o == 0 || o == 1)
255         continue;
256       if ((Id)o < 0)
257         {
258           i = -(Id)o;
259           if (i >= id)
260             abort();
261           pool->whatprovides[id] = pool->whatprovides[i];
262           continue;
263         }
264       lp = pool->whatprovidesdata + o;
265       if (lp < dp)
266         abort();
267       pool->whatprovides[id] = dp - pool->whatprovidesdata;
268       while ((*dp++ = *lp++) != 0)
269         ;
270     }
271   o = dp - pool->whatprovidesdata;
272   POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
273   if (pool->whatprovidesdataoff == o)
274     return;
275   r = pool->whatprovidesdataoff - o;
276   pool->whatprovidesdataoff = o;
277   pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
278   if (r > pool->whatprovidesdataleft)
279     r = pool->whatprovidesdataleft;
280   memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
281 }
282
283
284 /*
285  * pool_createwhatprovides()
286  * 
287  * create hashes over pool of solvables to ease provide lookups
288  * 
289  */
290 void
291 pool_createwhatprovides(Pool *pool)
292 {
293   int i, num, np, extra;
294   Offset off;
295   Solvable *s;
296   Id id;
297   Offset *idp, n;
298   Offset *whatprovides;
299   Id *whatprovidesdata, *d;
300
301   POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables);
302   POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
303
304   pool_freeidhashes(pool);      /* XXX: should not be here! */
305   pool_freewhatprovides(pool);
306   num = pool->ss.nstrings;
307   pool->whatprovides = whatprovides = sat_calloc((num + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK, sizeof(Offset));
308   pool->whatprovides_rel = sat_calloc((pool->nrels + WHATPROVIDES_BLOCK) & ~WHATPROVIDES_BLOCK, sizeof(Offset));
309
310   /* count providers for each name */
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       pp = s->repo->idarraydata + s->provides;
320       while ((id = *pp++) != ID_NULL)
321         {
322           while (ISRELDEP(id))
323             {
324               Reldep *rd = GETRELDEP(pool, id);
325               id = rd->name;
326             }
327           whatprovides[id]++;          /* inc count of providers */
328         }
329     }
330
331   off = 2;      /* first entry is undef, second is empty list */
332   idp = whatprovides;
333   np = 0;                              /* number of names provided */
334   for (i = 0; i < num; i++, idp++)
335     {
336       n = *idp;
337       if (!n)                          /* no providers */
338         continue;
339       *idp = off;                      /* move from counts to offsets into whatprovidesdata */
340       off += n + 1;                    /* make space for all providers + terminating ID_NULL */
341       np++;                            /* inc # of provider 'slots' */
342     }
343
344   POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
345
346   /* reserve some space for relation data */
347   extra = 2 * pool->nrels;
348   if (extra < 256)
349     extra = 256;
350
351   POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
352
353   /* alloc space for all providers + extra */
354   whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
355
356   /* now fill data for all provides */
357   for (i = 1; i < pool->nsolvables; i++)
358     {
359       Id *pp;
360       s = pool->solvables + i;
361       if (!s->provides)
362         continue;
363       if (!pool_installable(pool, s))
364         continue;
365
366       /* for all provides of this solvable */
367       pp = s->repo->idarraydata + s->provides;
368       while ((id = *pp++) != 0)
369         {
370           while (ISRELDEP(id))
371             {
372               Reldep *rd = GETRELDEP(pool, id);
373               id = rd->name;
374             }
375           d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
376           if (*d)
377             {
378               d++;
379               while (*d)               /* find free slot */
380                 d++;
381               if (d[-1] == i)
382                 continue;
383             }
384           *d = i;                      /* put solvable Id into data */
385         }
386     }
387   pool->whatprovidesdata = whatprovidesdata;
388   pool->whatprovidesdataoff = off;
389   pool->whatprovidesdataleft = extra;
390   pool_shrink_whatprovides(pool);
391 }
392
393 /*
394  * free all of our whatprovides data
395  * be careful, everything internalized with pool_queuetowhatprovides is gone, too
396  */
397 void
398 pool_freewhatprovides(Pool *pool)
399 {
400   pool->whatprovides = sat_free(pool->whatprovides);
401   pool->whatprovides_rel = sat_free(pool->whatprovides_rel);
402   pool->whatprovidesdata = sat_free(pool->whatprovidesdata);
403   pool->whatprovidesdataoff = 0;
404   pool->whatprovidesdataleft = 0;
405 }
406
407
408 /******************************************************************************/
409
410 /*
411  * pool_queuetowhatprovides  - add queue contents to whatprovidesdata
412  * 
413  * on-demand filling of provider information
414  * move queue data into whatprovidesdata
415  * q: queue of Ids
416  * returns: Offset into whatprovides
417  *
418  */
419 Id
420 pool_queuetowhatprovides(Pool *pool, Queue *q)
421 {
422   Offset off;
423   int count = q->count;
424
425   if (count == 0)                      /* queue empty -> ID_EMPTY */
426     return ID_EMPTY;
427
428   /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
429   if (pool->whatprovidesdataleft < count + 1)
430     {
431       POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n");
432       pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
433       pool->whatprovidesdataleft = count + 4096;
434     }
435
436   /* copy queue to next free slot */
437   off = pool->whatprovidesdataoff;
438   memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
439
440   /* adapt count and ID_NULL-terminate */
441   pool->whatprovidesdataoff += count;
442   pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
443   pool->whatprovidesdataleft -= count + 1;
444
445   return (Id)off;
446 }
447
448
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 (pool->nscallback)
500         {
501           p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
502           if (p > 1)
503             {
504               queue_free(&plist);
505               pool->whatprovides_rel[d] = p;
506               return pool->whatprovidesdata + p;
507             }
508           if (p == 1)
509             queue_push(&plist, SYSTEMSOLVABLE);
510         }
511       break;
512     default:
513       break;
514     }
515
516   /* convert to whatprovides id */
517 #if 0
518   POOL_DEBUG(DEBUG_1, "addrelproviders: what provides %s?\n", id2str(pool, name));
519 #endif
520   if (flags && flags < 8)
521     {
522       FOR_PROVIDES(p, pp, name)
523         {
524 #if 0
525           POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, pool->p[p].name));
526 #endif
527           /* solvable p provides name in some rels */
528           pidp = pool->solvables[p].repo->idarraydata + pool->solvables[p].provides;
529           while ((pid = *pidp++) != 0)
530             {
531               int pflags;
532               Id pevr;
533
534               if (pid == name)
535                 {
536 #ifdef DEBIAN_SEMANTICS
537                   continue;             /* unversioned provides can
538                                          * never match versioned deps */
539 #else
540                   break;                /* yes, provides all versions */
541 #endif
542                 }
543               if (!ISRELDEP(pid))
544                 continue;               /* wrong provides name */
545               prd = GETRELDEP(pool, pid);
546               if (prd->name != name)
547                 continue;               /* wrong provides name */
548               /* right package, both deps are rels */
549               pflags = prd->flags;
550               if (!pflags)
551                 continue;
552               if (flags == 7 || pflags == 7)
553                 break; /* included */
554               if ((pflags & flags & 5) != 0)
555                 break; /* same direction, match */
556               pevr = prd->evr;
557               if (pevr == evr)
558                 {
559                   if ((pflags & flags & 2) != 0)
560                     break; /* both have =, match */
561                 }
562               else
563                 {
564                   int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
565                   if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
566                     break;
567                 }
568             }
569           if (!pid)
570             continue;   /* no rel match */
571           queue_push(&plist, p);
572         }
573       /* make our system solvable provide all unknown rpmlib() stuff */
574       if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
575         queue_push(&plist, SYSTEMSOLVABLE);
576     }
577   /* add providers to whatprovides */
578 #if 0
579   POOL_DEBUG(DEBUG_1, "addrelproviders: adding %d packages to %d\n", plist.count, d);
580 #endif
581   pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
582   queue_free(&plist);
583
584   return pool->whatprovidesdata + pool->whatprovides_rel[d];
585 }
586
587 /*************************************************************************/
588
589 void
590 pool_debug(Pool *pool, int type, const char *format, ...)
591 {
592   va_list args;
593   char buf[1024];
594
595   if ((type & SAT_FATAL) == 0)
596     {
597       if ((pool->debugmask & type) == 0)
598         return;
599     }
600   va_start(args, format);
601   if (!pool->debugcallback)
602     {
603       if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
604         vprintf(format, args);
605       else
606         vfprintf(stderr, format, args);
607       return;
608     }
609   vsnprintf(buf, sizeof(buf), format, args);
610   pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
611 }
612
613 void
614 pool_setdebuglevel(Pool *pool, int level)
615 {
616   int mask = SAT_DEBUG_RESULT;
617   if (level > 0)
618     mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE;
619   if (level > 1)
620     mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY;
621   if (level > 2)
622     mask |= SAT_DEBUG_PROPAGATE;
623   if (level > 3)
624     mask |= SAT_DEBUG_RULE_CREATION;
625   if (level > 4)
626     mask |= SAT_DEBUG_SCHUBI;
627   pool->debugmask = mask;
628 }
629
630 /*************************************************************************/
631
632 struct searchfiles {
633   const char **files;
634   int nfiles;
635 };
636
637 #define SEARCHFILES_BLOCK 127
638
639 static void
640 pool_addfileprovides_dep(Pool *pool, Id *ida, Map *seen, struct searchfiles *sf)
641 {
642   Id dep, sid;
643   const char *s;
644
645   while ((dep = *ida++) != 0)
646     {
647       while (ISRELDEP(dep))
648         {
649           Reldep *rd;
650           sid = pool->ss.nstrings + GETRELID(dep);
651           if (MAPTST(seen, sid))
652             {
653               dep = 0;
654               break;
655             }
656           MAPSET(seen, sid);
657           rd = GETRELDEP(pool, dep);
658           if (rd->flags < 8)
659             dep = rd->name;
660           else if (rd->flags == REL_NAMESPACE)
661             {
662               if (rd->name == NAMESPACE_INSTALLED)
663                 {
664                   dep = 0;      /* for now */
665                   break;
666                 }
667               dep = rd->evr;
668             }
669           else
670             {
671               Id ids[2];
672               ids[0] = rd->name;
673               ids[1] = 0;
674               pool_addfileprovides_dep(pool, ids, seen, sf);
675               dep = rd->evr;
676             }
677         }
678       if (!dep)
679         continue;
680       if (MAPTST(seen, dep))
681         continue;
682       MAPSET(seen, dep);
683       s = id2str(pool, dep);
684       if (*s != '/')
685         continue;
686       if ((sf->nfiles & SEARCHFILES_BLOCK) == 0)
687         sf->files = sat_realloc2(sf->files, sf->nfiles + (SEARCHFILES_BLOCK + 1), sizeof(const char *));
688       sf->files[sf->nfiles++] = strdup(s);
689     }
690 }
691
692 #if 0
693 static int
694 addfileprovides_cb(void *data, Solvable *s, Id key, const char *str)
695 {
696   Pool *pool = s->repo->pool;
697   Id id;
698   id = str2id(pool, str, 0);
699   if (!id)
700     return 0;   /* can't happen */
701   s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
702   return 0;
703 }
704 #endif
705
706 void
707 pool_addfileprovides(Pool *pool)
708 {
709   Solvable *s;
710   Repo *repo;
711   Map seen;
712   struct searchfiles sf;
713   int i;
714
715   map_init(&seen, pool->ss.nstrings + pool->nrels);
716   memset(&sf, 0, sizeof(sf));
717
718   for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
719     {
720       repo = s->repo;
721       if (!repo)
722         continue;
723       if (s->obsoletes)
724         pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &seen, &sf);
725       if (s->conflicts)
726         pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &seen, &sf);
727       if (s->requires)
728         pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &seen, &sf);
729       if (s->recommends)
730         pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &seen, &sf);
731       if (s->suggests)
732         pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &seen, &sf);
733       if (s->supplements)
734         pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &seen, &sf);
735       if (s->enhances)
736         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &seen, &sf);
737       if (s->freshens)
738         pool_addfileprovides_dep(pool, repo->idarraydata + s->freshens, &seen, &sf);
739     }
740   map_free(&seen);
741   POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
742   if (!sf.nfiles)
743     return;
744 #if 0
745   for (i = 0; i < sf.nfiles; i++)
746     POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", sf.files[i]);
747 #endif
748   if ((sf.nfiles & SEARCHFILES_BLOCK) == 0)
749     sf.files = sat_realloc2(sf.files, sf.nfiles + (SEARCHFILES_BLOCK + 1), sizeof(const char *));
750   sf.files[sf.nfiles++] = 0;
751 #if 0
752   pool_search(0, SOLVABLE_FILELIST, (const char *)sf.files, SEARCH_STRING|SEARCH_MULTIPLE, addfileprovides_cb, 0);
753 #endif
754   sat_free(sf.files);
755   pool_freewhatprovides(pool);  /* as we have added provides */
756 }
757
758 // EOF