Imported Upstream version 0.7.0
[platform/upstream/libsolv.git] / src / repo.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  * 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
43   pool_freewhatprovides(pool);
44   repo = (Repo *)solv_calloc(1, sizeof(*repo));
45   if (!pool->nrepos)
46     {
47       pool->nrepos = 1; /* start with repoid 1 */
48       pool->repos = (Repo **)solv_calloc(2, sizeof(Repo *));
49     }
50   else
51     pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *));
52   pool->repos[pool->nrepos] = repo;
53   pool->urepos++;
54   repo->repoid = pool->nrepos++;
55   repo->name = name ? solv_strdup(name) : 0;
56   repo->pool = pool;
57   repo->start = pool->nsolvables;
58   repo->end = pool->nsolvables;
59   repo->nsolvables = 0;
60   return repo;
61 }
62
63 void
64 repo_freedata(Repo *repo)
65 {
66   int i;
67   for (i = 1; i < repo->nrepodata; i++)
68     repodata_freedata(repo->repodata + i);
69   solv_free(repo->repodata);
70   solv_free(repo->idarraydata);
71   solv_free(repo->rpmdbid);
72   solv_free(repo->lastidhash);
73   solv_free((char *)repo->name);
74   solv_free(repo);
75 }
76
77 /* delete all solvables and repodata blocks from this repo */
78
79 void
80 repo_empty(Repo *repo, int reuseids)
81 {
82   Pool *pool = repo->pool;
83   Solvable *s;
84   int i;
85
86   pool_freewhatprovides(pool);
87   if (reuseids && repo->end == pool->nsolvables)
88     {
89       /* it's ok to reuse the ids. As this is the last repo, we can
90          just shrink the solvable array */
91       for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
92         if (s->repo != repo)
93           break;
94       pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids);
95       repo->end = i + 1;
96     }
97   /* zero out (i.e. free) solvables belonging to this repo */
98   for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
99     if (s->repo == repo)
100       memset(s, 0, sizeof(*s));
101   repo->end = repo->start;
102   repo->nsolvables = 0;
103
104   /* free all data belonging to this repo */
105   repo->idarraydata = solv_free(repo->idarraydata);
106   repo->idarraysize = 0;
107   repo->lastoff = 0;
108   repo->rpmdbid = solv_free(repo->rpmdbid);
109   for (i = 1; i < repo->nrepodata; i++)
110     repodata_freedata(repo->repodata + i);
111   solv_free(repo->repodata);
112   repo->repodata = 0;
113   repo->nrepodata = 0;
114 }
115
116 /*
117  * remove repo from pool, delete solvables
118  *
119  */
120
121 void
122 repo_free(Repo *repo, int reuseids)
123 {
124   Pool *pool = repo->pool;
125   int i;
126
127   if (repo == pool->installed)
128     pool->installed = 0;
129   repo_empty(repo, reuseids);
130   for (i = 1; i < pool->nrepos; i++)    /* find repo in pool */
131     if (pool->repos[i] == repo)
132       break;
133   if (i == pool->nrepos)               /* repo not in pool, return */
134     return;
135   if (i == pool->nrepos - 1 && reuseids)
136     pool->nrepos--;
137   else
138     pool->repos[i] = 0;
139   pool->urepos--;
140   repo_freedata(repo);
141 }
142
143 Id
144 repo_add_solvable(Repo *repo)
145 {
146   Id p = pool_add_solvable(repo->pool);
147   if (!repo->start || repo->start == repo->end)
148     repo->start = repo->end = p;
149   /* warning: sidedata must be extended before adapting start/end */
150   if (repo->rpmdbid)
151     repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, 1);
152   if (p < repo->start)
153     repo->start = p;
154   if (p + 1 > repo->end)
155     repo->end = p + 1;
156   repo->nsolvables++;
157   repo->pool->solvables[p].repo = repo;
158   return p;
159 }
160
161 Id
162 repo_add_solvable_block(Repo *repo, int count)
163 {
164   Id p;
165   Solvable *s;
166   if (!count)
167     return 0;
168   p = pool_add_solvable_block(repo->pool, count);
169   if (!repo->start || repo->start == repo->end)
170     repo->start = repo->end = p;
171   /* warning: sidedata must be extended before adapting start/end */
172   if (repo->rpmdbid)
173     repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, count);
174   if (p < repo->start)
175     repo->start = p;
176   if (p + count > repo->end)
177     repo->end = p + count;
178   repo->nsolvables += count;
179   for (s = repo->pool->solvables + p; count--; s++)
180     s->repo = repo;
181   return p;
182 }
183
184 void
185 repo_free_solvable(Repo *repo, Id p, int reuseids)
186 {
187   repo_free_solvable_block(repo, p, 1, reuseids);
188 }
189
190 void
191 repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids)
192 {
193   Solvable *s;
194   Repodata *data;
195   int i;
196   if (start + count == repo->end)
197     repo->end -= count;
198   repo->nsolvables -= count;
199   for (s = repo->pool->solvables + start, i = count; i--; s++)
200     s->repo = 0;
201   pool_free_solvable_block(repo->pool, start, count, reuseids);
202   FOR_REPODATAS(repo, i, data)
203     {
204       int dstart, dend;
205       if (data->end > repo->end)
206         repodata_shrink(data, repo->end);
207       dstart = data->start > start ? data->start : start;
208       dend = data->end < start + count ? data->end : start + count;
209       if (dstart < dend)
210         {
211           if (data->attrs)
212             {
213               int j;
214               for (j = dstart; j < dend; j++)   
215                 data->attrs[j - data->start] = solv_free(data->attrs[j - data->start]);
216             }
217           if (data->incoreoffset)
218             memset(data->incoreoffset + (dstart - data->start), 0, (dend - dstart) * sizeof(Id));
219         }
220     }
221 }
222
223 /* specialized version of repo_add_solvable_block that inserts the new solvable
224  * block before the indicated repo, which gets relocated.
225  * used in repo_add_rpmdb
226  */
227 Id
228 repo_add_solvable_block_before(Repo *repo, int count, Repo *beforerepo)
229 {
230   Pool *pool = repo->pool;
231   Id p;
232   Solvable *s;
233   Repodata *data;
234   int i;
235
236   if (!count || !beforerepo || beforerepo->end != pool->nsolvables || beforerepo->start == beforerepo->end)
237     return repo_add_solvable_block(repo, count);
238   p = beforerepo->start;
239   /* make sure all solvables belong to beforerepo */
240   for (i = p, s = pool->solvables + i; i < beforerepo->end; i++, s++)
241     if (s->repo && s->repo != beforerepo)
242       return repo_add_solvable_block(repo, count);
243   /* now move beforerepo to back */
244   pool_add_solvable_block(pool, count); /* must return beforerepo->end! */
245   memmove(pool->solvables + p + count, pool->solvables + p, (beforerepo->end - p) * sizeof(Solvable));
246   memset(pool->solvables + p, 0, sizeof(Solvable) * count);
247   /* adapt repodata */
248   FOR_REPODATAS(beforerepo, i, data)
249     {
250       if (data->start < p)
251         continue;
252       data->start += count;
253       data->end += count;
254     }
255   beforerepo->start += count;
256   beforerepo->end += count;
257   /* we now have count free solvables at id p */
258   /* warning: sidedata must be extended before adapting start/end */
259   if (repo->rpmdbid)
260     repo->rpmdbid = (Id *)repo_sidedata_extend(repo, repo->rpmdbid, sizeof(Id), p, count);
261   if (p < repo->start)
262     repo->start = p;
263   if (p + count > repo->end)
264     repo->end = p + count;
265   repo->nsolvables += count;
266   for (s = pool->solvables + p; count--; s++)
267     s->repo = repo;
268   return p;
269 }
270
271
272 /* repository sidedata is solvable data allocated on demand.
273  * It is used for data that is normally not present
274  * in the solvable like the rpmdbid.
275  * The solvable allocation funcions need to make sure that
276  * the sidedata gets extended if new solvables get added.
277  */
278
279 #define REPO_SIDEDATA_BLOCK 63
280
281 void *
282 repo_sidedata_create(Repo *repo, size_t size)
283 {
284   return solv_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK);
285 }
286
287 void *
288 repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count)
289 {
290   int n = repo->end - repo->start;
291   if (p < repo->start)
292     {
293       int d = repo->start - p;
294       b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
295       memmove((char *)b + d * size, b, n * size);
296       memset(b, 0, d * size);
297       n += d;
298     }
299   if (p + count > repo->end)
300     {
301       int d = p + count - repo->end;
302       b = solv_extend(b, n, d, size, REPO_SIDEDATA_BLOCK);
303       memset((char *)b + n * size, 0, d * size);
304     }
305   return b;
306 }
307
308 /*
309  * add Id to idarraydata used to store dependencies
310  * olddeps: old array offset to extend
311  * returns new array offset
312  */
313
314 Offset
315 repo_addid(Repo *repo, Offset olddeps, Id id)
316 {
317   Id *idarray;
318   int idarraysize;
319   int i;
320
321   idarray = repo->idarraydata;
322   idarraysize = repo->idarraysize;
323
324   if (!idarray)                        /* alloc idarray if not done yet */
325     {
326       idarraysize = 1;
327       idarray = solv_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK);
328       idarray[0] = 0;
329       repo->lastoff = 0;
330     }
331
332   if (!olddeps)                         /* no deps yet */
333     {
334       olddeps = idarraysize;
335       idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
336     }
337   else if (olddeps == repo->lastoff)    /* extend at end */
338     idarraysize--;
339   else                                  /* can't extend, copy old */
340     {
341       i = olddeps;
342       olddeps = idarraysize;
343       for (; idarray[i]; i++)
344         {
345           idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
346           idarray[idarraysize++] = idarray[i];
347         }
348       idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
349     }
350
351   idarray[idarraysize++] = id;          /* insert Id into array */
352   idarray = solv_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK);
353   idarray[idarraysize++] = 0;           /* ensure NULL termination */
354
355   repo->idarraydata = idarray;
356   repo->idarraysize = idarraysize;
357   repo->lastoff = olddeps;
358
359   return olddeps;
360 }
361
362 #define REPO_ADDID_DEP_HASHTHRES        64
363 #define REPO_ADDID_DEP_HASHMIN          128
364
365 /*
366  * Optimization for packages with an excessive amount of provides/requires:
367  * if the number of deps exceed a threshold, we build a hash of the already
368  * seen ids.
369  */
370 static Offset
371 repo_addid_dep_hash(Repo *repo, Offset olddeps, Id id, Id marker, int size)
372 {
373   Id oid, *oidp;
374   int before;
375   Hashval h, hh;
376   Id hid;
377
378   before = 0;
379   if (marker)
380     {
381       if (marker < 0)
382         {
383           marker = -marker;
384           before = 1;
385         }
386       if (marker == id)
387         marker = 0;
388     }
389
390   /* maintain hash and lastmarkerpos */
391   if (repo->lastidhash_idarraysize != repo->idarraysize || (Hashval)size * 2 > repo->lastidhash_mask || repo->lastmarker != marker)
392     {
393       repo->lastmarkerpos = 0;
394       if (size * 2 > (Hashval)repo->lastidhash_mask)
395         {
396           repo->lastidhash_mask = mkmask(size < REPO_ADDID_DEP_HASHMIN ? REPO_ADDID_DEP_HASHMIN : size);
397           repo->lastidhash = solv_realloc2(repo->lastidhash, repo->lastidhash_mask + 1, sizeof(Id));
398         }
399       memset(repo->lastidhash, 0, (repo->lastidhash_mask + 1) * sizeof(Id));
400       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
401         {
402           h = oid & repo->lastidhash_mask;
403           hh = HASHCHAIN_START;
404           while (repo->lastidhash[h] != 0)
405             h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
406           repo->lastidhash[h] = oid;
407           if (marker && oid == marker)
408             repo->lastmarkerpos = oidp - repo->idarraydata;
409         }
410       repo->lastmarker = marker;
411       repo->lastidhash_idarraysize = repo->idarraysize;
412     }
413
414   /* check the hash! */
415   h = id & repo->lastidhash_mask;
416   hh = HASHCHAIN_START;
417   while ((hid = repo->lastidhash[h]) != 0 && hid != id)
418     h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
419   /* put new element in hash */
420   if (!hid)
421     repo->lastidhash[h] = id;
422   else if (marker == SOLVABLE_FILEMARKER && (!before || !repo->lastmarkerpos))
423     return olddeps;
424   if (marker && !before && !repo->lastmarkerpos)
425     {
426       /* we have to add the marker first */
427       repo->lastmarkerpos = repo->idarraysize - 1;
428       olddeps = repo_addid(repo, olddeps, marker);
429       /* now put marker in hash */
430       h = marker & repo->lastidhash_mask;
431       hh = HASHCHAIN_START;
432       while (repo->lastidhash[h] != 0)
433         h = HASHCHAIN_NEXT(h, hh, repo->lastidhash_mask);
434       repo->lastidhash[h] = marker;
435       repo->lastidhash_idarraysize = repo->idarraysize;
436     }
437   if (!hid)
438     {
439       /* new entry, insert in correct position */
440       if (marker && before && repo->lastmarkerpos)
441         {
442           /* need to add it before the marker */
443           olddeps = repo_addid(repo, olddeps, id);      /* dummy to make room */
444           memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (repo->idarraysize - repo->lastmarkerpos - 2) * sizeof(Id));
445           repo->idarraydata[repo->lastmarkerpos++] = id;
446         }
447       else
448         {
449           /* just append it to the end */
450           olddeps = repo_addid(repo, olddeps, id);
451         }
452       repo->lastidhash_idarraysize = repo->idarraysize;
453       return olddeps;
454     }
455   /* we already have it in the hash */
456   if (!marker)
457     return olddeps;
458   if (marker == SOLVABLE_FILEMARKER)
459     {
460       /* check if it is in the wrong half */
461       /* (we already made sure that "before" and "lastmarkerpos" are set, see above) */
462       for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
463         if (oid == id)
464           break;
465       if (!oid)
466         return olddeps;
467       /* yes, wrong half. copy it over */
468       memmove(repo->idarraydata + repo->lastmarkerpos + 1, repo->idarraydata + repo->lastmarkerpos, (oidp - (repo->idarraydata + repo->lastmarkerpos)) * sizeof(Id));
469       repo->idarraydata[repo->lastmarkerpos++] = id;
470       return olddeps;
471     }
472   if (before)
473     return olddeps;
474   /* check if it is in the correct half */
475   for (oidp = repo->idarraydata + repo->lastmarkerpos + 1; (oid = *oidp) != 0; oidp++)
476     if (oid == id)
477       return olddeps;
478   /* nope, copy it over */
479   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
480     if (oid == id)
481       break;
482   if (!oid)
483     return olddeps;     /* should not happen */
484   memmove(oidp, oidp + 1, (repo->idarraydata + repo->idarraysize - oidp - 2) * sizeof(Id));
485   repo->idarraydata[repo->idarraysize - 2] = id;
486   repo->lastmarkerpos--;        /* marker has been moved */
487   return olddeps;
488 }
489
490 /*
491  * add dependency (as Id) to repo, also unifies dependencies
492  * olddeps = offset into idarraydata
493  * marker= 0 for normal dep
494  * marker > 0 add dep after marker
495  * marker < 0 add dep before -marker
496  * returns new start of dependency array
497  */
498 Offset
499 repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker)
500 {
501   Id oid, *oidp, *markerp;
502   int before;
503
504   if (!olddeps)
505     {
506       if (marker > 0)
507         olddeps = repo_addid(repo, olddeps, marker);
508       return repo_addid(repo, olddeps, id);
509     }
510
511   /* check if we should use the hash optimization */
512   if (olddeps == repo->lastoff)
513     {
514       int size = repo->idarraysize - 1 - repo->lastoff;
515       if (size >= REPO_ADDID_DEP_HASHTHRES)
516         return repo_addid_dep_hash(repo, olddeps, id, marker, size);
517     }
518
519   before = 0;
520   if (marker)
521     {
522       if (marker < 0)
523         {
524           marker = -marker;
525           before = 1;
526         }
527       if (marker == id)
528         marker = 0;
529     }
530
531   if (!marker)
532     {
533       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
534         if (oid == id)
535           return olddeps;
536       return repo_addid(repo, olddeps, id);
537     }
538
539   markerp = 0;
540   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != 0; oidp++)
541     {
542       if (oid == marker)
543         markerp = oidp;
544       else if (oid == id)
545         break;
546     }
547
548   if (oid)
549     {
550       if (marker == SOLVABLE_FILEMARKER)
551         {
552           if (!markerp || !before)
553             return olddeps;
554           /* we found it, but in the second half */
555           memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
556           *markerp = id;
557           return olddeps;
558         }
559       if (markerp || before)
560         return olddeps;
561       /* we found it, but in the first half */
562       markerp = oidp++;
563       for (; (oid = *oidp) != 0; oidp++)
564         if (oid == marker)
565           break;
566       if (!oid)
567         {
568           /* no marker in array yet */
569           oidp--;
570           if (markerp < oidp)
571             memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
572           *oidp = marker;
573           return repo_addid(repo, olddeps, id);
574         }
575       while (oidp[1])
576         oidp++;
577       memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id));
578       *oidp = id;
579       return olddeps;
580     }
581   /* id not yet in array */
582   if (!before && !markerp)
583     olddeps = repo_addid(repo, olddeps, marker);
584   else if (before && markerp)
585     {
586       *markerp++ = id;
587       id = *--oidp;
588       if (markerp < oidp)
589         memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id));
590       *markerp = marker;
591     }
592   return repo_addid(repo, olddeps, id);
593 }
594
595 /* return standard marker for the keyname dependency.
596  * 1: return positive marker, -1: return negative marker
597  */
598 Id
599 solv_depmarker(Id keyname, Id marker)
600 {
601   if (marker != 1 && marker != -1)
602     return marker;
603   if (keyname == SOLVABLE_PROVIDES)
604     return marker < 0 ? -SOLVABLE_FILEMARKER : SOLVABLE_FILEMARKER;
605   if (keyname == SOLVABLE_REQUIRES)
606     return marker < 0 ? -SOLVABLE_PREREQMARKER : SOLVABLE_PREREQMARKER;
607   return 0;
608 }
609
610 /*
611  * reserve Ids
612  * make space for 'num' more dependencies
613  * returns new start of dependency array
614  *
615  * reserved ids will always begin at offset idarraysize
616  */
617 Offset
618 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
619 {
620   num++;        /* room for trailing ID_NULL */
621
622   if (!repo->idarraysize)              /* ensure buffer space */
623     {
624       repo->idarraysize = 1;
625       repo->idarraydata = solv_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK);
626       repo->idarraydata[0] = 0;
627       repo->lastoff = 1;
628       return 1;
629     }
630
631   if (olddeps && olddeps != repo->lastoff)   /* if not appending */
632     {
633       /* can't insert into idarray, this would invalidate all 'larger' offsets
634        * so create new space at end and move existing deps there.
635        * Leaving 'hole' at old position.
636        */
637
638       Id *idstart, *idend;
639       int count;
640
641       for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
642         ;
643       count = idend - idstart - 1 + num;               /* new size */
644
645       repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK);
646       /* move old deps to end */
647       olddeps = repo->lastoff = repo->idarraysize;
648       memcpy(repo->idarraydata + olddeps, idstart, count - num);
649       repo->idarraysize = olddeps + count - num;
650
651       return olddeps;
652     }
653
654   if (olddeps)                         /* appending */
655     repo->idarraysize--;
656
657   /* make room*/
658   repo->idarraydata = solv_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK);
659
660   /* appending or new */
661   repo->lastoff = olddeps ? olddeps : repo->idarraysize;
662
663   return repo->lastoff;
664 }
665
666
667 /***********************************************************************/
668
669 struct matchdata
670 {
671   Pool *pool;
672   int flags;
673   Datamatcher matcher;
674   int stop;
675   Id *keyskip;
676   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
677   void *callback_data;
678 };
679
680 static int
681 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
682 {
683   struct matchdata *md = cbdata;
684
685   if (md->matcher.match)
686     {
687       const char *str;
688       if (key->name == SOLVABLE_FILELIST && key->type == REPOKEY_TYPE_DIRSTRARRAY && (md->matcher.flags & SEARCH_FILES) != 0)
689         if (!datamatcher_checkbasename(&md->matcher, kv->str))
690           return 0;
691       if (!(str = repodata_stringify(md->pool, data, key, kv, md->flags)))
692         return 0;
693       if (!datamatcher_match(&md->matcher, str))
694         return 0;
695     }
696   else
697     {
698       /* stringify filelist if requested */
699       if (key->name == SOLVABLE_FILELIST && key->type == REPOKEY_TYPE_DIRSTRARRAY && (md->matcher.flags & SEARCH_FILES) != 0)
700         repodata_stringify(md->pool, data, key, kv, md->flags);
701     }
702   md->stop = md->callback(md->callback_data, s, data, key, kv);
703   return md->stop;
704 }
705
706
707 /* list of all keys we store in the solvable */
708 /* also used in the dataiterator code in repodata.c */
709 Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
710   { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
711   { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
712   { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
713   { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
714   { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
715   { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
716   { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
717   { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
718   { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
719   { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
720   { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
721   { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
722   { RPM_RPMDBID,          REPOKEY_TYPE_NUM, 0, KEY_STORAGE_SOLVABLE },
723 };
724
725 static void
726 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida)
727 {
728   KeyValue kv;
729   kv.entry = 0;
730   kv.parent = 0;
731   for (; *ida && !md->stop; ida++)
732     {
733       kv.id = *ida;
734       kv.eof = ida[1] ? 0 : 1;
735       repo_matchvalue(md, s, 0, repo_solvablekeys + (keyname - SOLVABLE_NAME), &kv);
736       kv.entry++;
737     }
738 }
739
740 static void
741 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
742 {
743   KeyValue kv;
744   Pool *pool = repo->pool;
745   Repodata *data;
746   int i, flags;
747   Solvable *s;
748   Id *keyskip;
749
750   kv.parent = 0;
751   md->stop = 0;
752   if (!p)
753     {
754       for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++)
755         {
756           if (s->repo == repo)
757             repo_search_md(repo, p, keyname, md);
758           if (md->stop > SEARCH_NEXT_SOLVABLE)
759             break;
760         }
761       return;
762     }
763   if (p < 0 && p != SOLVID_META)
764     return;             /* SOLVID_POS not supported yet */
765   flags = md->flags;
766   if (p > 0 && !(flags & SEARCH_NO_STORAGE_SOLVABLE))
767     {
768       s = pool->solvables + p;
769       switch(keyname)
770         {
771           case 0:
772           case SOLVABLE_NAME:
773             if (s->name)
774               {
775                 kv.id = s->name;
776                 repo_matchvalue(md, s, 0, repo_solvablekeys + 0, &kv);
777               }
778             if (keyname || md->stop > SEARCH_NEXT_KEY)
779               return;
780           case SOLVABLE_ARCH:
781             if (s->arch)
782               {
783                 kv.id = s->arch;
784                 repo_matchvalue(md, s, 0, repo_solvablekeys + 1, &kv);
785               }
786             if (keyname || md->stop > SEARCH_NEXT_KEY)
787               return;
788           case SOLVABLE_EVR:
789             if (s->evr)
790               {
791                 kv.id = s->evr;
792                 repo_matchvalue(md, s, 0, repo_solvablekeys + 2, &kv);
793               }
794             if (keyname || md->stop > SEARCH_NEXT_KEY)
795               return;
796           case SOLVABLE_VENDOR:
797             if (s->vendor)
798               {
799                 kv.id = s->vendor;
800                 repo_matchvalue(md, s, 0, repo_solvablekeys + 3, &kv);
801               }
802             if (keyname || md->stop > SEARCH_NEXT_KEY)
803               return;
804           case SOLVABLE_PROVIDES:
805             if (s->provides)
806               domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides);
807             if (keyname || md->stop > SEARCH_NEXT_KEY)
808               return;
809           case SOLVABLE_OBSOLETES:
810             if (s->obsoletes)
811               domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes);
812             if (keyname || md->stop > SEARCH_NEXT_KEY)
813               return;
814           case SOLVABLE_CONFLICTS:
815             if (s->conflicts)
816               domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts);
817             if (keyname || md->stop > SEARCH_NEXT_KEY)
818               return;
819           case SOLVABLE_REQUIRES:
820             if (s->requires)
821               domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires);
822             if (keyname || md->stop > SEARCH_NEXT_KEY)
823               return;
824           case SOLVABLE_RECOMMENDS:
825             if (s->recommends)
826               domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends);
827             if (keyname || md->stop > SEARCH_NEXT_KEY)
828               return;
829           case SOLVABLE_SUPPLEMENTS:
830             if (s->supplements)
831               domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements);
832             if (keyname || md->stop > SEARCH_NEXT_KEY)
833               return;
834           case SOLVABLE_SUGGESTS:
835             if (s->suggests)
836               domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests);
837             if (keyname || md->stop > SEARCH_NEXT_KEY)
838               return;
839           case SOLVABLE_ENHANCES:
840             if (s->enhances)
841               domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances);
842             if (keyname || md->stop > SEARCH_NEXT_KEY)
843               return;
844           case RPM_RPMDBID:
845             if (repo->rpmdbid)
846               {
847                 kv.num = repo->rpmdbid[p - repo->start];
848                 kv.num2 = 0;
849                 repo_matchvalue(md, s, 0, repo_solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv);
850               }
851             if (keyname || md->stop > SEARCH_NEXT_KEY)
852               return;
853             break;
854           default:
855             break;
856         }
857     }
858
859   if (keyname)
860     {
861       if (keyname == SOLVABLE_FILELIST)
862         data = repo_lookup_filelist_repodata(repo, p, &md->matcher);
863       else
864         data = repo_lookup_repodata_opt(repo, p, keyname);
865       if (data)
866         repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
867       return;
868     }
869
870   keyskip = repo_create_keyskip(repo, p, &md->keyskip);
871   FOR_REPODATAS(repo, i, data)
872     {
873       if (p != SOLVID_META && (p < data->start || p >= data->end))
874         continue;
875       repodata_search_keyskip(data, p, keyname, md->flags, keyskip, repo_matchvalue, md);
876       if (md->stop > SEARCH_NEXT_KEY)
877         break;
878     }
879 }
880
881 void
882 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)
883 {
884   struct matchdata md;
885
886   if (repo->disabled && !(flags & SEARCH_DISABLED_REPOS))
887     return;
888   memset(&md, 0, sizeof(md));
889   md.pool = repo->pool;
890   md.flags = flags;
891   md.callback = callback;
892   md.callback_data = cbdata;
893   if (match)
894     datamatcher_init(&md.matcher, match, flags);
895   repo_search_md(repo, p, keyname, &md);
896   if (match)
897     datamatcher_free(&md.matcher);
898   solv_free(md.keyskip);
899 }
900
901 Repodata *
902 repo_lookup_repodata(Repo *repo, Id entry, Id keyname)
903 {
904   Repodata *data;
905   int rdid;
906   Id type;
907
908   if (entry == SOLVID_POS)
909     {
910       Pool *pool = repo->pool;
911       return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
912     }
913   for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
914     {
915       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
916         continue;
917       if (!repodata_precheck_keyname(data, keyname))
918         continue;
919       if ((type = repodata_lookup_type(data, entry, keyname)) != 0)
920         return type == REPOKEY_TYPE_DELETED ? 0 : data;
921     }
922   return 0;
923 }
924
925 /* like repo_lookup_repodata, but may return a repodata that contains no match instead of NULL */
926 Repodata *
927 repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname)
928 {
929   Repodata *data, *found = 0;
930   int rdid;
931   Id type;
932
933   if (entry == SOLVID_POS)
934     {
935       Pool *pool = repo->pool;
936       return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
937     }
938   for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
939     {
940       if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
941         continue;
942       if (!repodata_precheck_keyname(data, keyname))
943         continue;
944       if (found && (type = repodata_lookup_type(found, entry, keyname)) != 0)
945         return type == REPOKEY_TYPE_DELETED ? 0 : found;
946       found = data;
947     }
948   return found;
949 }
950
951 Repodata *
952 repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher)
953 {
954   Repodata *data;
955   int haveextension;
956   int rdid;
957   Id type;
958
959   if (entry <= 0 || !matcher || !matcher->match || ((matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
960       && (matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB))
961     return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);    /* cannot use filtered filelist */
962
963   haveextension = 0;
964   for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
965     {    
966       if (entry < data->start || entry >= data->end)
967         continue;
968       if (data->filelisttype == REPODATA_FILELIST_FILTERED)
969         {
970           if (data->state != REPODATA_AVAILABLE)
971             {
972               if (data->state != REPODATA_STUB)
973                 continue;
974               repodata_load(data);
975               if (data->state != REPODATA_AVAILABLE || entry < data->start || entry >= data->end)
976                 continue;
977             }
978           /* does this contain any data about the solvable we're looking for? */
979           if (!data->incoreoffset[entry - data->start])
980             continue;   /* no, ignore */
981           if (haveextension && repodata_filelistfilter_matches(data, matcher->match))
982             return data;
983           break;        /* fall back to normal code */
984         }
985       if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
986         continue;
987       if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
988         {
989           haveextension++;
990           continue;
991         }
992       if ((type = repodata_lookup_type(data, entry, SOLVABLE_FILELIST)) != 0)
993         {
994           if (haveextension)
995             break;              /* need to look in extension */
996           return type == REPOKEY_TYPE_DELETED ? 0 : data;
997         }
998     }
999   /* cannot use filtered filelist */
1000   return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);
1001 }
1002
1003
1004 /* the keyskip array has the following format:
1005  * 0: keyname area size
1006  * 1: repoid base
1007  * 2: repoid end
1008  * 3: entry for keyname 0
1009  * 4: entry for keyname 1
1010  * ...
1011  */
1012 Id *
1013 repo_create_keyskip(Repo *repo, Id entry, Id **oldkeyskip)
1014 {
1015   Repodata *data, *last = 0;
1016   Id *keyskip;
1017   int rdid, cnt = 0;
1018
1019   if (repo->nrepodata <= 2)
1020     return 0;   /* just one repodata, nothing to filter */
1021   keyskip = oldkeyskip ? *oldkeyskip : 0;
1022   if (keyskip)
1023     {
1024       if (keyskip[1] >= 0x10000000)
1025         keyskip = solv_free(keyskip);
1026       else
1027         keyskip[1] = keyskip[2];
1028     }
1029   FOR_REPODATAS(repo, rdid, data)
1030     {
1031       if (entry != SOLVID_META)
1032         {
1033           if (data->state != REPODATA_AVAILABLE && data->state != REPODATA_LOADING)
1034             {
1035               if (data->state != REPODATA_STUB)
1036                 continue;
1037               repodata_load(data);
1038               if (data->state != REPODATA_AVAILABLE)
1039                 continue;
1040             }
1041           if ((entry < data->start || entry >= data->end))
1042             continue;
1043           if (!data->incoreoffset[entry - data->start])
1044             continue;
1045         }
1046       if (last)
1047         keyskip = repodata_fill_keyskip(last, entry, keyskip);
1048       last = data;
1049       cnt++;
1050     }
1051   if (cnt <= 1)
1052     {
1053       if (oldkeyskip)
1054         *oldkeyskip = keyskip;
1055       return 0;
1056     }
1057   keyskip = repodata_fill_keyskip(last, entry, keyskip);
1058   if (keyskip)
1059     keyskip[2] = keyskip[1] + repo->nrepodata;
1060   if (oldkeyskip)
1061     *oldkeyskip = keyskip;
1062   return keyskip;
1063 }
1064
1065 const char *
1066 repo_lookup_str(Repo *repo, Id entry, Id keyname)
1067 {
1068   Repodata *data;
1069
1070   if (entry >= 0)
1071     {
1072       Pool *pool = repo->pool;
1073       switch (keyname)
1074         {
1075         case SOLVABLE_NAME:
1076           return pool_id2str(pool, pool->solvables[entry].name);
1077         case SOLVABLE_ARCH:
1078           return pool_id2str(pool, pool->solvables[entry].arch);
1079         case SOLVABLE_EVR:
1080           return pool_id2str(pool, pool->solvables[entry].evr);
1081         case SOLVABLE_VENDOR:
1082           return pool_id2str(pool, pool->solvables[entry].vendor);
1083         }
1084     }
1085   data = repo_lookup_repodata_opt(repo, entry, keyname);
1086   return data ? repodata_lookup_str(data, entry, keyname) : 0;
1087 }
1088
1089
1090 unsigned long long
1091 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound)
1092 {
1093   Repodata *data;
1094
1095   if (entry >= 0)
1096     {
1097       if (keyname == RPM_RPMDBID)
1098         {
1099           if (repo->rpmdbid && entry >= repo->start && entry < repo->end)
1100             return repo->rpmdbid[entry - repo->start];
1101           return notfound;
1102         }
1103     }
1104   data = repo_lookup_repodata_opt(repo, entry, keyname);
1105   return data ? repodata_lookup_num(data, entry, keyname, notfound) : notfound;
1106 }
1107
1108 Id
1109 repo_lookup_id(Repo *repo, Id entry, Id keyname)
1110 {
1111   Repodata *data;
1112   Id id;
1113
1114   if (entry >= 0)
1115     {
1116       switch (keyname)
1117         {
1118         case SOLVABLE_NAME:
1119           return repo->pool->solvables[entry].name;
1120         case SOLVABLE_ARCH:
1121           return repo->pool->solvables[entry].arch;
1122         case SOLVABLE_EVR:
1123           return repo->pool->solvables[entry].evr;
1124         case SOLVABLE_VENDOR:
1125           return repo->pool->solvables[entry].vendor;
1126         }
1127     }
1128   data = repo_lookup_repodata_opt(repo, entry, keyname);
1129   if (data && (id = repodata_lookup_id(data, entry, keyname)) != 0)
1130     return data->localpool ? repodata_globalize_id(data, id, 1) : id;
1131   return 0;
1132 }
1133
1134 static int
1135 lookup_idarray_solvable(Repo *repo, Offset off, Queue *q)
1136 {
1137   Id *p;
1138
1139   queue_empty(q);
1140   if (off)
1141     for (p = repo->idarraydata + off; *p; p++)
1142       queue_push(q, *p);
1143   return 1;
1144 }
1145
1146 int
1147 repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
1148 {
1149   Repodata *data;
1150   int i;
1151   if (entry >= 0)
1152     {
1153       switch (keyname)
1154         {
1155         case SOLVABLE_PROVIDES:
1156           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].provides, q);
1157         case SOLVABLE_OBSOLETES:
1158           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].obsoletes, q);
1159         case SOLVABLE_CONFLICTS:
1160           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].conflicts, q);
1161         case SOLVABLE_REQUIRES:
1162           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].requires, q);
1163         case SOLVABLE_RECOMMENDS:
1164           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].recommends, q);
1165         case SOLVABLE_SUGGESTS:
1166           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].suggests, q);
1167         case SOLVABLE_SUPPLEMENTS:
1168           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].supplements, q);
1169         case SOLVABLE_ENHANCES:
1170           return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
1171         }
1172     }
1173   data = repo_lookup_repodata_opt(repo, entry, keyname);
1174   if (data && repodata_lookup_idarray(data, entry, keyname, q))
1175     {
1176       if (data->localpool)
1177         {
1178           for (i = 0; i < q->count; i++)
1179             q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
1180         }
1181       return 1;
1182     }
1183   queue_empty(q);
1184   return 0;
1185 }
1186
1187 int
1188 repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker)
1189 {
1190   int r = repo_lookup_idarray(repo, entry, keyname, q);
1191   if (!r)
1192     return 0;
1193   if (marker == -1 || marker == 1)
1194     marker = solv_depmarker(keyname, marker);
1195   if (marker && q->count)
1196     {
1197       int i;
1198       if (marker < 0)
1199         {
1200           marker = -marker;
1201           for (i = 0; i < q->count; i++)
1202             if (q->elements[i] == marker)
1203               {
1204                 queue_truncate(q, i);
1205                 return r;
1206               }
1207         }
1208       else
1209         {
1210           for (i = 0; i < q->count; i++)
1211             if (q->elements[i] == marker)
1212               {
1213                 queue_deleten(q, 0, i + 1);
1214                 return r;
1215               }
1216           queue_empty(q);
1217         }
1218     }
1219   return r;
1220 }
1221
1222 const unsigned char *
1223 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
1224 {
1225   const unsigned char *chk;
1226   Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
1227   if (data && (chk = repodata_lookup_bin_checksum(data, entry, keyname, typep)) != 0)
1228     return chk;
1229   *typep = 0;
1230   return 0;
1231 }
1232
1233 const char *
1234 repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
1235 {
1236   const unsigned char *chk = repo_lookup_bin_checksum(repo, entry, keyname, typep);
1237   return chk ? pool_bin2hex(repo->pool, chk, solv_chksum_len(*typep)) : 0;
1238 }
1239
1240 int
1241 repo_lookup_void(Repo *repo, Id entry, Id keyname)
1242 {
1243   Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
1244   if (data)
1245     return repodata_lookup_void(data, entry, keyname);
1246   return 0;
1247 }
1248
1249 Id
1250 repo_lookup_type(Repo *repo, Id entry, Id keyname)
1251 {
1252   Id type;
1253   Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
1254   if (data && (type = repodata_lookup_type(data, entry, keyname)) != 0 && type != REPOKEY_TYPE_DELETED)
1255     return type;
1256   return 0;
1257 }
1258
1259 const void *
1260 repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp)
1261 {
1262   const void *bin;
1263   Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
1264   if (data && (bin = repodata_lookup_binary(data, entry, keyname, lenp)) != 0)
1265     return bin;
1266   *lenp = 0;
1267   return 0;
1268 }
1269
1270 /***********************************************************************/
1271
1272 Repodata *
1273 repo_add_repodata(Repo *repo, int flags)
1274 {
1275   Repodata *data;
1276   int i;
1277   if ((flags & REPO_USE_LOADING) != 0)
1278     {
1279       for (i = repo->nrepodata - 1; i > 0; i--)
1280         if (repo->repodata[i].state == REPODATA_LOADING)
1281           {
1282             Repodata *data = repo->repodata + i;
1283             /* re-init */
1284             /* hack: we mis-use REPO_REUSE_REPODATA here */
1285             if (!(flags & REPO_REUSE_REPODATA))
1286               repodata_empty(data, (flags & REPO_LOCALPOOL) ? 1 : 0);
1287             return data;
1288           }
1289       return 0; /* must not create a new repodata! */
1290     }
1291   if ((flags & REPO_REUSE_REPODATA) != 0)
1292     {
1293       for (i = repo->nrepodata - 1; i > 0; i--)
1294         if (repo->repodata[i].state != REPODATA_STUB)
1295           return repo->repodata + i;
1296     }
1297   if (!repo->nrepodata)
1298     {
1299       repo->nrepodata = 2;      /* start with id 1 */
1300       repo->repodata = solv_calloc(repo->nrepodata, sizeof(*data));
1301     }
1302   else
1303     {
1304       repo->nrepodata++;
1305       repo->repodata = solv_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
1306     }
1307   data = repo->repodata + repo->nrepodata - 1;
1308   repodata_initdata(data, repo, (flags & REPO_LOCALPOOL) ? 1 : 0);
1309   return data;
1310 }
1311
1312 Repodata *
1313 repo_id2repodata(Repo *repo, Id id)
1314 {
1315   return id ? repo->repodata + id : 0;
1316 }
1317
1318 Repodata *
1319 repo_last_repodata(Repo *repo)
1320 {
1321   int i;
1322   for (i = repo->nrepodata - 1; i > 0; i--)
1323     if (repo->repodata[i].state != REPODATA_STUB)
1324       return repo->repodata + i;
1325   return repo_add_repodata(repo, 0);
1326 }
1327
1328 void
1329 repo_set_id(Repo *repo, Id p, Id keyname, Id id)
1330 {
1331   Repodata *data;
1332   if (p >= 0)
1333     {
1334       switch (keyname)
1335         {
1336         case SOLVABLE_NAME:
1337           repo->pool->solvables[p].name = id;
1338           return;
1339         case SOLVABLE_ARCH:
1340           repo->pool->solvables[p].arch = id;
1341           return;
1342         case SOLVABLE_EVR:
1343           repo->pool->solvables[p].evr = id;
1344           return;
1345         case SOLVABLE_VENDOR:
1346           repo->pool->solvables[p].vendor = id;
1347           return;
1348         }
1349     }
1350   data = repo_last_repodata(repo);
1351   if (data->localpool)
1352     id = repodata_localize_id(data, id, 1);
1353   repodata_set_id(data, p, keyname, id);
1354 }
1355
1356 void
1357 repo_set_num(Repo *repo, Id p, Id keyname, unsigned long long num)
1358 {
1359   Repodata *data;
1360   if (p >= 0)
1361     {
1362       if (keyname == RPM_RPMDBID)
1363         {
1364           if (!repo->rpmdbid)
1365             repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
1366           repo->rpmdbid[p - repo->start] = num;
1367           return;
1368         }
1369     }
1370   data = repo_last_repodata(repo);
1371   repodata_set_num(data, p, keyname, num);
1372 }
1373
1374 void
1375 repo_set_str(Repo *repo, Id p, Id keyname, const char *str)
1376 {
1377   Repodata *data;
1378   if (p >= 0)
1379     {
1380       switch (keyname)
1381         {
1382         case SOLVABLE_NAME:
1383         case SOLVABLE_ARCH:
1384         case SOLVABLE_EVR:
1385         case SOLVABLE_VENDOR:
1386           repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
1387           return;
1388         }
1389     }
1390   data = repo_last_repodata(repo);
1391   repodata_set_str(data, p, keyname, str);
1392 }
1393
1394 void
1395 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str)
1396 {
1397   Repodata *data;
1398   if (p >= 0)
1399     {
1400       switch (keyname)
1401         {
1402         case SOLVABLE_NAME:
1403         case SOLVABLE_ARCH:
1404         case SOLVABLE_EVR:
1405         case SOLVABLE_VENDOR:
1406           repo_set_id(repo, p, keyname, pool_str2id(repo->pool, str, 1));
1407           return;
1408         }
1409     }
1410   data = repo_last_repodata(repo);
1411   repodata_set_poolstr(data, p, keyname, str);
1412 }
1413
1414 void
1415 repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str)
1416 {
1417   Repodata *data = repo_last_repodata(repo);
1418   repodata_add_poolstr_array(data, p, keyname, str);
1419 }
1420
1421 void
1422 repo_add_deparray(Repo *repo, Id p, Id keyname, Id dep, Id marker)
1423 {
1424   Repodata *data;
1425   if (marker == -1 || marker == 1)
1426     marker = solv_depmarker(keyname, marker);
1427   if (p >= 0)
1428     {
1429       Solvable *s = repo->pool->solvables + p;
1430       switch (keyname)
1431         {
1432         case SOLVABLE_PROVIDES:
1433           s->provides = repo_addid_dep(repo, s->provides, dep, marker);
1434           return;
1435         case SOLVABLE_OBSOLETES:
1436           s->obsoletes = repo_addid_dep(repo, s->obsoletes, dep, marker);
1437           return;
1438         case SOLVABLE_CONFLICTS:
1439           s->conflicts = repo_addid_dep(repo, s->conflicts, dep, marker);
1440           return;
1441         case SOLVABLE_REQUIRES:
1442           s->requires = repo_addid_dep(repo, s->requires, dep, marker);
1443           return;
1444         case SOLVABLE_RECOMMENDS:
1445           s->recommends = repo_addid_dep(repo, s->recommends, dep, marker);
1446           return;
1447         case SOLVABLE_SUGGESTS:
1448           s->suggests = repo_addid_dep(repo, s->suggests, dep, marker);
1449           return;
1450         case SOLVABLE_SUPPLEMENTS:
1451           s->supplements = repo_addid_dep(repo, s->supplements, dep, marker);
1452           return;
1453         case SOLVABLE_ENHANCES:
1454           s->enhances = repo_addid_dep(repo, s->enhances, dep, marker);
1455           return;
1456         }
1457     }
1458   data = repo_last_repodata(repo);
1459   repodata_add_idarray(data, p, keyname, dep);
1460 }
1461
1462 void
1463 repo_add_idarray(Repo *repo, Id p, Id keyname, Id id)
1464 {
1465   repo_add_deparray(repo, p, keyname, id, 0);
1466 }
1467
1468 static Offset
1469 repo_set_idarray_solvable(Repo *repo, Queue *q)
1470 {
1471   Offset o = 0;
1472   int i;
1473   for (i = 0; i < q->count; i++)
1474     repo_addid_dep(repo, o, q->elements[i], 0);
1475   return o;
1476 }
1477
1478 void
1479 repo_set_deparray(Repo *repo, Id p, Id keyname, Queue *q, Id marker)
1480 {
1481   Repodata *data;
1482   if (marker == -1 || marker == 1)
1483     marker = solv_depmarker(keyname, marker);
1484   if (marker)
1485     {
1486       /* complex case, splice old and new arrays */
1487       int i;
1488       Queue q2;
1489       queue_init(&q2);
1490       repo_lookup_deparray(repo, p, keyname, &q2, -marker);
1491       if (marker > 0)
1492         {
1493           if (q->count)
1494             {
1495               queue_push(&q2, marker);
1496               for (i = 0; i < q->count; i++)
1497                 queue_push(&q2, q->elements[i]);
1498             }
1499         }
1500       else
1501         {
1502           if (q2.count)
1503             queue_insert(&q2, 0, -marker);
1504           queue_insertn(&q2, 0, q->count, q->elements);
1505         }
1506       repo_set_deparray(repo, p, keyname, &q2, 0);
1507       queue_free(&q2);
1508       return;
1509     }
1510   if (p >= 0)
1511     {
1512       Solvable *s = repo->pool->solvables + p;
1513       switch (keyname)
1514         {
1515         case SOLVABLE_PROVIDES:
1516           s->provides = repo_set_idarray_solvable(repo, q);
1517           return;
1518         case SOLVABLE_OBSOLETES:
1519           s->obsoletes = repo_set_idarray_solvable(repo, q);
1520           return;
1521         case SOLVABLE_CONFLICTS:
1522           s->conflicts = repo_set_idarray_solvable(repo, q);
1523           return;
1524         case SOLVABLE_REQUIRES:
1525           s->requires = repo_set_idarray_solvable(repo, q);
1526           return;
1527         case SOLVABLE_RECOMMENDS:
1528           s->recommends = repo_set_idarray_solvable(repo, q);
1529           return;
1530         case SOLVABLE_SUGGESTS:
1531           s->suggests = repo_set_idarray_solvable(repo, q);
1532           return;
1533         case SOLVABLE_SUPPLEMENTS:
1534           s->supplements = repo_set_idarray_solvable(repo, q);
1535           return;
1536         case SOLVABLE_ENHANCES:
1537           s->enhances = repo_set_idarray_solvable(repo, q);
1538           return;
1539         }
1540     }
1541   data = repo_last_repodata(repo);
1542   repodata_set_idarray(data, p, keyname, q);
1543 }
1544
1545 void
1546 repo_set_idarray(Repo *repo, Id p, Id keyname, Queue *q)
1547 {
1548   repo_set_deparray(repo, p, keyname, q, 0);
1549 }
1550
1551 void
1552 repo_unset(Repo *repo, Id p, Id keyname)
1553 {
1554   Repodata *data;
1555   if (p >= 0)
1556     {
1557       Solvable *s = repo->pool->solvables + p;
1558       switch (keyname)
1559         {
1560         case SOLVABLE_NAME:
1561           s->name = 0;
1562           return;
1563         case SOLVABLE_ARCH:
1564           s->arch = 0;
1565           return;
1566         case SOLVABLE_EVR:
1567           s->evr = 0;
1568           return;
1569         case SOLVABLE_VENDOR:
1570           s->vendor = 0;
1571           return;
1572         case RPM_RPMDBID:
1573           if (repo->rpmdbid)
1574             repo->rpmdbid[p - repo->start] = 0;
1575           return;
1576         case SOLVABLE_PROVIDES:
1577           s->provides = 0;
1578           return;
1579         case SOLVABLE_OBSOLETES:
1580           s->obsoletes = 0;
1581           return;
1582         case SOLVABLE_CONFLICTS:
1583           s->conflicts = 0;
1584           return;
1585         case SOLVABLE_REQUIRES:
1586           s->requires = 0;
1587           return;
1588         case SOLVABLE_RECOMMENDS:
1589           s->recommends = 0;
1590           return;
1591         case SOLVABLE_SUGGESTS:
1592           s->suggests = 0;
1593           return;
1594         case SOLVABLE_SUPPLEMENTS:
1595           s->supplements = 0;
1596         case SOLVABLE_ENHANCES:
1597           s->enhances = 0;
1598           return;
1599         default:
1600           break;
1601         }
1602     }
1603   data = repo_last_repodata(repo);
1604   repodata_unset(data, p, keyname);
1605 }
1606
1607 void
1608 repo_internalize(Repo *repo)
1609 {
1610   int i;
1611   Repodata *data;
1612
1613   FOR_REPODATAS(repo, i, data)
1614     if (data->attrs || data->xattrs)
1615       repodata_internalize(data);
1616 }
1617
1618 void
1619 repo_disable_paging(Repo *repo)
1620 {
1621   int i;
1622   Repodata *data;
1623
1624   FOR_REPODATAS(repo, i, data)
1625     repodata_disable_paging(data);
1626 }
1627