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