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)
985 di->keyname = keyname;
986 di->keynames[0] = keyname;
987 dataiterator_set_search(di, repo, p);
992 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
994 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
995 datamatcher_free(&di->matcher);
996 memset(&di->matcher, 0, sizeof(di->matcher));
1000 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1010 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1014 di->flags &= ~SEARCH_THISSOLVID;
1018 if (!di->pool->nrepos)
1026 di->repo = di->pool->repos[0];
1028 di->state = di_enterrepo;
1030 dataiterator_jump_to_solvid(di, p);
1034 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1037 di->keyname = keyname;
1038 di->keynames[0] = keyname;
1042 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1046 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1048 di->state = di_bye; /* sorry */
1051 for (i = di->nkeynames + 1; i > 0; i--)
1052 di->keynames[i] = di->keynames[i - 1];
1053 di->keynames[0] = di->keyname = keyname;
1058 dataiterator_free(Dataiterator *di)
1060 if (di->matcher.match)
1061 datamatcher_free(&di->matcher);
1064 static inline unsigned char *
1065 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1067 Id *keyp = di->keyp;
1068 Repokey *keys = di->data->keys;
1071 for (keyp = di->keyp; *keyp; keyp++)
1072 if (keys[*keyp].name == keyname)
1076 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1084 dataiterator_step(Dataiterator *di)
1092 case di_enterrepo: di_enterrepo:
1095 if (!(di->flags & SEARCH_THISSOLVID))
1097 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1098 goto di_nextsolvable;
1102 case di_entersolvable: di_entersolvable:
1103 if (di->repodataid >= 0)
1105 di->repodataid = 0; /* reset repodata iterator */
1106 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
1108 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1110 goto di_entersolvablekey;
1115 case di_enterrepodata: di_enterrepodata:
1116 if (di->repodataid >= 0)
1118 if (di->repodataid >= di->repo->nrepodata)
1119 goto di_nextsolvable;
1120 di->data = di->repo->repodata + di->repodataid;
1122 if (!maybe_load_repodata(di->data, di->keyname))
1123 goto di_nextrepodata;
1124 di->dp = solvid2data(di->data, di->solvid, &schema);
1126 goto di_nextrepodata;
1127 if (di->solvid == SOLVID_POS)
1128 di->solvid = di->pool->pos.solvid;
1129 /* reset key iterator */
1130 di->keyp = di->data->schemadata + di->data->schemata[schema];
1133 case di_enterschema: di_enterschema:
1135 di->dp = dataiterator_find_keyname(di, di->keyname);
1136 if (!di->dp || !*di->keyp)
1140 goto di_nextrepodata;
1144 case di_enterkey: di_enterkey:
1146 di->key = di->data->keys + *di->keyp;
1147 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1150 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1152 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1158 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1160 di->state = di_nextkey;
1162 di->state = di_nextattr;
1165 case di_nextkey: di_nextkey:
1166 if (!di->keyname && *++di->keyp)
1172 case di_nextrepodata: di_nextrepodata:
1173 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1174 goto di_enterrepodata;
1177 case di_nextsolvable: di_nextsolvable:
1178 if (!(di->flags & SEARCH_THISSOLVID))
1181 di->solvid = di->repo->start;
1184 for (; di->solvid < di->repo->end; di->solvid++)
1186 if (di->pool->solvables[di->solvid].repo == di->repo)
1187 goto di_entersolvable;
1193 if (di->repoid >= 0)
1196 if (di->repoid < di->pool->nrepos)
1198 di->repo = di->pool->repos[di->repoid];
1204 case di_bye: di_bye:
1208 case di_enterarray: di_enterarray:
1209 if (di->key->name == REPOSITORY_SOLVABLES)
1211 di->ddp = data_read_id(di->ddp, &di->kv.num);
1216 case di_nextarrayelement: di_nextarrayelement:
1219 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1220 if (di->kv.entry == di->kv.num)
1222 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1224 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1226 di->kv.str = (char *)di->ddp;
1228 di->state = di_nextkey;
1231 if (di->kv.entry == di->kv.num - 1)
1233 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1234 di->ddp = data_read_id(di->ddp, &di->kv.id);
1235 di->kv.str = (char *)di->ddp;
1236 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1238 if ((di->flags & SEARCH_SUB) != 0)
1239 di->state = di_entersub;
1241 di->state = di_nextarrayelement;
1244 case di_entersub: di_entersub:
1245 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1246 goto di_nextarrayelement; /* sorry, full */
1247 di->parents[di->nparents].kv = di->kv;
1248 di->parents[di->nparents].dp = di->dp;
1249 di->parents[di->nparents].keyp = di->keyp;
1250 di->dp = (unsigned char *)di->kv.str;
1251 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1252 memset(&di->kv, 0, sizeof(di->kv));
1253 di->kv.parent = &di->parents[di->nparents].kv;
1255 di->keyname = di->keynames[di->nparents - di->rootlevel];
1256 goto di_enterschema;
1258 case di_leavesub: di_leavesub:
1259 if (di->nparents - 1 < di->rootlevel)
1262 di->dp = di->parents[di->nparents].dp;
1263 di->kv = di->parents[di->nparents].kv;
1264 di->keyp = di->parents[di->nparents].keyp;
1265 di->key = di->data->keys + *di->keyp;
1266 di->ddp = (unsigned char *)di->kv.str;
1267 di->keyname = di->keynames[di->nparents - di->rootlevel];
1268 goto di_nextarrayelement;
1270 /* special solvable attr handling follows */
1272 case di_nextsolvableattr:
1273 di->kv.id = *di->idp++;
1278 di->state = di_nextsolvablekey;
1282 case di_nextsolvablekey: di_nextsolvablekey:
1283 if (di->keyname || di->key->name == RPM_RPMDBID)
1284 goto di_enterrepodata;
1288 case di_entersolvablekey: di_entersolvablekey:
1289 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1290 if (!di->idp || !di->idp[0])
1291 goto di_nextsolvablekey;
1292 di->kv.id = di->idp[0];
1293 di->kv.num = di->idp[0];
1295 if (!di->kv.eof && !di->idp[0])
1299 di->state = di_nextsolvablekey;
1301 di->state = di_nextsolvableattr;
1305 if (di->matcher.match)
1307 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1309 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1313 if (!datamatcher_match(&di->matcher, di->kv.str))
1316 /* found something! */
1322 dataiterator_entersub(Dataiterator *di)
1324 if (di->state == di_nextarrayelement)
1325 di->state = di_entersub;
1329 dataiterator_setpos(Dataiterator *di)
1331 if (di->kv.eof == 2)
1333 pool_clear_pos(di->pool);
1336 di->pool->pos.solvid = di->solvid;
1337 di->pool->pos.repo = di->repo;
1338 di->pool->pos.repodataid = di->data - di->repo->repodata;
1339 di->pool->pos.schema = di->kv.id;
1340 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1344 dataiterator_setpos_parent(Dataiterator *di)
1346 if (!di->kv.parent || di->kv.parent->eof == 2)
1348 pool_clear_pos(di->pool);
1351 di->pool->pos.solvid = di->solvid;
1352 di->pool->pos.repo = di->repo;
1353 di->pool->pos.repodataid = di->data - di->repo->repodata;
1354 di->pool->pos.schema = di->kv.parent->id;
1355 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1358 /* clones just the position, not the search keys/matcher */
1360 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1362 di->state = from->state;
1363 di->flags &= ~SEARCH_THISSOLVID;
1364 di->flags |= (from->flags & SEARCH_THISSOLVID);
1365 di->repo = from->repo;
1366 di->data = from->data;
1368 di->ddp = from->ddp;
1369 di->idp = from->idp;
1370 di->keyp = from->keyp;
1371 di->key = from->key;
1373 di->repodataid = from->repodataid;
1374 di->solvid = from->solvid;
1375 di->repoid = from->repoid;
1376 di->rootlevel = from->rootlevel;
1377 memcpy(di->parents, from->parents, sizeof(from->parents));
1378 di->nparents = from->nparents;
1382 for (i = 1; i < di->nparents; i++)
1383 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1384 di->kv.parent = &di->parents[di->nparents - 1].kv;
1389 dataiterator_seek(Dataiterator *di, int whence)
1391 if ((whence & DI_SEEK_STAY) != 0)
1392 di->rootlevel = di->nparents;
1393 switch (whence & ~DI_SEEK_STAY)
1396 if (di->state != di_nextarrayelement)
1398 if ((whence & DI_SEEK_STAY) != 0)
1399 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1400 di->state = di_entersub;
1402 case DI_SEEK_PARENT:
1409 if (di->rootlevel > di->nparents)
1410 di->rootlevel = di->nparents;
1411 di->dp = di->parents[di->nparents].dp;
1412 di->kv = di->parents[di->nparents].kv;
1413 di->keyp = di->parents[di->nparents].keyp;
1414 di->key = di->data->keys + *di->keyp;
1415 di->ddp = (unsigned char *)di->kv.str;
1416 di->keyname = di->keynames[di->nparents - di->rootlevel];
1417 di->state = di_nextarrayelement;
1419 case DI_SEEK_REWIND:
1425 di->dp = (unsigned char *)di->kv.parent->str;
1426 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1427 di->state = di_enterschema;
1435 dataiterator_skip_attribute(Dataiterator *di)
1437 if (di->state == di_nextsolvableattr)
1438 di->state = di_nextsolvablekey;
1440 di->state = di_nextkey;
1444 dataiterator_skip_solvable(Dataiterator *di)
1446 di->state = di_nextsolvable;
1450 dataiterator_skip_repo(Dataiterator *di)
1452 di->state = di_nextrepo;
1456 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1460 if (solvid == SOLVID_POS)
1462 di->repo = di->pool->pos.repo;
1469 di->data = di->repo->repodata + di->pool->pos.repodataid;
1470 di->repodataid = -1;
1471 di->solvid = solvid;
1472 di->state = di_enterrepo;
1473 di->flags |= SEARCH_THISSOLVID;
1478 di->repo = di->pool->solvables[solvid].repo;
1481 else if (di->repoid >= 0)
1483 if (!di->pool->nrepos)
1488 di->repo = di->pool->repos[0];
1492 di->solvid = solvid;
1494 di->flags |= SEARCH_THISSOLVID;
1495 di->state = di_enterrepo;
1499 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1507 di->flags &= ~SEARCH_THISSOLVID;
1508 di->state = di_enterrepo;
1512 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1514 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1518 return datamatcher_match(ma, di->kv.str);
1521 /************************************************************************
1522 * data modify functions
1525 /* extend repodata so that it includes solvables p */
1527 repodata_extend(Repodata *data, Id p)
1529 if (data->start == data->end)
1530 data->start = data->end = p;
1533 int old = data->end - data->start;
1534 int new = p - data->end + 1;
1537 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1538 memset(data->attrs + old, 0, new * sizeof(Id *));
1540 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1541 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1544 if (p < data->start)
1546 int old = data->end - data->start;
1547 int new = data->start - p;
1550 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1551 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1552 memset(data->attrs, 0, new * sizeof(Id *));
1554 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1555 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1556 memset(data->incoreoffset, 0, new * sizeof(Id));
1561 /* extend repodata so that it includes solvables from start to start + num - 1 */
1563 repodata_extend_block(Repodata *data, Id start, Id num)
1567 if (!data->incoreoffset)
1569 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1570 data->start = start;
1571 data->end = start + num;
1574 repodata_extend(data, start);
1576 repodata_extend(data, start + num - 1);
1579 /**********************************************************************/
1581 #define REPODATA_ATTRS_BLOCK 63
1582 #define REPODATA_ATTRDATA_BLOCK 1023
1583 #define REPODATA_ATTRIDDATA_BLOCK 63
1587 repodata_new_handle(Repodata *data)
1591 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1594 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1595 data->xattrs[data->nxattrs] = 0;
1596 return -(data->nxattrs++);
1600 repodata_get_attrp(Repodata *data, Id handle)
1602 if (handle == SOLVID_META)
1606 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1611 return data->xattrs - handle;
1612 if (handle < data->start || handle >= data->end)
1613 repodata_extend(data, handle);
1615 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1616 return data->attrs + (handle - data->start);
1620 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1626 app = repodata_get_attrp(data, handle);
1631 for (pp = ap; *pp; pp += 2)
1632 /* Determine equality based on the name only, allows us to change
1633 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1634 if (data->keys[*pp].name == data->keys[keyid].name)
1647 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1657 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1661 keyid = repodata_key2id(data, key, 1);
1662 repodata_insert_keyid(data, solvid, keyid, val, 1);
1666 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1670 key.type = REPOKEY_TYPE_ID;
1672 key.storage = KEY_STORAGE_INCORE;
1673 repodata_set(data, solvid, &key, id);
1677 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned int num)
1681 key.type = REPOKEY_TYPE_NUM;
1683 key.storage = KEY_STORAGE_INCORE;
1684 repodata_set(data, solvid, &key, (Id)num);
1688 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
1692 if (data->localpool)
1693 id = stringpool_str2id(&data->spool, str, 1);
1695 id = str2id(data->repo->pool, str, 1);
1697 key.type = REPOKEY_TYPE_ID;
1699 key.storage = KEY_STORAGE_INCORE;
1700 repodata_set(data, solvid, &key, id);
1704 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
1708 key.type = REPOKEY_TYPE_CONSTANT;
1709 key.size = constant;
1710 key.storage = KEY_STORAGE_INCORE;
1711 repodata_set(data, solvid, &key, 0);
1715 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
1719 key.type = REPOKEY_TYPE_CONSTANTID;
1721 key.storage = KEY_STORAGE_INCORE;
1722 repodata_set(data, solvid, &key, 0);
1726 repodata_set_void(Repodata *data, Id solvid, Id keyname)
1730 key.type = REPOKEY_TYPE_VOID;
1732 key.storage = KEY_STORAGE_INCORE;
1733 repodata_set(data, solvid, &key, 0);
1737 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
1742 l = strlen(str) + 1;
1744 key.type = REPOKEY_TYPE_STR;
1746 key.storage = KEY_STORAGE_INCORE;
1747 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1748 memcpy(data->attrdata + data->attrdatalen, str, l);
1749 repodata_set(data, solvid, &key, data->attrdatalen);
1750 data->attrdatalen += l;
1753 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
1754 * so that the caller can append the new element there */
1756 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
1759 Id *ida, *pp, **ppp;
1761 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
1763 /* great! just append the new data */
1764 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1765 data->attriddatalen--; /* overwrite terminating 0 */
1766 data->lastdatalen += entrysize;
1769 ppp = repodata_get_attrp(data, handle);
1772 for (; *pp; pp += 2)
1773 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
1777 /* not found. allocate new key */
1782 key.storage = KEY_STORAGE_INCORE;
1783 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1784 repodata_set(data, handle, &key, data->attriddatalen);
1785 data->lasthandle = 0; /* next time... */
1789 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
1790 oldsize += entrysize;
1791 if (ida + 1 == data->attriddata + data->attriddatalen)
1793 /* this was the last entry, just append it */
1794 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1795 data->attriddatalen--; /* overwrite terminating 0 */
1799 /* too bad. move to back. */
1800 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
1801 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
1802 pp[1] = data->attriddatalen;
1803 data->attriddatalen += oldsize;
1805 data->lasthandle = handle;
1806 data->lastkey = *pp;
1807 data->lastdatalen = data->attriddatalen + entrysize + 1;
1811 checksumtype2len(Id type)
1815 case REPOKEY_TYPE_MD5:
1817 case REPOKEY_TYPE_SHA1:
1819 case REPOKEY_TYPE_SHA256:
1820 return SIZEOF_SHA256;
1827 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1828 const unsigned char *str)
1831 int l = checksumtype2len(type);
1838 key.storage = KEY_STORAGE_INCORE;
1839 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1840 memcpy(data->attrdata + data->attrdatalen, str, l);
1841 repodata_set(data, solvid, &key, data->attrdatalen);
1842 data->attrdatalen += l;
1846 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
1849 for (i = 0; i < buflen; i++)
1851 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
1852 : ((c)>='a' && (c)<='f') ? ((c)-('a'-10)) \
1853 : ((c)>='A' && (c)<='F') ? ((c)-('A'-10)) \
1864 buf[i] = (buf[i] << 4) | v;
1871 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
1874 unsigned char buf[64];
1875 int l = checksumtype2len(type);
1879 if (hexstr2bytes(buf, str, l) != l)
1881 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
1885 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
1890 l = checksumtype2len(type);
1893 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
1894 for (i = 0; i < l; i++)
1896 unsigned char v = buf[i];
1897 unsigned char w = v >> 4;
1898 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1900 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
1906 /* rpm filenames don't contain the epoch, so strip it */
1907 static inline const char *
1908 evrid2vrstr(Pool *pool, Id evrid)
1910 const char *p, *evr = id2str(pool, evrid);
1913 for (p = evr; *p >= '0' && *p <= '9'; p++)
1915 return p != evr && *p == ':' ? p + 1 : evr;
1919 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
1921 Pool *pool = data->repo->pool;
1923 const char *str, *fp;
1927 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
1930 if ((dir = strrchr(file, '/')) != 0)
1941 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
1946 if (l == 1 && dir[0] == '.')
1948 s = pool->solvables + solvid;
1951 str = id2str(pool, s->arch);
1952 if (!strncmp(dir, str, l) && !str[l])
1953 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
1955 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir);
1958 char *dir2 = strdup(dir);
1960 repodata_set_str(data, solvid, SOLVABLE_MEDIADIR, dir2);
1965 str = id2str(pool, s->name);
1967 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
1970 str = evrid2vrstr(pool, s->evr);
1972 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
1975 str = id2str(pool, s->arch);
1977 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
1979 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
1984 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
1988 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
1992 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
1994 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
1995 data->attriddata[data->attriddatalen++] = dir;
1996 data->attriddata[data->attriddatalen++] = num;
1997 data->attriddata[data->attriddatalen++] = num2;
1998 data->attriddata[data->attriddatalen++] = 0;
2002 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2008 l = strlen(str) + 1;
2009 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2010 memcpy(data->attrdata + data->attrdatalen, str, l);
2011 stroff = data->attrdatalen;
2012 data->attrdatalen += l;
2015 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2017 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2018 data->attriddata[data->attriddatalen++] = dir;
2019 data->attriddata[data->attriddatalen++] = stroff;
2020 data->attriddata[data->attriddatalen++] = 0;
2024 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2027 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2029 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2030 data->attriddata[data->attriddatalen++] = id;
2031 data->attriddata[data->attriddatalen++] = 0;
2035 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2039 if (data->localpool)
2040 id = stringpool_str2id(&data->spool, str, 1);
2042 id = str2id(data->repo->pool, str, 1);
2043 repodata_add_idarray(data, solvid, keyname, id);
2047 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2049 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2050 data->attriddata[data->attriddatalen++] = ghandle;
2051 data->attriddata[data->attriddatalen++] = 0;
2055 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2057 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2058 data->attriddata[data->attriddatalen++] = ghandle;
2059 data->attriddata[data->attriddatalen++] = 0;
2062 /* add all attrs from src to dest */
2064 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2067 if (dest == src || !(keyp = data->attrs[src - data->start]))
2069 for (; *keyp; keyp += 2)
2070 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2076 /**********************************************************************/
2078 /* unify with repo_write! */
2080 #define EXTDATA_BLOCK 1023
2088 data_addid(struct extdata *xd, Id x)
2091 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2092 dp = xd->buf + xd->len;
2097 *dp++ = (x >> 28) | 128;
2099 *dp++ = (x >> 21) | 128;
2100 *dp++ = (x >> 14) | 128;
2103 *dp++ = (x >> 7) | 128;
2105 xd->len = dp - xd->buf;
2109 data_addideof(struct extdata *xd, Id x, int eof)
2112 x = (x & 63) | ((x & ~63) << 1);
2113 data_addid(xd, (eof ? x: x | 64));
2117 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2119 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2120 memcpy(xd->buf + xd->len, blob, len);
2124 /*********************************/
2127 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2128 struct extdata *newvincore,
2130 Repokey *key, Id val)
2132 /* Otherwise we have a new value. Parse it into the internal
2136 unsigned int oldvincorelen = 0;
2140 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2143 oldvincorelen = xd->len;
2147 case REPOKEY_TYPE_VOID:
2148 case REPOKEY_TYPE_CONSTANT:
2149 case REPOKEY_TYPE_CONSTANTID:
2151 case REPOKEY_TYPE_STR:
2152 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2154 case REPOKEY_TYPE_MD5:
2155 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2157 case REPOKEY_TYPE_SHA1:
2158 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2160 case REPOKEY_TYPE_SHA256:
2161 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2163 case REPOKEY_TYPE_ID:
2164 case REPOKEY_TYPE_NUM:
2165 case REPOKEY_TYPE_DIR:
2166 data_addid(xd, val);
2168 case REPOKEY_TYPE_IDARRAY:
2169 for (ida = data->attriddata + val; *ida; ida++)
2170 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2172 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2173 for (ida = data->attriddata + val; *ida; ida += 3)
2175 data_addid(xd, ida[0]);
2176 data_addid(xd, ida[1]);
2177 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2180 case REPOKEY_TYPE_DIRSTRARRAY:
2181 for (ida = data->attriddata + val; *ida; ida += 2)
2183 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2184 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2187 case REPOKEY_TYPE_FIXARRAY:
2191 for (ida = data->attriddata + val; *ida; ida++)
2194 fprintf(stderr, "serialize struct %d\n", *ida);
2197 Id *kp = data->xattrs[-*ida];
2204 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2210 schemaid = repodata_schema2id(data, schema, 1);
2211 else if (schemaid != repodata_schema2id(data, schema, 0))
2213 pool_debug(data->repo->pool, SAT_FATAL, "fixarray substructs with different schemas\n");
2217 fprintf(stderr, " schema %d\n", schemaid);
2222 data_addid(xd, num);
2223 data_addid(xd, schemaid);
2224 for (ida = data->attriddata + val; *ida; ida++)
2226 Id *kp = data->xattrs[-*ida];
2231 repodata_serialize_key(data, newincore, newvincore,
2232 schema, data->keys + *kp, kp[1]);
2237 case REPOKEY_TYPE_FLEXARRAY:
2240 for (ida = data->attriddata + val; *ida; ida++)
2242 data_addid(xd, num);
2243 for (ida = data->attriddata + val; *ida; ida++)
2245 Id *kp = data->xattrs[-*ida];
2248 data_addid(xd, 0); /* XXX */
2255 schemaid = repodata_schema2id(data, schema, 1);
2256 data_addid(xd, schemaid);
2257 kp = data->xattrs[-*ida];
2260 repodata_serialize_key(data, newincore, newvincore,
2261 schema, data->keys + *kp, kp[1]);
2267 pool_debug(data->repo->pool, SAT_FATAL, "don't know how to handle type %d\n", key->type);
2270 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2272 /* put offset/len in incore */
2273 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2274 oldvincorelen = xd->len - oldvincorelen;
2275 data_addid(newincore, oldvincorelen);
2280 repodata_internalize(Repodata *data)
2282 Repokey *key, solvkey;
2284 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2285 unsigned char *dp, *ndp;
2286 int newschema, oldcount;
2287 struct extdata newincore;
2288 struct extdata newvincore;
2291 if (!data->attrs && !data->xattrs)
2294 newvincore.buf = data->vincore;
2295 newvincore.len = data->vincorelen;
2297 /* find the solvables key, create if needed */
2298 memset(&solvkey, 0, sizeof(solvkey));
2299 solvkey.name = REPOSITORY_SOLVABLES;
2300 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2302 solvkey.storage = KEY_STORAGE_INCORE;
2303 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2305 schema = sat_malloc2(data->nkeys, sizeof(Id));
2306 seen = sat_malloc2(data->nkeys, sizeof(Id));
2308 /* Merge the data already existing (in data->schemata, ->incoredata and
2309 friends) with the new attributes in data->attrs[]. */
2310 nentry = data->end - data->start;
2311 memset(&newincore, 0, sizeof(newincore));
2312 data_addid(&newincore, 0); /* start data at offset 1 */
2314 data->mainschema = 0;
2315 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2317 /* join entry data */
2318 /* we start with the meta data, entry -1 */
2319 for (entry = -1; entry < nentry; entry++)
2321 memset(seen, 0, data->nkeys * sizeof(Id));
2323 dp = data->incoredata;
2326 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2327 dp = data_read_id(dp, &oldschema);
2330 fprintf(stderr, "oldschema %d\n", oldschema);
2331 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2332 fprintf(stderr, "schemadata %p\n", data->schemadata);
2334 /* seen: -1: old data 0: skipped >0: id + 1 */
2338 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2342 pool_debug(data->repo->pool, SAT_FATAL, "Inconsistent old data (key occured twice).\n");
2350 keyp = data->attrs ? data->attrs[entry] : 0;
2353 /* strip solvables key */
2355 for (sp = keyp = schema; *sp; sp++)
2356 if (*sp != solvkeyid)
2361 seen[solvkeyid] = 0;
2362 keyp = data->xattrs ? data->xattrs[1] : 0;
2365 for (; *keyp; keyp += 2)
2372 seen[*keyp] = keyp[1] + 1;
2374 if (entry < 0 && data->end != data->start)
2381 /* Ideally we'd like to sort the new schema here, to ensure
2382 schema equality independend of the ordering. We can't do that
2383 yet. For once see below (old ids need to come before new ids).
2384 An additional difficulty is that we also need to move
2385 the values with the keys. */
2386 schemaid = repodata_schema2id(data, schema, 1);
2388 schemaid = oldschema;
2391 /* Now create data blob. We walk through the (possibly new) schema
2392 and either copy over old data, or insert the new. */
2393 /* XXX Here we rely on the fact that the (new) schema has the form
2394 o1 o2 o3 o4 ... | n1 n2 n3 ...
2395 (oX being the old keyids (possibly overwritten), and nX being
2396 the new keyids). This rules out sorting the keyids in order
2397 to ensure a small schema count. */
2399 data->incoreoffset[entry] = newincore.len;
2400 data_addid(&newincore, schemaid);
2403 data->mainschema = schemaid;
2404 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2406 keypstart = data->schemadata + data->schemata[schemaid];
2407 for (keyp = keypstart; *keyp; keyp++)
2410 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2411 if (*keyp == solvkeyid)
2413 /* add flexarray entry count */
2414 data_addid(&newincore, data->end - data->start);
2417 key = data->keys + *keyp;
2419 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2424 /* Skip the data associated with this old key. */
2425 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2427 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2428 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2430 else if (key->storage == KEY_STORAGE_INCORE)
2431 ndp = data_skip_key(data, dp, key);
2434 if (seen[*keyp] == -1)
2436 /* If this key was an old one _and_ was not overwritten with
2437 a different value copy over the old value (we skipped it
2440 data_addblob(&newincore, dp, ndp - dp);
2443 else if (seen[*keyp])
2445 /* Otherwise we have a new value. Parse it into the internal
2447 repodata_serialize_key(data, &newincore, &newvincore,
2448 schema, key, seen[*keyp] - 1);
2452 if (entry >= 0 && data->attrs && data->attrs[entry])
2453 data->attrs[entry] = sat_free(data->attrs[entry]);
2455 /* free all xattrs */
2456 for (entry = 0; entry < data->nxattrs; entry++)
2457 if (data->xattrs[entry])
2458 sat_free(data->xattrs[entry]);
2459 data->xattrs = sat_free(data->xattrs);
2462 data->lasthandle = 0;
2464 data->lastdatalen = 0;
2467 repodata_free_schemahash(data);
2469 sat_free(data->incoredata);
2470 data->incoredata = newincore.buf;
2471 data->incoredatalen = newincore.len;
2472 data->incoredatafree = 0;
2474 sat_free(data->vincore);
2475 data->vincore = newvincore.buf;
2476 data->vincorelen = newvincore.len;
2478 data->attrs = sat_free(data->attrs);
2479 data->attrdata = sat_free(data->attrdata);
2480 data->attriddata = sat_free(data->attriddata);
2481 data->attrdatalen = 0;
2482 data->attriddatalen = 0;
2486 repodata_disable_paging(Repodata *data)
2488 if (maybe_load_repodata(data, 0))
2489 repopagestore_disable_paging(&data->store);
2493 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: