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