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