satsolver  0.17.2
pool.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007-2009, 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 *
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 #ifdef FEDORA
65  pool->obsoleteusescolors = 1;
66 #endif
67 #ifdef DEBIAN
68  pool->allowselfconflicts = 1;
69 # ifdef MULTI_SEMANTICS
70  pool->disttype = DISTTYPE_DEB;
71 # endif
72 #endif
73 #ifdef RPM5
74  pool->obsoleteusesprovides = 1;
76 #endif
77  return pool;
78 }
79 
80 
81 /* free all the resources of our pool */
82 void
84 {
85  int i;
86 
88  pool_freeidhashes(pool);
89  repo_freeallrepos(pool, 1);
90  sat_free(pool->id2arch);
91  sat_free(pool->solvables);
92  stringpool_free(&pool->ss);
93  sat_free(pool->rels);
94  pool_setvendorclasses(pool, 0);
95  queue_free(&pool->vendormap);
96  for (i = 0; i < POOL_TMPSPACEBUF; i++)
97  sat_free(pool->tmpspace.buf[i]);
98  for (i = 0; i < pool->nlanguages; i++)
99  free((char *)pool->languages[i]);
100  sat_free(pool->languages);
101  sat_free(pool->languagecache);
102  sat_free(pool);
103 }
104 
105 #ifdef MULTI_SEMANTICS
106 void
107 pool_setdisttype(Pool *pool, int disttype)
108 {
109  pool->disttype = disttype;
110 }
111 #endif
112 
113 Id
115 {
116  pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK);
117  memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable));
118  return pool->nsolvables++;
119 }
120 
121 Id
122 pool_add_solvable_block(Pool *pool, int count)
123 {
124  Id nsolvables = pool->nsolvables;
125  if (!count)
126  return nsolvables;
127  pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK);
128  memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count);
129  pool->nsolvables += count;
130  return nsolvables;
131 }
132 
133 void
134 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids)
135 {
136  if (!count)
137  return;
138  if (reuseids && start + count == pool->nsolvables)
139  {
140  /* might want to shrink solvable array */
141  pool->nsolvables = start;
142  return;
143  }
144  memset(pool->solvables + start, 0, sizeof(Solvable) * count);
145 }
146 
147 
148 void
149 pool_set_installed(Pool *pool, Repo *installed)
150 {
151  if (pool->installed == installed)
152  return;
153  pool->installed = installed;
154  pool_freewhatprovides(pool);
155 }
156 
157 static int
158 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp, void *dp)
159 {
160  int r;
161  Pool *pool = dp;
162  Id oa, ob, *da, *db;
163  oa = pool->whatprovides[*(Id *)ap];
164  ob = pool->whatprovides[*(Id *)bp];
165  if (oa == ob)
166  return *(Id *)ap - *(Id *)bp;
167  if (!oa)
168  return -1;
169  if (!ob)
170  return 1;
171  da = pool->whatprovidesdata + oa;
172  db = pool->whatprovidesdata + ob;
173  while (*db)
174  if ((r = (*da++ - *db++)) != 0)
175  return r;
176  if (*da)
177  return *da;
178  return *(Id *)ap - *(Id *)bp;
179 }
180 
181 /*
182  * pool_shrink_whatprovides - unify whatprovides data
183  *
184  * whatprovides_rel must be empty for this to work!
185  *
186  */
187 static void
189 {
190  Id i, id;
191  Id *sorted;
192  Id lastid, *last, *dp, *lp;
193  Offset o;
194  int r;
195 
196  if (pool->ss.nstrings < 3)
197  return;
198  sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id));
199  for (id = 0; id < pool->ss.nstrings; id++)
200  sorted[id] = id;
201  sat_sort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp, pool);
202  last = 0;
203  lastid = 0;
204  for (i = 1; i < pool->ss.nstrings; i++)
205  {
206  id = sorted[i];
207  o = pool->whatprovides[id];
208  if (o == 0 || o == 1)
209  continue;
210  dp = pool->whatprovidesdata + o;
211  if (last)
212  {
213  lp = last;
214  while (*dp)
215  if (*dp++ != *lp++)
216  {
217  last = 0;
218  break;
219  }
220  if (last && *lp)
221  last = 0;
222  if (last)
223  {
224  pool->whatprovides[id] = -lastid;
225  continue;
226  }
227  }
228  last = pool->whatprovidesdata + o;
229  lastid = id;
230  }
231  sat_free(sorted);
232  dp = pool->whatprovidesdata + 2;
233  for (id = 1; id < pool->ss.nstrings; id++)
234  {
235  o = pool->whatprovides[id];
236  if (o == 0 || o == 1)
237  continue;
238  if ((Id)o < 0)
239  {
240  i = -(Id)o;
241  if (i >= id)
242  abort();
243  pool->whatprovides[id] = pool->whatprovides[i];
244  continue;
245  }
246  lp = pool->whatprovidesdata + o;
247  if (lp < dp)
248  abort();
249  pool->whatprovides[id] = dp - pool->whatprovidesdata;
250  while ((*dp++ = *lp++) != 0)
251  ;
252  }
253  o = dp - pool->whatprovidesdata;
254  POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o);
255  if (pool->whatprovidesdataoff == o)
256  return;
257  r = pool->whatprovidesdataoff - o;
258  pool->whatprovidesdataoff = o;
259  pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id));
260  if (r > pool->whatprovidesdataleft)
261  r = pool->whatprovidesdataleft;
262  memset(pool->whatprovidesdata + o, 0, r * sizeof(Id));
263 }
264 
265 
266 /*
267  * pool_createwhatprovides()
268  *
269  * create hashes over pool of solvables to ease provide lookups
270  *
271  */
272 void
274 {
275  int i, num, np, extra;
276  Offset off;
277  Solvable *s;
278  Id id;
279  Offset *idp, n;
280  Offset *whatprovides;
281  Id *whatprovidesdata, *d;
282  Repo *installed = pool->installed;
283  unsigned int now;
284 
285  now = sat_timems(0);
286  POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables);
287  POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels);
288 
289  pool_freeidhashes(pool); /* XXX: should not be here! */
290  pool_freewhatprovides(pool);
291  num = pool->ss.nstrings;
292  pool->whatprovides = whatprovides = sat_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK);
294 
295  /* count providers for each name */
296  for (i = pool->nsolvables - 1; i > 0; i--)
297  {
298  Id *pp;
299  s = pool->solvables + i;
300  if (!s->provides || !s->repo || s->repo->disabled)
301  continue;
302  /* we always need the installed solvable in the whatprovides data,
303  otherwise obsoletes/conflicts on them won't work */
304  if (s->repo != installed && !pool_installable(pool, s))
305  continue;
306  pp = s->repo->idarraydata + s->provides;
307  while ((id = *pp++) != 0)
308  {
309  while (ISRELDEP(id))
310  {
311  Reldep *rd = GETRELDEP(pool, id);
312  id = rd->name;
313  }
314  whatprovides[id]++; /* inc count of providers */
315  }
316  }
317 
318  off = 2; /* first entry is undef, second is empty list */
319  np = 0; /* number of names provided */
320  for (i = 0, idp = whatprovides; i < num; i++, idp++)
321  {
322  n = *idp;
323  if (!n) /* no providers */
324  continue;
325  off += n; /* make space for all providers */
326  *idp = off++; /* now idp points to terminating zero */
327  np++; /* inc # of provider 'slots' for stats */
328  }
329 
330  POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
331 
332  /* reserve some space for relation data */
333  extra = 2 * pool->nrels;
334  if (extra < 256)
335  extra = 256;
336 
337  POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra);
338 
339  /* alloc space for all providers + extra */
340  whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
341 
342  /* now fill data for all provides */
343  for (i = pool->nsolvables - 1; i > 0; i--)
344  {
345  Id *pp;
346  s = pool->solvables + i;
347  if (!s->provides || !s->repo || s->repo->disabled)
348  continue;
349  if (s->repo != installed && !pool_installable(pool, s))
350  continue;
351 
352  /* for all provides of this solvable */
353  pp = s->repo->idarraydata + s->provides;
354  while ((id = *pp++) != 0)
355  {
356  while (ISRELDEP(id))
357  {
358  Reldep *rd = GETRELDEP(pool, id);
359  id = rd->name;
360  }
361  d = whatprovidesdata + whatprovides[id]; /* offset into whatprovidesdata */
362  if (*d != i) /* don't add same solvable twice */
363  {
364  d[-1] = i;
365  whatprovides[id]--;
366  }
367  }
368  }
369  pool->whatprovidesdata = whatprovidesdata;
370  pool->whatprovidesdataoff = off;
371  pool->whatprovidesdataleft = extra;
373  POOL_DEBUG(SAT_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id)));
374  POOL_DEBUG(SAT_DEBUG_STATS, "createwhatprovides took %d ms\n", sat_timems(now));
375 }
376 
377 /*
378  * free all of our whatprovides data
379  * be careful, everything internalized with pool_queuetowhatprovides is
380  * gone, too
381  */
382 void
384 {
385  pool->whatprovides = sat_free(pool->whatprovides);
388  pool->whatprovidesdataoff = 0;
389  pool->whatprovidesdataleft = 0;
390 }
391 
392 
393 /******************************************************************************/
394 
395 /*
396  * pool_queuetowhatprovides - add queue contents to whatprovidesdata
397  *
398  * on-demand filling of provider information
399  * move queue data into whatprovidesdata
400  * q: queue of Ids
401  * returns: Offset into whatprovides
402  *
403  */
404 Id
406 {
407  Offset off;
408  int count = q->count;
409 
410  if (count == 0) /* queue empty -> 1 */
411  return 1;
412 
413  /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */
414  if (pool->whatprovidesdataleft < count + 1)
415  {
416  POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n");
417  pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id));
418  pool->whatprovidesdataleft = count + 4096;
419  }
420 
421  /* copy queue to next free slot */
422  off = pool->whatprovidesdataoff;
423  memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id));
424 
425  /* adapt count and ID_NULL-terminate */
426  pool->whatprovidesdataoff += count;
427  pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL;
428  pool->whatprovidesdataleft -= count + 1;
429 
430  return (Id)off;
431 }
432 
433 
434 /*************************************************************************/
435 
436 #if defined(MULTI_SEMANTICS)
437 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
438 #elif defined(DEBIAN_SEMANTICS)
439 # define EVRCMP_DEPCMP EVRCMP_COMPARE
440 #else
441 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
442 #endif
443 
444 /* check if a package's nevr matches a dependency */
445 
446 int
448 {
449  Reldep *rd = GETRELDEP(pool, d);
450  Id name = rd->name;
451  Id evr = rd->evr;
452  int flags = rd->flags;
453 
454  if (flags > 7)
455  {
456  switch (flags)
457  {
458  case REL_ARCH:
459  if (s->arch != evr)
460  return 0;
461  return pool_match_nevr(pool, s, name);
462  case REL_OR:
463  if (pool_match_nevr(pool, s, name))
464  return 1;
465  return pool_match_nevr(pool, s, evr);
466  case REL_AND:
467  case REL_WITH:
468  if (!pool_match_nevr(pool, s, name))
469  return 0;
470  return pool_match_nevr(pool, s, evr);
471  default:
472  return 0;
473  }
474  }
475  if (!pool_match_nevr(pool, s, name))
476  return 0;
477  if (evr == s->evr)
478  return flags & 2 ? 1 : 0;
479  if (!flags)
480  return 0;
481  if (flags == 7)
482  return 1;
483  if (flags != 2 && flags != 5)
484  flags ^= 5;
485  if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP)))) != 0)
486  return 1;
487  return 0;
488 }
489 
490 /* match (flags, evr) against provider (pflags, pevr) */
491 static inline int
492 pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr)
493 {
494  if (!pflags || !flags || pflags >= 8 || flags >= 8)
495  return 0;
496  if (flags == 7 || pflags == 7)
497  return 1; /* rel provides every version */
498  if ((pflags & flags & 5) != 0)
499  return 1; /* both rels show in the same direction */
500  if (pevr == evr)
501  {
502  if ((pflags & flags & 2) != 0)
503  return 1; /* both have '=', match */
504  }
505  else
506  {
507  int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
508  if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)))) != 0)
509  return 1;
510  }
511  return 0;
512 }
513 
514 /* match two dependencies (d1 = provider) */
515 
516 int
517 pool_match_dep(Pool *pool, Id d1, Id d2)
518 {
519  Reldep *rd1, *rd2;
520 
521  if (d1 == d2)
522  return 1;
523  if (!ISRELDEP(d1))
524  {
525  if (!ISRELDEP(d2))
526  return 0;
527  rd2 = GETRELDEP(pool, d2);
528  return pool_match_dep(pool, d1, rd2->name);
529  }
530  rd1 = GETRELDEP(pool, d1);
531  if (!ISRELDEP(d2))
532  {
533  return pool_match_dep(pool, rd1->name, d2);
534  }
535  rd2 = GETRELDEP(pool, d2);
536  /* first match name */
537  if (!pool_match_dep(pool, rd1->name, rd2->name))
538  return 0;
539  /* name matches, check flags and evr */
540  return pool_match_flags_evr(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
541 }
542 
543 /*
544  * addrelproviders
545  *
546  * add packages fulfilling the relation to whatprovides array
547  * no exact providers, do range match
548  *
549  */
550 
551 Id
553 {
554  Reldep *rd = GETRELDEP(pool, d);
555  Reldep *prd;
556  Queue plist;
557  Id buf[16];
558  Id name = rd->name;
559  Id evr = rd->evr;
560  int flags = rd->flags;
561  Id pid, *pidp;
562  Id p, *pp;
563 
564  d = GETRELID(d);
565  queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
566 
567  if (flags >= 8)
568  {
569  /* special relation */
570  Id wp = 0;
571  Id *pp2, *pp3;
572 
573  switch (flags)
574  {
575  case REL_AND:
576  case REL_WITH:
577  wp = pool_whatprovides(pool, name);
578  pp2 = pool_whatprovides_ptr(pool, evr);
579  pp = pool->whatprovidesdata + wp;
580  while ((p = *pp++) != 0)
581  {
582  for (pp3 = pp2; *pp3; pp3++)
583  if (*pp3 == p)
584  break;
585  if (*pp3)
586  queue_push(&plist, p); /* found it */
587  else
588  wp = 0;
589  }
590  break;
591  case REL_OR:
592  wp = pool_whatprovides(pool, name);
593  pp = pool->whatprovidesdata + wp;
594  if (!*pp)
595  wp = pool_whatprovides(pool, evr);
596  else
597  {
598  int cnt;
599  while ((p = *pp++) != 0)
600  queue_push(&plist, p);
601  cnt = plist.count;
602  pp = pool_whatprovides_ptr(pool, evr);
603  while ((p = *pp++) != 0)
604  queue_pushunique(&plist, p);
605  if (plist.count != cnt)
606  wp = 0;
607  }
608  break;
609  case REL_NAMESPACE:
610  if (name == NAMESPACE_OTHERPROVIDERS)
611  {
612  wp = pool_whatprovides(pool, evr);
613  break;
614  }
615  if (pool->nscallback)
616  {
617  /* ask callback which packages provide the dependency
618  * 0: none
619  * 1: the system (aka SYSTEMSOLVABLE)
620  * >1: set of packages, stored as offset on whatprovidesdata
621  */
622  p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
623  if (p > 1)
624  wp = p;
625  if (p == 1)
626  queue_push(&plist, SYSTEMSOLVABLE);
627  }
628  break;
629  case REL_ARCH:
630  /* small hack: make it possible to match <pkg>.src
631  * we have to iterate over the solvables as src packages do not
632  * provide anything, thus they are not indexed in our
633  * whatprovides hash */
634  if (evr == ARCH_SRC)
635  {
636  Solvable *s;
637  for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
638  {
639  if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
640  continue;
641  if (pool_match_nevr(pool, s, name))
642  queue_push(&plist, p);
643  }
644  break;
645  }
646  wp = pool_whatprovides(pool, name);
647  pp = pool->whatprovidesdata + wp;
648  while ((p = *pp++) != 0)
649  {
650  Solvable *s = pool->solvables + p;
651  if (s->arch == evr)
652  queue_push(&plist, p);
653  else
654  wp = 0;
655  }
656  break;
657  case REL_FILECONFLICT:
658  pp = pool_whatprovides_ptr(pool, name);
659  while ((p = *pp++) != 0)
660  {
661  Id origd = MAKERELDEP(d);
662  Solvable *s = pool->solvables + p;
663  if (!s->provides)
664  continue;
665  pidp = s->repo->idarraydata + s->provides;
666  while ((pid = *pidp++) != 0)
667  if (pid == origd)
668  break;
669  if (pid)
670  queue_push(&plist, p);
671  }
672  break;
673  default:
674  break;
675  }
676  if (wp)
677  {
678  /* we can reuse an existing entry */
679  queue_free(&plist);
680  pool->whatprovides_rel[d] = wp;
681  return wp;
682  }
683  }
684  else if (flags)
685  {
686  /* simple version comparison relation */
687 #if 0
688  POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
689 #endif
690  pp = pool_whatprovides_ptr(pool, name);
691  while (ISRELDEP(name))
692  {
693  rd = GETRELDEP(pool, name);
694  name = rd->name;
695  }
696  while ((p = *pp++) != 0)
697  {
698  Solvable *s = pool->solvables + p;
699  if (!s->provides)
700  {
701  /* no provides - check nevr */
702  if (pool_match_nevr_rel(pool, s, MAKERELDEP(d)))
703  queue_push(&plist, p);
704  continue;
705  }
706  /* solvable p provides name in some rels */
707  pidp = s->repo->idarraydata + s->provides;
708  while ((pid = *pidp++) != 0)
709  {
710  if (pid == name)
711  {
712 #if defined(MULTI_SEMANTICS)
713  if (pool->disttype == DISTTYPE_DEB)
714  continue;
715  else
716  break;
717 #elif defined(DEBIAN_SEMANTICS)
718  continue; /* unversioned provides can
719  * never match versioned deps */
720 #else
721  break; /* yes, provides all versions */
722 #endif
723  }
724  if (!ISRELDEP(pid))
725  continue; /* wrong provides name */
726  prd = GETRELDEP(pool, pid);
727  if (prd->name != name)
728  continue; /* wrong provides name */
729  /* right package, both deps are rels. check flags/evr */
730  if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
731  break; /* matches */
732  }
733  if (!pid)
734  continue; /* none of the providers matched */
735  queue_push(&plist, p);
736  }
737  /* make our system solvable provide all unknown rpmlib() stuff */
738  if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7))
739  queue_push(&plist, SYSTEMSOLVABLE);
740  }
741  /* add providers to whatprovides */
742 #if 0
743  POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d);
744 #endif
745  pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist);
746  queue_free(&plist);
747 
748  return pool->whatprovides_rel[d];
749 }
750 
751 /*************************************************************************/
752 
753 void
754 pool_debug(Pool *pool, int type, const char *format, ...)
755 {
756  va_list args;
757  char buf[1024];
758 
759  if ((type & (SAT_FATAL|SAT_ERROR)) == 0)
760  {
761  if ((pool->debugmask & type) == 0)
762  return;
763  }
764  va_start(args, format);
765  if (!pool->debugcallback)
766  {
767  if ((type & (SAT_FATAL|SAT_ERROR)) == 0 && !(pool->debugmask & SAT_DEBUG_TO_STDERR))
768  vprintf(format, args);
769  else
770  vfprintf(stderr, format, args);
771  return;
772  }
773  vsnprintf(buf, sizeof(buf), format, args);
774  pool->debugcallback(pool, pool->debugcallbackdata, type, buf);
775 }
776 
777 void
778 pool_setdebuglevel(Pool *pool, int level)
779 {
780  int mask = SAT_DEBUG_RESULT;
781  if (level > 0)
783  if (level > 1)
785  if (level > 2)
786  mask |= SAT_DEBUG_PROPAGATE;
787  if (level > 3)
788  mask |= SAT_DEBUG_RULE_CREATION;
789  if (level > 4)
790  mask |= SAT_DEBUG_SCHUBI;
791  mask |= pool->debugmask & SAT_DEBUG_TO_STDERR; /* keep bit */
792  pool->debugmask = mask;
793 }
794 
795 /*************************************************************************/
796 
797 struct searchfiles {
798  Id *ids;
799  char **dirs;
800  char **names;
801  int nfiles;
803 };
804 
805 #define SEARCHFILES_BLOCK 127
806 
807 static void
808 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf)
809 {
810  Id dep, sid;
811  const char *s, *sr;
812  struct searchfiles *csf;
813 
814  while ((dep = *ida++) != 0)
815  {
816  csf = sf;
817  while (ISRELDEP(dep))
818  {
819  Reldep *rd;
820  sid = pool->ss.nstrings + GETRELID(dep);
821  if (MAPTST(&csf->seen, sid))
822  {
823  dep = 0;
824  break;
825  }
826  MAPSET(&csf->seen, sid);
827  rd = GETRELDEP(pool, dep);
828  if (rd->flags < 8)
829  dep = rd->name;
830  else if (rd->flags == REL_NAMESPACE)
831  {
832  if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES)
833  {
834  csf = isf;
835  if (!csf || MAPTST(&csf->seen, sid))
836  {
837  dep = 0;
838  break;
839  }
840  MAPSET(&csf->seen, sid);
841  }
842  dep = rd->evr;
843  }
844  else if (rd->flags == REL_FILECONFLICT)
845  {
846  dep = 0;
847  break;
848  }
849  else
850  {
851  Id ids[2];
852  ids[0] = rd->name;
853  ids[1] = 0;
854  pool_addfileprovides_dep(pool, ids, csf, isf);
855  dep = rd->evr;
856  }
857  }
858  if (!dep)
859  continue;
860  if (MAPTST(&csf->seen, dep))
861  continue;
862  MAPSET(&csf->seen, dep);
863  s = id2str(pool, dep);
864  if (*s != '/')
865  continue;
866  csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
867  csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
868  csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK);
869  csf->ids[csf->nfiles] = dep;
870  sr = strrchr(s, '/');
871  csf->names[csf->nfiles] = strdup(sr + 1);
872  csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1);
873  if (sr != s)
874  strncpy(csf->dirs[csf->nfiles], s, sr - s);
875  csf->dirs[csf->nfiles][sr - s] = 0;
876  csf->nfiles++;
877  }
878 }
879 
881  int nfiles;
882  Id *ids;
883  char **dirs;
884  char **names;
885 
887 
889 
891 };
892 
893 static int
894 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
895 {
896  struct addfileprovides_cbdata *cbd = cbdata;
897  int i;
898 
899  if (!cbd->useddirs.size)
900  {
901  map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
902  for (i = 0; i < cbd->nfiles; i++)
903  {
904  Id did;
905  if (MAPTST(&cbd->providedids, cbd->ids[i]))
906  {
907  cbd->dids[i] = 0;
908  continue;
909  }
910  did = repodata_str2dir(data, cbd->dirs[i], 0);
911  cbd->dids[i] = did;
912  if (did)
913  MAPSET(&cbd->useddirs, did);
914  }
915  }
916  if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
917  return 0;
918  for (i = 0; i < cbd->nfiles; i++)
919  {
920  if (cbd->dids[i] != value->id)
921  continue;
922  if (!strcmp(cbd->names[i], value->str))
923  break;
924  }
925  if (i == cbd->nfiles)
926  return 0;
927  s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
928  return 0;
929 }
930 
931 static void
932 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
933 {
934  Id p;
935  Repodata *data;
936  Repo *repo;
937  Queue fileprovidesq;
938  int i, j, repoid, repodataid;
939  int provstart, provend;
940  Map donemap;
941  int ndone, incomplete;
942 
943  if (!pool->nrepos)
944  return;
945 
946  cbd->nfiles = sf->nfiles;
947  cbd->ids = sf->ids;
948  cbd->dirs = sf->dirs;
949  cbd->names = sf->names;
950  cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
951  map_init(&cbd->providedids, pool->ss.nstrings);
952 
953  repoid = 0;
954  repo = repoonly ? repoonly : pool->repos[0];
955  map_init(&donemap, pool->nsolvables);
956  queue_init(&fileprovidesq);
957  provstart = provend = 0;
958  for (;;)
959  {
960  if (repo->disabled)
961  {
962  if (repoonly || ++repoid == pool->nrepos)
963  break;
964  repo = pool->repos[repoid];
965  continue;
966  }
967  ndone = 0;
968  for (data = repo->repodata, repodataid = 0; repodataid < repo->nrepodata; repodataid++, data++)
969  {
970  if (ndone >= repo->nsolvables)
971  break;
972 
973  if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
974  {
975  map_empty(&cbd->providedids);
976  for (i = 0; i < fileprovidesq.count; i++)
977  MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
978  provstart = data->start;
979  provend = data->end;
980  for (i = 0; i < cbd->nfiles; i++)
981  if (!MAPTST(&cbd->providedids, cbd->ids[i]))
982  break;
983  if (i == cbd->nfiles)
984  {
985  /* great! no need to search files */
986  for (p = data->start; p < data->end; p++)
987  if (pool->solvables[p].repo == repo)
988  {
989  if (MAPTST(&donemap, p))
990  continue;
991  MAPSET(&donemap, p);
992  ndone++;
993  }
994  continue;
995  }
996  }
997 
998  if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
999  continue;
1000 
1001  if (data->start < provstart || data->end > provend)
1002  {
1003  map_empty(&cbd->providedids);
1004  provstart = provend = 0;
1005  }
1006 
1007  /* check if the data is incomplete */
1008  incomplete = 0;
1009  if (data->state == REPODATA_AVAILABLE)
1010  {
1011  for (j = 1; j < data->nkeys; j++)
1012  if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1013  break;
1014  if (j < data->nkeys)
1015  {
1016 #if 0
1017  for (i = 0; i < cbd->nfiles; i++)
1018  if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
1019  printf("need complete filelist because of %s\n", id2str(pool, cbd->ids[i]));
1020 #endif
1021  for (i = 0; i < cbd->nfiles; i++)
1022  if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
1023  break;
1024  if (i < cbd->nfiles)
1025  incomplete = 1;
1026  }
1027  }
1028 
1029  /* do the search */
1030  map_init(&cbd->useddirs, 0);
1031  for (p = data->start; p < data->end; p++)
1032  if (pool->solvables[p].repo == repo)
1033  {
1034  if (MAPTST(&donemap, p))
1035  continue;
1036  repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
1037  if (!incomplete)
1038  {
1039  MAPSET(&donemap, p);
1040  ndone++;
1041  }
1042  }
1043  map_free(&cbd->useddirs);
1044  }
1045 
1046  if (repoonly || ++repoid == pool->nrepos)
1047  break;
1048  repo = pool->repos[repoid];
1049  }
1050  map_free(&donemap);
1051  queue_free(&fileprovidesq);
1052  map_free(&cbd->providedids);
1053 }
1054 
1055 void
1056 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
1057 {
1058  Solvable *s;
1059  Repo *repo;
1060  struct searchfiles sf, isf, *isfp;
1061  struct addfileprovides_cbdata cbd;
1062  int i;
1063  unsigned int now;
1064 
1065  now = sat_timems(0);
1066  memset(&sf, 0, sizeof(sf));
1067  map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
1068  memset(&isf, 0, sizeof(isf));
1069  map_init(&isf.seen, pool->ss.nstrings + pool->nrels);
1070 
1071  isfp = installed ? &isf : 0;
1072  for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++)
1073  {
1074  repo = s->repo;
1075  if (!repo)
1076  continue;
1077  if (s->obsoletes)
1078  pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp);
1079  if (s->conflicts)
1080  pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp);
1081  if (s->requires)
1082  pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp);
1083  if (s->recommends)
1084  pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp);
1085  if (s->suggests)
1086  pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp);
1087  if (s->supplements)
1088  pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp);
1089  if (s->enhances)
1090  pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
1091  }
1092  map_free(&sf.seen);
1093  map_free(&isf.seen);
1094  POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
1095  cbd.dids = 0;
1096  if (idp)
1097  *idp = 0;
1098  if (sf.nfiles)
1099  {
1100 #if 0
1101  for (i = 0; i < sf.nfiles; i++)
1102  POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i]));
1103 #endif
1104  pool_addfileprovides_search(pool, &cbd, &sf, 0);
1105  if (idp)
1106  {
1107  sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK);
1108  sf.ids[sf.nfiles] = 0;
1109  *idp = sf.ids;
1110  sf.ids = 0;
1111  }
1112  sat_free(sf.ids);
1113  for (i = 0; i < sf.nfiles; i++)
1114  {
1115  sat_free(sf.dirs[i]);
1116  sat_free(sf.names[i]);
1117  }
1118  sat_free(sf.dirs);
1119  sat_free(sf.names);
1120  }
1121  if (isf.nfiles)
1122  {
1123 #if 0
1124  for (i = 0; i < isf.nfiles; i++)
1125  POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i]));
1126 #endif
1127  if (installed)
1128  pool_addfileprovides_search(pool, &cbd, &isf, installed);
1129  sat_free(isf.ids);
1130  for (i = 0; i < isf.nfiles; i++)
1131  {
1132  sat_free(isf.dirs[i]);
1133  sat_free(isf.names[i]);
1134  }
1135  sat_free(isf.dirs);
1136  sat_free(isf.names);
1137  }
1138  sat_free(cbd.dids);
1139  pool_freewhatprovides(pool); /* as we have added provides */
1140  POOL_DEBUG(SAT_DEBUG_STATS, "addfileprovides took %d ms\n", sat_timems(now));
1141 }
1142 
1143 void
1145 {
1146  pool_addfileprovides_ids(pool, pool->installed, 0);
1147 }
1148 
1149 void
1150 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)
1151 {
1152  if (p)
1153  {
1154  if (pool->solvables[p].repo)
1155  repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1156  return;
1157  }
1158  /* FIXME: obey callback return value! */
1159  for (p = 1; p < pool->nsolvables; p++)
1160  if (pool->solvables[p].repo)
1161  repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata);
1162 }
1163 
1164 void
1166 {
1167  memset(&pool->pos, 0, sizeof(pool->pos));
1168 }
1169 
1170 
1171 void
1172 pool_set_languages(Pool *pool, const char **languages, int nlanguages)
1173 {
1174  int i;
1175 
1176  pool->languagecache = sat_free(pool->languagecache);
1177  pool->languagecacheother = 0;
1178  if (pool->nlanguages)
1179  {
1180  for (i = 0; i < pool->nlanguages; i++)
1181  free((char *)pool->languages[i]);
1182  free(pool->languages);
1183  }
1184  pool->nlanguages = nlanguages;
1185  if (!nlanguages)
1186  return;
1187  pool->languages = sat_calloc(nlanguages, sizeof(const char **));
1188  for (i = 0; i < pool->nlanguages; i++)
1189  pool->languages[i] = strdup(languages[i]);
1190 }
1191 
1192 Id
1193 pool_id2langid(Pool *pool, Id id, const char *lang, int create)
1194 {
1195  const char *n;
1196  char buf[256], *p;
1197  int l;
1198 
1199  if (!lang)
1200  return id;
1201  n = id2str(pool, id);
1202  l = strlen(n) + strlen(lang) + 2;
1203  if (l > sizeof(buf))
1204  p = sat_malloc(strlen(n) + strlen(lang) + 2);
1205  else
1206  p = buf;
1207  sprintf(p, "%s:%s", n, lang);
1208  id = str2id(pool, p, create);
1209  if (p != buf)
1210  free(p);
1211  return id;
1212 }
1213 
1214 char *
1215 pool_alloctmpspace(Pool *pool, int len)
1216 {
1217  int n = pool->tmpspace.n;
1218  if (!len)
1219  return 0;
1220  if (len > pool->tmpspace.len[n])
1221  {
1222  pool->tmpspace.buf[n] = sat_realloc(pool->tmpspace.buf[n], len + 32);
1223  pool->tmpspace.len[n] = len + 32;
1224  }
1225  pool->tmpspace.n = (n + 1) % POOL_TMPSPACEBUF;
1226  return pool->tmpspace.buf[n];
1227 }
1228 
1229 static char *
1230 pool_alloctmpspace_free(Pool *pool, const char *space, int len)
1231 {
1232  if (space)
1233  {
1234  int n, oldn;
1235  n = oldn = pool->tmpspace.n;
1236  for (;;)
1237  {
1238  if (!n--)
1239  n = POOL_TMPSPACEBUF - 1;
1240  if (n == oldn)
1241  break;
1242  if (pool->tmpspace.buf[n] != space)
1243  continue;
1244  if (len > pool->tmpspace.len[n])
1245  {
1246  pool->tmpspace.buf[n] = sat_realloc(pool->tmpspace.buf[n], len + 32);
1247  pool->tmpspace.len[n] = len + 32;
1248  }
1249  return pool->tmpspace.buf[n];
1250  }
1251  }
1252  return 0;
1253 }
1254 
1255 void
1256 pool_freetmpspace(Pool *pool, const char *space)
1257 {
1258  int n = pool->tmpspace.n;
1259  if (!space)
1260  return;
1261  n = (n + (POOL_TMPSPACEBUF - 1)) % POOL_TMPSPACEBUF;
1262  if (pool->tmpspace.buf[n] == space)
1263  pool->tmpspace.n = n;
1264 }
1265 
1266 char *
1267 pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3)
1268 {
1269  int l1, l2, l3;
1270  char *s, *str;
1271  l1 = str1 ? strlen(str1) : 0;
1272  l2 = str2 ? strlen(str2) : 0;
1273  l3 = str3 ? strlen(str3) : 0;
1274  s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
1275  if (l1)
1276  {
1277  strcpy(s, str1);
1278  s += l1;
1279  }
1280  if (l2)
1281  {
1282  strcpy(s, str2);
1283  s += l2;
1284  }
1285  if (l3)
1286  {
1287  strcpy(s, str3);
1288  s += l3;
1289  }
1290  *s = 0;
1291  return str;
1292 }
1293 
1294 char *
1295 pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3)
1296 {
1297  int l1, l2, l3;
1298  char *s, *str;
1299 
1300  l1 = str1 ? strlen(str1) : 0;
1301  l2 = str2 ? strlen(str2) : 0;
1302  l3 = str3 ? strlen(str3) : 0;
1303  str = pool_alloctmpspace_free(pool, str1, l1 + l2 + l3 + 1);
1304  if (str)
1305  str1 = str;
1306  else
1307  str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1);
1308  s = str;
1309  if (l1)
1310  {
1311  if (s != str1)
1312  strcpy(s, str1);
1313  s += l1;
1314  }
1315  if (l2)
1316  {
1317  strcpy(s, str2);
1318  s += l2;
1319  }
1320  if (l3)
1321  {
1322  strcpy(s, str3);
1323  s += l3;
1324  }
1325  *s = 0;
1326  return str;
1327 }
1328 
1329 const char *
1330 pool_bin2hex(Pool *pool, const unsigned char *buf, int len)
1331 {
1332  char *s;
1333  if (!len)
1334  return "";
1335  s = pool_alloctmpspace(pool, 2 * len + 1);
1336  sat_bin2hex(buf, len, s);
1337  return s;
1338 }
1339 
1340 /*******************************************************************/
1341 
1342 struct mptree {
1345  const char *comp;
1346  int compl;
1348 };
1349 
1350 struct ducbdata {
1352  struct mptree *mptree;
1353  int addsub;
1354  int hasdu;
1355 
1357  int nmap;
1359 };
1360 
1361 
1362 static int
1363 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
1364 {
1365  struct ducbdata *cbd = cbdata;
1366  Id mp;
1367 
1368  if (data != cbd->olddata)
1369  {
1370  Id dn, mp, comp, *dirmap, *dirs;
1371  int i, compl;
1372  const char *compstr;
1373  struct mptree *mptree;
1374 
1375  /* create map from dir to mptree */
1376  cbd->dirmap = sat_free(cbd->dirmap);
1377  cbd->nmap = 0;
1378  dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id));
1379  mptree = cbd->mptree;
1380  mp = 0;
1381  for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++)
1382  {
1383  comp = *dirs++;
1384  if (comp <= 0)
1385  {
1386  mp = dirmap[-comp];
1387  continue;
1388  }
1389  if (mp < 0)
1390  {
1391  /* unconnected */
1392  dirmap[dn] = mp;
1393  continue;
1394  }
1395  if (!mptree[mp].child)
1396  {
1397  dirmap[dn] = -mp;
1398  continue;
1399  }
1400  if (data->localpool)
1401  compstr = stringpool_id2str(&data->spool, comp);
1402  else
1403  compstr = id2str(data->repo->pool, comp);
1404  compl = strlen(compstr);
1405  for (i = mptree[mp].child; i; i = mptree[i].sibling)
1406  if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1407  break;
1408  dirmap[dn] = i ? i : -mp;
1409  }
1410  /* change dirmap to point to mountpoint instead of mptree */
1411  for (dn = 0; dn < data->dirpool.ndirs; dn++)
1412  {
1413  mp = dirmap[dn];
1414  dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint;
1415  }
1416  cbd->dirmap = dirmap;
1417  cbd->nmap = data->dirpool.ndirs;
1418  cbd->olddata = data;
1419  }
1420  cbd->hasdu = 1;
1421  if (value->id < 0 || value->id >= cbd->nmap)
1422  return 0;
1423  mp = cbd->dirmap[value->id];
1424  if (mp < 0)
1425  return 0;
1426  if (cbd->addsub > 0)
1427  {
1428  cbd->mps[mp].kbytes += value->num;
1429  cbd->mps[mp].files += value->num2;
1430  }
1431  else
1432  {
1433  cbd->mps[mp].kbytes -= value->num;
1434  cbd->mps[mp].files -= value->num2;
1435  }
1436  return 0;
1437 }
1438 
1439 static void
1441 {
1442  int i;
1443  if (mptree[pos].mountpoint == -1)
1444  mptree[pos].mountpoint = mountpoint;
1445  else
1446  mountpoint = mptree[pos].mountpoint;
1447  for (i = mptree[pos].child; i; i = mptree[i].sibling)
1448  propagate_mountpoints(mptree, i, mountpoint);
1449 }
1450 
1451 #define MPTREE_BLOCK 15
1452 
1453 void
1454 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
1455 {
1456  char *p;
1457  const char *path, *compstr;
1458  struct mptree *mptree;
1459  int i, nmptree;
1460  int pos, compl;
1461  int mp;
1462  struct ducbdata cbd;
1463  Solvable *s;
1464  Id sp;
1465  Map ignoredu;
1466  Repo *oldinstalled = pool->installed;
1467 
1468  memset(&ignoredu, 0, sizeof(ignoredu));
1469  cbd.mps = mps;
1470  cbd.addsub = 0;
1471  cbd.dirmap = 0;
1472  cbd.nmap = 0;
1473  cbd.olddata = 0;
1474 
1475  mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK);
1476 
1477  /* our root node */
1478  mptree[0].sibling = 0;
1479  mptree[0].child = 0;
1480  mptree[0].comp = 0;
1481  mptree[0].compl = 0;
1482  mptree[0].mountpoint = -1;
1483  nmptree = 1;
1484 
1485  /* create component tree */
1486  for (mp = 0; mp < nmps; mp++)
1487  {
1488  mps[mp].kbytes = 0;
1489  mps[mp].files = 0;
1490  pos = 0;
1491  path = mps[mp].path;
1492  while(*path == '/')
1493  path++;
1494  while (*path)
1495  {
1496  if ((p = strchr(path, '/')) == 0)
1497  {
1498  compstr = path;
1499  compl = strlen(compstr);
1500  path += compl;
1501  }
1502  else
1503  {
1504  compstr = path;
1505  compl = p - path;
1506  path = p + 1;
1507  while(*path == '/')
1508  path++;
1509  }
1510  for (i = mptree[pos].child; i; i = mptree[i].sibling)
1511  if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl))
1512  break;
1513  if (!i)
1514  {
1515  /* create new node */
1516  mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK);
1517  i = nmptree++;
1518  mptree[i].sibling = mptree[pos].child;
1519  mptree[i].child = 0;
1520  mptree[i].comp = compstr;
1521  mptree[i].compl = compl;
1522  mptree[i].mountpoint = -1;
1523  mptree[pos].child = i;
1524  }
1525  pos = i;
1526  }
1527  mptree[pos].mountpoint = mp;
1528  }
1529 
1530  propagate_mountpoints(mptree, 0, mptree[0].mountpoint);
1531 
1532 #if 0
1533  for (i = 0; i < nmptree; i++)
1534  {
1535  printf("#%d sibling: %d\n", i, mptree[i].sibling);
1536  printf("#%d child: %d\n", i, mptree[i].child);
1537  printf("#%d comp: %s\n", i, mptree[i].comp);
1538  printf("#%d compl: %d\n", i, mptree[i].compl);
1539  printf("#%d mountpont: %d\n", i, mptree[i].mountpoint);
1540  }
1541 #endif
1542 
1543  cbd.mptree = mptree;
1544  cbd.addsub = 1;
1545  for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1546  {
1547  if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1548  continue;
1549  if (!MAPTST(installedmap, sp))
1550  continue;
1551  cbd.hasdu = 0;
1552  repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1553  if (!cbd.hasdu && oldinstalled)
1554  {
1555  Id op, opp;
1556  /* no du data available, ignore data of all installed solvables we obsolete */
1557  if (!ignoredu.map)
1558  map_init(&ignoredu, oldinstalled->end - oldinstalled->start);
1559  if (s->obsoletes)
1560  {
1561  Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
1562  while ((obs = *obsp++) != 0)
1563  FOR_PROVIDES(op, opp, obs)
1564  if (op >= oldinstalled->start && op < oldinstalled->end)
1565  MAPSET(&ignoredu, op - oldinstalled->start);
1566  }
1567  FOR_PROVIDES(op, opp, s->name)
1568  if (pool->solvables[op].name == s->name)
1569  if (op >= oldinstalled->start && op < oldinstalled->end)
1570  MAPSET(&ignoredu, op - oldinstalled->start);
1571  }
1572  }
1573  cbd.addsub = -1;
1574  if (oldinstalled)
1575  {
1576  /* assumes we allways have du data for installed solvables */
1577  FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1578  {
1579  if (MAPTST(installedmap, sp))
1580  continue;
1581  if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
1582  continue;
1583  repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
1584  }
1585  }
1586  if (ignoredu.map)
1587  map_free(&ignoredu);
1588  sat_free(cbd.dirmap);
1589  sat_free(mptree);
1590 }
1591 
1592 int
1593 pool_calc_installsizechange(Pool *pool, Map *installedmap)
1594 {
1595  Id sp;
1596  Solvable *s;
1597  int change = 0;
1598  Repo *oldinstalled = pool->installed;
1599 
1600  for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++)
1601  {
1602  if (!s->repo || (oldinstalled && s->repo == oldinstalled))
1603  continue;
1604  if (!MAPTST(installedmap, sp))
1605  continue;
1606  change += solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1607  }
1608  if (oldinstalled)
1609  {
1610  FOR_REPO_SOLVABLES(oldinstalled, sp, s)
1611  {
1612  if (MAPTST(installedmap, sp))
1613  continue;
1614  change -= solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0);
1615  }
1616  }
1617  return change;
1618 }
1619 
1620 /* map:
1621  * 1: installed
1622  * 2: conflicts with installed
1623  * 8: interesting (only true if installed)
1624  * 16: undecided
1625  */
1626 
1627 static inline Id dep2name(Pool *pool, Id dep)
1628 {
1629  while (ISRELDEP(dep))
1630  {
1631  Reldep *rd = rd = GETRELDEP(pool, dep);
1632  dep = rd->name;
1633  }
1634  return dep;
1635 }
1636 
1637 static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con)
1638 {
1639  Id p, pp;
1640  Solvable *sn = pool->solvables + n;
1641 
1642  FOR_PROVIDES(p, pp, sn->name)
1643  {
1644  Solvable *s = pool->solvables + p;
1645  if (s->name != sn->name || s->arch != sn->arch)
1646  continue;
1647  if ((map[p] & 9) != 9)
1648  continue;
1649  if (pool_match_nevr(pool, pool->solvables + p, con))
1650  continue;
1651  return 1; /* found installed package that doesn't conflict */
1652  }
1653  return 0;
1654 }
1655 
1656 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *noobsoletesmap)
1657 {
1658  Id p, pp;
1659  int r = 0;
1660  FOR_PROVIDES(p, pp, dep)
1661  {
1662  if (p == SYSTEMSOLVABLE)
1663  return 1; /* always boring, as never constraining */
1664  if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
1665  continue;
1666  if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep))
1667  if (providedbyinstalled_multiversion(pool, map, p, dep))
1668  continue;
1669  if ((map[p] & 9) == 9)
1670  return 9;
1671  r |= map[p] & 17;
1672  }
1673  return r;
1674 }
1675 
1676 /*
1677  * pool_trivial_installable - calculate if a set of solvables is
1678  * trivial installable without any other installs/deinstalls of
1679  * packages not belonging to the set.
1680  *
1681  * the state is returned in the result queue:
1682  * 1: solvable is installable without any other package changes
1683  * 0: solvable is not installable
1684  * -1: solvable is installable, but doesn't constrain any installed packages
1685  */
1686 
1687 void
1688 pool_trivial_installable_noobsoletesmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *noobsoletesmap)
1689 {
1690  int i, r, m, did;
1691  Id p, *dp, con, *conp, req, *reqp;
1692  unsigned char *map;
1693  Solvable *s;
1694 
1695  map = sat_calloc(pool->nsolvables, 1);
1696  for (p = 1; p < pool->nsolvables; p++)
1697  {
1698  if (!MAPTST(installedmap, p))
1699  continue;
1700  map[p] |= 9;
1701  s = pool->solvables + p;
1702  if (!s->conflicts)
1703  continue;
1704  conp = s->repo->idarraydata + s->conflicts;
1705  while ((con = *conp++) != 0)
1706  {
1707  dp = pool_whatprovides_ptr(pool, con);
1708  for (; *dp; dp++)
1709  map[p] |= 2; /* XXX: self conflict ? */
1710  }
1711  }
1712  for (i = 0; i < pkgs->count; i++)
1713  map[pkgs->elements[i]] = 16;
1714 
1715  for (i = 0, did = 0; did < pkgs->count; i++, did++)
1716  {
1717  if (i == pkgs->count)
1718  i = 0;
1719  p = pkgs->elements[i];
1720  if ((map[p] & 16) == 0)
1721  continue;
1722  if ((map[p] & 2) != 0)
1723  {
1724  map[p] = 2;
1725  continue;
1726  }
1727  s = pool->solvables + p;
1728  m = 1;
1729  if (s->requires)
1730  {
1731  reqp = s->repo->idarraydata + s->requires;
1732  while ((req = *reqp++) != 0)
1733  {
1734  if (req == SOLVABLE_PREREQMARKER)
1735  continue;
1736  r = providedbyinstalled(pool, map, req, 0, 0);
1737  if (!r)
1738  {
1739  /* decided and miss */
1740  map[p] = 2;
1741  break;
1742  }
1743  m |= r; /* 1 | 9 | 16 | 17 */
1744  }
1745  if (req)
1746  continue;
1747  if ((m & 9) == 9)
1748  m = 9;
1749  }
1750  if (s->conflicts)
1751  {
1752  int ispatch = 0; /* see solver.c patch handling */
1753 
1754  if (!strncmp("patch:", id2str(pool, s->name), 6))
1755  ispatch = 1;
1756  conp = s->repo->idarraydata + s->conflicts;
1757  while ((con = *conp++) != 0)
1758  {
1759  if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
1760  {
1761  map[p] = 2;
1762  break;
1763  }
1764  if ((m == 1 || m == 17) && ISRELDEP(con))
1765  {
1766  con = dep2name(pool, con);
1767  if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0)
1768  m = 9;
1769  }
1770  }
1771  if (con)
1772  continue; /* found a conflict */
1773  }
1774 #if 0
1775  if (s->repo && s->repo != oldinstalled)
1776  {
1777  Id p2, obs, *obsp, *pp;
1778  Solvable *s2;
1779  if (s->obsoletes)
1780  {
1781  obsp = s->repo->idarraydata + s->obsoletes;
1782  while ((obs = *obsp++) != 0)
1783  {
1784  if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0)
1785  {
1786  map[p] = 2;
1787  break;
1788  }
1789  }
1790  if (obs)
1791  continue;
1792  }
1793  FOR_PROVIDES(p2, pp, s->name)
1794  {
1795  s2 = pool->solvables + p2;
1796  if (s2->name == s->name && (map[p2] & 1) != 0)
1797  {
1798  map[p] = 2;
1799  break;
1800  }
1801  }
1802  if (p2)
1803  continue;
1804  }
1805 #endif
1806  if (m != map[p])
1807  {
1808  map[p] = m;
1809  did = 0;
1810  }
1811  }
1812  queue_free(res);
1813  queue_init_clone(res, pkgs);
1814  for (i = 0; i < pkgs->count; i++)
1815  {
1816  m = map[pkgs->elements[i]];
1817  if ((m & 9) == 9)
1818  r = 1;
1819  else if (m & 1)
1820  r = -1;
1821  else
1822  r = 0;
1823  res->elements[i] = r;
1824  }
1825  free(map);
1826 }
1827 
1828 void
1829 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res)
1830 {
1831  pool_trivial_installable_noobsoletesmap(pool, installedmap, pkgs, res, 0);
1832 }
1833 
1834 const char *
1835 pool_lookup_str(Pool *pool, Id entry, Id keyname)
1836 {
1837  if (entry == SOLVID_POS && pool->pos.repo)
1838  return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
1839  if (entry <= 0)
1840  return 0;
1841  return solvable_lookup_str(pool->solvables + entry, keyname);
1842 }
1843 
1844 Id
1845 pool_lookup_id(Pool *pool, Id entry, Id keyname)
1846 {
1847  if (entry == SOLVID_POS && pool->pos.repo)
1848  {
1849  Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
1850  Id id = repodata_lookup_id(data, SOLVID_POS, keyname);
1851  return data->localpool ? repodata_globalize_id(data, id, 1) : id;
1852  }
1853  if (entry <= 0)
1854  return 0;
1855  return solvable_lookup_id(pool->solvables + entry, keyname);
1856 }
1857 
1858 unsigned int
1859 pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned int notfound)
1860 {
1861  if (entry == SOLVID_POS && pool->pos.repo)
1862  {
1863  unsigned int value;
1864  if (repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, &value))
1865  return value;
1866  return notfound;
1867  }
1868  if (entry <= 0)
1869  return notfound;
1870  return solvable_lookup_num(pool->solvables + entry, keyname, notfound);
1871 }
1872 
1873 int
1874 pool_lookup_void(Pool *pool, Id entry, Id keyname)
1875 {
1876  if (entry == SOLVID_POS && pool->pos.repo)
1877  return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname);
1878  if (entry <= 0)
1879  return 0;
1880  return solvable_lookup_void(pool->solvables + entry, keyname);
1881 }
1882 
1883 const unsigned char *
1884 pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
1885 {
1886  if (entry == SOLVID_POS && pool->pos.repo)
1887  return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
1888  if (entry <= 0)
1889  return 0;
1890  return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep);
1891 }
1892 
1893 const char *
1894 pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep)
1895 {
1896  if (entry == SOLVID_POS && pool->pos.repo)
1897  {
1898  const unsigned char *chk = repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep);
1899  return chk ? repodata_chk2str(pool->pos.repo->repodata + pool->pos.repodataid, *typep, chk) : 0;
1900  }
1901  if (entry <= 0)
1902  return 0;
1903  return solvable_lookup_checksum(pool->solvables + entry, keyname, typep);
1904 }
1905 
1906 void
1908 {
1909  int hadhashes = pool->relhashtbl ? 1 : 0;
1910  Solvable *s;
1911  Id fn, p, q, md5;
1912  Id id;
1913  int i;
1914 
1915  if (!conflicts->count)
1916  return;
1917  pool_freewhatprovides(pool);
1918  for (i = 0; i < conflicts->count; i += 5)
1919  {
1920  fn = conflicts->elements[i];
1921  p = conflicts->elements[i + 1];
1922  md5 = conflicts->elements[i + 2];
1923  q = conflicts->elements[i + 3];
1924  id = rel2id(pool, fn, md5, REL_FILECONFLICT, 1);
1925  s = pool->solvables + p;
1926  if (!s->repo)
1927  continue;
1928  s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
1929  s = pool->solvables + q;
1930  if (!s->repo)
1931  continue;
1932  s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0);
1933  }
1934  if (!hadhashes)
1935  pool_freeidhashes(pool);
1936 }
1937 
1938 /* EOF */