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