satsolver  0.17.2
repo.c
Go to the documentation of this file.
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  * repo.c
10  *
11  * Manage metadata coming from one repository
12  *
13  */
14 
15 #define _GNU_SOURCE
16 #include <string.h>
17 #include <fnmatch.h>
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 
22 
23 
24 #include "repo.h"
25 #include "pool.h"
26 #include "poolid_private.h"
27 #include "util.h"
28 #include "chksum.h"
29 
30 #define IDARRAY_BLOCK 4095
31 
32 
33 /*
34  * create empty repo
35  * and add to pool
36  */
37 
38 Repo *
39 repo_create(Pool *pool, const char *name)
40 {
41  Repo *repo;
42 
44  repo = (Repo *)sat_calloc(1, sizeof(*repo));
45  pool->repos = (Repo **)sat_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
46  pool->repos[pool->nrepos++] = repo;
47  repo->repoid = pool->nrepos;
48  repo->name = name ? strdup(name) : 0;
49  repo->pool = pool;
50  repo->start = pool->nsolvables;
51  repo->end = pool->nsolvables;
52  repo->nsolvables = 0;
53  return repo;
54 }
55 
56 static void
58 {
59  int i;
60  for (i = 0; i < repo->nrepodata; i++)
61  repodata_freedata(repo->repodata + i);
62  sat_free(repo->repodata);
63  sat_free(repo->idarraydata);
64  sat_free(repo->rpmdbid);
65  sat_free((char *)repo->name);
66  sat_free(repo);
67 }
68 
69 /* delete all solvables and repodata blocks from this repo */
70 
71 void
72 repo_empty(Repo *repo, int reuseids)
73 {
74  Pool *pool = repo->pool;
75  Solvable *s;
76  int i;
77 
79  if (reuseids && repo->end == pool->nsolvables)
80  {
81  /* it's ok to reuse the ids. As this is the last repo, we can
82  just shrink the solvable array */
83  for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
84  if (s->repo != repo)
85  break;
86  pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids);
87  }
88  /* zero out (i.e. free) solvables belonging to this repo */
89  for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
90  if (s->repo == repo)
91  memset(s, 0, sizeof(*s));
92  repo->nsolvables = 0;
93 
94  /* free all data belonging to this repo */
95  repo->idarraydata = sat_free(repo->idarraydata);
96  repo->idarraysize = 0;
97  repo->lastoff = 0;
98  repo->rpmdbid = sat_free(repo->rpmdbid);
99  for (i = 0; i < repo->nrepodata; i++)
100  repodata_freedata(repo->repodata + i);
101  sat_free(repo->repodata);
102  repo->repodata = 0;
103  repo->nrepodata = 0;
104 }
105 
106 /*
107  * remove repo from pool, delete solvables
108  *
109  */
110 
111 void
112 repo_free(Repo *repo, int reuseids)
113 {
114  Pool *pool = repo->pool;
115  int i;
116 
117  if (repo == pool->installed)
118  pool->installed = 0;
119  repo_empty(repo, reuseids);
120  for (i = 0; i < pool->nrepos; i++) /* find repo in pool */
121  if (pool->repos[i] == repo)
122  break;
123  if (i == pool->nrepos) /* repo not in pool, return */
124  return;
125  if (i < pool->nrepos - 1)
126  {
127  memmove(pool->repos + i, pool->repos + i + 1, (pool->nrepos - 1 - i) * sizeof(Repo *));
128  /* fix repo ids */
129  for (; i < pool->nrepos - 1; i++)
130  pool->repos[i]->repoid = i + 1;
131  }
132  pool->nrepos--;
133  repo_freedata(repo);
134 }
135 
136 void
137 repo_freeallrepos(Pool *pool, int reuseids)
138 {
139  int i;
140 
141  pool_freewhatprovides(pool);
142  for (i = 0; i < pool->nrepos; i++)
143  repo_freedata(pool->repos[i]);
144  pool->repos = sat_free(pool->repos);
145  pool->nrepos = 0;
146  /* the first two solvables don't belong to a repo */
147  pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
148 }
149 
150 void repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids)
151 {
152  Solvable *s;
153  Repodata *data;
154  int i;
155  if (start + count == repo->end)
156  repo->end -= count;
157  repo->nsolvables -= count;
158  for (s = repo->pool->solvables + start, i = count; i--; s++)
159  s->repo = 0;
160  pool_free_solvable_block(repo->pool, start, count, reuseids);
161  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
162  if (data->end > repo->end)
163  repodata_shrink(data, repo->end);
164 }
165 
166 
167 /* repository sidedata is solvable data allocated on demand.
168  * It is used for data that is normally not present
169  * in the solvable like the rpmdbid.
170  * The solvable allocation funcions need to make sure that
171  * the sidedata gets extended if new solvables get added.
172  */
173 
174 #define REPO_SIDEDATA_BLOCK 63
175 
176 void *
177 repo_sidedata_create(Repo *repo, size_t size)
178 {
179  return sat_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK);
180 }
181 
182 void *
183 repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count)
184 {
185  int n = repo->end - repo->start;
186  if (p < repo->start)
187  {
188  int d = repo->start - p;
189  b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
190  memmove((char *)b + d * size, b, n * size);
191  memset(b, 0, d * size);
192  n += d;
193  }
194  if (p + count > repo->end)
195  {
196  int d = p + count - repo->end;
197  b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
198  memset((char *)b + n * size, 0, d * size);
199  }
200  return b;
201 }
202 
203 /*
204  * add Id to idarraydata used to store dependencies
205  * olddeps: old array offset to extend
206  * returns new array offset
207  */
208 
209 Offset
210 repo_addid(Repo *repo, Offset olddeps, Id id)
211 {
212  Id *idarray;
213  int idarraysize;
214  int i;
215 
216  idarray = repo->idarraydata;
217  idarraysize = repo->idarraysize;
218 
219  if (!idarray) /* alloc idarray if not done yet */
220  {
221  idarraysize = 1;
222  idarray = sat_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK);
223  idarray[0] = 0;
224  repo->lastoff = 0;
225  }
226 
227  if (!olddeps) /* no deps yet */
228  {
229  olddeps = idarraysize;
230  idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
231  }
232  else if (olddeps == repo->lastoff) /* extend at end */
233  idarraysize--;
234  else /* can't extend, copy old */
235  {
236  i = olddeps;
237  olddeps = idarraysize;
238  for (; idarray[i]; i++)
239  {
240  idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
241  idarray[idarraysize++] = idarray[i];
242  }
243  idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
244  }
245 
246  idarray[idarraysize++] = id; /* insert Id into array */
247  idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
248  idarray[idarraysize++] = 0; /* ensure NULL termination */
249 
250  repo->idarraydata = idarray;
251  repo->idarraysize = idarraysize;
252  repo->lastoff = olddeps;
253 
254  return olddeps;
255 }
256 
257 
258 /*
259  * add dependency (as Id) to repo, also unifies dependencies
260  * olddeps = offset into idarraydata
261  * marker= 0 for normal dep
262  * marker > 0 add dep after marker
263  * marker < 0 add dep after -marker
264  * returns new start of dependency array
265  */
266 Offset
267 repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker)
268 {
269  Id oid, *oidp, *markerp;
270  int before;
271 
272  if (!olddeps)
273  {
274  if (marker > 0)
275  olddeps = repo_addid(repo, olddeps, marker);
276  return repo_addid(repo, olddeps, id);
277  }
278 
279  if (!marker)
280  {
281  for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
282  {
283  if (oid == id)
284  return olddeps;
285  }
286  return repo_addid(repo, olddeps, id);
287  }
288 
289  before = 0;
290  markerp = 0;
291  if (marker < 0)
292  {
293  before = 1;
294  marker = -marker;
295  }
296  for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
297  {
298  if (oid == marker)
299  markerp = oidp;
300  else if (oid == id)
301  break;
302  }
303 
304  if (oid)
305  {
306  if (markerp || before)
307  return olddeps;
308  /* we found it, but in the wrong half */
309  markerp = oidp++;
310  for (; (oid = *oidp) != ID_NULL; oidp++)
311  if (oid == marker)
312  break;
313  if (!oid)
314  {
315  /* no marker in array yet */
316  oidp--;
317  if (markerp < oidp)
318  memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
319  *oidp = marker;
320  return repo_addid(repo, olddeps, id);
321  }
322  while (oidp[1])
323  oidp++;
324  memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
325  *oidp = id;
326  return olddeps;
327  }
328  /* id not yet in array */
329  if (!before && !markerp)
330  olddeps = repo_addid(repo, olddeps, marker);
331  else if (before && markerp)
332  {
333  *markerp++ = id;
334  id = *--oidp;
335  if (markerp < oidp)
336  memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
337  *markerp = marker;
338  }
339  return repo_addid(repo, olddeps, id);
340 }
341 
342 
343 /*
344  * reserve Ids
345  * make space for 'num' more dependencies
346  * returns new start of dependency array
347  *
348  * reserved ids will always begin at offset idarraysize
349  */
350 
351 Offset
352 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
353 {
354  num++; /* room for trailing ID_NULL */
355 
356  if (!repo->idarraysize) /* ensure buffer space */
357  {
358  repo->idarraysize = 1;
359  repo->idarraydata = sat_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK);
360  repo->idarraydata[0] = 0;
361  repo->lastoff = 1;
362  return 1;
363  }
364 
365  if (olddeps && olddeps != repo->lastoff) /* if not appending */
366  {
367  /* can't insert into idarray, this would invalidate all 'larger' offsets
368  * so create new space at end and move existing deps there.
369  * Leaving 'hole' at old position.
370  */
371 
372  Id *idstart, *idend;
373  int count;
374 
375  for (idstart = idend = repo->idarraydata + olddeps; *idend++; ) /* find end */
376  ;
377  count = idend - idstart - 1 + num; /* new size */
378 
379  repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
380  /* move old deps to end */
381  olddeps = repo->lastoff = repo->idarraysize;
382  memcpy(repo->idarraydata + olddeps, idstart, count - num);
383  repo->idarraysize = olddeps + count - num;
384 
385  return olddeps;
386  }
387 
388  if (olddeps) /* appending */
389  repo->idarraysize--;
390 
391  /* make room*/
392  repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK);
393 
394  /* appending or new */
395  repo->lastoff = olddeps ? olddeps : repo->idarraysize;
396 
397  return repo->lastoff;
398 }
399 
400 
401 
402 Offset
403 repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens)
404 {
405  Pool *pool = repo->pool;
406  Id id, idp, idl;
407  char buf[1024], *p, *dep;
408  int i, l;
409 
410  if (provides)
411  {
412  for (i = provides; repo->idarraydata[i]; i++)
413  {
414  id = repo->idarraydata[i];
415  if (ISRELDEP(id))
416  continue;
417  dep = (char *)id2str(pool, id);
418  if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
419  {
420  idp = 0;
421  strcpy(buf + 2, dep);
422  dep = buf + 2 + 7;
423  if ((p = strchr(dep, ':')) != 0 && p != dep)
424  {
425  *p++ = 0;
426  idp = str2id(pool, dep, 1);
427  dep = p;
428  }
429  id = 0;
430  while ((p = strchr(dep, ';')) != 0)
431  {
432  if (p == dep)
433  {
434  dep = p + 1;
435  continue;
436  }
437  *p++ = 0;
438 #if 0
439  strncpy(dep - 9, "language:", 9);
440  idl = str2id(pool, dep - 9, 1);
441 #else
442  idl = str2id(pool, dep, 1);
443  idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
444 #endif
445  if (id)
446  id = rel2id(pool, id, idl, REL_OR, 1);
447  else
448  id = idl;
449  dep = p;
450  }
451  if (dep[0] && dep[1])
452  {
453  for (p = dep; *p && *p != ')'; p++)
454  ;
455  *p = 0;
456 #if 0
457  strncpy(dep - 9, "language:", 9);
458  idl = str2id(pool, dep - 9, 1);
459 #else
460  idl = str2id(pool, dep, 1);
461  idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1);
462 #endif
463  if (id)
464  id = rel2id(pool, id, idl, REL_OR, 1);
465  else
466  id = idl;
467  }
468  if (idp)
469  id = rel2id(pool, idp, id, REL_AND, 1);
470  if (id)
471  supplements = repo_addid_dep(repo, supplements, id, 0);
472  }
473  else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
474  {
475  strcpy(buf, dep);
476  p = buf + (p - dep);
477  *p++ = 0;
478  idp = str2id(pool, buf, 1);
479  /* strip trailing slashes */
480  l = strlen(p);
481  while (l > 1 && p[l - 1] == '/')
482  p[--l] = 0;
483  id = str2id(pool, p, 1);
484  id = rel2id(pool, idp, id, REL_WITH, 1);
485  id = rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1);
486  supplements = repo_addid_dep(repo, supplements, id, 0);
487  }
488  }
489  }
490  if (supplements)
491  {
492  for (i = supplements; repo->idarraydata[i]; i++)
493  {
494  id = repo->idarraydata[i];
495  if (ISRELDEP(id))
496  continue;
497  dep = (char *)id2str(pool, id);
498  if (!strncmp(dep, "system:modalias(", 16))
499  dep += 7;
500  if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
501  {
502  strcpy(buf, dep);
503  p = strchr(buf + 9, ':');
504  if (p && p != buf + 9 && strchr(p + 1, ':'))
505  {
506  *p++ = 0;
507  idp = str2id(pool, buf + 9, 1);
508  p[strlen(p) - 1] = 0;
509  id = str2id(pool, p, 1);
510  id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
511  id = rel2id(pool, idp, id, REL_AND, 1);
512  }
513  else
514  {
515  p = buf + 9;
516  p[strlen(p) - 1] = 0;
517  id = str2id(pool, p, 1);
518  id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1);
519  }
520  if (id)
521  repo->idarraydata[i] = id;
522  }
523  else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
524  {
525  strcpy(buf, dep);
526  id = 0;
527  dep = buf + 11;
528  while ((p = strchr(dep, ':')) != 0)
529  {
530  if (p == dep)
531  {
532  dep = p + 1;
533  continue;
534  }
535  *p++ = 0;
536  idp = str2id(pool, dep, 1);
537  if (id)
538  id = rel2id(pool, id, idp, REL_AND, 1);
539  else
540  id = idp;
541  dep = p;
542  }
543  if (dep[0] && dep[1])
544  {
545  dep[strlen(dep) - 1] = 0;
546  idp = str2id(pool, dep, 1);
547  if (id)
548  id = rel2id(pool, id, idp, REL_AND, 1);
549  else
550  id = idp;
551  }
552  if (id)
553  repo->idarraydata[i] = id;
554  }
555  else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf))
556  {
557  strcpy(buf, dep + 11);
558  if ((p = strrchr(buf, ')')) != 0)
559  *p = 0;
560  id = str2id(pool, buf, 1);
561  id = rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1);
562  repo->idarraydata[i] = id;
563  }
564  }
565  }
566  if (freshens && repo->idarraydata[freshens])
567  {
568  Id idsupp = 0, idfresh = 0;
569  if (!supplements)
570  return freshens;
571  for (i = supplements; repo->idarraydata[i]; i++)
572  {
573  if (!idsupp)
574  idsupp = repo->idarraydata[i];
575  else
576  idsupp = rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1);
577  }
578  for (i = freshens; repo->idarraydata[i]; i++)
579  {
580  if (!idfresh)
581  idfresh = repo->idarraydata[i];
582  else
583  idfresh = rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1);
584  }
585  if (!idsupp)
586  idsupp = idfresh;
587  else
588  idsupp = rel2id(pool, idsupp, idfresh, REL_AND, 1);
589  supplements = repo_addid_dep(repo, 0, idsupp, 0);
590  }
591  return supplements;
592 }
593 
594 Offset
595 repo_fix_conflicts(Repo *repo, Offset conflicts)
596 {
597  char buf[1024], *p, *dep;
598  Pool *pool = repo->pool;
599  Id id;
600  int i;
601 
602  if (!conflicts)
603  return conflicts;
604  for (i = conflicts; repo->idarraydata[i]; i++)
605  {
606  id = repo->idarraydata[i];
607  if (ISRELDEP(id))
608  continue;
609  dep = (char *)id2str(pool, id);
610  if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2)
611  {
612  strcpy(buf, dep + 15);
613  if ((p = strchr(buf, ')')) != 0)
614  *p = 0;
615  id = str2id(pool, buf, 1);
616  id = rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1);
617  repo->idarraydata[i] = id;
618  }
619  }
620  return conflicts;
621 }
622 
623 struct matchdata
624 {
626  int flags;
628  int stop;
629  int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
631 };
632 
633 int
634 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
635 {
636  struct matchdata *md = cbdata;
637 
638  if (md->matcher.match)
639  {
640  if (!repodata_stringify(md->pool, data, key, kv, md->flags))
641  return 0;
642  if (!datamatcher_match(&md->matcher, kv->str))
643  return 0;
644  }
645  md->stop = md->callback(md->callback_data, s, data, key, kv);
646  return md->stop;
647 }
648 
649 
650 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
651  { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
652  { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
653  { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
654  { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
655  { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
656  { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
657  { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
658  { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
659  { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
660  { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
661  { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
662  { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
663  { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
664 };
665 
666 static void
667 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
668 {
669  KeyValue kv;
670  kv.entry = 0;
671  kv.parent = 0;
672  for (; *ida && !md->stop; ida++)
673  {
674  kv.id = *ida;
675  kv.eof = ida[1] ? 0 : 1;
676  repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv);
677  kv.entry++;
678  }
679 }
680 
681 static void
682 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
683 {
684  KeyValue kv;
685  Pool *pool = repo->pool;
686  Repodata *data;
687  int i, j, flags;
688  Solvable *s;
689 
690  kv.parent = 0;
691  md->stop = 0;
692  if (!p)
693  {
694  for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
695  {
696  if (s->repo == repo)
697  repo_search_md(repo, p, keyname, md);
698  if (md->stop > SEARCH_NEXT_SOLVABLE)
699  break;
700  }
701  return;
702  }
703  else if (p < 0)
704  /* The callback only supports solvables, so we can't iterate over the
705  extra things. */
706  return;
707  flags = md->flags;
708  if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
709  {
710  s = pool->solvables + p;
711  switch(keyname)
712  {
713  case 0:
714  case SOLVABLE_NAME:
715  if (s->name)
716  {
717  kv.id = s->name;
718  repo_matchvalue(md, s, 0, solvablekeys + 0, &kv);
719  }
720  if (keyname || md->stop > SEARCH_NEXT_KEY)
721  return;
722  case SOLVABLE_ARCH:
723  if (s->arch)
724  {
725  kv.id = s->arch;
726  repo_matchvalue(md, s, 0, solvablekeys + 1, &kv);
727  }
728  if (keyname || md->stop > SEARCH_NEXT_KEY)
729  return;
730  case SOLVABLE_EVR:
731  if (s->evr)
732  {
733  kv.id = s->evr;
734  repo_matchvalue(md, s, 0, solvablekeys + 2, &kv);
735  }
736  if (keyname || md->stop > SEARCH_NEXT_KEY)
737  return;
738  case SOLVABLE_VENDOR:
739  if (s->vendor)
740  {
741  kv.id = s->vendor;
742  repo_matchvalue(md, s, 0, solvablekeys + 3, &kv);
743  }
744  if (keyname || md->stop > SEARCH_NEXT_KEY)
745  return;
746  case SOLVABLE_PROVIDES:
747  if (s->provides)
748  domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
749  if (keyname || md->stop > SEARCH_NEXT_KEY)
750  return;
751  case SOLVABLE_OBSOLETES:
752  if (s->obsoletes)
753  domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
754  if (keyname || md->stop > SEARCH_NEXT_KEY)
755  return;
756  case SOLVABLE_CONFLICTS:
757  if (s->conflicts)
758  domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
759  if (keyname || md->stop > SEARCH_NEXT_KEY)
760  return;
761  case SOLVABLE_REQUIRES:
762  if (s->requires)
763  domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
764  if (keyname || md->stop > SEARCH_NEXT_KEY)
765  return;
766  case SOLVABLE_RECOMMENDS:
767  if (s->recommends)
768  domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
769  if (keyname || md->stop > SEARCH_NEXT_KEY)
770  return;
771  case SOLVABLE_SUPPLEMENTS:
772  if (s->supplements)
773  domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
774  if (keyname || md->stop > SEARCH_NEXT_KEY)
775  return;
776  case SOLVABLE_SUGGESTS:
777  if (s->suggests)
778  domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
779  if (keyname || md->stop > SEARCH_NEXT_KEY)
780  return;
781  case SOLVABLE_ENHANCES:
782  if (s->enhances)
783  domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
784  if (keyname || md->stop > SEARCH_NEXT_KEY)
785  return;
786  case RPM_RPMDBID:
787  if (repo->rpmdbid)
788  {
789  kv.num = repo->rpmdbid[p - repo->start];
790  repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
791  }
792  if (keyname || md->stop > SEARCH_NEXT_KEY)
793  return;
794  break;
795  default:
796  break;
797  }
798  }
799 
800  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
801  {
802  if (p < data->start || p >= data->end)
803  continue;
804  if (keyname && !repodata_precheck_keyname(data, keyname))
805  continue;
806  if (keyname == SOLVABLE_FILELIST && !(md->flags & SEARCH_COMPLETE_FILELIST))
807  {
808  /* do not search filelist extensions */
809  if (data->state != REPODATA_AVAILABLE)
810  continue;
811  for (j = 1; j < data->nkeys; j++)
812  if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
813  break;
814  if (j == data->nkeys)
815  continue;
816  }
817  if (data->state == REPODATA_STUB)
818  {
819  if (keyname)
820  {
821  for (j = 1; j < data->nkeys; j++)
822  if (keyname == data->keys[j].name)
823  break;
824  if (j == data->nkeys)
825  continue;
826  }
827  /* load it */
828  if (data->loadcallback)
829  data->loadcallback(data);
830  else
831  data->state = REPODATA_ERROR;
832  }
833  if (data->state == REPODATA_ERROR)
834  continue;
835  repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
836  if (md->stop > SEARCH_NEXT_KEY)
837  break;
838  }
839 }
840 
841 void
842 repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
843 {
844  struct matchdata md;
845 
846  if (repo->disabled && !(flags & SEARCH_DISABLED_REPOS))
847  return;
848  memset(&md, 0, sizeof(md));
849  md.pool = repo->pool;
850  md.flags = flags;
851  md.callback = callback;
852  md.callback_data = cbdata;
853  if (match)
854  datamatcher_init(&md.matcher, match, flags);
855  repo_search_md(repo, p, keyname, &md);
856  if (match)
858 }
859 
860 const char *
861 repo_lookup_str(Repo *repo, Id entry, Id keyname)
862 {
863  Pool *pool = repo->pool;
864  Repodata *data;
865  int i;
866  const char *str;
867 
868  if (entry >= 0)
869  {
870  switch (keyname)
871  {
872  case SOLVABLE_NAME:
873  return id2str(pool, pool->solvables[entry].name);
874  case SOLVABLE_ARCH:
875  return id2str(pool, pool->solvables[entry].arch);
876  case SOLVABLE_EVR:
877  return id2str(pool, pool->solvables[entry].evr);
878  case SOLVABLE_VENDOR:
879  return id2str(pool, pool->solvables[entry].vendor);
880  }
881  }
882  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
883  {
884  if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
885  continue;
886  if (!repodata_precheck_keyname(data, keyname))
887  continue;
888  str = repodata_lookup_str(data, entry, keyname);
889  if (str)
890  return str;
891  if (repodata_lookup_type(data, entry, keyname))
892  return 0;
893  }
894  return 0;
895 }
896 
897 
898 unsigned int
899 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned int notfound)
900 {
901  Repodata *data;
902  int i;
903  unsigned int value;
904 
905  if (entry >= 0)
906  {
907  if (keyname == RPM_RPMDBID)
908  {
909  if (repo->rpmdbid && entry >= repo->start && entry < repo->end)
910  return repo->rpmdbid[entry - repo->start];
911  return notfound;
912  }
913  }
914  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
915  {
916  if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
917  continue;
918  if (!repodata_precheck_keyname(data, keyname))
919  continue;
920  if (repodata_lookup_num(data, entry, keyname, &value))
921  return value;
922  if (repodata_lookup_type(data, entry, keyname))
923  return notfound;
924  }
925  return notfound;
926 }
927 
928 Id
929 repo_lookup_id(Repo *repo, Id entry, Id keyname)
930 {
931  Repodata *data;
932  int i;
933  Id id;
934 
935  if (entry >= 0)
936  {
937  switch (keyname)
938  {
939  case SOLVABLE_NAME:
940  return repo->pool->solvables[entry].name;
941  case SOLVABLE_ARCH:
942  return repo->pool->solvables[entry].arch;
943  case SOLVABLE_EVR:
944  return repo->pool->solvables[entry].evr;
945  case SOLVABLE_VENDOR:
946  return repo->pool->solvables[entry].vendor;
947  }
948  }
949  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
950  {
951  if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
952  continue;
953  if (!repodata_precheck_keyname(data, keyname))
954  continue;
955  id = repodata_lookup_id(data, entry, keyname);
956  if (id)
957  return data->localpool ? repodata_globalize_id(data, id, 1) : id;
958  if (repodata_lookup_type(data, entry, keyname))
959  return 0;
960  }
961  return 0;
962 }
963 
964 static int
966 {
967  Id *p;
968 
969  queue_empty(q);
970  if (off)
971  for (p = repo->idarraydata + off; *p; p++)
972  queue_push(q, *p);
973  return 1;
974 }
975 
976 int
977 repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
978 {
979  Repodata *data;
980  int i;
981  if (entry >= 0)
982  {
983  switch (keyname)
984  {
985  case SOLVABLE_PROVIDES:
986  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].provides, q);
987  case SOLVABLE_OBSOLETES:
988  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].obsoletes, q);
989  case SOLVABLE_CONFLICTS:
990  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].conflicts, q);
991  case SOLVABLE_REQUIRES:
992  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].requires, q);
993  case SOLVABLE_RECOMMENDS:
994  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].recommends, q);
995  case SOLVABLE_SUGGESTS:
996  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].suggests, q);
997  case SOLVABLE_SUPPLEMENTS:
998  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].supplements, q);
999  case SOLVABLE_ENHANCES:
1000  return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
1001  }
1002  }
1003  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1004  {
1005  if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1006  continue;
1007  if (!repodata_precheck_keyname(data, keyname))
1008  continue;
1009  if (repodata_lookup_idarray(data, entry, keyname, q))
1010  {
1011  if (data->localpool)
1012  {
1013  for (i = 0; i < q->count; i++)
1014  q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
1015  }
1016  return 1;
1017  }
1018  if (repodata_lookup_type(data, entry, keyname))
1019  break;
1020  }
1021  queue_empty(q);
1022  return 0;
1023 }
1024 
1025 const unsigned char *
1026 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
1027 {
1028  Repodata *data;
1029  int i;
1030  const unsigned char *chk;
1031 
1032  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1033  {
1034  if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1035  continue;
1036  if (!repodata_precheck_keyname(data, keyname))
1037  continue;
1038  chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
1039  if (chk)
1040  return chk;
1041  if (repodata_lookup_type(data, entry, keyname))
1042  return 0;
1043  }
1044  *typep = 0;
1045  return 0;
1046 }
1047 
1048 const char *
1049 repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
1050 {
1051  const unsigned char *chk = repo_lookup_bin_checksum(repo, entry, keyname, typep);
1052  return chk ? pool_bin2hex(repo->pool, chk, sat_chksum_len(*typep)) : 0;
1053 }
1054 
1055 int
1056 repo_lookup_void(Repo *repo, Id entry, Id keyname)
1057 {
1058  Repodata *data;
1059  int i;
1060  Id type;
1061 
1062  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1063  {
1064  if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1065  continue;
1066  if (!repodata_precheck_keyname(data, keyname))
1067  continue;
1068  type = repodata_lookup_type(data, entry, keyname);
1069  if (type)
1070  return type == REPOKEY_TYPE_VOID;
1071  }
1072  return 0;
1073 }
1074 
1075 Id
1076 repo_lookup_type(Repo *repo, Id entry, Id keyname)
1077 {
1078  Repodata *data;
1079  int i;
1080  Id type;
1081 
1082  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1083  {
1084  if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
1085  continue;
1086  if (!repodata_precheck_keyname(data, keyname))
1087  continue;
1088  type = repodata_lookup_type(data, entry, keyname);
1089  if (type)
1090  return type == REPOKEY_TYPE_DELETED ? 0 : type;
1091  }
1092  return 0;
1093 }
1094 
1095 /***********************************************************************/
1096 
1097 Repodata *
1098 repo_add_repodata(Repo *repo, int flags)
1099 {
1100  int i;
1101  if ((flags & REPO_USE_LOADING) != 0)
1102  {
1103  for (i = repo->nrepodata - 1; i >= 0; i--)
1104  if (repo->repodata[i].state == REPODATA_LOADING)
1105  {
1106  Repodata *data = repo->repodata + i;
1107  /* re-init */
1108  /* hack: we mis-use REPO_REUSE_REPODATA here */
1109  if (!(flags & REPO_REUSE_REPODATA))
1110  repodata_empty(data, (flags & REPO_LOCALPOOL) ? 1 : 0);
1111  return data;
1112  }
1113  return 0; /* must not create a new repodata! */
1114  }
1115  if ((flags & REPO_REUSE_REPODATA) != 0)
1116  {
1117  for (i = repo->nrepodata - 1; i >= 0; i--)
1118  if (repo->repodata[i].state != REPODATA_STUB)
1119  return repo->repodata + i;
1120  }
1121  return repodata_create(repo, (flags & REPO_LOCALPOOL) ? 1 : 0);
1122 }
1123 
1124 Repodata *
1126 {
1127  int i;
1128  for (i = repo->nrepodata - 1; i >= 0; i--)
1129  if (repo->repodata[i].state != REPODATA_STUB)
1130  return repo->repodata + i;
1131  return repo_add_repodata(repo, 0);
1132 }
1133 
1134 void
1135 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
1136 {
1137  Repodata *data;
1138  if (p >= 0)
1139  {
1140  switch (keyname)
1141  {
1142  case SOLVABLE_NAME:
1143  repo->pool->solvables[p].name = id;
1144  return;
1145  case SOLVABLE_ARCH:
1146  repo->pool->solvables[p].arch = id;
1147  return;
1148  case SOLVABLE_EVR:
1149  repo->pool->solvables[p].evr = id;
1150  return;
1151  case SOLVABLE_VENDOR:
1152  repo->pool->solvables[p].vendor = id;
1153  return;
1154  }
1155  }
1156  data = repo_last_repodata(repo);
1157  if (data->localpool)
1158  id = repodata_localize_id(data, id, 1);
1159  repodata_set_id(data, p, keyname, id);
1160 }
1161 
1162 void
1163 repo_set_num(Repo *repo, Id p, Id keyname, unsigned int num)
1164 {
1165  Repodata *data;
1166  if (p >= 0)
1167  {
1168  if (keyname == RPM_RPMDBID)
1169  {
1170  if (!repo->rpmdbid)
1171  repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1172  repo->rpmdbid[p] = num;
1173  return;
1174  }
1175  }
1176  data = repo_last_repodata(repo);
1177  repodata_set_num(data, p, keyname, num);
1178 }
1179 
1180 void
1181 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
1182 {
1183  Repodata *data;
1184  if (p >= 0)
1185  {
1186  switch (keyname)
1187  {
1188  case SOLVABLE_NAME:
1189  case SOLVABLE_ARCH:
1190  case SOLVABLE_EVR:
1191  case SOLVABLE_VENDOR:
1192  repo_set_id(repo, p, keyname, str2id(repo->pool, str, 1));
1193  return;
1194  }
1195  }
1196  data = repo_last_repodata(repo);
1197  repodata_set_str(data, p, keyname, str);
1198 }
1199 
1200 void
1201 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
1202 {
1203  Repodata *data;
1204  if (p >= 0)
1205  {
1206  switch (keyname)
1207  {
1208  case SOLVABLE_NAME:
1209  case SOLVABLE_ARCH:
1210  case SOLVABLE_EVR:
1211  case SOLVABLE_VENDOR:
1212  repo_set_id(repo, p, keyname, str2id(repo->pool, str, 1));
1213  return;
1214  }
1215  }
1216  data = repo_last_repodata(repo);
1217  repodata_set_poolstr(data, p, keyname, str);
1218 }
1219 
1220 void
1221 repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
1222 {
1223  Repodata *data = repo_last_repodata(repo);
1224  repodata_add_poolstr_array(data, p, keyname, str);
1225 }
1226 
1227 void
1229 {
1230  int i;
1231  Repodata *data;
1232 
1233  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1234  if (data->attrs || data->xattrs)
1235  repodata_internalize(data);
1236 }
1237 
1238 void
1240 {
1241  int i;
1242  Repodata *data;
1243 
1244  for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
1246 }
1247 // EOF
1248 /*
1249 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4:
1250 */