1 /* 2 * Copyright (c) 2007, Novell Inc. 3 * 4 * This program is licensed under the BSD license, read LICENSE.BSD 5 * for further information 6 */ 7 8 /* 9 * repo.c 10 * 11 * Manage metadata coming from one repository 12 * 13 */ 14 15 #define _GNU_SOURCE 16 #include <string.h> 17 #include <fnmatch.h> 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 22 23 24 #include "repo.h" 25 #include "pool.h" 26 #include "poolid_private.h" 27 #include "util.h" 28 #include "chksum.h" 29 30 #define IDARRAY_BLOCK 4095 31 32 33 /* 34 * create empty repo 35 * and add to pool 36 */ 37 38 Repo * 39 repo_create(Pool *pool, const char *name) 40 { 41 Repo *repo; 42 43 pool_freewhatprovides(pool); 44 repo = (Repo *)solv_calloc(1, sizeof(*repo)); 45 if (!pool->nrepos) 46 { 47 pool->nrepos = 1; /* start with repoid 1 */ 48 pool->repos = (Repo **)solv_calloc(2, sizeof(Repo *)); 49 } 50 else 51 pool->repos = (Repo **)solv_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *)); 52 pool->repos[pool->nrepos] = repo; 53 pool->urepos++; 54 repo->repoid = pool->nrepos++; 55 repo->name = name ? solv_strdup(name) : 0; 56 repo->pool = pool; 57 repo->start = pool->nsolvables; 58 repo->end = pool->nsolvables; 59 repo->nsolvables = 0; 60 return repo; 61 } 62 63 void 64 repo_freedata(Repo *repo) 65 { 66 int i; 67 for (i = 1; i < repo->nrepodata; i++) 68 repodata_freedata(repo->repodata + i); 69 solv_free(repo->repodata); 70 solv_free(repo->idarraydata); 71 solv_free(repo->rpmdbid); 72 solv_free(repo->lastidhash); 73 solv_free((char *)repo->name); 74 solv_free(repo); 75 } 76 77 /* delete all solvables and repodata blocks from this repo */ 78 79 void 80 repo_empty(Repo *repo, int reuseids) 81 { 82 Pool *pool = repo->pool; 83 Solvable *s; 84 int i; 85 86 pool_freewhatprovides(pool); 87 if (reuseids && repo->end == pool->nsolvables) 88 { 89 /* it's ok to reuse the ids. As this is the last repo, we can 90 just shrink the solvable array */ 91 for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--) 92 if (s->repo != repo) 93 break; 94 pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids); 95 } 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 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 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 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 183 repo_free_solvable(Repo *repo, Id p, int reuseids) 184 { 185 repo_free_solvable_block(repo, p, 1, reuseids); 186 } 187 188 void 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 * 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 * 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 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 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 * 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 * 1382 repo_id2repodata(Repo *repo, Id id) 1383 { 1384 return id ? repo->repodata + id : 0; 1385 } 1386 1387 Repodata * 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 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 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 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 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 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 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 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 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 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 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 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 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 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