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