2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
27 #include "poolid_private.h"
33 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
34 unsigned char *out, unsigned int out_len);
35 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
38 unsigned int out_len);
40 #define REPODATA_BLOCK 255
44 repodata_init(Repodata *data, Repo *repo, int localpool)
46 memset(data, 0, sizeof (*data));
48 data->localpool = localpool;
50 stringpool_init_empty(&data->spool);
51 data->keys = sat_calloc(1, sizeof(Repokey));
53 data->schemata = sat_calloc(1, sizeof(Id));
54 data->schemadata = sat_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_free(Repodata *data)
67 sat_free(data->schemata);
68 sat_free(data->schemadata);
69 sat_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 sat_free(data->mainschemaoffsets);
75 sat_free(data->incoredata);
76 sat_free(data->incoreoffset);
77 sat_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 sat_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 sat_free(data->attrs[i]);
86 sat_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 sat_free(data->xattrs[i]);
90 sat_free(data->xattrs);
92 sat_free(data->attrdata);
93 sat_free(data->attriddata);
97 /***************************************************************
101 /* this is not so time critical that we need a hash, so we do a simple
104 repodata_key2id(Repodata *data, Repokey *key, int create)
108 for (keyid = 1; keyid < data->nkeys; keyid++)
109 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
111 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
115 if (keyid == data->nkeys)
119 /* allocate new key */
120 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
121 data->keys[data->nkeys++] = *key;
122 if (data->verticaloffset)
124 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
125 data->verticaloffset[data->nkeys - 1] = 0;
127 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
133 /***************************************************************
134 * schema pool management
137 #define SCHEMATA_BLOCK 31
138 #define SCHEMATADATA_BLOCK 255
141 repodata_schema2id(Repodata *data, Id *schema, int create)
147 if ((schematahash = data->schematahash) == 0)
149 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
150 for (i = 0; i < data->nschemata; i++)
152 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
155 schematahash[h] = i + 1;
157 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
158 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
161 for (sp = schema, len = 0, h = 0; *sp; len++)
166 cid = schematahash[h];
170 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
173 for (cid = 0; cid < data->nschemata; cid++)
174 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
180 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
181 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
183 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
184 data->schemata[data->nschemata] = data->schemadatalen;
185 data->schemadatalen += len;
186 schematahash[h] = data->nschemata + 1;
188 fprintf(stderr, "schema2id: new schema\n");
190 return data->nschemata++;
194 repodata_free_schemahash(Repodata *data)
196 data->schematahash = sat_free(data->schematahash);
198 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
199 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
203 /***************************************************************
204 * dir pool management
208 repodata_str2dir(Repodata *data, const char *dir, int create)
214 while (*dir == '/' && dir[1] == '/')
216 if (*dir == '/' && !dir[1])
220 dire = strchrnul(dir, '/');
222 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
224 id = strn2id(data->repo->pool, dir, dire - dir, create);
227 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
240 repodata_dir2str(Repodata *data, Id did, const char *suf)
242 Pool *pool = data->repo->pool;
249 return suf ? suf : "";
253 comp = dirpool_compid(&data->dirpool, parent);
254 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
256 parent = dirpool_parent(&data->dirpool, parent);
261 l += strlen(suf) + 1;
262 p = pool_alloctmpspace(pool, l + 1) + l;
273 comp = dirpool_compid(&data->dirpool, parent);
274 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
277 strncpy(p, comps, l);
278 parent = dirpool_parent(&data->dirpool, parent);
286 /***************************************************************
290 static inline unsigned char *
291 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
293 Id *keyp = data->schemadata + data->schemata[schema];
294 for (; *keyp; keyp++)
295 dp = data_skip_key(data, dp, data->keys + *keyp);
300 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
302 int nentries, schema;
305 case REPOKEY_TYPE_FIXARRAY:
306 dp = data_read_id(dp, &nentries);
309 dp = data_read_id(dp, &schema);
311 dp = data_skip_schema(data, dp, schema);
313 case REPOKEY_TYPE_FLEXARRAY:
314 dp = data_read_id(dp, &nentries);
317 dp = data_read_id(dp, &schema);
318 dp = data_skip_schema(data, dp, schema);
322 if (key->storage == KEY_STORAGE_INCORE)
323 dp = data_skip(dp, key->type);
324 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
326 dp = data_skip(dp, REPOKEY_TYPE_ID);
327 dp = data_skip(dp, REPOKEY_TYPE_ID);
333 static unsigned char *
334 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
340 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
343 for (i = 0; (k = *keyp++) != 0; i++)
345 return data->incoredata + data->mainschemaoffsets[i];
348 while ((k = *keyp++) != 0)
352 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
354 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
355 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
358 if (data->keys[k].storage != KEY_STORAGE_INCORE)
360 dp = data_skip_key(data, dp, data->keys + k);
365 static unsigned char *
366 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
371 if (off >= data->lastverticaloffset)
373 off -= data->lastverticaloffset;
374 if (off + len > data->vincorelen)
376 return data->vincore + off;
378 if (off + len > key->size)
380 /* we now have the offset, go into vertical */
381 off += data->verticaloffset[key - data->keys];
382 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
383 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
385 dp += off % BLOB_PAGESIZE;
389 static inline unsigned char *
390 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
392 unsigned char *dp = *dpp;
396 if (key->storage == KEY_STORAGE_INCORE)
399 *dpp = data_skip_key(data, dp, key);
402 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
405 dp = data_read_id(dp, &off);
406 dp = data_read_id(dp, &len);
409 return get_vertical_data(data, key, off, len);
415 load_repodata(Repodata *data)
417 if (data->loadcallback)
419 data->loadcallback(data);
420 if (data->state == REPODATA_AVAILABLE)
423 data->state = REPODATA_ERROR;
428 maybe_load_repodata(Repodata *data, Id keyname)
430 if (keyname && !repodata_precheck_keyname(data, keyname))
431 return 0; /* do not bother... */
438 for (i = 0; i < data->nkeys; i++)
439 if (keyname == data->keys[i].name)
441 if (i == data->nkeys)
444 return load_repodata(data);
447 case REPODATA_AVAILABLE:
450 data->state = REPODATA_ERROR;
455 static inline unsigned char*
456 solvid2data(Repodata *data, Id solvid, Id *schemap)
458 unsigned char *dp = data->incoredata;
461 if (solvid == SOLVID_META) /* META */
463 else if (solvid == SOLVID_POS) /* META */
465 Pool *pool = data->repo->pool;
466 if (data->repo != pool->pos.repo)
468 if (data != data->repo->repodata + pool->pos.repodataid)
470 *schemap = pool->pos.schema;
471 return data->incoredata + pool->pos.dp;
475 if (solvid < data->start || solvid >= data->end)
477 dp += data->incoreoffset[solvid - data->start];
479 return data_read_id(dp, schemap);
482 /************************************************************************
486 static inline unsigned char *
487 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
490 Id schema, *keyp, *kp;
493 if (!maybe_load_repodata(data, keyname))
495 dp = solvid2data(data, solvid, &schema);
498 keyp = data->schemadata + data->schemata[schema];
499 for (kp = keyp; *kp; kp++)
500 if (data->keys[*kp].name == keyname)
504 *keypp = key = data->keys + *kp;
505 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
506 return dp; /* no need to forward... */
507 dp = forward_to_key(data, *kp, keyp, dp);
510 return get_data(data, key, &dp, 0);
515 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
521 dp = find_key_data(data, solvid, keyname, &key);
524 if (key->type == REPOKEY_TYPE_CONSTANTID)
526 if (key->type != REPOKEY_TYPE_ID)
528 dp = data_read_id(dp, &id);
533 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
539 dp = find_key_data(data, solvid, keyname, &key);
542 if (key->type == REPOKEY_TYPE_STR)
543 return (const char *)dp;
544 if (key->type == REPOKEY_TYPE_CONSTANTID)
545 return id2str(data->repo->pool, key->size);
546 if (key->type == REPOKEY_TYPE_ID)
547 dp = data_read_id(dp, &id);
551 return data->spool.stringspace + data->spool.strings[id];
552 return id2str(data->repo->pool, id);
556 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
563 dp = find_key_data(data, solvid, keyname, &key);
566 if (key->type == REPOKEY_TYPE_NUM
567 || key->type == REPOKEY_TYPE_U32
568 || key->type == REPOKEY_TYPE_CONSTANT)
570 dp = data_fetch(dp, &kv, key);
578 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
584 if (!maybe_load_repodata(data, keyname))
586 dp = solvid2data(data, solvid, &schema);
589 /* can't use find_key_data as we need to test the type */
590 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
591 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
596 const unsigned char *
597 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
602 dp = find_key_data(data, solvid, keyname, &key);
610 /************************************************************************
616 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
620 case REPOKEY_TYPE_ID:
621 case REPOKEY_TYPE_CONSTANTID:
622 case REPOKEY_TYPE_IDARRAY:
623 if (data && data->localpool)
624 kv->str = stringpool_id2str(&data->spool, kv->id);
626 kv->str = id2str(pool, kv->id);
627 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
629 const char *s = strchr(kv->str, ':');
634 case REPOKEY_TYPE_STR:
636 case REPOKEY_TYPE_DIRSTRARRAY:
637 if (!(flags & SEARCH_FILES))
638 return 1; /* match just the basename */
639 /* Put the full filename into kv->str. */
640 kv->str = repodata_dir2str(data, kv->id, kv->str);
641 /* And to compensate for that put the "empty" directory into
642 kv->id, so that later calls to repodata_dir2str on this data
643 come up with the same filename again. */
652 struct subschema_data {
658 /* search a specific repodata */
660 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
664 Id keyid, *kp, *keyp;
665 unsigned char *dp, *ddp;
671 if (!maybe_load_repodata(data, keyname))
673 if (solvid == SOLVID_SUBSCHEMA)
675 struct subschema_data *subd = cbdata;
676 cbdata = subd->cbdata;
678 schema = subd->parent->id;
679 dp = (unsigned char *)subd->parent->str;
680 kv.parent = subd->parent;
685 dp = solvid2data(data, solvid, &schema);
688 s = data->repo->pool->solvables + solvid;
691 keyp = data->schemadata + data->schemata[schema];
694 /* search for a specific key */
695 for (kp = keyp; *kp; kp++)
696 if (data->keys[*kp].name == keyname)
700 dp = forward_to_key(data, *kp, keyp, dp);
706 while ((keyid = *keyp++) != 0)
709 key = data->keys + keyid;
710 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
712 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
714 struct subschema_data subd;
718 subd.cbdata = cbdata;
721 ddp = data_read_id(ddp, &nentries);
725 while (ddp && nentries > 0)
729 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
730 ddp = data_read_id(ddp, &schema);
732 kv.str = (char *)ddp;
733 stop = callback(cbdata, s, data, key, &kv);
734 if (stop > SEARCH_NEXT_KEY)
736 if (stop && stop != SEARCH_ENTERSUB)
738 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
739 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
740 ddp = data_skip_schema(data, ddp, schema);
743 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
747 kv.str = (char *)ddp;
748 stop = callback(cbdata, s, data, key, &kv);
749 if (stop > SEARCH_NEXT_KEY)
759 ddp = data_fetch(ddp, &kv, key);
762 stop = callback(cbdata, s, data, key, &kv);
765 while (!kv.eof && !stop);
766 if (onekey || stop > SEARCH_NEXT_KEY)
772 repodata_setpos_kv(Repodata *data, KeyValue *kv)
774 Pool *pool = data->repo->pool;
776 pool_clear_pos(pool);
779 pool->pos.repo = data->repo;
780 pool->pos.repodataid = data - data->repo->repodata;
781 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
782 pool->pos.schema = kv->id;
786 /************************************************************************
787 * data iterator functions
790 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
791 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
792 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
793 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
794 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
795 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
796 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
797 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
798 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
799 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
800 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
801 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
802 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
803 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
807 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
821 case SOLVABLE_VENDOR:
824 case SOLVABLE_PROVIDES:
826 return s->provides ? s->repo->idarraydata + s->provides : 0;
827 case SOLVABLE_OBSOLETES:
829 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
830 case SOLVABLE_CONFLICTS:
832 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
833 case SOLVABLE_REQUIRES:
835 return s->requires ? s->repo->idarraydata + s->requires : 0;
836 case SOLVABLE_RECOMMENDS:
838 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
839 case SOLVABLE_SUPPLEMENTS:
841 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
842 case SOLVABLE_SUGGESTS:
844 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
845 case SOLVABLE_ENHANCES:
847 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
850 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
857 datamatcher_init(Datamatcher *ma, const char *match, int flags)
859 ma->match = (void *)match;
862 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
864 ma->match = sat_calloc(1, sizeof(regex_t));
865 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
869 ma->match = (void *)match;
870 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
877 datamatcher_free(Datamatcher *ma)
879 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
882 ma->match = sat_free(ma->match);
887 datamatcher_match(Datamatcher *ma, const char *str)
889 switch ((ma->flags & SEARCH_STRINGMASK))
891 case SEARCH_SUBSTRING:
892 if (ma->flags & SEARCH_NOCASE)
894 if (!strcasestr(str, (const char *)ma->match))
899 if (!strstr(str, (const char *)ma->match))
904 if (ma->flags & SEARCH_NOCASE)
906 if (strcasecmp((const char *)ma->match, str))
911 if (strcmp((const char *)ma->match, str))
916 if (fnmatch((const char *)ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
920 if (regexec((const regex_t *)ma->match, str, 0, NULL, 0))
955 /* see repo.h for documentation */
957 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
959 memset(di, 0, sizeof(*di));
961 if (!pool || (repo && repo->pool != pool))
969 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
976 di->keyname = keyname;
977 di->keynames[0] = keyname;
978 di->flags = flags & ~SEARCH_THISSOLVID;
987 dataiterator_jump_to_solvid(di, p);
991 di->repo = pool->repos[0];
992 di->state = di_enterrepo;
998 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1002 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1004 di->state = di_bye; /* sorry */
1007 for (i = di->nkeynames + 1; i > 0; i--)
1008 di->keynames[i] = di->keynames[i - 1];
1009 di->keynames[0] = di->keyname = keyname;
1014 dataiterator_free(Dataiterator *di)
1016 if (di->matcher.match)
1017 datamatcher_free(&di->matcher);
1020 static inline unsigned char *
1021 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1023 Id *keyp = di->keyp;
1024 Repokey *keys = di->data->keys;
1027 for (keyp = di->keyp; *keyp; keyp++)
1028 if (keys[*keyp].name == keyname)
1032 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1040 dataiterator_step(Dataiterator *di)
1048 case di_enterrepo: di_enterrepo:
1051 if (!(di->flags & SEARCH_THISSOLVID))
1053 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1054 goto di_nextsolvable;
1058 case di_entersolvable: di_entersolvable:
1059 if (di->repodataid >= 0)
1061 di->repodataid = 0; /* reset repodata iterator */
1062 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1064 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1066 goto di_entersolvablekey;
1071 case di_enterrepodata: di_enterrepodata:
1072 if (di->repodataid >= 0)
1074 if (di->repodataid >= di->repo->nrepodata)
1075 goto di_nextsolvable;
1076 di->data = di->repo->repodata + di->repodataid;
1078 if (!maybe_load_repodata(di->data, di->keyname))
1079 goto di_nextrepodata;
1080 di->dp = solvid2data(di->data, di->solvid, &schema);
1082 goto di_nextrepodata;
1083 /* reset key iterator */
1084 di->keyp = di->data->schemadata + di->data->schemata[schema];
1087 case di_enterschema: di_enterschema:
1089 di->dp = dataiterator_find_keyname(di, di->keyname);
1090 if (!di->dp || !*di->keyp)
1094 goto di_nextrepodata;
1098 case di_enterkey: di_enterkey:
1100 di->key = di->data->keys + *di->keyp;
1101 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1104 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1106 if (di->nparents < di->nkeynames)
1112 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1114 di->state = di_nextkey;
1116 di->state = di_nextattr;
1119 case di_nextkey: di_nextkey:
1120 if (!di->keyname && *++di->keyp)
1126 case di_nextrepodata: di_nextrepodata:
1127 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1128 goto di_enterrepodata;
1131 case di_nextsolvable: di_nextsolvable:
1132 if (!(di->flags & SEARCH_THISSOLVID))
1135 di->solvid = di->repo->start;
1138 for (; di->solvid < di->repo->end; di->solvid++)
1140 if (di->pool->solvables[di->solvid].repo == di->repo)
1141 goto di_entersolvable;
1147 if (di->repoid >= 0)
1150 if (di->repoid < di->pool->nrepos)
1152 di->repo = di->pool->repos[di->repoid];
1158 case di_bye: di_bye:
1162 case di_enterarray: di_enterarray:
1163 if (di->key->name == REPOSITORY_SOLVABLES)
1165 di->ddp = data_read_id(di->ddp, &di->kv.num);
1170 case di_nextarrayelement: di_nextarrayelement:
1173 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1174 if (di->kv.entry == di->kv.num)
1176 if (di->nparents < di->nkeynames)
1178 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1180 di->kv.str = (char *)di->ddp;
1182 di->state = di_nextkey;
1185 if (di->kv.entry == di->kv.num - 1)
1187 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1188 di->ddp = data_read_id(di->ddp, &di->kv.id);
1189 di->kv.str = (char *)di->ddp;
1190 if (di->nparents < di->nkeynames)
1192 if ((di->flags & SEARCH_SUB) != 0)
1193 di->state = di_entersub;
1195 di->state = di_nextarrayelement;
1198 case di_entersub: di_entersub:
1199 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1200 goto di_nextarrayelement; /* sorry, full */
1201 di->parents[di->nparents].kv = di->kv;
1202 di->parents[di->nparents].dp = di->dp;
1203 di->parents[di->nparents].keyp = di->keyp;
1204 di->dp = (unsigned char *)di->kv.str;
1205 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1206 memset(&di->kv, 0, sizeof(di->kv));
1207 di->kv.parent = &di->parents[di->nparents].kv;
1209 di->keyname = di->keynames[di->nparents];
1210 goto di_enterschema;
1212 case di_leavesub: di_leavesub:
1214 di->dp = di->parents[di->nparents].dp;
1215 di->kv = di->parents[di->nparents].kv;
1216 di->keyp = di->parents[di->nparents].keyp;
1217 di->key = di->data->keys + *di->keyp;
1218 di->ddp = (unsigned char *)di->kv.str;
1219 di->keyname = di->keynames[di->nparents];
1220 goto di_nextarrayelement;
1222 /* special solvable attr handling follows */
1224 case di_nextsolvableattr:
1225 di->kv.id = *di->idp++;
1230 di->state = di_nextsolvablekey;
1234 case di_nextsolvablekey: di_nextsolvablekey:
1235 if (di->keyname || di->key->name == RPM_RPMDBID)
1236 goto di_enterrepodata;
1240 case di_entersolvablekey: di_entersolvablekey:
1241 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1242 if (!di->idp || !di->idp[0])
1243 goto di_nextsolvablekey;
1244 di->kv.id = di->idp[0];
1245 di->kv.num = di->idp[0];
1247 if (!di->kv.eof && !di->idp[0])
1251 di->state = di_nextsolvablekey;
1253 di->state = di_nextsolvableattr;
1257 if (di->matcher.match)
1259 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1261 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1265 if (!datamatcher_match(&di->matcher, di->kv.str))
1268 /* found something! */
1274 dataiterator_entersub(Dataiterator *di)
1276 if (di->state == di_nextarrayelement)
1277 di->state = di_entersub;
1281 dataiterator_setpos(Dataiterator *di)
1285 pool_clear_pos(di->pool);
1288 di->pool->pos.solvid = di->solvid;
1289 di->pool->pos.repo = di->repo;
1290 di->pool->pos.repodataid = di->data - di->repo->repodata;
1291 di->pool->pos.schema = di->kv.id;
1292 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1296 dataiterator_setpos_parent(Dataiterator *di)
1300 pool_clear_pos(di->pool);
1303 di->pool->pos.solvid = di->solvid;
1304 di->pool->pos.repo = di->repo;
1305 di->pool->pos.repodataid = di->data - di->repo->repodata;
1306 di->pool->pos.schema = di->kv.parent->id;
1307 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1311 dataiterator_skip_attribute(Dataiterator *di)
1313 if (di->state == di_nextsolvableattr)
1314 di->state = di_nextsolvablekey;
1316 di->state = di_nextkey;
1320 dataiterator_skip_solvable(Dataiterator *di)
1322 di->state = di_nextsolvable;
1326 dataiterator_skip_repo(Dataiterator *di)
1328 di->state = di_nextrepo;
1332 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1335 if (solvid == SOLVID_POS)
1337 di->repo = di->pool->pos.repo;
1344 di->data = di->repo->repodata + di->pool->pos.repodataid;
1345 di->repodataid = -1;
1346 di->solvid = di->pool->pos.solvid;
1347 di->state = di_enterrepo;
1348 di->flags |= SEARCH_THISSOLVID;
1353 di->repo = di->pool->solvables[solvid].repo;
1356 else if (di->repoid >= 0)
1358 if (!di->pool->nrepos)
1363 di->repo = di->pool->repos[0];
1367 di->solvid = solvid;
1369 di->flags |= SEARCH_THISSOLVID;
1370 di->state = di_enterrepo;
1374 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1381 di->flags &= ~SEARCH_THISSOLVID;
1382 di->state = di_enterrepo;
1386 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1388 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1390 return datamatcher_match(ma, di->kv.str);
1394 dataiterator_match_obsolete(Dataiterator *di, int flags, const void *vmatch)
1396 Datamatcher matcher;
1398 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, flags))
1400 matcher = di->matcher;
1401 matcher.flags = flags;
1402 matcher.match = (void *)vmatch;
1403 return datamatcher_match(&matcher, di->kv.str);
1407 /************************************************************************
1408 * data modify functions
1411 /* extend repodata so that it includes solvables p */
1413 repodata_extend(Repodata *data, Id p)
1415 if (data->start == data->end)
1416 data->start = data->end = p;
1419 int old = data->end - data->start;
1420 int new = p - data->end + 1;
1423 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1424 memset(data->attrs + old, 0, new * sizeof(Id *));
1426 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1427 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1430 if (p < data->start)
1432 int old = data->end - data->start;
1433 int new = data->start - p;
1436 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1437 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1438 memset(data->attrs, 0, new * sizeof(Id *));
1440 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1441 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1442 memset(data->incoreoffset, 0, new * sizeof(Id));
1448 repodata_extend_block(Repodata *data, Id start, Id num)
1452 if (!data->incoreoffset)
1454 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1455 data->start = start;
1456 data->end = start + num;
1459 repodata_extend(data, start);
1461 repodata_extend(data, start + num - 1);
1464 /**********************************************************************/
1466 #define REPODATA_ATTRS_BLOCK 63
1467 #define REPODATA_ATTRDATA_BLOCK 1023
1468 #define REPODATA_ATTRIDDATA_BLOCK 63
1472 repodata_new_handle(Repodata *data)
1476 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1479 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1480 data->xattrs[data->nxattrs] = 0;
1481 return -(data->nxattrs++);
1485 repodata_get_attrp(Repodata *data, Id handle)
1487 if (handle == SOLVID_META)
1491 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1496 return data->xattrs - handle;
1497 if (handle < data->start || handle >= data->end)
1498 repodata_extend(data, handle);
1500 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1501 return data->attrs + (handle - data->start);
1505 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1511 app = repodata_get_attrp(data, handle);
1516 for (pp = ap; *pp; pp += 2)
1517 /* Determine equality based on the name only, allows us to change
1518 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1519 if (data->keys[*pp].name == data->keys[keyid].name)
1532 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1542 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1546 keyid = repodata_key2id(data, key, 1);
1547 repodata_insert_keyid(data, solvid, keyid, val, 1);
1551 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1555 key.type = REPOKEY_TYPE_ID;
1557 key.storage = KEY_STORAGE_INCORE;
1558 repodata_set(data, solvid, &key, id);
1562 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1566 key.type = REPOKEY_TYPE_NUM;
1568 key.storage = KEY_STORAGE_INCORE;
1569 repodata_set(data, solvid, &key, (Id)num);
1573 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1577 if (data->localpool)
1578 id = stringpool_str2id(&data->spool, str, 1);
1580 id = str2id(data->repo->pool, str, 1);
1582 key.type = REPOKEY_TYPE_ID;
1584 key.storage = KEY_STORAGE_INCORE;
1585 repodata_set(data, solvid, &key, id);
1589 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1593 key.type = REPOKEY_TYPE_CONSTANT;
1594 key.size = constant;
1595 key.storage = KEY_STORAGE_INCORE;
1596 repodata_set(data, solvid, &key, 0);
1600 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1604 key.type = REPOKEY_TYPE_CONSTANTID;
1606 key.storage = KEY_STORAGE_INCORE;
1607 repodata_set(data, solvid, &key, 0);
1611 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1615 key.type = REPOKEY_TYPE_VOID;
1617 key.storage = KEY_STORAGE_INCORE;
1618 repodata_set(data, solvid, &key, 0);
1622 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1627 l = strlen(str) + 1;
1629 key.type = REPOKEY_TYPE_STR;
1631 key.storage = KEY_STORAGE_INCORE;
1632 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1633 memcpy(data->attrdata + data->attrdatalen, str, l);
1634 repodata_set(data, solvid, &key, data->attrdatalen);
1635 data->attrdatalen += l;
1639 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1642 Id *ida, *pp, **ppp;
1644 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1646 /* great! just append the new data */
1647 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1648 data->attriddatalen--; /* overwrite terminating 0 */
1649 data->lastdatalen += entrysize;
1652 ppp = repodata_get_attrp(data, handle);
1655 for (; *pp; pp += 2)
1656 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1660 /* not found. allocate new key */
1665 key.storage = KEY_STORAGE_INCORE;
1666 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1667 repodata_set(data, handle, &key, data->attriddatalen);
1668 data->lasthandle = 0; /* next time... */
1672 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1673 oldsize += entrysize;
1674 if (ida + 1 == data->attriddata + data->attriddatalen)
1676 /* this was the last entry, just append it */
1677 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1678 data->attriddatalen--; /* overwrite terminating 0 */
1682 /* too bad. move to back. */
1683 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1684 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1685 pp[1] = data->attriddatalen;
1686 data->attriddatalen += oldsize;
1688 data->lasthandle = handle;
1689 data->lastkey = *pp;
1690 data->lastdatalen = data->attriddatalen + entrysize + 1;
1694 checksumtype2len(Id type)
1698 case REPOKEY_TYPE_MD5:
1700 case REPOKEY_TYPE_SHA1:
1702 case REPOKEY_TYPE_SHA256:
1703 return SIZEOF_SHA256;
1710 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1711 const unsigned char *str)
1714 int l = checksumtype2len(type);
1721 key.storage = KEY_STORAGE_INCORE;
1722 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1723 memcpy(data->attrdata + data->attrdatalen, str, l);
1724 repodata_set(data, solvid, &key, data->attrdatalen);
1725 data->attrdatalen += l;
1729 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1732 for (i = 0; i < buflen; i++)
1734 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1735 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
1736 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
1747 buf[i] = (buf[i] << 4) | v;
1754 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1757 unsigned char buf[64];
1758 int l = checksumtype2len(type);
1762 if (hexstr2bytes(buf, str, l) != l)
1764 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1768 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1773 l = checksumtype2len(type);
1776 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1777 for (i = 0; i < l; i++)
1779 unsigned char v = buf[i];
1780 unsigned char w = v >> 4;
1781 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1783 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1789 static inline const char *
1790 evrid2vrstr(Pool *pool, Id evrid)
1792 const char *p, *evr = id2str(pool, evrid);
1795 for (p = evr; *p >= '0' && *p <= '9'; p++)
1797 return p != evr && *p == ':' ? p + 1 : evr;
1801 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
1803 Pool *pool = data->repo->pool;
1805 const char *str, *fp;
1809 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
1812 if ((dir = strrchr(file, '/')) != 0)
1823 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
1828 if (l == 1 && dir[0] == '.')
1830 s = pool->solvables + solvid;
1833 str = id2str(pool, s->arch);
1834 if (!strncmp(dir, str, l) && !str[l])
1835 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
1837 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
1840 char *dir2 = strdup(dir);
1842 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
1847 str = id2str(pool, s->name);
1849 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
1852 str = evrid2vrstr(pool, s->evr);
1854 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
1857 str = id2str(pool, s->arch);
1859 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
1861 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
1866 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
1870 repodata_globalize_id(Repodata *data, Id id)
1872 if (!data || !data->localpool)
1874 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
1878 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
1882 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
1884 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1885 data->attriddata[data->attriddatalen++] = dir;
1886 data->attriddata[data->attriddatalen++] = num;
1887 data->attriddata[data->attriddatalen++] = num2;
1888 data->attriddata[data->attriddatalen++] = 0;
1892 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
1898 l = strlen(str) + 1;
1899 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1900 memcpy(data->attrdata + data->attrdatalen, str, l);
1901 stroff = data->attrdatalen;
1902 data->attrdatalen += l;
1905 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
1907 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1908 data->attriddata[data->attriddatalen++] = dir;
1909 data->attriddata[data->attriddatalen++] = stroff;
1910 data->attriddata[data->attriddatalen++] = 0;
1914 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
1917 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
1919 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
1920 data->attriddata[data->attriddatalen++] = id;
1921 data->attriddata[data->attriddatalen++] = 0;
1925 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
1929 if (data->localpool)
1930 id = stringpool_str2id(&data->spool, str, 1);
1932 id = str2id(data->repo->pool, str, 1);
1933 repodata_add_idarray(data, solvid, keyname, id);
1937 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
1939 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
1940 data->attriddata[data->attriddatalen++] = ghandle;
1941 data->attriddata[data->attriddatalen++] = 0;
1945 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
1947 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
1948 data->attriddata[data->attriddatalen++] = ghandle;
1949 data->attriddata[data->attriddatalen++] = 0;
1953 repodata_merge_attrs(Repodata *data, Id dest, Id src)
1956 if (dest == src || !(keyp = data->attrs[src]))
1958 for (; *keyp; keyp += 2)
1959 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
1965 /**********************************************************************/
1967 /* unify with repo_write! */
1969 #define EXTDATA_BLOCK 1023
1977 data_addid(struct extdata *xd, Id x)
1980 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
1981 dp = xd->buf + xd->len;
1986 *dp++ = (x >> 28) | 128;
1988 *dp++ = (x >> 21) | 128;
1989 *dp++ = (x >> 14) | 128;
1992 *dp++ = (x >> 7) | 128;
1994 xd->len = dp - xd->buf;
1998 data_addideof(struct extdata *xd, Id x, int eof)
2001 x = (x & 63) | ((x & ~63) << 1);
2002 data_addid(xd, (eof ? x: x | 64));
2006 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2008 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2009 memcpy(xd->buf + xd->len, blob, len);
2013 /*********************************/
2016 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2017 struct extdata *newvincore,
2019 Repokey *key, Id val)
2021 /* Otherwise we have a new value. Parse it into the internal
2025 unsigned int oldvincorelen = 0;
2029 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2032 oldvincorelen = xd->len;
2036 case REPOKEY_TYPE_VOID:
2037 case REPOKEY_TYPE_CONSTANT:
2038 case REPOKEY_TYPE_CONSTANTID:
2040 case REPOKEY_TYPE_STR:
2041 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2043 case REPOKEY_TYPE_MD5:
2044 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2046 case REPOKEY_TYPE_SHA1:
2047 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2049 case REPOKEY_TYPE_SHA256:
2050 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2052 case REPOKEY_TYPE_ID:
2053 case REPOKEY_TYPE_NUM:
2054 case REPOKEY_TYPE_DIR:
2055 data_addid(xd, val);
2057 case REPOKEY_TYPE_IDARRAY:
2058 for (ida = data->attriddata + val; *ida; ida++)
2059 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2061 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2062 for (ida = data->attriddata + val; *ida; ida += 3)
2064 data_addid(xd, ida[0]);
2065 data_addid(xd, ida[1]);
2066 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2069 case REPOKEY_TYPE_DIRSTRARRAY:
2070 for (ida = data->attriddata + val; *ida; ida += 2)
2072 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2073 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2076 case REPOKEY_TYPE_FIXARRAY:
2080 for (ida = data->attriddata + val; *ida; ida++)
2083 fprintf(stderr, "serialize struct %d\n", *ida);
2086 Id *kp = data->xattrs[-*ida];
2093 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2099 schemaid = repodata_schema2id(data, schema, 1);
2100 else if (schemaid != repodata_schema2id(data, schema, 0))
2102 pool_debug(data->repo->pool, SAT_FATAL, "substructs with different schemas\n");
2106 fprintf(stderr, " schema %d\n", schemaid);
2111 data_addid(xd, num);
2112 data_addid(xd, schemaid);
2113 for (ida = data->attriddata + val; *ida; ida++)
2115 Id *kp = data->xattrs[-*ida];
2120 repodata_serialize_key(data, newincore, newvincore,
2121 schema, data->keys + *kp, kp[1]);
2126 case REPOKEY_TYPE_FLEXARRAY:
2129 for (ida = data->attriddata + val; *ida; ida++)
2131 data_addid(xd, num);
2132 for (ida = data->attriddata + val; *ida; ida++)
2134 Id *kp = data->xattrs[-*ida];
2137 data_addid(xd, 0); /* XXX */
2144 schemaid = repodata_schema2id(data, schema, 1);
2145 data_addid(xd, schemaid);
2146 kp = data->xattrs[-*ida];
2149 repodata_serialize_key(data, newincore, newvincore,
2150 schema, data->keys + *kp, kp[1]);
2156 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2159 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2161 /* put offset/len in incore */
2162 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2163 oldvincorelen = xd->len - oldvincorelen;
2164 data_addid(newincore, oldvincorelen);
2169 repodata_internalize(Repodata *data)
2171 Repokey *key, solvkey;
2173 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2174 unsigned char *dp, *ndp;
2175 int newschema, oldcount;
2176 struct extdata newincore;
2177 struct extdata newvincore;
2180 if (!data->attrs && !data->xattrs)
2183 newvincore.buf = data->vincore;
2184 newvincore.len = data->vincorelen;
2186 /* find the solvables key, create if needed */
2187 memset(&solvkey, 0, sizeof(solvkey));
2188 solvkey.name = REPOSITORY_SOLVABLES;
2189 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2191 solvkey.storage = KEY_STORAGE_INCORE;
2192 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2194 schema = sat_malloc2(data->nkeys, sizeof(Id));
2195 seen = sat_malloc2(data->nkeys, sizeof(Id));
2197 /* Merge the data already existing (in data->schemata, ->incoredata and
2198 friends) with the new attributes in data->attrs[]. */
2199 nentry = data->end - data->start;
2200 memset(&newincore, 0, sizeof(newincore));
2201 data_addid(&newincore, 0); /* start data at offset 1 */
2203 data->mainschema = 0;
2204 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2206 /* join entry data */
2207 /* we start with the meta data, entry -1 */
2208 for (entry = -1; entry < nentry; entry++)
2210 memset(seen, 0, data->nkeys * sizeof(Id));
2212 dp = data->incoredata;
2215 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2216 dp = data_read_id(dp, &oldschema);
2219 fprintf(stderr, "oldschema %d\n", oldschema);
2220 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2221 fprintf(stderr, "schemadata %p\n", data->schemadata);
2223 /* seen: -1: old data 0: skipped >0: id + 1 */
2227 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2231 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2239 keyp = data->attrs ? data->attrs[entry] : 0;
2242 /* strip solvables key */
2244 for (sp = keyp = schema; *sp; sp++)
2245 if (*sp != solvkeyid)
2250 seen[solvkeyid] = 0;
2251 keyp = data->xattrs ? data->xattrs[1] : 0;
2254 for (; *keyp; keyp += 2)
2261 seen[*keyp] = keyp[1] + 1;
2263 if (entry < 0 && data->end != data->start)
2270 /* Ideally we'd like to sort the new schema here, to ensure
2271 schema equality independend of the ordering. We can't do that
2272 yet. For once see below (old ids need to come before new ids).
2273 An additional difficulty is that we also need to move
2274 the values with the keys. */
2275 schemaid = repodata_schema2id(data, schema, 1);
2277 schemaid = oldschema;
2280 /* Now create data blob. We walk through the (possibly new) schema
2281 and either copy over old data, or insert the new. */
2282 /* XXX Here we rely on the fact that the (new) schema has the form
2283 o1 o2 o3 o4 ... | n1 n2 n3 ...
2284 (oX being the old keyids (possibly overwritten), and nX being
2285 the new keyids). This rules out sorting the keyids in order
2286 to ensure a small schema count. */
2288 data->incoreoffset[entry] = newincore.len;
2289 data_addid(&newincore, schemaid);
2292 data->mainschema = schemaid;
2293 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2295 keypstart = data->schemadata + data->schemata[schemaid];
2296 for (keyp = keypstart; *keyp; keyp++)
2299 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2300 if (*keyp == solvkeyid)
2302 /* add flexarray entry count */
2303 data_addid(&newincore, data->end - data->start);
2306 key = data->keys + *keyp;
2308 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2313 /* Skip the data associated with this old key. */
2314 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2316 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2317 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2319 else if (key->storage == KEY_STORAGE_INCORE)
2320 ndp = data_skip_key(data, dp, key);
2323 if (seen[*keyp] == -1)
2325 /* If this key was an old one _and_ was not overwritten with
2326 a different value copy over the old value (we skipped it
2329 data_addblob(&newincore, dp, ndp - dp);
2332 else if (seen[*keyp])
2334 /* Otherwise we have a new value. Parse it into the internal
2336 repodata_serialize_key(data, &newincore, &newvincore,
2337 schema, key, seen[*keyp] - 1);
2341 if (entry >= 0 && data->attrs && data->attrs[entry])
2342 data->attrs[entry] = sat_free(data->attrs[entry]);
2344 /* free all xattrs */
2345 for (entry = 0; entry < data->nxattrs; entry++)
2346 if (data->xattrs[entry])
2347 sat_free(data->xattrs[entry]);
2348 data->xattrs = sat_free(data->xattrs);
2351 data->lasthandle = 0;
2353 data->lastdatalen = 0;
2356 repodata_free_schemahash(data);
2358 sat_free(data->incoredata);
2359 data->incoredata = newincore.buf;
2360 data->incoredatalen = newincore.len;
2361 data->incoredatafree = 0;
2363 sat_free(data->vincore);
2364 data->vincore = newvincore.buf;
2365 data->vincorelen = newvincore.len;
2367 data->attrs = sat_free(data->attrs);
2368 data->attrdata = sat_free(data->attrdata);
2369 data->attriddata = sat_free(data->attriddata);
2370 data->attrdatalen = 0;
2371 data->attriddatalen = 0;
2375 repodata_disable_paging(Repodata *data)
2377 if (maybe_load_repodata(data, 0))
2378 repopagestore_disable_paging(&data->store);
2382 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: