00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 #define _GNU_SOURCE
00018 #include <string.h>
00019 #include <fnmatch.h>
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <assert.h>
00025 #include <regex.h>
00026 
00027 #include "repo.h"
00028 #include "pool.h"
00029 #include "poolid_private.h"
00030 #include "util.h"
00031 #include "hash.h"
00032 #include "chksum.h"
00033 
00034 #include "repopack.h"
00035 #include "repopage.h"
00036 
00037 #define REPODATA_BLOCK 255
00038 
00039 static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
00040 
00041 void
00042 repodata_initdata(Repodata *data, Repo *repo, int localpool)
00043 {
00044   memset(data, 0, sizeof (*data));
00045   data->repo = repo;
00046   data->localpool = localpool;
00047   if (localpool)
00048     stringpool_init_empty(&data->spool);
00049   
00050   data->keys = sat_calloc(1, sizeof(Repokey));
00051   data->nkeys = 1;
00052   data->schemata = sat_calloc(1, sizeof(Id));
00053   data->schemadata = sat_calloc(1, sizeof(Id));
00054   data->nschemata = 1;
00055   data->schemadatalen = 1;
00056   repopagestore_init(&data->store);
00057 }
00058 
00059 void
00060 repodata_freedata(Repodata *data)
00061 {
00062   int i;
00063 
00064   sat_free(data->keys);
00065 
00066   sat_free(data->schemata);
00067   sat_free(data->schemadata);
00068   sat_free(data->schematahash);
00069 
00070   stringpool_free(&data->spool);
00071   dirpool_free(&data->dirpool);
00072 
00073   sat_free(data->mainschemaoffsets);
00074   sat_free(data->incoredata);
00075   sat_free(data->incoreoffset);
00076   sat_free(data->verticaloffset);
00077 
00078   repopagestore_free(&data->store);
00079 
00080   sat_free(data->vincore);
00081 
00082   if (data->attrs)
00083     for (i = 0; i < data->end - data->start; i++)
00084       sat_free(data->attrs[i]);
00085   sat_free(data->attrs);
00086   if (data->xattrs)
00087     for (i = 0; i < data->nxattrs; i++)
00088       sat_free(data->xattrs[i]);
00089   sat_free(data->xattrs);
00090 
00091   sat_free(data->attrdata);
00092   sat_free(data->attriddata);
00093 }
00094 
00095 Repodata *
00096 repodata_create(Repo *repo, int localpool)
00097 {
00098   Repodata *data;
00099 
00100   repo->nrepodata++;
00101   repo->repodata = sat_realloc2(repo->repodata, repo->nrepodata, sizeof(*data));
00102   data = repo->repodata + repo->nrepodata - 1;
00103   repodata_initdata(data, repo, localpool);
00104   return data;
00105 }
00106 
00107 void
00108 repodata_free(Repodata *data)
00109 {
00110   Repo *repo = data->repo;
00111   int i = data - repo->repodata;
00112   repodata_freedata(data);
00113   if (i < repo->nrepodata - 1)
00114     memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
00115   repo->nrepodata--;
00116 }
00117 
00118 void
00119 repodata_empty(Repodata *data, int localpool)
00120 {
00121   void (*loadcallback)(Repodata *) = data->loadcallback;
00122   int state = data->state;
00123   repodata_freedata(data);
00124   repodata_initdata(data, data->repo, localpool);
00125   data->state = state;
00126   data->loadcallback = loadcallback;
00127 }
00128 
00129 
00130 
00131 
00132 
00133 
00134 
00135 
00136 Id
00137 repodata_key2id(Repodata *data, Repokey *key, int create)
00138 {
00139   Id keyid;
00140 
00141   for (keyid = 1; keyid < data->nkeys; keyid++)
00142     if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
00143       {
00144         if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
00145           continue;
00146         break;
00147       }
00148   if (keyid == data->nkeys)
00149     {
00150       if (!create)
00151         return 0;
00152       
00153       data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
00154       data->keys[data->nkeys++] = *key;
00155       if (data->verticaloffset)
00156         {
00157           data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
00158           data->verticaloffset[data->nkeys - 1] = 0;
00159         }
00160       data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
00161     }
00162   return keyid;
00163 }
00164 
00165 
00166 
00167 
00168 
00169 
00170 #define SCHEMATA_BLOCK 31
00171 #define SCHEMATADATA_BLOCK 255
00172 
00173 Id
00174 repodata_schema2id(Repodata *data, Id *schema, int create)
00175 {
00176   int h, len, i;
00177   Id *sp, cid;
00178   Id *schematahash;
00179 
00180   if (!*schema)
00181     return 0;   
00182   if ((schematahash = data->schematahash) == 0)
00183     {
00184       data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
00185       for (i = 1; i < data->nschemata; i++)
00186         {
00187           for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
00188             h = h * 7 + *sp++;
00189           h &= 255;
00190           schematahash[h] = i;
00191         }
00192       data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
00193       data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
00194     }
00195 
00196   for (sp = schema, len = 0, h = 0; *sp; len++)
00197     h = h * 7 + *sp++;
00198   h &= 255;
00199   len++;
00200 
00201   cid = schematahash[h];
00202   if (cid)
00203     {
00204       if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
00205         return cid;
00206       
00207       for (cid = 1; cid < data->nschemata; cid++)
00208         if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
00209           return cid;
00210     }
00211   
00212   if (!create)
00213     return 0;
00214   data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
00215   data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
00216   
00217   memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
00218   data->schemata[data->nschemata] = data->schemadatalen;
00219   data->schemadatalen += len;
00220   schematahash[h] = data->nschemata;
00221 #if 0
00222 fprintf(stderr, "schema2id: new schema\n");
00223 #endif
00224   return data->nschemata++;
00225 }
00226 
00227 void
00228 repodata_free_schemahash(Repodata *data)
00229 {
00230   data->schematahash = sat_free(data->schematahash);
00231   
00232   data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
00233   data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
00234 }
00235 
00236 
00237 
00238 
00239 
00240 
00241 #ifndef HAVE_STRCHRNUL
00242 static inline const char *strchrnul(const char *str, char x)
00243 {
00244   const char *p = strchr(str, x);
00245   return p ? p : str + strlen(str);
00246 }
00247 #endif
00248 
00249 Id
00250 repodata_str2dir(Repodata *data, const char *dir, int create)
00251 {
00252   Id id, parent;
00253   const char *dire;
00254 
00255   parent = 0;
00256   while (*dir == '/' && dir[1] == '/')
00257     dir++;
00258   if (*dir == '/' && !dir[1])
00259     {
00260       if (data->dirpool.ndirs)
00261         return 1;
00262       return dirpool_add_dir(&data->dirpool, 0, 1, create);
00263     }
00264   while (*dir)
00265     {
00266       dire = strchrnul(dir, '/');
00267       if (data->localpool)
00268         id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
00269       else
00270         id = strn2id(data->repo->pool, dir, dire - dir, create);
00271       if (!id)
00272         return 0;
00273       parent = dirpool_add_dir(&data->dirpool, parent, id, create);
00274       if (!parent)
00275         return 0;
00276       if (!*dire)
00277         break;
00278       dir = dire + 1;
00279       while (*dir == '/')
00280         dir++;
00281     }
00282   return parent;
00283 }
00284 
00285 const char *
00286 repodata_dir2str(Repodata *data, Id did, const char *suf)
00287 {
00288   Pool *pool = data->repo->pool;
00289   int l = 0;
00290   Id parent, comp;
00291   const char *comps;
00292   char *p;
00293 
00294   if (!did)
00295     return suf ? suf : "";
00296   parent = did;
00297   while (parent)
00298     {
00299       comp = dirpool_compid(&data->dirpool, parent);
00300       comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
00301       l += strlen(comps);
00302       parent = dirpool_parent(&data->dirpool, parent);
00303       if (parent)
00304         l++;
00305     }
00306   if (suf)
00307     l += strlen(suf) + 1;
00308   p = pool_alloctmpspace(pool, l + 1) + l;
00309   *p = 0;
00310   if (suf)
00311     {
00312       p -= strlen(suf);
00313       strcpy(p, suf);
00314       *--p = '/';
00315     }
00316   parent = did;
00317   while (parent)
00318     {
00319       comp = dirpool_compid(&data->dirpool, parent);
00320       comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
00321       l = strlen(comps);
00322       p -= l;
00323       strncpy(p, comps, l);
00324       parent = dirpool_parent(&data->dirpool, parent);
00325       if (parent)
00326         *--p = '/';
00327     }
00328   return p;
00329 }
00330 
00331 
00332 
00333 
00334 
00335 
00336 static inline unsigned char *
00337 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
00338 {
00339   Id *keyp = data->schemadata + data->schemata[schema];
00340   for (; *keyp; keyp++)
00341     dp = data_skip_key(data, dp, data->keys + *keyp);
00342   return dp;
00343 }
00344 
00345 static unsigned char *
00346 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
00347 {
00348   int nentries, schema;
00349   switch(key->type)
00350     {
00351     case REPOKEY_TYPE_FIXARRAY:
00352       dp = data_read_id(dp, &nentries);
00353       if (!nentries)
00354         return dp;
00355       dp = data_read_id(dp, &schema);
00356       while (nentries--)
00357         dp = data_skip_schema(data, dp, schema);
00358       return dp;
00359     case REPOKEY_TYPE_FLEXARRAY:
00360       dp = data_read_id(dp, &nentries);
00361       while (nentries--)
00362         {
00363           dp = data_read_id(dp, &schema);
00364           dp = data_skip_schema(data, dp, schema);
00365         }
00366       return dp;
00367     default:
00368       if (key->storage == KEY_STORAGE_INCORE)
00369         dp = data_skip(dp, key->type);
00370       else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
00371         {
00372           dp = data_skip(dp, REPOKEY_TYPE_ID);
00373           dp = data_skip(dp, REPOKEY_TYPE_ID);
00374         }
00375       return dp;
00376     }
00377 }
00378 
00379 static unsigned char *
00380 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
00381 {
00382   Id k;
00383 
00384   if (!keyid)
00385     return 0;
00386   if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
00387     {
00388       int i;
00389       for (i = 0; (k = *keyp++) != 0; i++)
00390         if (k == keyid)
00391           return data->incoredata + data->mainschemaoffsets[i];
00392       return 0;
00393     }
00394   while ((k = *keyp++) != 0)
00395     {
00396       if (k == keyid)
00397         return dp;
00398       if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
00399         {
00400           dp = data_skip(dp, REPOKEY_TYPE_ID);  
00401           dp = data_skip(dp, REPOKEY_TYPE_ID);  
00402           continue;
00403         }
00404       if (data->keys[k].storage != KEY_STORAGE_INCORE)
00405         continue;
00406       dp = data_skip_key(data, dp, data->keys + k);
00407     }
00408   return 0;
00409 }
00410 
00411 static unsigned char *
00412 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
00413 {
00414   unsigned char *dp;
00415   if (!len)
00416     return 0;
00417   if (off >= data->lastverticaloffset)
00418     {
00419       off -= data->lastverticaloffset;
00420       if (off + len > data->vincorelen)
00421         return 0;
00422       return data->vincore + off;
00423     }
00424   if (off + len > key->size)
00425     return 0;
00426   
00427   off += data->verticaloffset[key - data->keys];
00428   
00429   dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
00430   if (dp)
00431     dp += off % BLOB_PAGESIZE;
00432   return dp;
00433 }
00434 
00435 static inline unsigned char *
00436 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
00437 {
00438   unsigned char *dp = *dpp;
00439 
00440   if (!dp)
00441     return 0;
00442   if (key->storage == KEY_STORAGE_INCORE)
00443     {
00444       if (advance)
00445         *dpp = data_skip_key(data, dp, key);
00446       return dp;
00447     }
00448   else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
00449     {
00450       Id off, len;
00451       dp = data_read_id(dp, &off);
00452       dp = data_read_id(dp, &len);
00453       if (advance)
00454         *dpp = dp;
00455       return get_vertical_data(data, key, off, len);
00456     }
00457   return 0;
00458 }
00459 
00460 static int
00461 load_repodata(Repodata *data)
00462 {
00463   if (data->loadcallback)
00464     {
00465       data->loadcallback(data);
00466       if (data->state == REPODATA_AVAILABLE)
00467         return 1;
00468     }
00469   data->state = REPODATA_ERROR;
00470   return 0;
00471 }
00472 
00473 static inline int
00474 maybe_load_repodata(Repodata *data, Id keyname)
00475 {
00476   if (keyname && !repodata_precheck_keyname(data, keyname))
00477     return 0;   
00478   switch(data->state)
00479     {
00480     case REPODATA_STUB:
00481       if (keyname)
00482         {
00483           int i;
00484           for (i = 0; i < data->nkeys; i++)
00485             if (keyname == data->keys[i].name)
00486               break;
00487           if (i == data->nkeys)
00488             return 0;
00489         }
00490       return load_repodata(data);
00491     case REPODATA_ERROR:
00492       return 0;
00493     case REPODATA_AVAILABLE:
00494     case REPODATA_LOADING:
00495       return 1;
00496     default:
00497       data->state = REPODATA_ERROR;
00498       return 0;
00499     }
00500 }
00501 
00502 static inline unsigned char *
00503 solvid2data(Repodata *data, Id solvid, Id *schemap)
00504 {
00505   unsigned char *dp = data->incoredata;
00506   if (!dp)
00507     return 0;
00508   if (solvid == SOLVID_META)    
00509     dp += 1;
00510   else if (solvid == SOLVID_POS)        
00511     {
00512       Pool *pool = data->repo->pool;
00513       if (data->repo != pool->pos.repo)
00514         return 0;
00515       if (data != data->repo->repodata + pool->pos.repodataid)
00516         return 0;
00517       *schemap = pool->pos.schema;
00518       return data->incoredata + pool->pos.dp;
00519     }
00520   else
00521     {
00522       if (solvid < data->start || solvid >= data->end)
00523         return 0;
00524       dp += data->incoreoffset[solvid - data->start];
00525     }
00526   return data_read_id(dp, schemap);
00527 }
00528 
00529 
00530 
00531 
00532 
00533 static inline unsigned char *
00534 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
00535 {
00536   unsigned char *dp;
00537   Id schema, *keyp, *kp;
00538   Repokey *key;
00539 
00540   if (!maybe_load_repodata(data, keyname))
00541     return 0;
00542   dp = solvid2data(data, solvid, &schema);
00543   if (!dp)
00544     return 0;
00545   keyp = data->schemadata + data->schemata[schema];
00546   for (kp = keyp; *kp; kp++)
00547     if (data->keys[*kp].name == keyname)
00548       break;
00549   if (!*kp)
00550     return 0;
00551   *keypp = key = data->keys + *kp;
00552   if (key->type == REPOKEY_TYPE_DELETED)
00553     return 0;
00554   if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
00555     return dp;  
00556   dp = forward_to_key(data, *kp, keyp, dp);
00557   if (!dp)
00558     return 0;
00559   return get_data(data, key, &dp, 0);
00560 }
00561 
00562 Id
00563 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
00564 {
00565   Id schema, *keyp, *kp;
00566   if (!maybe_load_repodata(data, keyname))
00567     return 0;
00568   if (!solvid2data(data, solvid, &schema))
00569     return 0;
00570   keyp = data->schemadata + data->schemata[schema];
00571   for (kp = keyp; *kp; kp++)
00572     if (data->keys[*kp].name == keyname)
00573       return data->keys[*kp].type;
00574   return 0;
00575 }
00576 
00577 Id
00578 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
00579 {
00580   unsigned char *dp;
00581   Repokey *key;
00582   Id id;
00583 
00584   dp = find_key_data(data, solvid, keyname, &key);
00585   if (!dp)
00586     return 0;
00587   if (key->type == REPOKEY_TYPE_CONSTANTID)
00588     return key->size;
00589   if (key->type != REPOKEY_TYPE_ID)
00590     return 0;
00591   dp = data_read_id(dp, &id);
00592   return id;
00593 }
00594 
00595 const char *
00596 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
00597 {
00598   unsigned char *dp;
00599   Repokey *key;
00600   Id id;
00601 
00602   dp = find_key_data(data, solvid, keyname, &key);
00603   if (!dp)
00604     return 0;
00605   if (key->type == REPOKEY_TYPE_STR)
00606     return (const char *)dp;
00607   if (key->type == REPOKEY_TYPE_CONSTANTID)
00608     id = key->size;
00609   else if (key->type == REPOKEY_TYPE_ID)
00610     dp = data_read_id(dp, &id);
00611   else
00612     return 0;
00613   if (data->localpool)
00614     return stringpool_id2str(&data->spool, id);
00615   return id2str(data->repo->pool, id);
00616 }
00617 
00618 int
00619 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
00620 {
00621   unsigned char *dp;
00622   Repokey *key;
00623   KeyValue kv;
00624 
00625   *value = 0;
00626   dp = find_key_data(data, solvid, keyname, &key);
00627   if (!dp)
00628     return 0;
00629   if (key->type == REPOKEY_TYPE_NUM
00630       || key->type == REPOKEY_TYPE_U32
00631       || key->type == REPOKEY_TYPE_CONSTANT)
00632     {
00633       kv.num = 0;
00634       dp = data_fetch(dp, &kv, key);
00635       *value = kv.num;
00636       return 1;
00637     }
00638   return 0;
00639 }
00640 
00641 int
00642 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
00643 {
00644   Id schema;
00645   Id *keyp;
00646   unsigned char *dp;
00647 
00648   if (!maybe_load_repodata(data, keyname))
00649     return 0;
00650   dp = solvid2data(data, solvid, &schema);
00651   if (!dp)
00652     return 0;
00653   
00654   for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
00655     if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
00656       return 1;
00657   return 0;
00658 }
00659 
00660 const unsigned char *
00661 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
00662 {
00663   unsigned char *dp;
00664   Repokey *key;
00665 
00666   dp = find_key_data(data, solvid, keyname, &key);
00667   if (!dp)
00668     return 0;
00669   *typep = key->type;
00670   return dp;
00671 }
00672 
00673 int
00674 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
00675 {
00676   unsigned char *dp;
00677   Repokey *key;
00678   Id id;
00679   int eof = 0;
00680 
00681   queue_empty(q);
00682   dp = find_key_data(data, solvid, keyname, &key);
00683   if (!dp)
00684     return 0;
00685   if (key->type != REPOKEY_TYPE_IDARRAY && key->type != REPOKEY_TYPE_REL_IDARRAY)
00686     return 0;
00687   for (;;)
00688     {
00689       dp = data_read_ideof(dp, &id, &eof);
00690       queue_push(q, id);
00691       if (eof)
00692         break;
00693     }
00694   return 1;
00695 }
00696 
00697 Id
00698 repodata_globalize_id(Repodata *data, Id id, int create)
00699 {
00700   if (!id || !data || !data->localpool)
00701     return id;
00702   return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
00703 }
00704 
00705 Id
00706 repodata_localize_id(Repodata *data, Id id, int create)
00707 {
00708   if (!id || !data || !data->localpool)
00709     return id;
00710   return stringpool_str2id(&data->spool, id2str(data->repo->pool, id), create);
00711 }
00712 
00713 
00714 
00715 
00716 
00717 
00718 
00719 int
00720 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
00721 {
00722   switch (key->type)
00723     {
00724     case REPOKEY_TYPE_ID:
00725     case REPOKEY_TYPE_CONSTANTID:
00726     case REPOKEY_TYPE_IDARRAY:
00727       if (data && data->localpool)
00728         kv->str = stringpool_id2str(&data->spool, kv->id);
00729       else
00730         kv->str = id2str(pool, kv->id);
00731       if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
00732         {
00733           const char *s;
00734           for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
00735             ;
00736           if (*s == ':' && s > kv->str)
00737             kv->str = s + 1;
00738         }
00739       return 1;
00740     case REPOKEY_TYPE_STR:
00741       return 1;
00742     case REPOKEY_TYPE_DIRSTRARRAY:
00743       if (!(flags & SEARCH_FILES))
00744         return 1;       
00745       
00746       kv->str = repodata_dir2str(data, kv->id, kv->str);
00747       
00748 
00749 
00750       kv->id = 0;
00751       return 1;
00752     case REPOKEY_TYPE_MD5:
00753     case REPOKEY_TYPE_SHA1:
00754     case REPOKEY_TYPE_SHA256:
00755       if (!(flags & SEARCH_CHECKSUMS))
00756         return 0;       
00757       kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
00758       return 1;
00759     default:
00760       return 0;
00761     }
00762 }
00763 
00764 
00765 struct subschema_data {
00766   Solvable *s;
00767   void *cbdata;
00768   KeyValue *parent;
00769 };
00770 
00771 
00772 void
00773 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
00774 {
00775   Id schema;
00776   Repokey *key;
00777   Id keyid, *kp, *keyp;
00778   unsigned char *dp, *ddp;
00779   int onekey = 0;
00780   int stop;
00781   KeyValue kv;
00782   Solvable *s;
00783 
00784   if (!maybe_load_repodata(data, keyname))
00785     return;
00786   if (solvid == SOLVID_SUBSCHEMA)
00787     {
00788       struct subschema_data *subd = cbdata;
00789       cbdata = subd->cbdata;
00790       s = subd->s;
00791       schema = subd->parent->id;
00792       dp = (unsigned char *)subd->parent->str;
00793       kv.parent = subd->parent;
00794     }
00795   else
00796     {
00797       schema = 0;
00798       dp = solvid2data(data, solvid, &schema);
00799       if (!dp)
00800         return;
00801       s = data->repo->pool->solvables + solvid;
00802       kv.parent = 0;
00803     }
00804   keyp = data->schemadata + data->schemata[schema];
00805   if (keyname)
00806     {
00807       
00808       for (kp = keyp; *kp; kp++)
00809         if (data->keys[*kp].name == keyname)
00810           break;
00811       if (!*kp)
00812         return;
00813       dp = forward_to_key(data, *kp, keyp, dp);
00814       if (!dp)
00815         return;
00816       keyp = kp;
00817       onekey = 1;
00818     }
00819   while ((keyid = *keyp++) != 0)
00820     {
00821       stop = 0;
00822       key = data->keys + keyid;
00823       ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
00824 
00825       if (key->type == REPOKEY_TYPE_DELETED)
00826         continue;
00827       if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
00828         {
00829           struct subschema_data subd;
00830           int nentries;
00831           Id schema = 0;
00832 
00833           subd.cbdata = cbdata;
00834           subd.s = s;
00835           subd.parent = &kv;
00836           ddp = data_read_id(ddp, &nentries);
00837           kv.num = nentries;
00838           kv.entry = 0;
00839           kv.eof = 0;
00840           while (ddp && nentries > 0)
00841             {
00842               if (!--nentries)
00843                 kv.eof = 1;
00844               if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
00845                 ddp = data_read_id(ddp, &schema);
00846               kv.id = schema;
00847               kv.str = (char *)ddp;
00848               stop = callback(cbdata, s, data, key, &kv);
00849               if (stop > SEARCH_NEXT_KEY)
00850                 return;
00851               if (stop && stop != SEARCH_ENTERSUB)
00852                 break;
00853               if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
00854                 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
00855               ddp = data_skip_schema(data, ddp, schema);
00856               kv.entry++;
00857             }
00858           if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
00859             {
00860               
00861               kv.eof = 2;
00862               kv.str = (char *)ddp;
00863               stop = callback(cbdata, s, data, key, &kv);
00864               if (stop > SEARCH_NEXT_KEY)
00865                 return;
00866             }
00867           if (onekey)
00868             return;
00869           continue;
00870         }
00871       kv.entry = 0;
00872       do
00873         {
00874           ddp = data_fetch(ddp, &kv, key);
00875           if (!ddp)
00876             break;
00877           stop = callback(cbdata, s, data, key, &kv);
00878           kv.entry++;
00879         }
00880       while (!kv.eof && !stop);
00881       if (onekey || stop > SEARCH_NEXT_KEY)
00882         return;
00883     }
00884 }
00885 
00886 void
00887 repodata_setpos_kv(Repodata *data, KeyValue *kv)
00888 {
00889   Pool *pool = data->repo->pool;
00890   if (!kv)
00891     pool_clear_pos(pool);
00892   else
00893     {
00894       pool->pos.repo = data->repo;
00895       pool->pos.repodataid = data - data->repo->repodata;
00896       pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
00897       pool->pos.schema = kv->id;
00898     }
00899 }
00900 
00901 
00902 
00903 
00904 
00905 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
00906   { SOLVABLE_NAME,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
00907   { SOLVABLE_ARCH,        REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
00908   { SOLVABLE_EVR,         REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
00909   { SOLVABLE_VENDOR,      REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
00910   { SOLVABLE_PROVIDES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00911   { SOLVABLE_OBSOLETES,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00912   { SOLVABLE_CONFLICTS,   REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00913   { SOLVABLE_REQUIRES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00914   { SOLVABLE_RECOMMENDS,  REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00915   { SOLVABLE_SUGGESTS,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00916   { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00917   { SOLVABLE_ENHANCES,    REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
00918   { RPM_RPMDBID,          REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
00919 };
00920 
00921 static inline Id *
00922 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
00923 {
00924   kv->id = keyname;
00925   switch (keyname)
00926     {
00927     case SOLVABLE_NAME:
00928       kv->eof = 1;
00929       return &s->name;
00930     case SOLVABLE_ARCH:
00931       kv->eof = 1;
00932       return &s->arch;
00933     case SOLVABLE_EVR:
00934       kv->eof = 1;
00935       return &s->evr;
00936     case SOLVABLE_VENDOR:
00937       kv->eof = 1;
00938       return &s->vendor;
00939     case SOLVABLE_PROVIDES:
00940       kv->eof = 0;
00941       return s->provides ? s->repo->idarraydata + s->provides : 0;
00942     case SOLVABLE_OBSOLETES:
00943       kv->eof = 0;
00944       return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
00945     case SOLVABLE_CONFLICTS:
00946       kv->eof = 0;
00947       return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
00948     case SOLVABLE_REQUIRES:
00949       kv->eof = 0;
00950       return s->requires ? s->repo->idarraydata + s->requires : 0;
00951     case SOLVABLE_RECOMMENDS:
00952       kv->eof = 0;
00953       return s->recommends ? s->repo->idarraydata + s->recommends : 0;
00954     case SOLVABLE_SUPPLEMENTS:
00955       kv->eof = 0;
00956       return s->supplements ? s->repo->idarraydata + s->supplements : 0;
00957     case SOLVABLE_SUGGESTS:
00958       kv->eof = 0;
00959       return s->suggests ? s->repo->idarraydata + s->suggests : 0;
00960     case SOLVABLE_ENHANCES:
00961       kv->eof = 0;
00962       return s->enhances ? s->repo->idarraydata + s->enhances : 0;
00963     case RPM_RPMDBID:
00964       kv->eof = 1;
00965       return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
00966     default:
00967       return 0;
00968     }
00969 }
00970 
00971 int
00972 datamatcher_init(Datamatcher *ma, const char *match, int flags)
00973 {
00974   ma->match = match;
00975   ma->flags = flags;
00976   ma->error = 0;
00977   ma->matchdata = 0;
00978   if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
00979     {
00980       ma->matchdata = sat_calloc(1, sizeof(regex_t));
00981       ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
00982       if (ma->error)
00983         {
00984           sat_free(ma->matchdata);
00985           ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
00986         }
00987     }
00988   return ma->error;
00989 }
00990 
00991 void
00992 datamatcher_free(Datamatcher *ma)
00993 {
00994   if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
00995     {
00996       regfree(ma->matchdata);
00997       ma->matchdata = sat_free(ma->matchdata);
00998     }
00999 }
01000 
01001 int
01002 datamatcher_match(Datamatcher *ma, const char *str)
01003 {
01004   int l;
01005   switch ((ma->flags & SEARCH_STRINGMASK))
01006     {
01007     case SEARCH_SUBSTRING:
01008       if (ma->flags & SEARCH_NOCASE)
01009         {
01010           if (!strcasestr(str, ma->match))
01011             return 0;
01012         }
01013       else
01014         {
01015           if (!strstr(str, ma->match))
01016             return 0;
01017         }
01018       break;
01019     case SEARCH_STRING:
01020       if (ma->flags & SEARCH_NOCASE)
01021         {
01022           if (strcasecmp(ma->match, str))
01023             return 0;
01024         }
01025       else
01026         {
01027           if (strcmp(ma->match, str))
01028             return 0;
01029         }
01030       break;
01031     case SEARCH_STRINGSTART:
01032       if (ma->flags & SEARCH_NOCASE)
01033         {
01034           if (strncasecmp(ma->match, str, strlen(ma->match)))
01035             return 0;
01036         }
01037       else
01038         {
01039           if (strncmp(ma->match, str, strlen(ma->match)))
01040             return 0;
01041         }
01042       break;
01043     case SEARCH_STRINGEND:
01044       l = strlen(str) - strlen(ma->match);
01045       if (l < 0)
01046         return 0;
01047       if (ma->flags & SEARCH_NOCASE)
01048         {
01049           if (strcasecmp(ma->match, str + l))
01050             return 0;
01051         }
01052       else
01053         {
01054           if (strcmp(ma->match, str + l))
01055             return 0;
01056         }
01057       break;
01058     case SEARCH_GLOB:
01059       if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
01060         return 0;
01061       break;
01062     case SEARCH_REGEX:
01063       if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
01064         return 0;
01065       break;
01066     default:
01067       return 0;
01068     }
01069   return 1;
01070 }
01071 
01072 int
01073 repodata_filelistfilter_matches(Repodata *data, const char *str)
01074 {
01075   
01076   
01077   if (strstr(str, "bin/"))
01078     return 1;
01079   if (!strncmp(str, "/etc/", 5))
01080     return 1;
01081   if (!strcmp(str, "/usr/lib/sendmail"))
01082     return 1;
01083   return 0;
01084 }
01085 
01086 
01087 enum {
01088   di_bye,
01089 
01090   di_enterrepo,
01091   di_entersolvable,
01092   di_enterrepodata,
01093   di_enterschema,
01094   di_enterkey,
01095 
01096   di_nextattr,
01097   di_nextkey,
01098   di_nextrepodata,
01099   di_nextsolvable,
01100   di_nextrepo,
01101 
01102   di_enterarray,
01103   di_nextarrayelement,
01104 
01105   di_entersub,
01106   di_leavesub,
01107 
01108   di_nextsolvableattr,
01109   di_nextsolvablekey,
01110   di_entersolvablekey
01111 };
01112 
01113 
01114 int
01115 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
01116 {
01117   memset(di, 0, sizeof(*di));
01118   di->pool = pool;
01119   di->flags = flags & ~SEARCH_THISSOLVID;
01120   if (!pool || (repo && repo->pool != pool))
01121     {
01122       di->state = di_bye;
01123       return -1;
01124     }
01125   if (match)
01126     {
01127       int error;
01128       if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
01129         {
01130           di->state = di_bye;
01131           return error;
01132         }
01133     }
01134   di->keyname = keyname;
01135   di->keynames[0] = keyname;
01136   dataiterator_set_search(di, repo, p);
01137   return 0;
01138 }
01139 
01140 void
01141 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
01142 {
01143   *di = *from;
01144   memset(&di->matcher, 0, sizeof(di->matcher));
01145   if (from->matcher.match)
01146     datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
01147   if (di->nparents)
01148     {
01149       
01150       int i;
01151       for (i = 1; i < di->nparents; i++)
01152         di->parents[i].kv.parent = &di->parents[i - 1].kv;
01153       di->kv.parent = &di->parents[di->nparents - 1].kv;
01154     }
01155 }
01156 
01157 int
01158 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
01159 {
01160   di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
01161   datamatcher_free(&di->matcher);
01162   memset(&di->matcher, 0, sizeof(di->matcher));
01163   if (match)
01164     {
01165       int error;
01166       if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
01167         {
01168           di->state = di_bye;
01169           return error;
01170         }
01171     }
01172   return 0;
01173 }
01174 
01175 void
01176 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
01177 {
01178   di->repo = repo;
01179   di->repoid = -1;
01180   di->flags &= ~SEARCH_THISSOLVID;
01181   di->nparents = 0;
01182   di->rootlevel = 0;
01183   di->repodataid = 0;
01184   if (!di->pool->nrepos)
01185     {
01186       di->state = di_bye;
01187       return;
01188     }
01189   if (!repo)
01190     {
01191       di->repoid = 0;
01192       di->repo = di->pool->repos[0];
01193     }
01194   di->state = di_enterrepo;
01195   if (p)
01196     dataiterator_jump_to_solvid(di, p);
01197 }
01198 
01199 void
01200 dataiterator_set_keyname(Dataiterator *di, Id keyname)
01201 {
01202   di->nkeynames = 0;
01203   di->keyname = keyname;
01204   di->keynames[0] = keyname;
01205 }
01206 
01207 void
01208 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
01209 {
01210   int i;
01211 
01212   if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
01213     {
01214       di->state = di_bye;       
01215       return;
01216     }
01217   for (i = di->nkeynames + 1; i > 0; i--)
01218     di->keynames[i] = di->keynames[i - 1];
01219   di->keynames[0] = di->keyname = keyname;
01220   di->nkeynames++;
01221 }
01222 
01223 void
01224 dataiterator_free(Dataiterator *di)
01225 {
01226   if (di->matcher.match)
01227     datamatcher_free(&di->matcher);
01228 }
01229 
01230 static inline unsigned char *
01231 dataiterator_find_keyname(Dataiterator *di, Id keyname)
01232 {
01233   Id *keyp = di->keyp;
01234   Repokey *keys = di->data->keys;
01235   unsigned char *dp;
01236 
01237   for (keyp = di->keyp; *keyp; keyp++)
01238     if (keys[*keyp].name == keyname)
01239       break;
01240   if (!*keyp)
01241     return 0;
01242   dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
01243   if (!dp)
01244     return 0;
01245   di->keyp = keyp;
01246   return dp;
01247 }
01248 
01249 static int
01250 dataiterator_filelistcheck(Dataiterator *di)
01251 {
01252   int j;
01253   int needcomplete = 0;
01254   Repodata *data = di->data;
01255 
01256   if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
01257     if (!di->matcher.match
01258        || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
01259            && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
01260        || !repodata_filelistfilter_matches(di->data, di->matcher.match))
01261       needcomplete = 1;
01262   if (data->state != REPODATA_AVAILABLE)
01263     return needcomplete ? 1 : 0;
01264   for (j = 1; j < data->nkeys; j++)
01265     if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
01266       break;
01267   return j == data->nkeys && !needcomplete ? 0 : 1;
01268 }
01269 
01270 int
01271 dataiterator_step(Dataiterator *di)
01272 {
01273   Id schema;
01274 
01275   for (;;)
01276     {
01277       switch (di->state)
01278         {
01279         case di_enterrepo: di_enterrepo:
01280           if (!di->repo)
01281             goto di_bye;
01282           if (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS))
01283             goto di_nextrepo;
01284           if (!(di->flags & SEARCH_THISSOLVID))
01285             {
01286               di->solvid = di->repo->start - 1; 
01287               goto di_nextsolvable;
01288             }
01289           
01290 
01291         case di_entersolvable: di_entersolvable:
01292           if (di->repodataid >= 0)
01293             {
01294               di->repodataid = 0;       
01295               if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
01296                 {
01297                   di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
01298                   di->data = 0;
01299                   goto di_entersolvablekey;
01300                 }
01301             }
01302           
01303 
01304         case di_enterrepodata: di_enterrepodata:
01305           if (di->repodataid >= 0)
01306             {
01307               if (di->repodataid >= di->repo->nrepodata)
01308                 goto di_nextsolvable;
01309               di->data = di->repo->repodata + di->repodataid;
01310             }
01311           if (di->repodataid >= 0 && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
01312             goto di_nextrepodata;
01313           if (!maybe_load_repodata(di->data, di->keyname))
01314             goto di_nextrepodata;
01315           di->dp = solvid2data(di->data, di->solvid, &schema);
01316           if (!di->dp)
01317             goto di_nextrepodata;
01318           if (di->solvid == SOLVID_POS)
01319             di->solvid = di->pool->pos.solvid;
01320           
01321           di->keyp = di->data->schemadata + di->data->schemata[schema];
01322           
01323 
01324         case di_enterschema: di_enterschema:
01325           if (di->keyname)
01326             di->dp = dataiterator_find_keyname(di, di->keyname);
01327           if (!di->dp || !*di->keyp)
01328             {
01329               if (di->kv.parent)
01330                 goto di_leavesub;
01331               goto di_nextrepodata;
01332             }
01333           
01334 
01335         case di_enterkey: di_enterkey:
01336           di->kv.entry = -1;
01337           di->key = di->data->keys + *di->keyp;
01338           di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
01339           if (!di->ddp)
01340             goto di_nextkey;
01341           if (di->key->type == REPOKEY_TYPE_DELETED)
01342             goto di_nextkey;
01343           if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
01344             goto di_enterarray;
01345           if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
01346             goto di_nextkey;
01347           
01348 
01349         case di_nextattr:
01350           di->kv.entry++;
01351           di->ddp = data_fetch(di->ddp, &di->kv, di->key);
01352           if (di->kv.eof)
01353             di->state = di_nextkey;
01354           else
01355             di->state = di_nextattr;
01356           break;
01357 
01358         case di_nextkey: di_nextkey:
01359           if (!di->keyname && *++di->keyp)
01360             goto di_enterkey;
01361           if (di->kv.parent)
01362             goto di_leavesub;
01363           
01364 
01365         case di_nextrepodata: di_nextrepodata:
01366           if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
01367               goto di_enterrepodata;
01368           
01369 
01370         case di_nextsolvable: di_nextsolvable:
01371           if (!(di->flags & SEARCH_THISSOLVID))
01372             {
01373               if (di->solvid < 0)
01374                 di->solvid = di->repo->start;
01375               else
01376                 di->solvid++;
01377               for (; di->solvid < di->repo->end; di->solvid++)
01378                 {
01379                   if (di->pool->solvables[di->solvid].repo == di->repo)
01380                     goto di_entersolvable;
01381                 }
01382             }
01383           
01384 
01385         case di_nextrepo: di_nextrepo:
01386           if (di->repoid >= 0)
01387             {
01388               di->repoid++;
01389               di->repodataid = 0;
01390               if (di->repoid < di->pool->nrepos)
01391                 {
01392                   di->repo = di->pool->repos[di->repoid];
01393                   goto di_enterrepo;
01394                 }
01395             }
01396         
01397 
01398         case di_bye: di_bye:
01399           di->state = di_bye;
01400           return 0;
01401 
01402         case di_enterarray: di_enterarray:
01403           if (di->key->name == REPOSITORY_SOLVABLES)
01404             goto di_nextkey;
01405           di->ddp = data_read_id(di->ddp, &di->kv.num);
01406           di->kv.eof = 0;
01407           di->kv.entry = -1;
01408           
01409 
01410         case di_nextarrayelement: di_nextarrayelement:
01411           di->kv.entry++;
01412           if (di->kv.entry)
01413             di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
01414           if (di->kv.entry == di->kv.num)
01415             {
01416               if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
01417                 goto di_nextkey;
01418               if (!(di->flags & SEARCH_ARRAYSENTINEL))
01419                 goto di_nextkey;
01420               di->kv.str = (char *)di->ddp;
01421               di->kv.eof = 2;
01422               di->state = di_nextkey;
01423               break;
01424             }
01425           if (di->kv.entry == di->kv.num - 1)
01426             di->kv.eof = 1;
01427           if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
01428             di->ddp = data_read_id(di->ddp, &di->kv.id);
01429           di->kv.str = (char *)di->ddp;
01430           if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
01431             goto di_entersub;
01432           if ((di->flags & SEARCH_SUB) != 0)
01433             di->state = di_entersub;
01434           else
01435             di->state = di_nextarrayelement;
01436           break;
01437 
01438         case di_entersub: di_entersub:
01439           if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
01440             goto di_nextarrayelement;   
01441           di->parents[di->nparents].kv = di->kv;
01442           di->parents[di->nparents].dp = di->dp;
01443           di->parents[di->nparents].keyp = di->keyp;
01444           di->dp = (unsigned char *)di->kv.str;
01445           di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
01446           memset(&di->kv, 0, sizeof(di->kv));
01447           di->kv.parent = &di->parents[di->nparents].kv;
01448           di->nparents++;
01449           di->keyname = di->keynames[di->nparents - di->rootlevel];
01450           goto di_enterschema;
01451 
01452         case di_leavesub: di_leavesub:
01453           if (di->nparents - 1 < di->rootlevel)
01454             goto di_bye;
01455           di->nparents--;
01456           di->dp = di->parents[di->nparents].dp;
01457           di->kv = di->parents[di->nparents].kv;
01458           di->keyp = di->parents[di->nparents].keyp;
01459           di->key = di->data->keys + *di->keyp;
01460           di->ddp = (unsigned char *)di->kv.str;
01461           di->keyname = di->keynames[di->nparents - di->rootlevel];
01462           goto di_nextarrayelement;
01463 
01464         
01465 
01466         case di_nextsolvableattr:
01467           di->kv.id = *di->idp++;
01468           di->kv.entry++;
01469           if (!*di->idp)
01470             {
01471               di->kv.eof = 1;
01472               di->state = di_nextsolvablekey;
01473             }
01474           break;
01475 
01476         case di_nextsolvablekey: di_nextsolvablekey:
01477           if (di->keyname || di->key->name == RPM_RPMDBID)
01478             goto di_enterrepodata;
01479           di->key++;
01480           
01481 
01482         case di_entersolvablekey: di_entersolvablekey:
01483           di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
01484           if (!di->idp || !di->idp[0])
01485             goto di_nextsolvablekey;
01486           di->kv.id = di->idp[0];
01487           di->kv.num = di->idp[0];
01488           di->idp++;
01489           if (!di->kv.eof && !di->idp[0])
01490             di->kv.eof = 1;
01491           di->kv.entry = 0;
01492           if (di->kv.eof)
01493             di->state = di_nextsolvablekey;
01494           else
01495             di->state = di_nextsolvableattr;
01496           break;
01497         }
01498 
01499       if (di->matcher.match)
01500         {
01501           
01502           if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && di->matcher.match && (di->matcher.flags & (SEARCH_FILES|SEARCH_NOCASE|SEARCH_STRINGMASK)) == (SEARCH_FILES|SEARCH_STRING))
01503             {
01504               int l = strlen(di->matcher.match) - strlen(di->kv.str);
01505               if (l < 0 || strcmp(di->matcher.match + l, di->kv.str))
01506                 continue;
01507             }
01508           if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
01509             {
01510               if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
01511                 return 1;
01512               continue;
01513             }
01514           if (!datamatcher_match(&di->matcher, di->kv.str))
01515             continue;
01516         }
01517       
01518       return 1;
01519     }
01520 }
01521 
01522 void
01523 dataiterator_entersub(Dataiterator *di)
01524 {
01525   if (di->state == di_nextarrayelement)
01526     di->state = di_entersub;
01527 }
01528 
01529 void
01530 dataiterator_setpos(Dataiterator *di)
01531 {
01532   if (di->kv.eof == 2)
01533     {
01534       pool_clear_pos(di->pool);
01535       return;
01536     }
01537   di->pool->pos.solvid = di->solvid;
01538   di->pool->pos.repo = di->repo;
01539   di->pool->pos.repodataid = di->data - di->repo->repodata;
01540   di->pool->pos.schema = di->kv.id;
01541   di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
01542 }
01543 
01544 void
01545 dataiterator_setpos_parent(Dataiterator *di)
01546 {
01547   if (!di->kv.parent || di->kv.parent->eof == 2)
01548     {
01549       pool_clear_pos(di->pool);
01550       return;
01551     }
01552   di->pool->pos.solvid = di->solvid;
01553   di->pool->pos.repo = di->repo;
01554   di->pool->pos.repodataid = di->data - di->repo->repodata;
01555   di->pool->pos.schema = di->kv.parent->id;
01556   di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
01557 }
01558 
01559 
01560 void
01561 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
01562 {
01563   di->state = from->state;
01564   di->flags &= ~SEARCH_THISSOLVID;
01565   di->flags |= (from->flags & SEARCH_THISSOLVID);
01566   di->repo = from->repo;
01567   di->data = from->data;
01568   di->dp = from->dp;
01569   di->ddp = from->ddp;
01570   di->idp = from->idp;
01571   di->keyp = from->keyp;
01572   di->key = from->key;
01573   di->kv = from->kv;
01574   di->repodataid = from->repodataid;
01575   di->solvid = from->solvid;
01576   di->repoid = from->repoid;
01577   di->rootlevel = from->rootlevel;
01578   memcpy(di->parents, from->parents, sizeof(from->parents));
01579   di->nparents = from->nparents;
01580   if (di->nparents)
01581     {
01582       int i;
01583       for (i = 1; i < di->nparents; i++)
01584         di->parents[i].kv.parent = &di->parents[i - 1].kv;
01585       di->kv.parent = &di->parents[di->nparents - 1].kv;
01586     }
01587 }
01588 
01589 void
01590 dataiterator_seek(Dataiterator *di, int whence)
01591 {
01592   if ((whence & DI_SEEK_STAY) != 0)
01593     di->rootlevel = di->nparents;
01594   switch (whence & ~DI_SEEK_STAY)
01595     {
01596     case DI_SEEK_CHILD:
01597       if (di->state != di_nextarrayelement)
01598         break;
01599       if ((whence & DI_SEEK_STAY) != 0)
01600         di->rootlevel = di->nparents + 1;       
01601       di->state = di_entersub;
01602       break;
01603     case DI_SEEK_PARENT:
01604       if (!di->nparents)
01605         {
01606           di->state = di_bye;
01607           break;
01608         }
01609       di->nparents--;
01610       if (di->rootlevel > di->nparents)
01611         di->rootlevel = di->nparents;
01612       di->dp = di->parents[di->nparents].dp;
01613       di->kv = di->parents[di->nparents].kv;
01614       di->keyp = di->parents[di->nparents].keyp;
01615       di->key = di->data->keys + *di->keyp;
01616       di->ddp = (unsigned char *)di->kv.str;
01617       di->keyname = di->keynames[di->nparents - di->rootlevel];
01618       di->state = di_nextarrayelement;
01619       break;
01620     case DI_SEEK_REWIND:
01621       if (!di->nparents)
01622         {
01623           di->state = di_bye;
01624           break;
01625         }
01626       di->dp = (unsigned char *)di->kv.parent->str;
01627       di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
01628       di->state = di_enterschema;
01629       break;
01630     default:
01631       break;
01632     }
01633 }
01634 
01635 void
01636 dataiterator_skip_attribute(Dataiterator *di)
01637 {
01638   if (di->state == di_nextsolvableattr)
01639     di->state = di_nextsolvablekey;
01640   else
01641     di->state = di_nextkey;
01642 }
01643 
01644 void
01645 dataiterator_skip_solvable(Dataiterator *di)
01646 {
01647   di->nparents = 0;
01648   di->kv.parent = 0;
01649   di->rootlevel = 0;
01650   di->keyname = di->keynames[0];
01651   di->state = di_nextsolvable;
01652 }
01653 
01654 void
01655 dataiterator_skip_repo(Dataiterator *di)
01656 {
01657   di->nparents = 0;
01658   di->kv.parent = 0;
01659   di->rootlevel = 0;
01660   di->keyname = di->keynames[0];
01661   di->state = di_nextrepo;
01662 }
01663 
01664 void
01665 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
01666 {
01667   di->nparents = 0;
01668   di->kv.parent = 0;
01669   di->rootlevel = 0;
01670   di->keyname = di->keynames[0];
01671   if (solvid == SOLVID_POS)
01672     {
01673       di->repo = di->pool->pos.repo;
01674       if (!di->repo)
01675         {
01676           di->state = di_bye;
01677           return;
01678         }
01679       di->repoid = -1;
01680       di->data = di->repo->repodata + di->pool->pos.repodataid;
01681       di->repodataid = -1;
01682       di->solvid = solvid;
01683       di->state = di_enterrepo;
01684       di->flags |= SEARCH_THISSOLVID;
01685       return;
01686     }
01687   if (solvid > 0)
01688     {
01689       di->repo = di->pool->solvables[solvid].repo;
01690       di->repoid = -1;
01691     }
01692   else if (di->repoid >= 0)
01693     {
01694       if (!di->pool->nrepos)
01695         {
01696           di->state = di_bye;
01697           return;
01698         }
01699       di->repo = di->pool->repos[0];
01700       di->repoid = 0;
01701     }
01702   di->repodataid = 0;
01703   di->solvid = solvid;
01704   if (solvid)
01705     di->flags |= SEARCH_THISSOLVID;
01706   di->state = di_enterrepo;
01707 }
01708 
01709 void
01710 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
01711 {
01712   di->nparents = 0;
01713   di->kv.parent = 0;
01714   di->rootlevel = 0;
01715   di->repo = repo;
01716   di->repoid = -1;
01717   di->repodataid = 0;
01718   di->solvid = 0;
01719   di->flags &= ~SEARCH_THISSOLVID;
01720   di->state = di_enterrepo;
01721 }
01722 
01723 int
01724 dataiterator_match(Dataiterator *di, Datamatcher *ma)
01725 {
01726   if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
01727     return 0;
01728   if (!ma)
01729     return 1;
01730   return datamatcher_match(ma, di->kv.str);
01731 }
01732 
01733 
01734 
01735 
01736 
01737 
01738 void
01739 repodata_extend(Repodata *data, Id p)
01740 {
01741   if (data->start == data->end)
01742     data->start = data->end = p;
01743   if (p >= data->end)
01744     {
01745       int old = data->end - data->start;
01746       int new = p - data->end + 1;
01747       if (data->attrs)
01748         {
01749           data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
01750           memset(data->attrs + old, 0, new * sizeof(Id *));
01751         }
01752       data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
01753       memset(data->incoreoffset + old, 0, new * sizeof(Id));
01754       data->end = p + 1;
01755     }
01756   if (p < data->start)
01757     {
01758       int old = data->end - data->start;
01759       int new = data->start - p;
01760       if (data->attrs)
01761         {
01762           data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
01763           memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
01764           memset(data->attrs, 0, new * sizeof(Id *));
01765         }
01766       data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
01767       memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
01768       memset(data->incoreoffset, 0, new * sizeof(Id));
01769       data->start = p;
01770     }
01771 }
01772 
01773 
01774 void
01775 repodata_shrink(Repodata *data, int end)
01776 {
01777   int i;
01778 
01779   if (data->end <= end)
01780     return;
01781   if (data->start >= end)
01782     {
01783       if (data->attrs)
01784         {
01785           for (i = 0; i < data->end - data->start; i++)
01786             sat_free(data->attrs[i]);
01787           data->attrs = sat_free(data->attrs);
01788         }
01789       data->incoreoffset = sat_free(data->incoreoffset);
01790       data->start = data->end = 0;
01791       return;
01792     }
01793   if (data->attrs)
01794     {
01795       for (i = end; i < data->end; i++)
01796         sat_free(data->attrs[i - data->start]);
01797       data->attrs = sat_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
01798     }
01799   if (data->incoreoffset)
01800     data->incoreoffset = sat_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
01801   data->end = end;
01802 }
01803 
01804 
01805 void
01806 repodata_extend_block(Repodata *data, Id start, Id num)
01807 {
01808   if (!num)
01809     return;
01810   if (!data->incoreoffset)
01811     {
01812       data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
01813       data->start = start;
01814       data->end = start + num;
01815       return;
01816     }
01817   repodata_extend(data, start);
01818   if (num > 1)
01819     repodata_extend(data, start + num - 1);
01820 }
01821 
01822 
01823 
01824 
01825 #define REPODATA_ATTRS_BLOCK 31
01826 #define REPODATA_ATTRDATA_BLOCK 1023
01827 #define REPODATA_ATTRIDDATA_BLOCK 63
01828 
01829 
01830 Id
01831 repodata_new_handle(Repodata *data)
01832 {
01833   if (!data->nxattrs)
01834     {
01835       data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
01836       data->nxattrs = 2;        
01837     }
01838   data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
01839   data->xattrs[data->nxattrs] = 0;
01840   return -(data->nxattrs++);
01841 }
01842 
01843 static inline Id **
01844 repodata_get_attrp(Repodata *data, Id handle)
01845 {
01846   if (handle < 0)
01847     {
01848       if (handle == SOLVID_META && !data->xattrs)
01849         {
01850           data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
01851           data->nxattrs = 2;
01852         }
01853       return data->xattrs - handle;
01854     }
01855   if (handle < data->start || handle >= data->end)
01856     repodata_extend(data, handle);
01857   if (!data->attrs)
01858     data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
01859   return data->attrs + (handle - data->start);
01860 }
01861 
01862 static void
01863 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
01864 {
01865   Id *pp;
01866   Id *ap, **app;
01867   int i;
01868 
01869   app = repodata_get_attrp(data, handle);
01870   ap = *app;
01871   i = 0;
01872   if (ap)
01873     {
01874       
01875 
01876       for (pp = ap; *pp; pp += 2)
01877         if (data->keys[*pp].name == data->keys[keyid].name)
01878           break;
01879       if (*pp)
01880         {
01881           if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
01882             {
01883               pp[0] = keyid;
01884               pp[1] = val;
01885             }
01886           return;
01887         }
01888       i = pp - ap;
01889     }
01890   ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
01891   *app = ap;
01892   pp = ap + i;
01893   *pp++ = keyid;
01894   *pp++ = val;
01895   *pp = 0;
01896 }
01897 
01898 
01899 static void
01900 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
01901 {
01902   Id keyid;
01903 
01904   keyid = repodata_key2id(data, key, 1);
01905   repodata_insert_keyid(data, solvid, keyid, val, 1);
01906 }
01907 
01908 void
01909 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
01910 {
01911   Repokey key;
01912   key.name = keyname;
01913   key.type = REPOKEY_TYPE_ID;
01914   key.size = 0;
01915   key.storage = KEY_STORAGE_INCORE;
01916   repodata_set(data, solvid, &key, id);
01917 }
01918 
01919 void
01920 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
01921 {
01922   Repokey key;
01923   key.name = keyname;
01924   key.type = REPOKEY_TYPE_NUM;
01925   key.size = 0;
01926   key.storage = KEY_STORAGE_INCORE;
01927   repodata_set(data, solvid, &key, (Id)num);
01928 }
01929 
01930 void
01931 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
01932 {
01933   Repokey key;
01934   Id id;
01935   if (data->localpool)
01936     id = stringpool_str2id(&data->spool, str, 1);
01937   else
01938     id = str2id(data->repo->pool, str, 1);
01939   key.name = keyname;
01940   key.type = REPOKEY_TYPE_ID;
01941   key.size = 0;
01942   key.storage = KEY_STORAGE_INCORE;
01943   repodata_set(data, solvid, &key, id);
01944 }
01945 
01946 void
01947 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
01948 {
01949   Repokey key;
01950   key.name = keyname;
01951   key.type = REPOKEY_TYPE_CONSTANT;
01952   key.size = constant;
01953   key.storage = KEY_STORAGE_INCORE;
01954   repodata_set(data, solvid, &key, 0);
01955 }
01956 
01957 void
01958 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
01959 {
01960   Repokey key;
01961   key.name = keyname;
01962   key.type = REPOKEY_TYPE_CONSTANTID;
01963   key.size = id;
01964   key.storage = KEY_STORAGE_INCORE;
01965   repodata_set(data, solvid, &key, 0);
01966 }
01967 
01968 void
01969 repodata_set_void(Repodata *data, Id solvid, Id keyname)
01970 {
01971   Repokey key;
01972   key.name = keyname;
01973   key.type = REPOKEY_TYPE_VOID;
01974   key.size = 0;
01975   key.storage = KEY_STORAGE_INCORE;
01976   repodata_set(data, solvid, &key, 0);
01977 }
01978 
01979 void
01980 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
01981 {
01982   Repokey key;
01983   int l;
01984 
01985   l = strlen(str) + 1;
01986   key.name = keyname;
01987   key.type = REPOKEY_TYPE_STR;
01988   key.size = 0;
01989   key.storage = KEY_STORAGE_INCORE;
01990   data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
01991   memcpy(data->attrdata + data->attrdatalen, str, l);
01992   repodata_set(data, solvid, &key, data->attrdatalen);
01993   data->attrdatalen += l;
01994 }
01995 
01996 void
01997 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
01998 {
01999   Repokey key;
02000   unsigned char *dp;
02001 
02002   key.name = keyname;
02003   key.type = REPOKEY_TYPE_BINARY;
02004   key.size = 0;
02005   key.storage = KEY_STORAGE_INCORE;
02006   data->attrdata = sat_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
02007   dp = data->attrdata + data->attrdatalen;
02008   if (len >= (1 << 14))
02009     {
02010       if (len >= (1 << 28))
02011         *dp++ = (len >> 28) | 128;
02012       if (len >= (1 << 21))
02013         *dp++ = (len >> 21) | 128;
02014       *dp++ = (len >> 14) | 128;
02015     }
02016   if (len >= (1 << 7))
02017     *dp++ = (len >> 7) | 128;
02018   *dp++ = len & 127;
02019   if (len)
02020     memcpy(dp, buf, len);
02021   repodata_set(data, solvid, &key, data->attrdatalen);
02022   data->attrdatalen = dp + len - data->attrdata;
02023 }
02024 
02025 
02026 
02027 static void
02028 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
02029 {
02030   int oldsize;
02031   Id *ida, *pp, **ppp;
02032 
02033   
02034   if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
02035     {
02036       
02037       data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
02038       data->attriddatalen--;    
02039       data->lastdatalen += entrysize;
02040       return;
02041     }
02042 
02043   ppp = repodata_get_attrp(data, handle);
02044   pp = *ppp;
02045   if (pp)
02046     {
02047       for (; *pp; pp += 2)
02048         if (data->keys[*pp].name == keyname)
02049           break;
02050     }
02051   if (!pp || !*pp || data->keys[*pp].type != keytype)
02052     {
02053       
02054       Repokey key;
02055       Id keyid;
02056       key.name = keyname;
02057       key.type = keytype;
02058       key.size = 0;
02059       key.storage = KEY_STORAGE_INCORE;
02060       data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
02061       keyid = repodata_key2id(data, &key, 1);
02062       repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
02063       data->lasthandle = handle;
02064       data->lastkey = keyid;
02065       data->lastdatalen = data->attriddatalen + entrysize + 1;
02066       return;
02067     }
02068   oldsize = 0;
02069   for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
02070     oldsize += entrysize;
02071   if (ida + 1 == data->attriddata + data->attriddatalen)
02072     {
02073       
02074       data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
02075       data->attriddatalen--;    
02076     }
02077   else
02078     {
02079       
02080       data->attriddata = sat_extend(data->attriddata, data->attriddatalen,  oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
02081       memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
02082       pp[1] = data->attriddatalen;
02083       data->attriddatalen += oldsize;
02084     }
02085   data->lasthandle = handle;
02086   data->lastkey = *pp;
02087   data->lastdatalen = data->attriddatalen + entrysize + 1;
02088 }
02089 
02090 void
02091 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
02092                       const unsigned char *str)
02093 {
02094   Repokey key;
02095   int l;
02096 
02097   if (!(l = sat_chksum_len(type)))
02098     return;
02099   key.name = keyname;
02100   key.type = type;
02101   key.size = 0;
02102   key.storage = KEY_STORAGE_INCORE;
02103   data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
02104   memcpy(data->attrdata + data->attrdatalen, str, l);
02105   repodata_set(data, solvid, &key, data->attrdatalen);
02106   data->attrdatalen += l;
02107 }
02108 
02109 void
02110 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
02111                       const char *str)
02112 {
02113   unsigned char buf[64];
02114   int l;
02115 
02116   if (!(l = sat_chksum_len(type)))
02117     return;
02118   if (l > sizeof(buf) || sat_hex2bin(&str, buf, l) != l)
02119     return;
02120   repodata_set_bin_checksum(data, solvid, keyname, type, buf);
02121 }
02122 
02123 const char *
02124 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
02125 {
02126   int l;
02127 
02128   if (!(l = sat_chksum_len(type)))
02129     return "";
02130   return pool_bin2hex(data->repo->pool, buf, l);
02131 }
02132 
02133 
02134 static inline const char *
02135 evrid2vrstr(Pool *pool, Id evrid)
02136 {
02137   const char *p, *evr = id2str(pool, evrid);
02138   if (!evr)
02139     return evr;
02140   for (p = evr; *p >= '0' && *p <= '9'; p++)
02141     ;
02142   return p != evr && *p == ':' ? p + 1 : evr;
02143 }
02144 
02145 void
02146 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
02147 {
02148   Pool *pool = data->repo->pool;
02149   Solvable *s;
02150   const char *str, *fp;
02151   int l = 0;
02152 
02153   if (medianr)
02154     repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
02155   if (!dir)
02156     {
02157       if ((dir = strrchr(file, '/')) != 0)
02158         {
02159           l = dir - file;
02160           dir = file;
02161           file = dir + l + 1;
02162           if (!l)
02163             l++;
02164         }
02165     }
02166   else
02167     l = strlen(dir);
02168   if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
02169     {
02170       dir += 2;
02171       l -= 2;
02172     }
02173   if (l == 1 && dir[0] == '.')
02174     l = 0;
02175   s = pool->solvables + solvid;
02176   if (dir && l)
02177     {
02178       str = id2str(pool, s->arch);
02179       if (!strncmp(dir, str, l) && !str[l])
02180         repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
02181       else if (!dir[l])
02182         repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
02183       else
02184         {
02185           char *dir2 = strdup(dir);
02186           dir2[l] = 0;
02187           repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
02188           free(dir2);
02189         }
02190     }
02191   fp = file;
02192   str = id2str(pool, s->name);
02193   l = strlen(str);
02194   if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
02195     {
02196       fp += l + 1;
02197       str = evrid2vrstr(pool, s->evr);
02198       l = strlen(str);
02199       if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
02200         {
02201           fp += l + 1;
02202           str = id2str(pool, s->arch);
02203           l = strlen(str);
02204           if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
02205             {
02206               repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
02207               return;
02208             }
02209         }
02210     }
02211   repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
02212 }
02213 
02214 void
02215 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
02216 {
02217   Repokey key;
02218   int i;
02219 
02220   key.name = keyname;
02221   key.type = REPOKEY_TYPE_IDARRAY;
02222   key.size = 0;
02223   key.storage = KEY_STORAGE_INCORE;
02224   repodata_set(data, solvid, &key, data->attriddatalen);
02225   data->attriddata = sat_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
02226   for (i = 0; i < q->count; i++)
02227     data->attriddata[data->attriddatalen++] = q->elements[i];
02228   data->attriddata[data->attriddatalen++] = 0;
02229 }
02230 
02231 void
02232 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
02233 {
02234   assert(dir);
02235 #if 0
02236 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
02237 #endif
02238   repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
02239   data->attriddata[data->attriddatalen++] = dir;
02240   data->attriddata[data->attriddatalen++] = num;
02241   data->attriddata[data->attriddatalen++] = num2;
02242   data->attriddata[data->attriddatalen++] = 0;
02243 }
02244 
02245 void
02246 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
02247 {
02248   Id stroff;
02249   int l;
02250 
02251   assert(dir);
02252   l = strlen(str) + 1;
02253   data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
02254   memcpy(data->attrdata + data->attrdatalen, str, l);
02255   stroff = data->attrdatalen;
02256   data->attrdatalen += l;
02257 
02258 #if 0
02259 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str,  data->attriddatalen);
02260 #endif
02261   repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
02262   data->attriddata[data->attriddatalen++] = dir;
02263   data->attriddata[data->attriddatalen++] = stroff;
02264   data->attriddata[data->attriddatalen++] = 0;
02265 }
02266 
02267 void
02268 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
02269 {
02270 #if 0
02271 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
02272 #endif
02273   repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
02274   data->attriddata[data->attriddatalen++] = id;
02275   data->attriddata[data->attriddatalen++] = 0;
02276 }
02277 
02278 void
02279 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
02280                            const char *str)
02281 {
02282   Id id;
02283   if (data->localpool)
02284     id = stringpool_str2id(&data->spool, str, 1);
02285   else
02286     id = str2id(data->repo->pool, str, 1);
02287   repodata_add_idarray(data, solvid, keyname, id);
02288 }
02289 
02290 void
02291 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
02292 {
02293   repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
02294   data->attriddata[data->attriddatalen++] = ghandle;
02295   data->attriddata[data->attriddatalen++] = 0;
02296 }
02297 
02298 void
02299 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
02300 {
02301   repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
02302   data->attriddata[data->attriddatalen++] = ghandle;
02303   data->attriddata[data->attriddatalen++] = 0;
02304 }
02305 
02306 void
02307 repodata_delete_uninternalized(Repodata *data, Id solvid, Id keyname)
02308 {
02309   Id *pp, *ap, **app;
02310   app = repodata_get_attrp(data, solvid);
02311   ap = *app;
02312   if (!ap)
02313     return;
02314   for (; *ap; ap += 2)
02315     if (data->keys[*ap].name == keyname)
02316       break;
02317   if (!*ap)
02318     return;
02319   pp = ap;
02320   ap += 2;
02321   for (; *ap; ap += 2)
02322     {
02323       if (data->keys[*ap].name == keyname)
02324         continue;
02325       *pp++ = ap[0];
02326       *pp++ = ap[1];
02327     }
02328   *pp = 0;
02329 }
02330 
02331 
02332 void
02333 repodata_delete(Repodata *data, Id solvid, Id keyname)
02334 {
02335   Repokey key;
02336   key.name = keyname;
02337   key.type = REPOKEY_TYPE_DELETED;
02338   key.size = 0;
02339   key.storage = KEY_STORAGE_INCORE;
02340   repodata_set(data, solvid, &key, 0);
02341 }
02342 
02343 
02344 void
02345 repodata_merge_attrs(Repodata *data, Id dest, Id src)
02346 {
02347   Id *keyp;
02348   if (dest == src || !(keyp = data->attrs[src - data->start]))
02349     return;
02350   for (; *keyp; keyp += 2)
02351     repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
02352 }
02353 
02354 
02355 void
02356 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
02357 {
02358   Id *keyp;
02359   if (dest == src || !(keyp = data->attrs[src - data->start]))
02360     return;
02361   for (; *keyp; keyp += 2)
02362     if (!keyidmap || MAPTST(keyidmap, keyp[0]))
02363       repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
02364 }
02365 
02366 
02367 
02368 
02369 
02370 
02371 
02372 #define EXTDATA_BLOCK 1023
02373 
02374 struct extdata {
02375   unsigned char *buf;
02376   int len;
02377 };
02378 
02379 static void
02380 data_addid(struct extdata *xd, Id x)
02381 {
02382   unsigned char *dp;
02383 
02384   xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
02385   dp = xd->buf + xd->len;
02386 
02387   if (x >= (1 << 14))
02388     {
02389       if (x >= (1 << 28))
02390         *dp++ = (x >> 28) | 128;
02391       if (x >= (1 << 21))
02392         *dp++ = (x >> 21) | 128;
02393       *dp++ = (x >> 14) | 128;
02394     }
02395   if (x >= (1 << 7))
02396     *dp++ = (x >> 7) | 128;
02397   *dp++ = x & 127;
02398   xd->len = dp - xd->buf;
02399 }
02400 
02401 static void
02402 data_addideof(struct extdata *xd, Id x, int eof)
02403 {
02404   if (x >= 64)
02405     x = (x & 63) | ((x & ~63) << 1);
02406   data_addid(xd, (eof ? x : x | 64));
02407 }
02408 
02409 static void
02410 data_addblob(struct extdata *xd, unsigned char *blob, int len)
02411 {
02412   xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
02413   memcpy(xd->buf + xd->len, blob, len);
02414   xd->len += len;
02415 }
02416 
02417 
02418 
02419 
02420 
02421 static void
02422 repodata_serialize_key(Repodata *data, struct extdata *newincore,
02423                        struct extdata *newvincore,
02424                        Id *schema,
02425                        Repokey *key, Id val)
02426 {
02427   Id *ida;
02428   struct extdata *xd;
02429   unsigned int oldvincorelen = 0;
02430   Id schemaid, *sp;
02431 
02432   xd = newincore;
02433   if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
02434     {
02435       xd = newvincore;
02436       oldvincorelen = xd->len;
02437     }
02438   switch (key->type)
02439     {
02440     case REPOKEY_TYPE_VOID:
02441     case REPOKEY_TYPE_CONSTANT:
02442     case REPOKEY_TYPE_CONSTANTID:
02443       break;
02444     case REPOKEY_TYPE_STR:
02445       data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
02446       break;
02447     case REPOKEY_TYPE_MD5:
02448       data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
02449       break;
02450     case REPOKEY_TYPE_SHA1:
02451       data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
02452       break;
02453     case REPOKEY_TYPE_SHA256:
02454       data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
02455       break;
02456     case REPOKEY_TYPE_ID:
02457     case REPOKEY_TYPE_NUM:
02458     case REPOKEY_TYPE_DIR:
02459       data_addid(xd, val);
02460       break;
02461     case REPOKEY_TYPE_BINARY:
02462       {
02463         Id len;
02464         unsigned char *dp = data_read_id(data->attrdata + val, &len);
02465         dp += len;
02466         data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
02467       }
02468       break;
02469     case REPOKEY_TYPE_IDARRAY:
02470       for (ida = data->attriddata + val; *ida; ida++)
02471         data_addideof(xd, ida[0], ida[1] ? 0 : 1);
02472       break;
02473     case REPOKEY_TYPE_DIRNUMNUMARRAY:
02474       for (ida = data->attriddata + val; *ida; ida += 3)
02475         {
02476           data_addid(xd, ida[0]);
02477           data_addid(xd, ida[1]);
02478           data_addideof(xd, ida[2], ida[3] ? 0 : 1);
02479         }
02480       break;
02481     case REPOKEY_TYPE_DIRSTRARRAY:
02482       for (ida = data->attriddata + val; *ida; ida += 2)
02483         {
02484           data_addideof(xd, ida[0], ida[2] ? 0 : 1);
02485           data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
02486         }
02487       break;
02488     case REPOKEY_TYPE_FIXARRAY:
02489       {
02490         int num = 0;
02491         schemaid = 0;
02492         for (ida = data->attriddata + val; *ida; ida++)
02493           {
02494             sp = schema;
02495             Id *kp = data->xattrs[-*ida];
02496             if (!kp)
02497               continue;
02498             num++;
02499             for (;*kp; kp += 2)
02500               *sp++ = *kp;
02501             *sp = 0;
02502             if (!schemaid)
02503               schemaid = repodata_schema2id(data, schema, 1);
02504             else if (schemaid != repodata_schema2id(data, schema, 0))
02505               {
02506                 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
02507                 exit(1);
02508               }
02509           }
02510         if (!num)
02511           break;
02512         data_addid(xd, num);
02513         data_addid(xd, schemaid);
02514         for (ida = data->attriddata + val; *ida; ida++)
02515           {
02516             Id *kp = data->xattrs[-*ida];
02517             if (!kp)
02518               continue;
02519             for (;*kp; kp += 2)
02520               repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
02521           }
02522         break;
02523       }
02524     case REPOKEY_TYPE_FLEXARRAY:
02525       {
02526         int num = 0;
02527         for (ida = data->attriddata + val; *ida; ida++)
02528           num++;
02529         data_addid(xd, num);
02530         for (ida = data->attriddata + val; *ida; ida++)
02531           {
02532             Id *kp = data->xattrs[-*ida];
02533             if (!kp)
02534               {
02535                 data_addid(xd, 0);      
02536                 continue;
02537               }
02538             sp = schema;
02539             for (;*kp; kp += 2)
02540               *sp++ = *kp;
02541             *sp = 0;
02542             schemaid = repodata_schema2id(data, schema, 1);
02543             data_addid(xd, schemaid);
02544             kp = data->xattrs[-*ida];
02545             for (;*kp; kp += 2)
02546               repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
02547           }
02548         break;
02549       }
02550     default:
02551       pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
02552       exit(1);
02553     }
02554   if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
02555     {
02556       
02557       data_addid(newincore, data->lastverticaloffset + oldvincorelen);
02558       oldvincorelen = xd->len - oldvincorelen;
02559       data_addid(newincore, oldvincorelen);
02560     }
02561 }
02562 
02563 void
02564 repodata_internalize(Repodata *data)
02565 {
02566   Repokey *key, solvkey;
02567   Id entry, nentry;
02568   Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
02569   unsigned char *dp, *ndp;
02570   int newschema, oldcount;
02571   struct extdata newincore;
02572   struct extdata newvincore;
02573   Id solvkeyid;
02574 
02575   if (!data->attrs && !data->xattrs)
02576     return;
02577 
02578   newvincore.buf = data->vincore;
02579   newvincore.len = data->vincorelen;
02580 
02581   
02582   memset(&solvkey, 0, sizeof(solvkey));
02583   solvkey.name = REPOSITORY_SOLVABLES;
02584   solvkey.type = REPOKEY_TYPE_FLEXARRAY;
02585   solvkey.size = 0;
02586   solvkey.storage = KEY_STORAGE_INCORE;
02587   solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
02588 
02589   schema = sat_malloc2(data->nkeys, sizeof(Id));
02590   seen = sat_malloc2(data->nkeys, sizeof(Id));
02591 
02592   
02593 
02594   nentry = data->end - data->start;
02595   memset(&newincore, 0, sizeof(newincore));
02596   data_addid(&newincore, 0);    
02597 
02598   data->mainschema = 0;
02599   data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
02600 
02601   
02602   
02603   for (entry = -1; entry < nentry; entry++)
02604     {
02605       memset(seen, 0, data->nkeys * sizeof(Id));
02606       oldschema = 0;
02607       dp = data->incoredata;
02608       if (dp)
02609         {
02610           dp += entry >= 0 ? data->incoreoffset[entry] : 1;
02611           dp = data_read_id(dp, &oldschema);
02612         }
02613 #if 0
02614 fprintf(stderr, "oldschema %d\n", oldschema);
02615 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
02616 fprintf(stderr, "schemadata %p\n", data->schemadata);
02617 #endif
02618       
02619       newschema = 0;
02620       oldcount = 0;
02621       sp = schema;
02622       for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
02623         {
02624           if (seen[*keyp])
02625             {
02626               pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
02627               exit(1);
02628             }
02629           seen[*keyp] = -1;
02630           *sp++ = *keyp;
02631           oldcount++;
02632         }
02633       if (entry >= 0)
02634         keyp = data->attrs ? data->attrs[entry] : 0;
02635       else
02636         {
02637           
02638           *sp = 0;
02639           for (sp = keyp = schema; *sp; sp++)
02640             if (*sp != solvkeyid)
02641               *keyp++ = *sp;
02642             else
02643               oldcount--;
02644           sp = keyp;
02645           seen[solvkeyid] = 0;
02646           keyp = data->xattrs ? data->xattrs[1] : 0;
02647         }
02648       if (keyp)
02649         for (; *keyp; keyp += 2)
02650           {
02651             if (!seen[*keyp])
02652               {
02653                 newschema = 1;
02654                 *sp++ = *keyp;
02655               }
02656             seen[*keyp] = keyp[1] + 1;
02657           }
02658       if (entry < 0 && data->end != data->start)
02659         {
02660           *sp++ = solvkeyid;
02661           newschema = 1;
02662         }
02663       *sp = 0;
02664       if (newschema)
02665         
02666 
02667 
02668 
02669 
02670         schemaid = repodata_schema2id(data, schema, 1);
02671       else
02672         schemaid = oldschema;
02673 
02674 
02675       
02676 
02677       
02678 
02679 
02680 
02681 
02682       if (entry >= 0)
02683         data->incoreoffset[entry] = newincore.len;
02684       data_addid(&newincore, schemaid);
02685       if (entry == -1)
02686         {
02687           data->mainschema = schemaid;
02688           data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
02689         }
02690       keypstart = data->schemadata + data->schemata[schemaid];
02691       for (keyp = keypstart; *keyp; keyp++)
02692         {
02693           if (entry == -1)
02694             data->mainschemaoffsets[keyp - keypstart] = newincore.len;
02695           if (*keyp == solvkeyid)
02696             {
02697               
02698               data_addid(&newincore, data->end - data->start);
02699               break;
02700             }
02701           key = data->keys + *keyp;
02702 #if 0
02703           fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
02704 #endif
02705           ndp = dp;
02706           if (oldcount)
02707             {
02708               
02709               if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
02710                 {
02711                   ndp = data_skip(dp, REPOKEY_TYPE_ID);
02712                   ndp = data_skip(ndp, REPOKEY_TYPE_ID);
02713                 }
02714               else if (key->storage == KEY_STORAGE_INCORE)
02715                 ndp = data_skip_key(data, dp, key);
02716               oldcount--;
02717             }
02718           if (seen[*keyp] == -1)
02719             {
02720               
02721 
02722 
02723               if (dp != ndp)
02724                 data_addblob(&newincore, dp, ndp - dp);
02725               seen[*keyp] = 0;
02726             }
02727           else if (seen[*keyp])
02728             {
02729               
02730 
02731               repodata_serialize_key(data, &newincore, &newvincore,
02732                                      schema, key, seen[*keyp] - 1);
02733             }
02734           dp = ndp;
02735         }
02736       if (entry >= 0 && data->attrs && data->attrs[entry])
02737         data->attrs[entry] = sat_free(data->attrs[entry]);
02738     }
02739   
02740   for (entry = 0; entry < data->nxattrs; entry++)
02741     if (data->xattrs[entry])
02742       sat_free(data->xattrs[entry]);
02743   data->xattrs = sat_free(data->xattrs);
02744   data->nxattrs = 0;
02745 
02746   data->lasthandle = 0;
02747   data->lastkey = 0;
02748   data->lastdatalen = 0;
02749   sat_free(schema);
02750   sat_free(seen);
02751   repodata_free_schemahash(data);
02752 
02753   sat_free(data->incoredata);
02754   data->incoredata = newincore.buf;
02755   data->incoredatalen = newincore.len;
02756   data->incoredatafree = 0;
02757 
02758   sat_free(data->vincore);
02759   data->vincore = newvincore.buf;
02760   data->vincorelen = newvincore.len;
02761 
02762   data->attrs = sat_free(data->attrs);
02763   data->attrdata = sat_free(data->attrdata);
02764   data->attriddata = sat_free(data->attriddata);
02765   data->attrdatalen = 0;
02766   data->attriddatalen = 0;
02767 }
02768 
02769 void
02770 repodata_disable_paging(Repodata *data)
02771 {
02772   if (maybe_load_repodata(data, 0))
02773     repopagestore_disable_paging(&data->store);
02774 }
02775 
02776 static void
02777 repodata_load_stub(Repodata *data)
02778 {
02779   Repo *repo = data->repo;
02780   Pool *pool = repo->pool;
02781   int r, i;
02782   struct _Pool_tmpspace oldtmpspace;
02783 
02784   if (!pool->loadcallback)
02785     {
02786       data->state = REPODATA_ERROR;
02787       return;
02788     }
02789   data->state = REPODATA_LOADING;
02790 
02791   
02792   oldtmpspace = pool->tmpspace;
02793   memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
02794 
02795   r = pool->loadcallback(pool, data, pool->loadcallbackdata);
02796 
02797   
02798   for (i = 0; i < POOL_TMPSPACEBUF; i++)
02799     sat_free(pool->tmpspace.buf[i]);
02800   pool->tmpspace = oldtmpspace;
02801 
02802   data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
02803 }
02804 
02805 void
02806 repodata_create_stubs(Repodata *data)
02807 {
02808   Repo *repo = data->repo;
02809   Pool *pool = repo->pool;
02810   Repodata *sdata;
02811   int *stubdataids;
02812   Dataiterator di;
02813   Id xkeyname = 0;
02814   int i, cnt = 0;
02815   int repodataid;
02816   int datastart, dataend;
02817 
02818   repodataid = data - repo->repodata;
02819   datastart = data->start;
02820   dataend = data->end;
02821   dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
02822   while (dataiterator_step(&di))
02823     {
02824       if (di.data - repo->repodata != repodataid)
02825         continue;
02826       cnt++;
02827     }
02828   dataiterator_free(&di);
02829   if (!cnt)
02830     return;
02831   stubdataids = sat_calloc(cnt, sizeof(*stubdataids));
02832   for (i = 0; i < cnt; i++)
02833     {
02834       sdata = repo_add_repodata(repo, 0);
02835       if (dataend > datastart)
02836         repodata_extend_block(sdata, datastart, dataend - datastart);
02837       stubdataids[i] = sdata - repo->repodata;
02838       sdata->state = REPODATA_STUB;
02839       sdata->loadcallback = repodata_load_stub;
02840     }
02841   i = 0;
02842   dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
02843   sdata = 0;
02844   while (dataiterator_step(&di))
02845     {
02846       if (di.data - repo->repodata != repodataid)
02847         continue;
02848       if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
02849         {
02850           dataiterator_entersub(&di);
02851           sdata = repo->repodata + stubdataids[i++];
02852           xkeyname = 0;
02853           continue;
02854         }
02855       switch (di.key->type)
02856         {
02857         case REPOKEY_TYPE_ID:
02858           repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
02859           break;
02860         case REPOKEY_TYPE_CONSTANTID:
02861           repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
02862           break;
02863         case REPOKEY_TYPE_STR:
02864           repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
02865           break;
02866         case REPOKEY_TYPE_VOID:
02867           repodata_set_void(sdata, SOLVID_META, di.key->name);
02868           break;
02869         case REPOKEY_TYPE_NUM:
02870           repodata_set_num(sdata, SOLVID_META, di.key->name, di.kv.num);
02871           break;
02872         case REPOKEY_TYPE_MD5:
02873         case REPOKEY_TYPE_SHA1:
02874         case REPOKEY_TYPE_SHA256:
02875           repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
02876           break;
02877         case REPOKEY_TYPE_IDARRAY:
02878           repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
02879           if (di.key->name == REPOSITORY_KEYS)
02880             {
02881               Repokey xkey;
02882 
02883               if (!xkeyname)
02884                 {
02885                   if (!di.kv.eof)
02886                     xkeyname = di.kv.id;
02887                   continue;
02888                 }
02889               xkey.name = xkeyname;
02890               xkey.type = di.kv.id;
02891               xkey.storage = KEY_STORAGE_INCORE;
02892               xkey.size = 0; 
02893               repodata_key2id(sdata, &xkey, 1);
02894               xkeyname = 0;
02895             }
02896         default:
02897           break;
02898         }
02899     }
02900   dataiterator_free(&di);
02901   for (i = 0; i < cnt; i++)
02902     repodata_internalize(repo->repodata + stubdataids[i]);
02903   sat_free(stubdataids);
02904 }
02905 
02906 
02907 
02908