satsolver 0.16.3
|
00001 /* 00002 * Copyright (c) 2007, Novell Inc. 00003 * 00004 * This program is licensed under the BSD license, read LICENSE.BSD 00005 * for further information 00006 */ 00007 00008 /* 00009 * repo.c 00010 * 00011 * Manage metadata coming from one repository 00012 * 00013 */ 00014 00015 #define _GNU_SOURCE 00016 #include <string.h> 00017 #include <fnmatch.h> 00018 00019 #include <stdio.h> 00020 #include <stdlib.h> 00021 00022 00023 00024 #include "repo.h" 00025 #include "pool.h" 00026 #include "poolid_private.h" 00027 #include "util.h" 00028 #if 0 00029 #include "attr_store_p.h" 00030 #endif 00031 00032 #define IDARRAY_BLOCK 4095 00033 00034 00035 /* 00036 * create empty repo 00037 * and add to pool 00038 */ 00039 00040 Repo * 00041 repo_create(Pool *pool, const char *name) 00042 { 00043 Repo *repo; 00044 00045 pool_freewhatprovides(pool); 00046 repo = (Repo *)sat_calloc(1, sizeof(*repo)); 00047 pool->repos = (Repo **)sat_realloc2(pool->repos, pool->nrepos + 1, sizeof(Repo *)); 00048 pool->repos[pool->nrepos++] = repo; 00049 repo->repoid = pool->nrepos; 00050 repo->name = name ? strdup(name) : 0; 00051 repo->pool = pool; 00052 repo->start = pool->nsolvables; 00053 repo->end = pool->nsolvables; 00054 repo->nsolvables = 0; 00055 return repo; 00056 } 00057 00058 static void 00059 repo_freedata(Repo *repo) 00060 { 00061 int i; 00062 for (i = 0; i < repo->nrepodata; i++) 00063 repodata_freedata(repo->repodata + i); 00064 sat_free(repo->repodata); 00065 sat_free(repo->idarraydata); 00066 sat_free(repo->rpmdbid); 00067 sat_free((char *)repo->name); 00068 sat_free(repo); 00069 } 00070 00071 /* delete all solvables and repodata blocks from this repo */ 00072 00073 void 00074 repo_empty(Repo *repo, int reuseids) 00075 { 00076 Pool *pool = repo->pool; 00077 Solvable *s; 00078 int i; 00079 00080 pool_freewhatprovides(pool); 00081 if (repo == pool->installed) 00082 pool->installed = 0; 00083 00084 if (reuseids && repo->end == pool->nsolvables) 00085 { 00086 /* it's ok to reuse the ids. As this is the last repo, we can 00087 just shrink the solvable array */ 00088 for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--) 00089 if (s->repo != repo) 00090 break; 00091 pool_free_solvable_block(pool, i + 1, repo->end - (i + 1), reuseids); 00092 } 00093 /* zero out (i.e. free) solvables belonging to this repo */ 00094 for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++) 00095 if (s->repo == repo) 00096 memset(s, 0, sizeof(*s)); 00097 repo->nsolvables = 0; 00098 00099 /* free all data belonging to this repo */ 00100 repo->idarraydata = sat_free(repo->idarraydata); 00101 repo->idarraysize = 0; 00102 repo->lastoff = 0; 00103 repo->rpmdbid = sat_free(repo->rpmdbid); 00104 for (i = 0; i < repo->nrepodata; i++) 00105 repodata_freedata(repo->repodata + i); 00106 sat_free(repo->repodata); 00107 repo->repodata = 0; 00108 repo->nrepodata = 0; 00109 } 00110 00111 /* 00112 * remove repo from pool, delete solvables 00113 * 00114 */ 00115 00116 void 00117 repo_free(Repo *repo, int reuseids) 00118 { 00119 Pool *pool = repo->pool; 00120 int i; 00121 00122 repo_empty(repo, reuseids); 00123 for (i = 0; i < pool->nrepos; i++) /* find repo in pool */ 00124 if (pool->repos[i] == repo) 00125 break; 00126 if (i == pool->nrepos) /* repo not in pool, return */ 00127 return; 00128 if (i < pool->nrepos - 1) 00129 { 00130 memmove(pool->repos + i, pool->repos + i + 1, (pool->nrepos - 1 - i) * sizeof(Repo *)); 00131 /* fix repo ids */ 00132 for (; i < pool->nrepos - 1; i++) 00133 pool->repos[i]->repoid = i + 1; 00134 } 00135 pool->nrepos--; 00136 repo_freedata(repo); 00137 } 00138 00139 void 00140 repo_freeallrepos(Pool *pool, int reuseids) 00141 { 00142 int i; 00143 00144 pool_freewhatprovides(pool); 00145 for (i = 0; i < pool->nrepos; i++) 00146 repo_freedata(pool->repos[i]); 00147 pool->repos = sat_free(pool->repos); 00148 pool->nrepos = 0; 00149 /* the first two solvables don't belong to a repo */ 00150 pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids); 00151 } 00152 00153 void repo_free_solvable_block(Repo *repo, Id start, int count, int reuseids) 00154 { 00155 Solvable *s; 00156 Repodata *data; 00157 int i; 00158 if (start + count == repo->end) 00159 repo->end -= count; 00160 repo->nsolvables -= count; 00161 for (s = repo->pool->solvables + start, i = count; i--; s++) 00162 s->repo = 0; 00163 pool_free_solvable_block(repo->pool, start, count, reuseids); 00164 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00165 if (data->end > repo->end) 00166 repodata_shrink(data, repo->end); 00167 } 00168 00169 00170 /* repository sidedata is solvable data allocated on demand. 00171 * It is used for data that is normally not present 00172 * in the solvable like the rpmdbid. 00173 * The solvable allocation funcions need to make sure that 00174 * the sidedata gets extended if new solvables get added. 00175 */ 00176 00177 #define REPO_SIDEDATA_BLOCK 63 00178 00179 void * 00180 repo_sidedata_create(Repo *repo, size_t size) 00181 { 00182 return sat_calloc_block(repo->end - repo->start, size, REPO_SIDEDATA_BLOCK); 00183 } 00184 00185 void * 00186 repo_sidedata_extend(Repo *repo, void *b, size_t size, Id p, int count) 00187 { 00188 int n = repo->end - repo->start; 00189 if (p < repo->start) 00190 { 00191 int d = repo->start - p; 00192 b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK); 00193 memmove((char *)b + d * size, b, n * size); 00194 memset(b, 0, d * size); 00195 n += d; 00196 } 00197 if (p + count > repo->end) 00198 { 00199 int d = p + count - repo->end; 00200 b = sat_extend(b, n, d, size, REPO_SIDEDATA_BLOCK); 00201 memset((char *)b + n * size, 0, d * size); 00202 } 00203 return b; 00204 } 00205 00206 /* 00207 * add Id to idarraydata used to store dependencies 00208 * olddeps: old array offset to extend 00209 * returns new array offset 00210 */ 00211 00212 Offset 00213 repo_addid(Repo *repo, Offset olddeps, Id id) 00214 { 00215 Id *idarray; 00216 int idarraysize; 00217 int i; 00218 00219 idarray = repo->idarraydata; 00220 idarraysize = repo->idarraysize; 00221 00222 if (!idarray) /* alloc idarray if not done yet */ 00223 { 00224 idarraysize = 1; 00225 idarray = sat_extend_resize(0, 1, sizeof(Id), IDARRAY_BLOCK); 00226 idarray[0] = 0; 00227 repo->lastoff = 0; 00228 } 00229 00230 if (!olddeps) /* no deps yet */ 00231 { 00232 olddeps = idarraysize; 00233 idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); 00234 } 00235 else if (olddeps == repo->lastoff) /* extend at end */ 00236 idarraysize--; 00237 else /* can't extend, copy old */ 00238 { 00239 i = olddeps; 00240 olddeps = idarraysize; 00241 for (; idarray[i]; i++) 00242 { 00243 idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); 00244 idarray[idarraysize++] = idarray[i]; 00245 } 00246 idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); 00247 } 00248 00249 idarray[idarraysize++] = id; /* insert Id into array */ 00250 idarray = sat_extend(idarray, idarraysize, 1, sizeof(Id), IDARRAY_BLOCK); 00251 idarray[idarraysize++] = 0; /* ensure NULL termination */ 00252 00253 repo->idarraydata = idarray; 00254 repo->idarraysize = idarraysize; 00255 repo->lastoff = olddeps; 00256 00257 return olddeps; 00258 } 00259 00260 00261 /* 00262 * add dependency (as Id) to repo, also unifies dependencies 00263 * olddeps = offset into idarraydata 00264 * marker= 0 for normal dep 00265 * marker > 0 add dep after marker 00266 * marker < 0 add dep after -marker 00267 * returns new start of dependency array 00268 */ 00269 Offset 00270 repo_addid_dep(Repo *repo, Offset olddeps, Id id, Id marker) 00271 { 00272 Id oid, *oidp, *markerp; 00273 int before; 00274 00275 if (!olddeps) 00276 { 00277 if (marker > 0) 00278 olddeps = repo_addid(repo, olddeps, marker); 00279 return repo_addid(repo, olddeps, id); 00280 } 00281 00282 if (!marker) 00283 { 00284 for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++) 00285 { 00286 if (oid == id) 00287 return olddeps; 00288 } 00289 return repo_addid(repo, olddeps, id); 00290 } 00291 00292 before = 0; 00293 markerp = 0; 00294 if (marker < 0) 00295 { 00296 before = 1; 00297 marker = -marker; 00298 } 00299 for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++) 00300 { 00301 if (oid == marker) 00302 markerp = oidp; 00303 else if (oid == id) 00304 break; 00305 } 00306 00307 if (oid) 00308 { 00309 if (markerp || before) 00310 return olddeps; 00311 /* we found it, but in the wrong half */ 00312 markerp = oidp++; 00313 for (; (oid = *oidp) != ID_NULL; oidp++) 00314 if (oid == marker) 00315 break; 00316 if (!oid) 00317 { 00318 /* no marker in array yet */ 00319 oidp--; 00320 if (markerp < oidp) 00321 memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id)); 00322 *oidp = marker; 00323 return repo_addid(repo, olddeps, id); 00324 } 00325 while (oidp[1]) 00326 oidp++; 00327 memmove(markerp, markerp + 1, (oidp - markerp) * sizeof(Id)); 00328 *oidp = id; 00329 return olddeps; 00330 } 00331 /* id not yet in array */ 00332 if (!before && !markerp) 00333 olddeps = repo_addid(repo, olddeps, marker); 00334 else if (before && markerp) 00335 { 00336 *markerp++ = id; 00337 id = *--oidp; 00338 if (markerp < oidp) 00339 memmove(markerp + 1, markerp, (oidp - markerp) * sizeof(Id)); 00340 *markerp = marker; 00341 } 00342 return repo_addid(repo, olddeps, id); 00343 } 00344 00345 00346 /* 00347 * reserve Ids 00348 * make space for 'num' more dependencies 00349 * returns new start of dependency array 00350 * 00351 * reserved ids will always begin at offset idarraysize 00352 */ 00353 00354 Offset 00355 repo_reserve_ids(Repo *repo, Offset olddeps, int num) 00356 { 00357 num++; /* room for trailing ID_NULL */ 00358 00359 if (!repo->idarraysize) /* ensure buffer space */ 00360 { 00361 repo->idarraysize = 1; 00362 repo->idarraydata = sat_extend_resize(0, 1 + num, sizeof(Id), IDARRAY_BLOCK); 00363 repo->idarraydata[0] = 0; 00364 repo->lastoff = 1; 00365 return 1; 00366 } 00367 00368 if (olddeps && olddeps != repo->lastoff) /* if not appending */ 00369 { 00370 /* can't insert into idarray, this would invalidate all 'larger' offsets 00371 * so create new space at end and move existing deps there. 00372 * Leaving 'hole' at old position. 00373 */ 00374 00375 Id *idstart, *idend; 00376 int count; 00377 00378 for (idstart = idend = repo->idarraydata + olddeps; *idend++; ) /* find end */ 00379 ; 00380 count = idend - idstart - 1 + num; /* new size */ 00381 00382 repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, count, sizeof(Id), IDARRAY_BLOCK); 00383 /* move old deps to end */ 00384 olddeps = repo->lastoff = repo->idarraysize; 00385 memcpy(repo->idarraydata + olddeps, idstart, count - num); 00386 repo->idarraysize = olddeps + count - num; 00387 00388 return olddeps; 00389 } 00390 00391 if (olddeps) /* appending */ 00392 repo->idarraysize--; 00393 00394 /* make room*/ 00395 repo->idarraydata = sat_extend(repo->idarraydata, repo->idarraysize, num, sizeof(Id), IDARRAY_BLOCK); 00396 00397 /* appending or new */ 00398 repo->lastoff = olddeps ? olddeps : repo->idarraysize; 00399 00400 return repo->lastoff; 00401 } 00402 00403 00404 00405 Offset 00406 repo_fix_supplements(Repo *repo, Offset provides, Offset supplements, Offset freshens) 00407 { 00408 Pool *pool = repo->pool; 00409 Id id, idp, idl; 00410 char buf[1024], *p, *dep; 00411 int i, l; 00412 00413 if (provides) 00414 { 00415 for (i = provides; repo->idarraydata[i]; i++) 00416 { 00417 id = repo->idarraydata[i]; 00418 if (ISRELDEP(id)) 00419 continue; 00420 dep = (char *)id2str(pool, id); 00421 if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2) 00422 { 00423 idp = 0; 00424 strcpy(buf + 2, dep); 00425 dep = buf + 2 + 7; 00426 if ((p = strchr(dep, ':')) != 0 && p != dep) 00427 { 00428 *p++ = 0; 00429 idp = str2id(pool, dep, 1); 00430 dep = p; 00431 } 00432 id = 0; 00433 while ((p = strchr(dep, ';')) != 0) 00434 { 00435 if (p == dep) 00436 { 00437 dep = p + 1; 00438 continue; 00439 } 00440 *p++ = 0; 00441 #if 0 00442 strncpy(dep - 9, "language:", 9); 00443 idl = str2id(pool, dep - 9, 1); 00444 #else 00445 idl = str2id(pool, dep, 1); 00446 idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1); 00447 #endif 00448 if (id) 00449 id = rel2id(pool, id, idl, REL_OR, 1); 00450 else 00451 id = idl; 00452 dep = p; 00453 } 00454 if (dep[0] && dep[1]) 00455 { 00456 for (p = dep; *p && *p != ')'; p++) 00457 ; 00458 *p = 0; 00459 #if 0 00460 strncpy(dep - 9, "language:", 9); 00461 idl = str2id(pool, dep - 9, 1); 00462 #else 00463 idl = str2id(pool, dep, 1); 00464 idl = rel2id(pool, NAMESPACE_LANGUAGE, idl, REL_NAMESPACE, 1); 00465 #endif 00466 if (id) 00467 id = rel2id(pool, id, idl, REL_OR, 1); 00468 else 00469 id = idl; 00470 } 00471 if (idp) 00472 id = rel2id(pool, idp, id, REL_AND, 1); 00473 if (id) 00474 supplements = repo_addid_dep(repo, supplements, id, 0); 00475 } 00476 else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf)) 00477 { 00478 strcpy(buf, dep); 00479 p = buf + (p - dep); 00480 *p++ = 0; 00481 idp = str2id(pool, buf, 1); 00482 /* strip trailing slashes */ 00483 l = strlen(p); 00484 while (l > 1 && p[l - 1] == '/') 00485 p[--l] = 0; 00486 id = str2id(pool, p, 1); 00487 id = rel2id(pool, idp, id, REL_WITH, 1); 00488 id = rel2id(pool, NAMESPACE_SPLITPROVIDES, id, REL_NAMESPACE, 1); 00489 supplements = repo_addid_dep(repo, supplements, id, 0); 00490 } 00491 } 00492 } 00493 if (supplements) 00494 { 00495 for (i = supplements; repo->idarraydata[i]; i++) 00496 { 00497 id = repo->idarraydata[i]; 00498 if (ISRELDEP(id)) 00499 continue; 00500 dep = (char *)id2str(pool, id); 00501 if (!strncmp(dep, "system:modalias(", 16)) 00502 dep += 7; 00503 if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf)) 00504 { 00505 strcpy(buf, dep); 00506 p = strchr(buf + 9, ':'); 00507 if (p && p != buf + 9 && strchr(p + 1, ':')) 00508 { 00509 *p++ = 0; 00510 idp = str2id(pool, buf + 9, 1); 00511 p[strlen(p) - 1] = 0; 00512 id = str2id(pool, p, 1); 00513 id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1); 00514 id = rel2id(pool, idp, id, REL_AND, 1); 00515 } 00516 else 00517 { 00518 p = buf + 9; 00519 p[strlen(p) - 1] = 0; 00520 id = str2id(pool, p, 1); 00521 id = rel2id(pool, NAMESPACE_MODALIAS, id, REL_NAMESPACE, 1); 00522 } 00523 if (id) 00524 repo->idarraydata[i] = id; 00525 } 00526 else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf)) 00527 { 00528 strcpy(buf, dep); 00529 id = 0; 00530 dep = buf + 11; 00531 while ((p = strchr(dep, ':')) != 0) 00532 { 00533 if (p == dep) 00534 { 00535 dep = p + 1; 00536 continue; 00537 } 00538 *p++ = 0; 00539 idp = str2id(pool, dep, 1); 00540 if (id) 00541 id = rel2id(pool, id, idp, REL_AND, 1); 00542 else 00543 id = idp; 00544 dep = p; 00545 } 00546 if (dep[0] && dep[1]) 00547 { 00548 dep[strlen(dep) - 1] = 0; 00549 idp = str2id(pool, dep, 1); 00550 if (id) 00551 id = rel2id(pool, id, idp, REL_AND, 1); 00552 else 00553 id = idp; 00554 } 00555 if (id) 00556 repo->idarraydata[i] = id; 00557 } 00558 else if (!strncmp(dep, "filesystem(", 11) && strlen(dep) < sizeof(buf)) 00559 { 00560 strcpy(buf, dep + 11); 00561 if ((p = strrchr(buf, ')')) != 0) 00562 *p = 0; 00563 id = str2id(pool, buf, 1); 00564 id = rel2id(pool, NAMESPACE_FILESYSTEM, id, REL_NAMESPACE, 1); 00565 repo->idarraydata[i] = id; 00566 } 00567 } 00568 } 00569 if (freshens && repo->idarraydata[freshens]) 00570 { 00571 Id idsupp = 0, idfresh = 0; 00572 if (!supplements) 00573 return freshens; 00574 for (i = supplements; repo->idarraydata[i]; i++) 00575 { 00576 if (!idsupp) 00577 idsupp = repo->idarraydata[i]; 00578 else 00579 idsupp = rel2id(pool, idsupp, repo->idarraydata[i], REL_OR, 1); 00580 } 00581 for (i = freshens; repo->idarraydata[i]; i++) 00582 { 00583 if (!idfresh) 00584 idfresh = repo->idarraydata[i]; 00585 else 00586 idfresh = rel2id(pool, idfresh, repo->idarraydata[i], REL_OR, 1); 00587 } 00588 if (!idsupp) 00589 idsupp = idfresh; 00590 else 00591 idsupp = rel2id(pool, idsupp, idfresh, REL_AND, 1); 00592 supplements = repo_addid_dep(repo, 0, idsupp, 0); 00593 } 00594 return supplements; 00595 } 00596 00597 Offset 00598 repo_fix_conflicts(Repo *repo, Offset conflicts) 00599 { 00600 char buf[1024], *p, *dep; 00601 Pool *pool = repo->pool; 00602 Id id; 00603 int i; 00604 00605 if (!conflicts) 00606 return conflicts; 00607 for (i = conflicts; repo->idarraydata[i]; i++) 00608 { 00609 id = repo->idarraydata[i]; 00610 if (ISRELDEP(id)) 00611 continue; 00612 dep = (char *)id2str(pool, id); 00613 if (!strncmp(dep, "otherproviders(", 15) && strlen(dep) < sizeof(buf) - 2) 00614 { 00615 strcpy(buf, dep + 15); 00616 if ((p = strchr(buf, ')')) != 0) 00617 *p = 0; 00618 id = str2id(pool, buf, 1); 00619 id = rel2id(pool, NAMESPACE_OTHERPROVIDERS, id, REL_NAMESPACE, 1); 00620 repo->idarraydata[i] = id; 00621 } 00622 } 00623 return conflicts; 00624 } 00625 00626 struct matchdata 00627 { 00628 Pool *pool; 00629 int flags; 00630 Datamatcher matcher; 00631 int stop; 00632 int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv); 00633 void *callback_data; 00634 }; 00635 00636 int 00637 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv) 00638 { 00639 struct matchdata *md = cbdata; 00640 00641 if (md->matcher.match) 00642 { 00643 if (!repodata_stringify(md->pool, data, key, kv, md->flags)) 00644 return 0; 00645 if (!datamatcher_match(&md->matcher, kv->str)) 00646 return 0; 00647 } 00648 md->stop = md->callback(md->callback_data, s, data, key, kv); 00649 return md->stop; 00650 } 00651 00652 00653 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = { 00654 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, 00655 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, 00656 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, 00657 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE }, 00658 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00659 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00660 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00661 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00662 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00663 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00664 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00665 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE }, 00666 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE }, 00667 }; 00668 00669 static void 00670 domatch_idarray(Solvable *s, Id keyname, struct matchdata *md, Id *ida) 00671 { 00672 KeyValue kv; 00673 kv.entry = 0; 00674 kv.parent = 0; 00675 for (; *ida && !md->stop; ida++) 00676 { 00677 kv.id = *ida; 00678 kv.eof = ida[1] ? 0 : 1; 00679 repo_matchvalue(md, s, 0, solvablekeys + (keyname - SOLVABLE_NAME), &kv); 00680 kv.entry++; 00681 } 00682 } 00683 00684 static void 00685 repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md) 00686 { 00687 KeyValue kv; 00688 Pool *pool = repo->pool; 00689 Repodata *data; 00690 int i, j, flags; 00691 Solvable *s; 00692 00693 kv.parent = 0; 00694 md->stop = 0; 00695 if (!p) 00696 { 00697 for (p = repo->start, s = repo->pool->solvables + p; p < repo->end; p++, s++) 00698 { 00699 if (s->repo == repo) 00700 repo_search_md(repo, p, keyname, md); 00701 if (md->stop > SEARCH_NEXT_SOLVABLE) 00702 break; 00703 } 00704 return; 00705 } 00706 else if (p < 0) 00707 /* The callback only supports solvables, so we can't iterate over the 00708 extra things. */ 00709 return; 00710 flags = md->flags; 00711 if (!(flags & SEARCH_NO_STORAGE_SOLVABLE)) 00712 { 00713 s = pool->solvables + p; 00714 switch(keyname) 00715 { 00716 case 0: 00717 case SOLVABLE_NAME: 00718 if (s->name) 00719 { 00720 kv.id = s->name; 00721 repo_matchvalue(md, s, 0, solvablekeys + 0, &kv); 00722 } 00723 if (keyname || md->stop > SEARCH_NEXT_KEY) 00724 return; 00725 case SOLVABLE_ARCH: 00726 if (s->arch) 00727 { 00728 kv.id = s->arch; 00729 repo_matchvalue(md, s, 0, solvablekeys + 1, &kv); 00730 } 00731 if (keyname || md->stop > SEARCH_NEXT_KEY) 00732 return; 00733 case SOLVABLE_EVR: 00734 if (s->evr) 00735 { 00736 kv.id = s->evr; 00737 repo_matchvalue(md, s, 0, solvablekeys + 2, &kv); 00738 } 00739 if (keyname || md->stop > SEARCH_NEXT_KEY) 00740 return; 00741 case SOLVABLE_VENDOR: 00742 if (s->vendor) 00743 { 00744 kv.id = s->vendor; 00745 repo_matchvalue(md, s, 0, solvablekeys + 3, &kv); 00746 } 00747 if (keyname || md->stop > SEARCH_NEXT_KEY) 00748 return; 00749 case SOLVABLE_PROVIDES: 00750 if (s->provides) 00751 domatch_idarray(s, SOLVABLE_PROVIDES, md, repo->idarraydata + s->provides); 00752 if (keyname || md->stop > SEARCH_NEXT_KEY) 00753 return; 00754 case SOLVABLE_OBSOLETES: 00755 if (s->obsoletes) 00756 domatch_idarray(s, SOLVABLE_OBSOLETES, md, repo->idarraydata + s->obsoletes); 00757 if (keyname || md->stop > SEARCH_NEXT_KEY) 00758 return; 00759 case SOLVABLE_CONFLICTS: 00760 if (s->conflicts) 00761 domatch_idarray(s, SOLVABLE_CONFLICTS, md, repo->idarraydata + s->conflicts); 00762 if (keyname || md->stop > SEARCH_NEXT_KEY) 00763 return; 00764 case SOLVABLE_REQUIRES: 00765 if (s->requires) 00766 domatch_idarray(s, SOLVABLE_REQUIRES, md, repo->idarraydata + s->requires); 00767 if (keyname || md->stop > SEARCH_NEXT_KEY) 00768 return; 00769 case SOLVABLE_RECOMMENDS: 00770 if (s->recommends) 00771 domatch_idarray(s, SOLVABLE_RECOMMENDS, md, repo->idarraydata + s->recommends); 00772 if (keyname || md->stop > SEARCH_NEXT_KEY) 00773 return; 00774 case SOLVABLE_SUPPLEMENTS: 00775 if (s->supplements) 00776 domatch_idarray(s, SOLVABLE_SUPPLEMENTS, md, repo->idarraydata + s->supplements); 00777 if (keyname || md->stop > SEARCH_NEXT_KEY) 00778 return; 00779 case SOLVABLE_SUGGESTS: 00780 if (s->suggests) 00781 domatch_idarray(s, SOLVABLE_SUGGESTS, md, repo->idarraydata + s->suggests); 00782 if (keyname || md->stop > SEARCH_NEXT_KEY) 00783 return; 00784 case SOLVABLE_ENHANCES: 00785 if (s->enhances) 00786 domatch_idarray(s, SOLVABLE_ENHANCES, md, repo->idarraydata + s->enhances); 00787 if (keyname || md->stop > SEARCH_NEXT_KEY) 00788 return; 00789 case RPM_RPMDBID: 00790 if (repo->rpmdbid) 00791 { 00792 kv.num = repo->rpmdbid[p - repo->start]; 00793 repo_matchvalue(md, s, 0, solvablekeys + (RPM_RPMDBID - SOLVABLE_NAME), &kv); 00794 } 00795 if (keyname || md->stop > SEARCH_NEXT_KEY) 00796 return; 00797 break; 00798 default: 00799 break; 00800 } 00801 } 00802 00803 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00804 { 00805 if (p < data->start || p >= data->end) 00806 continue; 00807 if (keyname && !repodata_precheck_keyname(data, keyname)) 00808 continue; 00809 if (keyname == SOLVABLE_FILELIST && !(md->flags & SEARCH_COMPLETE_FILELIST)) 00810 { 00811 /* do not search filelist extensions */ 00812 if (data->state != REPODATA_AVAILABLE) 00813 continue; 00814 for (j = 1; j < data->nkeys; j++) 00815 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) 00816 break; 00817 if (j == data->nkeys) 00818 continue; 00819 } 00820 if (data->state == REPODATA_STUB) 00821 { 00822 if (keyname) 00823 { 00824 for (j = 1; j < data->nkeys; j++) 00825 if (keyname == data->keys[j].name) 00826 break; 00827 if (j == data->nkeys) 00828 continue; 00829 } 00830 /* load it */ 00831 if (data->loadcallback) 00832 data->loadcallback(data); 00833 else 00834 data->state = REPODATA_ERROR; 00835 } 00836 if (data->state == REPODATA_ERROR) 00837 continue; 00838 repodata_search(data, p, keyname, md->flags, repo_matchvalue, md); 00839 if (md->stop > SEARCH_NEXT_KEY) 00840 break; 00841 } 00842 } 00843 00844 void 00845 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) 00846 { 00847 struct matchdata md; 00848 00849 if (repo->disabled && !(flags & SEARCH_DISABLED_REPOS)) 00850 return; 00851 memset(&md, 0, sizeof(md)); 00852 md.pool = repo->pool; 00853 md.flags = flags; 00854 md.callback = callback; 00855 md.callback_data = cbdata; 00856 if (match) 00857 datamatcher_init(&md.matcher, match, flags); 00858 repo_search_md(repo, p, keyname, &md); 00859 if (match) 00860 datamatcher_free(&md.matcher); 00861 } 00862 00863 const char * 00864 repo_lookup_str(Repo *repo, Id entry, Id keyname) 00865 { 00866 Pool *pool = repo->pool; 00867 Repodata *data; 00868 int i, j; 00869 00870 switch(keyname) 00871 { 00872 case SOLVABLE_NAME: 00873 return id2str(pool, pool->solvables[entry].name); 00874 case SOLVABLE_ARCH: 00875 return id2str(pool, pool->solvables[entry].arch); 00876 case SOLVABLE_EVR: 00877 return id2str(pool, pool->solvables[entry].evr); 00878 case SOLVABLE_VENDOR: 00879 return id2str(pool, pool->solvables[entry].vendor); 00880 } 00881 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00882 { 00883 if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) 00884 continue; 00885 if (!repodata_precheck_keyname(data, keyname)) 00886 continue; 00887 for (j = 1; j < data->nkeys; j++) 00888 { 00889 if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID || data->keys[j].type == REPOKEY_TYPE_STR)) 00890 return repodata_lookup_str(data, entry, keyname); 00891 } 00892 } 00893 return 0; 00894 } 00895 00896 00897 unsigned int 00898 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned int notfound) 00899 { 00900 Repodata *data; 00901 int i, j; 00902 00903 if (keyname == RPM_RPMDBID) 00904 { 00905 if (repo->rpmdbid && entry >= repo->start && entry < repo->end) 00906 return repo->rpmdbid[entry - repo->start]; 00907 return notfound; 00908 } 00909 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00910 { 00911 if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) 00912 continue; 00913 if (!repodata_precheck_keyname(data, keyname)) 00914 continue; 00915 for (j = 1; j < data->nkeys; j++) 00916 { 00917 if (data->keys[j].name == keyname 00918 && (data->keys[j].type == REPOKEY_TYPE_U32 00919 || data->keys[j].type == REPOKEY_TYPE_NUM 00920 || data->keys[j].type == REPOKEY_TYPE_CONSTANT)) 00921 { 00922 unsigned value; 00923 if (repodata_lookup_num(data, entry, keyname, &value)) 00924 return value; 00925 } 00926 } 00927 } 00928 return notfound; 00929 } 00930 00931 Id 00932 repo_lookup_id(Repo *repo, Id entry, Id keyname) 00933 { 00934 Repodata *data; 00935 int i, j; 00936 00937 switch(keyname) 00938 { 00939 case SOLVABLE_NAME: 00940 return repo->pool->solvables[entry].name; 00941 case SOLVABLE_ARCH: 00942 return repo->pool->solvables[entry].arch; 00943 case SOLVABLE_EVR: 00944 return repo->pool->solvables[entry].evr; 00945 case SOLVABLE_VENDOR: 00946 return repo->pool->solvables[entry].vendor; 00947 } 00948 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00949 { 00950 if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) 00951 continue; 00952 if (!repodata_precheck_keyname(data, keyname)) 00953 continue; 00954 for (j = 1; j < data->nkeys; j++) 00955 { 00956 if (data->keys[j].name == keyname && (data->keys[j].type == REPOKEY_TYPE_ID || data->keys[j].type == REPOKEY_TYPE_CONSTANTID)) 00957 { 00958 Id id = repodata_lookup_id(data, entry, keyname); 00959 if (id) 00960 return data->localpool ? repodata_globalize_id(data, id, 1) : id; 00961 } 00962 } 00963 } 00964 return 0; 00965 } 00966 00967 const unsigned char * 00968 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep) 00969 { 00970 Repodata *data; 00971 int i, j; 00972 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00973 { 00974 if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) 00975 continue; 00976 if (!repodata_precheck_keyname(data, keyname)) 00977 continue; 00978 for (j = 1; j < data->nkeys; j++) 00979 { 00980 if (data->keys[j].name == keyname) 00981 { 00982 const unsigned char *chk = repodata_lookup_bin_checksum(data, entry, keyname, typep); 00983 if (chk) 00984 return chk; 00985 } 00986 } 00987 } 00988 *typep = 0; 00989 return 0; 00990 } 00991 00992 int 00993 repo_lookup_void(Repo *repo, Id entry, Id keyname) 00994 { 00995 Repodata *data; 00996 int i, j; 00997 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00998 { 00999 if (entry != SOLVID_META && (entry < data->start || entry >= data->end)) 01000 continue; 01001 if (!repodata_precheck_keyname(data, keyname)) 01002 continue; 01003 for (j = 1; j < data->nkeys; j++) 01004 { 01005 if (data->keys[j].name == keyname 01006 && (data->keys[j].type == REPOKEY_TYPE_VOID)) 01007 { 01008 if (repodata_lookup_void(data, entry, keyname)) 01009 return 1; 01010 } 01011 } 01012 } 01013 return 0; 01014 } 01015 01016 /***********************************************************************/ 01017 01018 Repodata * 01019 repo_add_repodata(Repo *repo, int flags) 01020 { 01021 int i; 01022 if ((flags & REPO_USE_LOADING) != 0) 01023 { 01024 for (i = repo->nrepodata - 1; i >= 0; i--) 01025 if (repo->repodata[i].state == REPODATA_LOADING) 01026 { 01027 Repodata *data = repo->repodata + i; 01028 /* re-init */ 01029 /* hack: we mis-use REPO_REUSE_REPODATA here */ 01030 if (!(flags & REPO_REUSE_REPODATA)) 01031 { 01032 repodata_freedata(data); 01033 repodata_initdata(data, repo, (flags & REPO_LOCALPOOL) ? 1 : 0); 01034 } 01035 return data; 01036 } 01037 return 0; /* must not create a new repodata! */ 01038 } 01039 if ((flags & REPO_REUSE_REPODATA) != 0) 01040 { 01041 for (i = repo->nrepodata - 1; i >= 0; i--) 01042 if (repo->repodata[i].state != REPODATA_STUB) 01043 return repo->repodata + i; 01044 } 01045 return repodata_create(repo, (flags & REPO_LOCALPOOL) ? 1 : 0); 01046 } 01047 01048 Repodata * 01049 repo_last_repodata(Repo *repo) 01050 { 01051 int i; 01052 for (i = repo->nrepodata - 1; i >= 0; i--) 01053 if (repo->repodata[i].state != REPODATA_STUB) 01054 return repo->repodata + i; 01055 return repo_add_repodata(repo, 0); 01056 } 01057 01058 void 01059 repo_set_id(Repo *repo, Id p, Id keyname, Id id) 01060 { 01061 Repodata *data = repo_last_repodata(repo); 01062 repodata_set_id(data, p, keyname, id); 01063 } 01064 01065 void 01066 repo_set_num(Repo *repo, Id p, Id keyname, Id num) 01067 { 01068 Repodata *data = repo_last_repodata(repo); 01069 repodata_set_num(data, p, keyname, num); 01070 } 01071 01072 void 01073 repo_set_str(Repo *repo, Id p, Id keyname, const char *str) 01074 { 01075 Repodata *data = repo_last_repodata(repo); 01076 repodata_set_str(data, p, keyname, str); 01077 } 01078 01079 void 01080 repo_set_poolstr(Repo *repo, Id p, Id keyname, const char *str) 01081 { 01082 Repodata *data = repo_last_repodata(repo); 01083 repodata_set_poolstr(data, p, keyname, str); 01084 } 01085 01086 void 01087 repo_add_poolstr_array(Repo *repo, Id p, Id keyname, const char *str) 01088 { 01089 Repodata *data = repo_last_repodata(repo); 01090 repodata_add_poolstr_array(data, p, keyname, str); 01091 } 01092 01093 void 01094 repo_internalize(Repo *repo) 01095 { 01096 int i; 01097 Repodata *data; 01098 01099 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 01100 if (data->attrs || data->xattrs) 01101 repodata_internalize(data); 01102 } 01103 01104 void 01105 repo_disable_paging(Repo *repo) 01106 { 01107 int i; 01108 Repodata *data; 01109 01110 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 01111 repodata_disable_paging(data); 01112 } 01113 // EOF 01114 /* 01115 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: 01116 */