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
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
35 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
36 unsigned char *out, unsigned int out_len);
37 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
40 unsigned int out_len);
42 #define REPODATA_BLOCK 255
46 repodata_init(Repodata *data, Repo *repo, int localpool)
48 memset(data, 0, sizeof (*data));
50 data->localpool = localpool;
52 stringpool_init_empty(&data->spool);
53 data->keys = sat_calloc(1, sizeof(Repokey));
55 data->schemata = sat_calloc(1, sizeof(Id));
56 data->schemadata = sat_calloc(1, sizeof(Id));
58 data->schemadatalen = 1;
59 repopagestore_init(&data->store);
63 repodata_free(Repodata *data)
69 sat_free(data->schemata);
70 sat_free(data->schemadata);
71 sat_free(data->schematahash);
73 stringpool_free(&data->spool);
74 dirpool_free(&data->dirpool);
76 sat_free(data->mainschemaoffsets);
77 sat_free(data->incoredata);
78 sat_free(data->incoreoffset);
79 sat_free(data->verticaloffset);
81 repopagestore_free(&data->store);
83 sat_free(data->vincore);
86 for (i = 0; i < data->end - data->start; i++)
87 sat_free(data->attrs[i]);
88 sat_free(data->attrs);
90 for (i = 0; i < data->nxattrs; i++)
91 sat_free(data->xattrs[i]);
92 sat_free(data->xattrs);
94 sat_free(data->attrdata);
95 sat_free(data->attriddata);
99 /***************************************************************
100 * key pool management
103 /* this is not so time critical that we need a hash, so we do a simple
106 repodata_key2id(Repodata *data, Repokey *key, int create)
110 for (keyid = 1; keyid < data->nkeys; keyid++)
111 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
113 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
117 if (keyid == data->nkeys)
121 /* allocate new key */
122 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
123 data->keys[data->nkeys++] = *key;
124 if (data->verticaloffset)
126 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
127 data->verticaloffset[data->nkeys - 1] = 0;
129 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
135 /***************************************************************
136 * schema pool management
139 #define SCHEMATA_BLOCK 31
140 #define SCHEMATADATA_BLOCK 255
143 repodata_schema2id(Repodata *data, Id *schema, int create)
149 if ((schematahash = data->schematahash) == 0)
151 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
152 for (i = 0; i < data->nschemata; i++)
154 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
157 schematahash[h] = i + 1;
159 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
160 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
163 for (sp = schema, len = 0, h = 0; *sp; len++)
168 cid = schematahash[h];
172 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
175 for (cid = 0; cid < data->nschemata; cid++)
176 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
182 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
183 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
185 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
186 data->schemata[data->nschemata] = data->schemadatalen;
187 data->schemadatalen += len;
188 schematahash[h] = data->nschemata + 1;
190 fprintf(stderr, "schema2id: new schema\n");
192 return data->nschemata++;
196 repodata_free_schemahash(Repodata *data)
198 data->schematahash = sat_free(data->schematahash);
200 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
201 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
205 /***************************************************************
206 * dir pool management
210 repodata_str2dir(Repodata *data, const char *dir, int create)
216 while (*dir == '/' && dir[1] == '/')
218 if (*dir == '/' && !dir[1])
222 dire = strchrnul(dir, '/');
224 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
226 id = strn2id(data->repo->pool, dir, dire - dir, create);
229 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
242 repodata_dir2str(Repodata *data, Id did, const char *suf)
244 Pool *pool = data->repo->pool;
251 return suf ? suf : "";
255 comp = dirpool_compid(&data->dirpool, parent);
256 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
258 parent = dirpool_parent(&data->dirpool, parent);
263 l += strlen(suf) + 1;
264 p = pool_alloctmpspace(pool, l + 1) + l;
275 comp = dirpool_compid(&data->dirpool, parent);
276 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
279 strncpy(p, comps, l);
280 parent = dirpool_parent(&data->dirpool, parent);
288 /***************************************************************
292 static inline unsigned char *
293 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
295 Id *keyp = data->schemadata + data->schemata[schema];
296 for (; *keyp; keyp++)
297 dp = data_skip_key(data, dp, data->keys + *keyp);
302 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
304 int nentries, schema;
307 case REPOKEY_TYPE_FIXARRAY:
308 dp = data_read_id(dp, &nentries);
311 dp = data_read_id(dp, &schema);
313 dp = data_skip_schema(data, dp, schema);
315 case REPOKEY_TYPE_FLEXARRAY:
316 dp = data_read_id(dp, &nentries);
319 dp = data_read_id(dp, &schema);
320 dp = data_skip_schema(data, dp, schema);
324 if (key->storage == KEY_STORAGE_INCORE)
325 dp = data_skip(dp, key->type);
326 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
328 dp = data_skip(dp, REPOKEY_TYPE_ID);
329 dp = data_skip(dp, REPOKEY_TYPE_ID);
335 static unsigned char *
336 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
342 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
345 for (i = 0; (k = *keyp++) != 0; i++)
347 return data->incoredata + data->mainschemaoffsets[i];
350 while ((k = *keyp++) != 0)
354 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
356 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
357 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
360 if (data->keys[k].storage != KEY_STORAGE_INCORE)
362 dp = data_skip_key(data, dp, data->keys + k);
367 static unsigned char *
368 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
373 if (off >= data->lastverticaloffset)
375 off -= data->lastverticaloffset;
376 if (off + len > data->vincorelen)
378 return data->vincore + off;
380 if (off + len > key->size)
382 /* we now have the offset, go into vertical */
383 off += data->verticaloffset[key - data->keys];
384 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
385 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
387 dp += off % BLOB_PAGESIZE;
391 static inline unsigned char *
392 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
394 unsigned char *dp = *dpp;
398 if (key->storage == KEY_STORAGE_INCORE)
401 *dpp = data_skip_key(data, dp, key);
404 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
407 dp = data_read_id(dp, &off);
408 dp = data_read_id(dp, &len);
411 return get_vertical_data(data, key, off, len);
417 load_repodata(Repodata *data)
419 if (data->loadcallback)
421 data->loadcallback(data);
422 if (data->state == REPODATA_AVAILABLE)
425 data->state = REPODATA_ERROR;
430 maybe_load_repodata(Repodata *data, Id keyname)
432 if (keyname && !repodata_precheck_keyname(data, keyname))
433 return 0; /* do not bother... */
440 for (i = 0; i < data->nkeys; i++)
441 if (keyname == data->keys[i].name)
443 if (i == data->nkeys)
446 return load_repodata(data);
449 case REPODATA_AVAILABLE:
452 data->state = REPODATA_ERROR;
457 static inline unsigned char *
458 solvid2data(Repodata *data, Id solvid, Id *schemap)
460 unsigned char *dp = data->incoredata;
463 if (solvid == SOLVID_META) /* META */
465 else if (solvid == SOLVID_POS) /* META */
467 Pool *pool = data->repo->pool;
468 if (data->repo != pool->pos.repo)
470 if (data != data->repo->repodata + pool->pos.repodataid)
472 *schemap = pool->pos.schema;
473 return data->incoredata + pool->pos.dp;
477 if (solvid < data->start || solvid >= data->end)
479 dp += data->incoreoffset[solvid - data->start];
481 return data_read_id(dp, schemap);
484 /************************************************************************
488 static inline unsigned char *
489 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
492 Id schema, *keyp, *kp;
495 if (!maybe_load_repodata(data, keyname))
497 dp = solvid2data(data, solvid, &schema);
500 keyp = data->schemadata + data->schemata[schema];
501 for (kp = keyp; *kp; kp++)
502 if (data->keys[*kp].name == keyname)
506 *keypp = key = data->keys + *kp;
507 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
508 return dp; /* no need to forward... */
509 dp = forward_to_key(data, *kp, keyp, dp);
512 return get_data(data, key, &dp, 0);
517 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
523 dp = find_key_data(data, solvid, keyname, &key);
526 if (key->type == REPOKEY_TYPE_CONSTANTID)
528 if (key->type != REPOKEY_TYPE_ID)
530 dp = data_read_id(dp, &id);
535 repodata_globalize_id(Repodata *data, Id id, int create)
537 if (!id || !data || !data->localpool)
539 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
543 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
549 dp = find_key_data(data, solvid, keyname, &key);
552 if (key->type == REPOKEY_TYPE_STR)
553 return (const char *)dp;
554 if (key->type == REPOKEY_TYPE_CONSTANTID)
555 return id2str(data->repo->pool, key->size);
556 if (key->type == REPOKEY_TYPE_ID)
557 dp = data_read_id(dp, &id);
561 return data->spool.stringspace + data->spool.strings[id];
562 return id2str(data->repo->pool, id);
566 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned int *value)
573 dp = find_key_data(data, solvid, keyname, &key);
576 if (key->type == REPOKEY_TYPE_NUM
577 || key->type == REPOKEY_TYPE_U32
578 || key->type == REPOKEY_TYPE_CONSTANT)
580 dp = data_fetch(dp, &kv, key);
588 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
594 if (!maybe_load_repodata(data, keyname))
596 dp = solvid2data(data, solvid, &schema);
599 /* can't use find_key_data as we need to test the type */
600 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
601 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
606 const unsigned char *
607 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
612 dp = find_key_data(data, solvid, keyname, &key);
620 /************************************************************************
626 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
630 case REPOKEY_TYPE_ID:
631 case REPOKEY_TYPE_CONSTANTID:
632 case REPOKEY_TYPE_IDARRAY:
633 if (data && data->localpool)
634 kv->str = stringpool_id2str(&data->spool, kv->id);
636 kv->str = id2str(pool, kv->id);
637 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
639 const char *s = strchr(kv->str, ':');
644 case REPOKEY_TYPE_STR:
646 case REPOKEY_TYPE_DIRSTRARRAY:
647 if (!(flags & SEARCH_FILES))
648 return 1; /* match just the basename */
649 /* Put the full filename into kv->str. */
650 kv->str = repodata_dir2str(data, kv->id, kv->str);
651 /* And to compensate for that put the "empty" directory into
652 kv->id, so that later calls to repodata_dir2str on this data
653 come up with the same filename again. */
662 struct subschema_data {
668 /* search a specific repodata */
670 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
674 Id keyid, *kp, *keyp;
675 unsigned char *dp, *ddp;
681 if (!maybe_load_repodata(data, keyname))
683 if (solvid == SOLVID_SUBSCHEMA)
685 struct subschema_data *subd = cbdata;
686 cbdata = subd->cbdata;
688 schema = subd->parent->id;
689 dp = (unsigned char *)subd->parent->str;
690 kv.parent = subd->parent;
695 dp = solvid2data(data, solvid, &schema);
698 s = data->repo->pool->solvables + solvid;
701 keyp = data->schemadata + data->schemata[schema];
704 /* search for a specific key */
705 for (kp = keyp; *kp; kp++)
706 if (data->keys[*kp].name == keyname)
710 dp = forward_to_key(data, *kp, keyp, dp);
716 while ((keyid = *keyp++) != 0)
719 key = data->keys + keyid;
720 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
722 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
724 struct subschema_data subd;
728 subd.cbdata = cbdata;
731 ddp = data_read_id(ddp, &nentries);
735 while (ddp && nentries > 0)
739 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
740 ddp = data_read_id(ddp, &schema);
742 kv.str = (char *)ddp;
743 stop = callback(cbdata, s, data, key, &kv);
744 if (stop > SEARCH_NEXT_KEY)
746 if (stop && stop != SEARCH_ENTERSUB)
748 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
749 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
750 ddp = data_skip_schema(data, ddp, schema);
753 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
757 kv.str = (char *)ddp;
758 stop = callback(cbdata, s, data, key, &kv);
759 if (stop > SEARCH_NEXT_KEY)
769 ddp = data_fetch(ddp, &kv, key);
772 stop = callback(cbdata, s, data, key, &kv);
775 while (!kv.eof && !stop);
776 if (onekey || stop > SEARCH_NEXT_KEY)
782 repodata_setpos_kv(Repodata *data, KeyValue *kv)
784 Pool *pool = data->repo->pool;
786 pool_clear_pos(pool);
789 pool->pos.repo = data->repo;
790 pool->pos.repodataid = data - data->repo->repodata;
791 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
792 pool->pos.schema = kv->id;
796 /************************************************************************
797 * data iterator functions
800 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
801 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
802 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
803 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
804 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
805 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
806 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
807 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
808 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
809 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
810 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
811 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
812 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
813 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
817 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
831 case SOLVABLE_VENDOR:
834 case SOLVABLE_PROVIDES:
836 return s->provides ? s->repo->idarraydata + s->provides : 0;
837 case SOLVABLE_OBSOLETES:
839 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
840 case SOLVABLE_CONFLICTS:
842 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
843 case SOLVABLE_REQUIRES:
845 return s->requires ? s->repo->idarraydata + s->requires : 0;
846 case SOLVABLE_RECOMMENDS:
848 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
849 case SOLVABLE_SUPPLEMENTS:
851 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
852 case SOLVABLE_SUGGESTS:
854 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
855 case SOLVABLE_ENHANCES:
857 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
860 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
867 datamatcher_init(Datamatcher *ma, const char *match, int flags)
869 ma->match = (void *)match;
872 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
874 ma->match = sat_calloc(1, sizeof(regex_t));
875 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
879 ma->match = (void *)match;
880 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
887 datamatcher_free(Datamatcher *ma)
889 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
892 ma->match = sat_free(ma->match);
897 datamatcher_match(Datamatcher *ma, const char *str)
899 switch ((ma->flags & SEARCH_STRINGMASK))
901 case SEARCH_SUBSTRING:
902 if (ma->flags & SEARCH_NOCASE)
904 if (!strcasestr(str, (const char *)ma->match))
909 if (!strstr(str, (const char *)ma->match))
914 if (ma->flags & SEARCH_NOCASE)
916 if (strcasecmp((const char *)ma->match, str))
921 if (strcmp((const char *)ma->match, str))
926 if (fnmatch((const char *)ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
930 if (regexec((const regex_t *)ma->match, str, 0, NULL, 0))
965 /* see repo.h for documentation */
967 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
969 memset(di, 0, sizeof(*di));
971 if (!pool || (repo && repo->pool != pool))
979 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
986 di->keyname = keyname;
987 di->keynames[0] = keyname;
988 di->flags = flags & ~SEARCH_THISSOLVID;
997 dataiterator_jump_to_solvid(di, p);
1001 di->repo = pool->repos[0];
1002 di->state = di_enterrepo;
1008 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1012 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1014 di->state = di_bye; /* sorry */
1017 for (i = di->nkeynames + 1; i > 0; i--)
1018 di->keynames[i] = di->keynames[i - 1];
1019 di->keynames[0] = di->keyname = keyname;
1024 dataiterator_free(Dataiterator *di)
1026 if (di->matcher.match)
1027 datamatcher_free(&di->matcher);
1030 static inline unsigned char *
1031 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1033 Id *keyp = di->keyp;
1034 Repokey *keys = di->data->keys;
1037 for (keyp = di->keyp; *keyp; keyp++)
1038 if (keys[*keyp].name == keyname)
1042 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1050 dataiterator_step(Dataiterator *di)
1058 case di_enterrepo: di_enterrepo:
1061 if (!(di->flags & SEARCH_THISSOLVID))
1063 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1064 goto di_nextsolvable;
1068 case di_entersolvable: di_entersolvable:
1069 if (di->repodataid >= 0)
1071 di->repodataid = 0; /* reset repodata iterator */
1072 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents == di->nkeynames)
1074 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1076 goto di_entersolvablekey;
1081 case di_enterrepodata: di_enterrepodata:
1082 if (di->repodataid >= 0)
1084 if (di->repodataid >= di->repo->nrepodata)
1085 goto di_nextsolvable;
1086 di->data = di->repo->repodata + di->repodataid;
1088 if (!maybe_load_repodata(di->data, di->keyname))
1089 goto di_nextrepodata;
1090 di->dp = solvid2data(di->data, di->solvid, &schema);
1092 goto di_nextrepodata;
1093 if (di->solvid == SOLVID_POS)
1094 di->solvid = di->pool->pos.solvid;
1095 /* reset key iterator */
1096 di->keyp = di->data->schemadata + di->data->schemata[schema];
1099 case di_enterschema: di_enterschema:
1101 di->dp = dataiterator_find_keyname(di, di->keyname);
1102 if (!di->dp || !*di->keyp)
1106 goto di_nextrepodata;
1110 case di_enterkey: di_enterkey:
1112 di->key = di->data->keys + *di->keyp;
1113 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1116 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1118 if (di->nparents < di->nkeynames)
1124 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1126 di->state = di_nextkey;
1128 di->state = di_nextattr;
1131 case di_nextkey: di_nextkey:
1132 if (!di->keyname && *++di->keyp)
1138 case di_nextrepodata: di_nextrepodata:
1139 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1140 goto di_enterrepodata;
1143 case di_nextsolvable: di_nextsolvable:
1144 if (!(di->flags & SEARCH_THISSOLVID))
1147 di->solvid = di->repo->start;
1150 for (; di->solvid < di->repo->end; di->solvid++)
1152 if (di->pool->solvables[di->solvid].repo == di->repo)
1153 goto di_entersolvable;
1159 if (di->repoid >= 0)
1162 if (di->repoid < di->pool->nrepos)
1164 di->repo = di->pool->repos[di->repoid];
1170 case di_bye: di_bye:
1174 case di_enterarray: di_enterarray:
1175 if (di->key->name == REPOSITORY_SOLVABLES)
1177 di->ddp = data_read_id(di->ddp, &di->kv.num);
1182 case di_nextarrayelement: di_nextarrayelement:
1185 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1186 if (di->kv.entry == di->kv.num)
1188 if (di->nparents < di->nkeynames)
1190 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1192 di->kv.str = (char *)di->ddp;
1194 di->state = di_nextkey;
1197 if (di->kv.entry == di->kv.num - 1)
1199 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1200 di->ddp = data_read_id(di->ddp, &di->kv.id);
1201 di->kv.str = (char *)di->ddp;
1202 if (di->nparents < di->nkeynames)
1204 if ((di->flags & SEARCH_SUB) != 0)
1205 di->state = di_entersub;
1207 di->state = di_nextarrayelement;
1210 case di_entersub: di_entersub:
1211 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1212 goto di_nextarrayelement; /* sorry, full */
1213 di->parents[di->nparents].kv = di->kv;
1214 di->parents[di->nparents].dp = di->dp;
1215 di->parents[di->nparents].keyp = di->keyp;
1216 di->dp = (unsigned char *)di->kv.str;
1217 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1218 memset(&di->kv, 0, sizeof(di->kv));
1219 di->kv.parent = &di->parents[di->nparents].kv;
1221 di->keyname = di->keynames[di->nparents];
1222 goto di_enterschema;
1224 case di_leavesub: di_leavesub:
1226 di->dp = di->parents[di->nparents].dp;
1227 di->kv = di->parents[di->nparents].kv;
1228 di->keyp = di->parents[di->nparents].keyp;
1229 di->key = di->data->keys + *di->keyp;
1230 di->ddp = (unsigned char *)di->kv.str;
1231 di->keyname = di->keynames[di->nparents];
1234 goto di_nextarrayelement;
1236 /* special solvable attr handling follows */
1238 case di_nextsolvableattr:
1239 di->kv.id = *di->idp++;
1244 di->state = di_nextsolvablekey;
1248 case di_nextsolvablekey: di_nextsolvablekey:
1249 if (di->keyname || di->key->name == RPM_RPMDBID)
1250 goto di_enterrepodata;
1254 case di_entersolvablekey: di_entersolvablekey:
1255 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1256 if (!di->idp || !di->idp[0])
1257 goto di_nextsolvablekey;
1258 di->kv.id = di->idp[0];
1259 di->kv.num = di->idp[0];
1261 if (!di->kv.eof && !di->idp[0])
1265 di->state = di_nextsolvablekey;
1267 di->state = di_nextsolvableattr;
1271 if (di->matcher.match)
1273 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1275 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1279 if (!datamatcher_match(&di->matcher, di->kv.str))
1282 /* found something! */
1288 dataiterator_entersub(Dataiterator *di)
1290 if (di->state == di_nextarrayelement)
1291 di->state = di_entersub;
1295 dataiterator_setpos(Dataiterator *di)
1297 if (di->kv.eof == 2)
1299 pool_clear_pos(di->pool);
1302 di->pool->pos.solvid = di->solvid;
1303 di->pool->pos.repo = di->repo;
1304 di->pool->pos.repodataid = di->data - di->repo->repodata;
1305 di->pool->pos.schema = di->kv.id;
1306 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1310 dataiterator_setpos_parent(Dataiterator *di)
1312 if (!di->kv.parent || di->kv.parent->eof == 2)
1314 pool_clear_pos(di->pool);
1317 di->pool->pos.solvid = di->solvid;
1318 di->pool->pos.repo = di->repo;
1319 di->pool->pos.repodataid = di->data - di->repo->repodata;
1320 di->pool->pos.schema = di->kv.parent->id;
1321 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1324 /* clones just the position, not the search keys/matcher */
1326 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1328 di->state = from->state;
1329 di->flags &= ~SEARCH_THISSOLVID;
1330 di->flags |= (from->flags & SEARCH_THISSOLVID);
1331 di->repo = from->repo;
1332 di->data = from->data;
1334 di->ddp = from->ddp;
1335 di->idp = from->idp;
1336 di->keyp = from->keyp;
1337 di->key = from->key;
1339 di->repodataid = from->repodataid;
1340 di->solvid = from->solvid;
1341 di->repoid = from->repoid;
1342 memcpy(di->parents, from->parents, sizeof(from->parents));
1346 for (i = 1; i < di->nparents; i++)
1347 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1348 di->kv.parent = &di->parents[di->nparents - 1].kv;
1353 dataiterator_seek(Dataiterator *di, int whence)
1355 const char *lastparentstr = 0;
1358 if ((whence & DI_SEEK_STAY) != 0)
1360 for (i = 0; i < di->nparents; i++)
1361 di->parents[i].kv.str = 0;
1362 lastparentstr = di->nparents ? di->parents[di->nparents - 1].kv.str : 0;
1364 switch (whence & ~DI_SEEK_STAY)
1367 if (di->state != di_nextarrayelement)
1369 if ((whence & DI_SEEK_STAY) != 0)
1371 di->state = di_entersub;
1373 case DI_SEEK_PARENT:
1376 if ((whence & DI_SEEK_STAY) != 0)
1377 di->parents[di->nparents - 1].kv.str = lastparentstr;
1379 di->dp = di->parents[di->nparents].dp;
1380 di->kv = di->parents[di->nparents].kv;
1381 di->keyp = di->parents[di->nparents].keyp;
1382 di->key = di->data->keys + *di->keyp;
1383 di->ddp = (unsigned char *)di->kv.str;
1384 di->keyname = di->keynames[di->nparents];
1385 di->state = di->ddp ? di_nextarrayelement : di_bye;
1387 case DI_SEEK_REWIND:
1390 di->dp = (unsigned char *)di->kv.parent->str;
1391 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1392 di->state = di_enterschema;
1400 dataiterator_skip_attribute(Dataiterator *di)
1402 if (di->state == di_nextsolvableattr)
1403 di->state = di_nextsolvablekey;
1405 di->state = di_nextkey;
1409 dataiterator_skip_solvable(Dataiterator *di)
1411 di->state = di_nextsolvable;
1415 dataiterator_skip_repo(Dataiterator *di)
1417 di->state = di_nextrepo;
1421 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1424 if (solvid == SOLVID_POS)
1426 di->repo = di->pool->pos.repo;
1433 di->data = di->repo->repodata + di->pool->pos.repodataid;
1434 di->repodataid = -1;
1435 di->solvid = solvid;
1436 di->state = di_enterrepo;
1437 di->flags |= SEARCH_THISSOLVID;
1442 di->repo = di->pool->solvables[solvid].repo;
1445 else if (di->repoid >= 0)
1447 if (!di->pool->nrepos)
1452 di->repo = di->pool->repos[0];
1456 di->solvid = solvid;
1458 di->flags |= SEARCH_THISSOLVID;
1459 di->state = di_enterrepo;
1463 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1470 di->flags &= ~SEARCH_THISSOLVID;
1471 di->state = di_enterrepo;
1475 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1477 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1481 return datamatcher_match(ma, di->kv.str);
1484 /************************************************************************
1485 * data modify functions
1488 /* extend repodata so that it includes solvables p */
1490 repodata_extend(Repodata *data, Id p)
1492 if (data->start == data->end)
1493 data->start = data->end = p;
1496 int old = data->end - data->start;
1497 int new = p - data->end + 1;
1500 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1501 memset(data->attrs + old, 0, new * sizeof(Id *));
1503 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1504 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1507 if (p < data->start)
1509 int old = data->end - data->start;
1510 int new = data->start - p;
1513 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1514 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1515 memset(data->attrs, 0, new * sizeof(Id *));
1517 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1518 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1519 memset(data->incoreoffset, 0, new * sizeof(Id));
1524 /* extend repodata so that it includes solvables from start to start + num - 1 */
1526 repodata_extend_block(Repodata *data, Id start, Id num)
1530 if (!data->incoreoffset)
1532 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1533 data->start = start;
1534 data->end = start + num;
1537 repodata_extend(data, start);
1539 repodata_extend(data, start + num - 1);
1542 /**********************************************************************/
1544 #define REPODATA_ATTRS_BLOCK 63
1545 #define REPODATA_ATTRDATA_BLOCK 1023
1546 #define REPODATA_ATTRIDDATA_BLOCK 63
1550 repodata_new_handle(Repodata *data)
1554 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1557 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1558 data->xattrs[data->nxattrs] = 0;
1559 return -(data->nxattrs++);
1563 repodata_get_attrp(Repodata *data, Id handle)
1565 if (handle == SOLVID_META)
1569 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1574 return data->xattrs - handle;
1575 if (handle < data->start || handle >= data->end)
1576 repodata_extend(data, handle);
1578 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1579 return data->attrs + (handle - data->start);
1583 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1589 app = repodata_get_attrp(data, handle);
1594 for (pp = ap; *pp; pp += 2)
1595 /* Determine equality based on the name only, allows us to change
1596 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1597 if (data->keys[*pp].name == data->keys[keyid].name)
1610 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1620 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1624 keyid = repodata_key2id(data, key, 1);
1625 repodata_insert_keyid(data, solvid, keyid, val, 1);
1629 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1633 key.type = REPOKEY_TYPE_ID;
1635 key.storage = KEY_STORAGE_INCORE;
1636 repodata_set(data, solvid, &key, id);
1640 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1644 key.type = REPOKEY_TYPE_NUM;
1646 key.storage = KEY_STORAGE_INCORE;
1647 repodata_set(data, solvid, &key, (Id)num);
1651 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1655 if (data->localpool)
1656 id = stringpool_str2id(&data->spool, str, 1);
1658 id = str2id(data->repo->pool, str, 1);
1660 key.type = REPOKEY_TYPE_ID;
1662 key.storage = KEY_STORAGE_INCORE;
1663 repodata_set(data, solvid, &key, id);
1667 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1671 key.type = REPOKEY_TYPE_CONSTANT;
1672 key.size = constant;
1673 key.storage = KEY_STORAGE_INCORE;
1674 repodata_set(data, solvid, &key, 0);
1678 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1682 key.type = REPOKEY_TYPE_CONSTANTID;
1684 key.storage = KEY_STORAGE_INCORE;
1685 repodata_set(data, solvid, &key, 0);
1689 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1693 key.type = REPOKEY_TYPE_VOID;
1695 key.storage = KEY_STORAGE_INCORE;
1696 repodata_set(data, solvid, &key, 0);
1700 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1705 l = strlen(str) + 1;
1707 key.type = REPOKEY_TYPE_STR;
1709 key.storage = KEY_STORAGE_INCORE;
1710 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1711 memcpy(data->attrdata + data->attrdatalen, str, l);
1712 repodata_set(data, solvid, &key, data->attrdatalen);
1713 data->attrdatalen += l;
1716 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1717 * so that the caller can append the new element there */
1719 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1722 Id *ida, *pp, **ppp;
1724 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1726 /* great! just append the new data */
1727 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1728 data->attriddatalen--; /* overwrite terminating 0 */
1729 data->lastdatalen += entrysize;
1732 ppp = repodata_get_attrp(data, handle);
1735 for (; *pp; pp += 2)
1736 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1740 /* not found. allocate new key */
1745 key.storage = KEY_STORAGE_INCORE;
1746 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1747 repodata_set(data, handle, &key, data->attriddatalen);
1748 data->lasthandle = 0; /* next time... */
1752 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1753 oldsize += entrysize;
1754 if (ida + 1 == data->attriddata + data->attriddatalen)
1756 /* this was the last entry, just append it */
1757 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1758 data->attriddatalen--; /* overwrite terminating 0 */
1762 /* too bad. move to back. */
1763 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1764 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1765 pp[1] = data->attriddatalen;
1766 data->attriddatalen += oldsize;
1768 data->lasthandle = handle;
1769 data->lastkey = *pp;
1770 data->lastdatalen = data->attriddatalen + entrysize + 1;
1774 checksumtype2len(Id type)
1778 case REPOKEY_TYPE_MD5:
1780 case REPOKEY_TYPE_SHA1:
1782 case REPOKEY_TYPE_SHA256:
1783 return SIZEOF_SHA256;
1790 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1791 const unsigned char *str)
1794 int l = checksumtype2len(type);
1801 key.storage = KEY_STORAGE_INCORE;
1802 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1803 memcpy(data->attrdata + data->attrdatalen, str, l);
1804 repodata_set(data, solvid, &key, data->attrdatalen);
1805 data->attrdatalen += l;
1809 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1812 for (i = 0; i < buflen; i++)
1814 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1815 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1816 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1827 buf[i] = (buf[i] << 4) | v;
1834 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1837 unsigned char buf[64];
1838 int l = checksumtype2len(type);
1842 if (hexstr2bytes(buf, str, l) != l)
1844 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1848 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1853 l = checksumtype2len(type);
1856 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1857 for (i = 0; i < l; i++)
1859 unsigned char v = buf[i];
1860 unsigned char w = v >> 4;
1861 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1863 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1869 /* rpm filenames don't contain the epoch, so strip it */
1870 static inline const char *
1871 evrid2vrstr(Pool *pool, Id evrid)
1873 const char *p, *evr = id2str(pool, evrid);
1876 for (p = evr; *p >= '0' && *p <= '9'; p++)
1878 return p != evr && *p == ':' ? p + 1 : evr;
1882 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
1884 Pool *pool = data->repo->pool;
1886 const char *str, *fp;
1890 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
1893 if ((dir = strrchr(file, '/')) != 0)
1904 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
1909 if (l == 1 && dir[0] == '.')
1911 s = pool->solvables + solvid;
1914 str = id2str(pool, s->arch);
1915 if (!strncmp(dir, str, l) && !str[l])
1916 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
1918 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
1921 char *dir2 = strdup(dir);
1923 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
1928 str = id2str(pool, s->name);
1930 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
1933 str = evrid2vrstr(pool, s->evr);
1935 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
1938 str = id2str(pool, s->arch);
1940 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
1942 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
1947 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
1951 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
1955 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
1957 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1958 data->attriddata[data->attriddatalen++] = dir;
1959 data->attriddata[data->attriddatalen++] = num;
1960 data->attriddata[data->attriddatalen++] = num2;
1961 data->attriddata[data->attriddatalen++] = 0;
1965 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
1971 l = strlen(str) + 1;
1972 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1973 memcpy(data->attrdata + data->attrdatalen, str, l);
1974 stroff = data->attrdatalen;
1975 data->attrdatalen += l;
1978 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
1980 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
1981 data->attriddata[data->attriddatalen++] = dir;
1982 data->attriddata[data->attriddatalen++] = stroff;
1983 data->attriddata[data->attriddatalen++] = 0;
1987 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
1990 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
1992 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
1993 data->attriddata[data->attriddatalen++] = id;
1994 data->attriddata[data->attriddatalen++] = 0;
1998 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2002 if (data->localpool)
2003 id = stringpool_str2id(&data->spool, str, 1);
2005 id = str2id(data->repo->pool, str, 1);
2006 repodata_add_idarray(data, solvid, keyname, id);
2010 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2012 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2013 data->attriddata[data->attriddatalen++] = ghandle;
2014 data->attriddata[data->attriddatalen++] = 0;
2018 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2020 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2021 data->attriddata[data->attriddatalen++] = ghandle;
2022 data->attriddata[data->attriddatalen++] = 0;
2025 /* add all attrs from src to dest */
2027 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2030 if (dest == src || !(keyp = data->attrs[src - data->start]))
2032 for (; *keyp; keyp += 2)
2033 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2039 /**********************************************************************/
2041 /* unify with repo_write! */
2043 #define EXTDATA_BLOCK 1023
2051 data_addid(struct extdata *xd, Id x)
2054 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2055 dp = xd->buf + xd->len;
2060 *dp++ = (x >> 28) | 128;
2062 *dp++ = (x >> 21) | 128;
2063 *dp++ = (x >> 14) | 128;
2066 *dp++ = (x >> 7) | 128;
2068 xd->len = dp - xd->buf;
2072 data_addideof(struct extdata *xd, Id x, int eof)
2075 x = (x & 63) | ((x & ~63) << 1);
2076 data_addid(xd, (eof ? x: x | 64));
2080 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2082 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2083 memcpy(xd->buf + xd->len, blob, len);
2087 /*********************************/
2090 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2091 struct extdata *newvincore,
2093 Repokey *key, Id val)
2095 /* Otherwise we have a new value. Parse it into the internal
2099 unsigned int oldvincorelen = 0;
2103 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2106 oldvincorelen = xd->len;
2110 case REPOKEY_TYPE_VOID:
2111 case REPOKEY_TYPE_CONSTANT:
2112 case REPOKEY_TYPE_CONSTANTID:
2114 case REPOKEY_TYPE_STR:
2115 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2117 case REPOKEY_TYPE_MD5:
2118 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2120 case REPOKEY_TYPE_SHA1:
2121 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2123 case REPOKEY_TYPE_SHA256:
2124 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2126 case REPOKEY_TYPE_ID:
2127 case REPOKEY_TYPE_NUM:
2128 case REPOKEY_TYPE_DIR:
2129 data_addid(xd, val);
2131 case REPOKEY_TYPE_IDARRAY:
2132 for (ida = data->attriddata + val; *ida; ida++)
2133 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2135 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2136 for (ida = data->attriddata + val; *ida; ida += 3)
2138 data_addid(xd, ida[0]);
2139 data_addid(xd, ida[1]);
2140 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2143 case REPOKEY_TYPE_DIRSTRARRAY:
2144 for (ida = data->attriddata + val; *ida; ida += 2)
2146 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2147 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2150 case REPOKEY_TYPE_FIXARRAY:
2154 for (ida = data->attriddata + val; *ida; ida++)
2157 fprintf(stderr, "serialize struct %d\n", *ida);
2160 Id *kp = data->xattrs[-*ida];
2167 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2173 schemaid = repodata_schema2id(data, schema, 1);
2174 else if (schemaid != repodata_schema2id(data, schema, 0))
2176 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2180 fprintf(stderr, " schema %d\n", schemaid);
2185 data_addid(xd, num);
2186 data_addid(xd, schemaid);
2187 for (ida = data->attriddata + val; *ida; ida++)
2189 Id *kp = data->xattrs[-*ida];
2194 repodata_serialize_key(data, newincore, newvincore,
2195 schema, data->keys + *kp, kp[1]);
2200 case REPOKEY_TYPE_FLEXARRAY:
2203 for (ida = data->attriddata + val; *ida; ida++)
2205 data_addid(xd, num);
2206 for (ida = data->attriddata + val; *ida; ida++)
2208 Id *kp = data->xattrs[-*ida];
2211 data_addid(xd, 0); /* XXX */
2218 schemaid = repodata_schema2id(data, schema, 1);
2219 data_addid(xd, schemaid);
2220 kp = data->xattrs[-*ida];
2223 repodata_serialize_key(data, newincore, newvincore,
2224 schema, data->keys + *kp, kp[1]);
2230 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2233 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2235 /* put offset/len in incore */
2236 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2237 oldvincorelen = xd->len - oldvincorelen;
2238 data_addid(newincore, oldvincorelen);
2243 repodata_internalize(Repodata *data)
2245 Repokey *key, solvkey;
2247 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2248 unsigned char *dp, *ndp;
2249 int newschema, oldcount;
2250 struct extdata newincore;
2251 struct extdata newvincore;
2254 if (!data->attrs && !data->xattrs)
2257 newvincore.buf = data->vincore;
2258 newvincore.len = data->vincorelen;
2260 /* find the solvables key, create if needed */
2261 memset(&solvkey, 0, sizeof(solvkey));
2262 solvkey.name = REPOSITORY_SOLVABLES;
2263 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2265 solvkey.storage = KEY_STORAGE_INCORE;
2266 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2268 schema = sat_malloc2(data->nkeys, sizeof(Id));
2269 seen = sat_malloc2(data->nkeys, sizeof(Id));
2271 /* Merge the data already existing (in data->schemata, ->incoredata and
2272 friends) with the new attributes in data->attrs[]. */
2273 nentry = data->end - data->start;
2274 memset(&newincore, 0, sizeof(newincore));
2275 data_addid(&newincore, 0); /* start data at offset 1 */
2277 data->mainschema = 0;
2278 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2280 /* join entry data */
2281 /* we start with the meta data, entry -1 */
2282 for (entry = -1; entry < nentry; entry++)
2284 memset(seen, 0, data->nkeys * sizeof(Id));
2286 dp = data->incoredata;
2289 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2290 dp = data_read_id(dp, &oldschema);
2293 fprintf(stderr, "oldschema %d\n", oldschema);
2294 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2295 fprintf(stderr, "schemadata %p\n", data->schemadata);
2297 /* seen: -1: old data 0: skipped >0: id + 1 */
2301 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2305 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2313 keyp = data->attrs ? data->attrs[entry] : 0;
2316 /* strip solvables key */
2318 for (sp = keyp = schema; *sp; sp++)
2319 if (*sp != solvkeyid)
2324 seen[solvkeyid] = 0;
2325 keyp = data->xattrs ? data->xattrs[1] : 0;
2328 for (; *keyp; keyp += 2)
2335 seen[*keyp] = keyp[1] + 1;
2337 if (entry < 0 && data->end != data->start)
2344 /* Ideally we'd like to sort the new schema here, to ensure
2345 schema equality independend of the ordering. We can't do that
2346 yet. For once see below (old ids need to come before new ids).
2347 An additional difficulty is that we also need to move
2348 the values with the keys. */
2349 schemaid = repodata_schema2id(data, schema, 1);
2351 schemaid = oldschema;
2354 /* Now create data blob. We walk through the (possibly new) schema
2355 and either copy over old data, or insert the new. */
2356 /* XXX Here we rely on the fact that the (new) schema has the form
2357 o1 o2 o3 o4 ... | n1 n2 n3 ...
2358 (oX being the old keyids (possibly overwritten), and nX being
2359 the new keyids). This rules out sorting the keyids in order
2360 to ensure a small schema count. */
2362 data->incoreoffset[entry] = newincore.len;
2363 data_addid(&newincore, schemaid);
2366 data->mainschema = schemaid;
2367 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2369 keypstart = data->schemadata + data->schemata[schemaid];
2370 for (keyp = keypstart; *keyp; keyp++)
2373 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2374 if (*keyp == solvkeyid)
2376 /* add flexarray entry count */
2377 data_addid(&newincore, data->end - data->start);
2380 key = data->keys + *keyp;
2382 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2387 /* Skip the data associated with this old key. */
2388 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2390 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2391 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2393 else if (key->storage == KEY_STORAGE_INCORE)
2394 ndp = data_skip_key(data, dp, key);
2397 if (seen[*keyp] == -1)
2399 /* If this key was an old one _and_ was not overwritten with
2400 a different value copy over the old value (we skipped it
2403 data_addblob(&newincore, dp, ndp - dp);
2406 else if (seen[*keyp])
2408 /* Otherwise we have a new value. Parse it into the internal
2410 repodata_serialize_key(data, &newincore, &newvincore,
2411 schema, key, seen[*keyp] - 1);
2415 if (entry >= 0 && data->attrs && data->attrs[entry])
2416 data->attrs[entry] = sat_free(data->attrs[entry]);
2418 /* free all xattrs */
2419 for (entry = 0; entry < data->nxattrs; entry++)
2420 if (data->xattrs[entry])
2421 sat_free(data->xattrs[entry]);
2422 data->xattrs = sat_free(data->xattrs);
2425 data->lasthandle = 0;
2427 data->lastdatalen = 0;
2430 repodata_free_schemahash(data);
2432 sat_free(data->incoredata);
2433 data->incoredata = newincore.buf;
2434 data->incoredatalen = newincore.len;
2435 data->incoredatafree = 0;
2437 sat_free(data->vincore);
2438 data->vincore = newvincore.buf;
2439 data->vincorelen = newvincore.len;
2441 data->attrs = sat_free(data->attrs);
2442 data->attrdata = sat_free(data->attrdata);
2443 data->attriddata = sat_free(data->attriddata);
2444 data->attrdatalen = 0;
2445 data->attriddatalen = 0;
2449 repodata_disable_paging(Repodata *data)
2451 if (maybe_load_repodata(data, 0))
2452 repopagestore_disable_paging(&data->store);
2456 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: