repo.c

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

Generated on Mon Dec 15 17:56:24 2014 for satsolver by  doxygen 1.5.6