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
26 #include "poolid_private.h"
32 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
33 unsigned char *out, unsigned int out_len);
34 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
37 unsigned int out_len);
39 #define REPODATA_BLOCK 255
43 repodata_init(Repodata *data, Repo *repo, int localpool)
45 memset(data, 0, sizeof (*data));
47 data->localpool = localpool;
49 stringpool_init_empty(&data->spool);
50 data->keys = sat_calloc(1, sizeof(Repokey));
52 data->schemata = sat_calloc(1, sizeof(Id));
53 data->schemadata = sat_calloc(1, sizeof(Id));
55 data->schemadatalen = 1;
60 repodata_free(Repodata *data)
66 sat_free(data->schemata);
67 sat_free(data->schemadata);
68 sat_free(data->schematahash);
70 stringpool_free(&data->spool);
71 dirpool_free(&data->dirpool);
73 sat_free(data->mainschemaoffsets);
74 sat_free(data->incoredata);
75 sat_free(data->incoreoffset);
76 sat_free(data->verticaloffset);
78 sat_free(data->blob_store);
79 sat_free(data->pages);
80 sat_free(data->mapped);
82 sat_free(data->vincore);
85 for (i = 0; i < data->end - data->start; i++)
86 sat_free(data->attrs[i]);
87 sat_free(data->attrs);
89 for (i = 0; i < data->nxattrs; i++)
90 sat_free(data->xattrs[i]);
91 sat_free(data->xattrs);
93 sat_free(data->attrdata);
94 sat_free(data->attriddata);
96 if (data->pagefd != -1)
101 /***************************************************************
102 * key pool management
105 /* this is not so time critical that we need a hash, so we do a simple
108 repodata_key2id(Repodata *data, Repokey *key, int create)
112 for (keyid = 1; keyid < data->nkeys; keyid++)
113 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
115 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
119 if (keyid == data->nkeys)
123 /* allocate new key */
124 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
125 data->keys[data->nkeys++] = *key;
126 if (data->verticaloffset)
128 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
129 data->verticaloffset[data->nkeys - 1] = 0;
131 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
137 /***************************************************************
138 * schema pool management
141 #define SCHEMATA_BLOCK 31
142 #define SCHEMATADATA_BLOCK 255
145 repodata_schema2id(Repodata *data, Id *schema, int create)
151 if ((schematahash = data->schematahash) == 0)
153 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
154 for (i = 0; i < data->nschemata; i++)
156 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
159 schematahash[h] = i + 1;
161 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
162 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
165 for (sp = schema, len = 0, h = 0; *sp; len++)
170 cid = schematahash[h];
174 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
177 for (cid = 0; cid < data->nschemata; cid++)
178 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
184 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
185 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
187 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
188 data->schemata[data->nschemata] = data->schemadatalen;
189 data->schemadatalen += len;
190 schematahash[h] = data->nschemata + 1;
192 fprintf(stderr, "schema2id: new schema\n");
194 return data->nschemata++;
198 repodata_free_schemahash(Repodata *data)
200 data->schematahash = sat_free(data->schematahash);
202 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
203 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
207 /***************************************************************
208 * dir pool management
212 repodata_str2dir(Repodata *data, const char *dir, int create)
218 while (*dir == '/' && dir[1] == '/')
220 if (*dir == '/' && !dir[1])
224 dire = strchrnul(dir, '/');
226 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
228 id = strn2id(data->repo->pool, dir, dire - dir, create);
231 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
244 repodata_dir2str(Repodata *data, Id did, const char *suf)
246 Pool *pool = data->repo->pool;
253 return suf ? suf : "";
257 comp = dirpool_compid(&data->dirpool, parent);
258 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
260 parent = dirpool_parent(&data->dirpool, parent);
265 l += strlen(suf) + 1;
266 p = pool_alloctmpspace(pool, l + 1) + l;
277 comp = dirpool_compid(&data->dirpool, parent);
278 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
281 strncpy(p, comps, l);
282 parent = dirpool_parent(&data->dirpool, parent);
290 /***************************************************************
294 static inline unsigned char *
295 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
297 Id *keyp = data->schemadata + data->schemata[schema];
298 for (; *keyp; keyp++)
299 dp = data_skip_key(data, dp, data->keys + *keyp);
304 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
306 int nentries, schema;
309 case REPOKEY_TYPE_FIXARRAY:
310 dp = data_read_id(dp, &nentries);
313 dp = data_read_id(dp, &schema);
315 dp = data_skip_schema(data, dp, schema);
317 case REPOKEY_TYPE_FLEXARRAY:
318 dp = data_read_id(dp, &nentries);
321 dp = data_read_id(dp, &schema);
322 dp = data_skip_schema(data, dp, schema);
326 if (key->storage == KEY_STORAGE_INCORE)
327 dp = data_skip(dp, key->type);
328 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
330 dp = data_skip(dp, REPOKEY_TYPE_ID);
331 dp = data_skip(dp, REPOKEY_TYPE_ID);
337 static unsigned char *
338 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
344 while ((k = *keyp++) != 0)
348 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
350 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
351 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
354 if (data->keys[k].storage != KEY_STORAGE_INCORE)
356 dp = data_skip_key(data, dp, data->keys + k);
361 static unsigned char *
362 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
367 if (off >= data->lastverticaloffset)
369 off -= data->lastverticaloffset;
370 if (off + len > data->vincorelen)
372 return data->vincore + off;
374 if (off + len > key->size)
376 /* we now have the offset, go into vertical */
377 off += data->verticaloffset[key - data->keys];
378 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
379 dp = repodata_load_page_range(data, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
381 dp += off % BLOB_PAGESIZE;
385 static inline unsigned char *
386 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
388 unsigned char *dp = *dpp;
392 if (key->storage == KEY_STORAGE_INCORE)
394 /* hmm, this is a bit expensive */
395 *dpp = data_skip_key(data, dp, key);
398 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
401 dp = data_read_id(dp, &off);
402 dp = data_read_id(dp, &len);
404 return get_vertical_data(data, key, off, len);
410 load_repodata(Repodata *data)
412 if (data->loadcallback)
414 data->loadcallback(data);
415 if (data->state == REPODATA_AVAILABLE)
418 data->state = REPODATA_ERROR;
423 maybe_load_repodata(Repodata *data, Id keyname)
425 if (keyname && !repodata_precheck_keyname(data, keyname))
426 return 0; /* do not bother... */
433 for (i = 0; i < data->nkeys; i++)
434 if (keyname == data->keys[i].name)
436 if (i == data->nkeys)
439 return load_repodata(data);
442 case REPODATA_AVAILABLE:
445 data->state = REPODATA_ERROR;
450 static inline unsigned char*
451 entry2data(Repodata *data, Id entry, Id *schemap)
453 unsigned char *dp = data->incoredata;
456 if (entry == REPOENTRY_META) /* META */
458 else if (entry == REPOENTRY_POS) /* META */
460 Pool *pool = data->repo->pool;
461 if (data->repo != pool->pos.repo)
463 if (data != data->repo->repodata + pool->pos.repodataid)
465 *schemap = pool->pos.schema;
466 return data->incoredata + pool->pos.dp;
470 if (entry < data->start || entry >= data->end)
472 dp += data->incoreoffset[entry - data->start];
474 return data_read_id(dp, schemap);
477 /************************************************************************
482 find_schema_key(Repodata *data, Id schema, Id keyname)
485 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
486 if (data->keys[*keyp].name == keyname)
491 static inline unsigned char *
492 find_key_data(Repodata *data, Id entry, Id keyname, Repokey **keyp)
494 unsigned char *dp, *ddp;
498 if (!maybe_load_repodata(data, keyname))
500 dp = entry2data(data, entry, &schema);
503 keyid = find_schema_key(data, schema, keyname);
506 key = data->keys + keyid;
508 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
510 dp = forward_to_key(data, keyid, data->schemadata + data->schemata[schema], dp);
513 ddp = get_data(data, key, &dp);
519 repodata_lookup_id(Repodata *data, Id entry, Id keyname)
525 dp = find_key_data(data, entry, keyname, &key);
528 if (key->type == REPOKEY_TYPE_CONSTANTID)
530 if (key->type != REPOKEY_TYPE_ID)
532 dp = data_read_id(dp, &id);
537 repodata_lookup_str(Repodata *data, Id entry, Id keyname)
543 dp = find_key_data(data, entry, keyname, &key);
546 if (key->type == REPOKEY_TYPE_STR)
547 return (const char *)dp;
548 if (key->type == REPOKEY_TYPE_CONSTANTID)
549 return id2str(data->repo->pool, key->size);
550 if (key->type == REPOKEY_TYPE_ID)
551 dp = data_read_id(dp, &id);
555 return data->spool.stringspace + data->spool.strings[id];
556 return id2str(data->repo->pool, id);
560 repodata_lookup_num(Repodata *data, Id entry, Id keyname, unsigned int *value)
567 dp = find_key_data(data, entry, keyname, &key);
570 if (key->type == REPOKEY_TYPE_NUM
571 || key->type == REPOKEY_TYPE_U32
572 || key->type == REPOKEY_TYPE_CONSTANT)
574 dp = data_fetch(dp, &kv, key);
582 repodata_lookup_void(Repodata *data, Id entry, Id keyname)
588 if (!maybe_load_repodata(data, keyname))
590 dp = entry2data(data, entry, &schema);
593 /* can't use find_schema_key as we need to test the type */
594 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
595 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
600 const unsigned char *
601 repodata_lookup_bin_checksum(Repodata *data, Id entry, Id keyname, Id *typep)
606 dp = find_key_data(data, entry, keyname, &key);
614 /************************************************************************
618 struct subschema_data {
624 /* search in a specific entry */
626 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
630 Id k, keyid, *kp, *keyp;
631 unsigned char *dp, *ddp;
637 if (!maybe_load_repodata(data, keyname))
639 if (entry == REPOENTRY_SUBSCHEMA)
641 struct subschema_data *subd = cbdata;
642 cbdata = subd->cbdata;
644 schema = subd->parent->id;
645 dp = (unsigned char *)subd->parent->str;
646 kv.parent = subd->parent;
651 dp = entry2data(data, entry, &schema);
654 s = data->repo->pool->solvables + entry;
657 keyp = data->schemadata + data->schemata[schema];
660 /* search for a specific key */
661 for (kp = keyp; (k = *kp++) != 0; )
662 if (data->keys[k].name == keyname)
666 dp = forward_to_key(data, k, data->schemadata + data->schemata[schema], dp);
672 while ((keyid = *keyp++) != 0)
675 key = data->keys + keyid;
676 ddp = get_data(data, key, &dp);
678 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
680 struct subschema_data subd;
684 subd.cbdata = cbdata;
687 ddp = data_read_id(ddp, &nentries);
691 while (ddp && nentries > 0)
693 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
694 ddp = data_read_id(ddp, &schema);
696 kv.str = (char *)ddp;
697 stop = callback(cbdata, s, data, key, &kv);
698 if (stop > SEARCH_NEXT_KEY)
703 repodata_search(data, REPOENTRY_SUBSCHEMA, 0, callback, &subd);
704 ddp = data_skip_schema(data, ddp, schema);
712 kv.str = (char *)ddp;
713 stop = callback(cbdata, s, data, key, &kv);
714 if (stop > SEARCH_NEXT_KEY)
724 ddp = data_fetch(ddp, &kv, key);
727 stop = callback(cbdata, s, data, key, &kv);
730 while (!kv.eof && !stop);
731 if (onekey || stop > SEARCH_NEXT_KEY)
737 repodata_setpos_kv(Repodata *data, KeyValue *kv)
739 Pool *pool = data->repo->pool;
743 pool->pos.repodataid = 0;
745 pool->pos.schema = 0;
750 pool->pos.repodataid = data - data->repo->repodata;
751 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
752 pool->pos.schema = kv->id;
756 /************************************************************************/
758 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
759 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
760 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
761 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
762 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
763 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
764 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
765 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
766 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
767 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
768 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
769 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
770 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
771 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
776 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
790 case SOLVABLE_VENDOR:
793 case SOLVABLE_PROVIDES:
795 return s->provides ? s->repo->idarraydata + s->provides : 0;
796 case SOLVABLE_OBSOLETES:
798 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
799 case SOLVABLE_CONFLICTS:
801 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
802 case SOLVABLE_REQUIRES:
804 return s->requires ? s->repo->idarraydata + s->requires : 0;
805 case SOLVABLE_RECOMMENDS:
807 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
808 case SOLVABLE_SUPPLEMENTS:
810 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
811 case SOLVABLE_SUGGESTS:
813 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
814 case SOLVABLE_ENHANCES:
816 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
819 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
826 datamatcher_init(Datamatcher *ma, Pool *pool, const char *match, int flags)
829 ma->match = (void *)match;
832 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
834 ma->match = sat_calloc(1, sizeof(regex_t));
835 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
839 ma->match = (void *)match;
840 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
846 datamatcher_free(Datamatcher *ma)
848 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
851 ma->match = sat_free(ma->match);
856 datamatcher_match(Datamatcher *ma, Repodata *data, Repokey *key, KeyValue *kv)
860 case REPOKEY_TYPE_ID:
861 case REPOKEY_TYPE_IDARRAY:
862 if (data && data->localpool)
863 kv->str = stringpool_id2str(&data->spool, kv->id);
865 kv->str = id2str(ma->pool, kv->id);
867 case REPOKEY_TYPE_STR:
869 case REPOKEY_TYPE_DIRSTRARRAY:
870 if (!(ma->flags & SEARCH_FILES))
872 /* Put the full filename into kv->str. */
873 kv->str = repodata_dir2str(data, kv->id, kv->str);
874 /* And to compensate for that put the "empty" directory into
875 kv->id, so that later calls to repodata_dir2str on this data
876 come up with the same filename again. */
882 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
883 for the others we can't know if a colon separates a kind or not. */
884 if ((ma->flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
886 const char *s = strchr(kv->str, ':');
890 switch ((ma->flags & SEARCH_STRINGMASK))
892 case SEARCH_SUBSTRING:
893 if (ma->flags & SEARCH_NOCASE)
895 if (!strcasestr(kv->str, (const char *)ma->match))
900 if (!strstr(kv->str, (const char *)ma->match))
905 if (ma->flags & SEARCH_NOCASE)
907 if (strcasecmp((const char *)ma->match, kv->str))
912 if (strcmp((const char *)ma->match, kv->str))
917 if (fnmatch((const char *)ma->match, kv->str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
921 if (regexec((const regex_t *)ma->match, kv->str, 0, NULL, 0))
954 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname, const char *match, int flags)
956 memset(di, 0, sizeof(*di));
958 di->keyname = keyname;
960 di->pool = repo->pool;
962 flags |= SEARCH_THISENTRY;
967 datamatcher_init(&di->matcher, di->pool, match, flags);
968 if (p == REPOENTRY_POS)
970 di->repo = di->pool->pos.repo;
971 di->data = di->repo->repodata + di->pool->pos.repodataid;
975 di->state = di_enterrepo;
979 dataiterator_free(Dataiterator *di)
981 if (di->matcher.match)
982 datamatcher_free(&di->matcher);
986 dataiterator_step(Dataiterator *di)
994 case di_nextattr: di_nextattr:
996 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
998 di->state = di_nextkey;
1000 di->state = di_nextattr;
1003 case di_nextkey: di_nextkey:
1009 else if ((di->flags & SEARCH_SUB) != 0)
1011 Id *keyp = di->keyp;
1012 for (keyp++; *keyp; keyp++)
1013 if (di->data->keys[*keyp].name == di->keyname ||
1014 di->data->keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
1015 di->data->keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
1017 if (*keyp && (di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp)) != 0)
1028 case di_nextrepodata: di_nextrepodata:
1029 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1030 goto di_enterrepodata;
1033 case di_nextsolvable:
1034 if (!(di->flags & SEARCH_THISENTRY))
1037 di->entry = di->repo->start;
1040 for (; di->entry < di->repo->end; di->entry++)
1042 if (di->pool->solvables[di->entry].repo == di->repo)
1043 goto di_entersolvable;
1049 if (di->repoid >= 0)
1052 if (di->repoid < di->pool->nrepos)
1054 di->repo = di->pool->repos[di->repoid];
1064 case di_enterrepo: di_enterrepo:
1065 if (!(di->flags & SEARCH_THISENTRY))
1066 di->entry = di->repo->start;
1069 case di_entersolvable: di_entersolvable:
1070 if (di->repodataid >= 0)
1073 if (di->entry > 0 && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1075 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1077 goto di_entersolvablekey;
1081 case di_enterrepodata: di_enterrepodata:
1082 if (di->repodataid >= 0)
1083 di->data = di->repo->repodata + di->repodataid;
1084 if (!maybe_load_repodata(di->data, di->keyname))
1085 goto di_nextrepodata;
1086 di->dp = entry2data(di->data, di->entry, &schema);
1088 goto di_nextrepodata;
1089 di->keyp = di->data->schemadata + di->data->schemata[schema];
1093 if ((di->flags & SEARCH_SUB) != 0)
1098 for (keyp = di->keyp; *keyp; keyp++)
1099 if (di->data->keys[*keyp].name == di->keyname)
1102 goto di_nextrepodata;
1103 di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1106 goto di_nextrepodata;
1109 case di_enterkey: di_enterkey:
1111 di->key = di->data->keys + *di->keyp;
1112 di->ddp = get_data(di->data, di->key, &di->dp);
1115 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1117 di->ddp = data_read_id(di->ddp, &di->kv.num);
1120 goto di_nextarrayelement;
1124 case di_nextarrayelement: di_nextarrayelement:
1127 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1128 if (di->kv.entry == di->kv.num)
1130 if (di->keyname && di->key->name != di->keyname)
1132 di->kv.str = (char *)di->ddp;
1134 di->state = di_nextkey;
1137 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1138 di->ddp = data_read_id(di->ddp, &di->kv.id);
1139 di->kv.str = (char *)di->ddp;
1140 if (di->keyname && di->key->name != di->keyname)
1142 if ((di->flags & SEARCH_SUB) != 0)
1143 di->state = di_entersub;
1145 di->state = di_nextarrayelement;
1148 case di_entersub: di_entersub:
1149 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1150 goto di_nextarrayelement; /* sorry, full */
1151 di->parents[di->nparents].kv = di->kv;
1152 di->parents[di->nparents].dp = di->dp;
1153 di->parents[di->nparents].keyp = di->keyp;
1154 di->dp = (unsigned char *)di->kv.str;
1155 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1156 memset(&di->kv, 0, sizeof(di->kv));
1157 di->kv.parent = &di->parents[di->nparents].kv;
1162 case di_leavesub: di_leavesub:
1164 di->dp = di->parents[di->nparents].dp;
1165 di->kv = di->parents[di->nparents].kv;
1166 di->keyp = di->parents[di->nparents].keyp;
1167 di->key = di->data->keys + *di->keyp;
1168 di->ddp = (unsigned char *)di->kv.str;
1169 goto di_nextarrayelement;
1171 /* special solvable attr handling follows */
1173 case di_nextsolvableattr:
1174 di->kv.id = *di->idp++;
1179 di->state = di_nextsolvablekey;
1183 case di_nextsolvablekey: di_nextsolvablekey:
1184 if (di->keyname || di->key->name == RPM_RPMDBID)
1185 goto di_enterrepodata;
1189 case di_entersolvablekey: di_entersolvablekey:
1190 di->idp = solvabledata_fetch(di->pool->solvables + di->entry, &di->kv, di->key->name);
1191 if (!di->idp || !di->idp[0])
1192 goto di_nextsolvablekey;
1193 di->kv.id = di->idp[0];
1194 di->kv.num = di->idp[0];
1195 if (!di->kv.eof && !di->idp[1])
1199 di->state = di_nextsolvablekey;
1201 di->state = di_nextsolvableattr;
1205 if (di->matcher.match)
1206 if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
1208 /* found something! */
1214 dataiterator_setpos(Dataiterator *di)
1216 di->pool->pos.repo = di->repo;
1217 di->pool->pos.repodataid = di->data - di->repo->repodata;
1218 di->pool->pos.schema = di->kv.id;
1219 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1223 dataiterator_skip_attribute(Dataiterator *di)
1225 if (di->state == di_nextsolvableattr)
1226 di->state = di_nextsolvablekey;
1228 di->state = di_nextkey;
1232 dataiterator_skip_solvable(Dataiterator *di)
1234 di->state = di_nextsolvable;
1238 dataiterator_skip_repo(Dataiterator *di)
1240 di->state = di_nextrepo;
1244 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1248 di->entry = s - di->pool->solvables;
1249 di->state = di_entersolvable;
1253 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1257 di->state = di_enterrepo;
1261 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1263 Datamatcher matcher = di->matcher;
1264 matcher.flags = flags;
1265 matcher.match = (void *)vmatch;
1266 return datamatcher_match(&matcher, di->data, di->key, &di->kv);
1271 /************************************************************************
1272 * data search iterator
1276 dataiterator_newdata(Dataiterator *di)
1278 Id keyname = di->keyname;
1279 Repodata *data = di->data;
1282 if (data->state == REPODATA_STUB)
1287 for (j = 1; j < data->nkeys; j++)
1288 if (keyname == data->keys[j].name)
1290 if (j == data->nkeys)
1294 if (data->loadcallback)
1295 data->loadcallback(data);
1297 data->state = REPODATA_ERROR;
1299 if (data->state == REPODATA_ERROR)
1303 unsigned char *dp = data->incoredata;
1306 if (di->solvid >= 0)
1307 dp += data->incoreoffset[di->solvid - data->start];
1308 dp = data_read_id(dp, &schema);
1309 Id *keyp = data->schemadata + data->schemata[schema];
1313 /* search in a specific key */
1314 for (kp = keyp; (k = *kp++) != 0; )
1315 if (data->keys[k].name == keyname)
1319 dp = forward_to_key(data, k, keyp, dp);
1329 di->key = di->data->keys + keyid;
1334 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1339 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
1340 const char *match, int flags)
1346 di->flags |= __SEARCH_ONESOLVABLE;
1347 di->data = repo->repodata - 1;
1348 if (flags & SEARCH_NO_STORAGE_SOLVABLE)
1355 di->solvid = repo->start - 1;
1358 fprintf(stderr, "A repo contains the NULL solvable!\n");
1361 di->data = repo->repodata + repo->nrepodata - 1;
1366 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1370 /* We feed multiple lines eventually (e.g. authors or descriptions),
1371 so set REG_NEWLINE. */
1373 regcomp(&di->regex, di->match,
1374 REG_EXTENDED | REG_NOSUB | REG_NEWLINE
1375 | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1377 if (di->regex_err != 0)
1379 fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
1380 fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
1387 di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
1393 di->keyname = keyname;
1394 static Id zeroid = 0;
1402 /* FIXME factor and merge with repo_matchvalue */
1404 dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
1406 KeyValue *kv = &di->kv;
1407 const char *match = vmatch;
1408 if ((flags & SEARCH_STRINGMASK) != 0)
1410 switch (di->key->type)
1412 case REPOKEY_TYPE_ID:
1413 case REPOKEY_TYPE_IDARRAY:
1414 if (di->data && di->data->localpool)
1415 kv->str = stringpool_id2str(&di->data->spool, kv->id);
1417 kv->str = id2str(di->repo->pool, kv->id);
1419 case REPOKEY_TYPE_STR:
1421 case REPOKEY_TYPE_DIRSTRARRAY:
1422 if (!(flags & SEARCH_FILES))
1424 /* Put the full filename into kv->str. */
1425 kv->str = repodata_dir2str(di->data, kv->id, kv->str);
1426 /* And to compensate for that put the "empty" directory into
1427 kv->id, so that later calls to repodata_dir2str on this data
1428 come up with the same filename again. */
1434 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
1435 for the others we can't know if a colon separates a kind or not. */
1436 if ((flags & SEARCH_SKIP_KIND)
1437 && di->key->storage == KEY_STORAGE_SOLVABLE)
1439 const char *s = strchr(kv->str, ':');
1443 switch ((flags & SEARCH_STRINGMASK))
1445 case SEARCH_SUBSTRING:
1446 if (flags & SEARCH_NOCASE)
1448 if (!strcasestr(kv->str, match))
1453 if (!strstr(kv->str, match))
1458 if (flags & SEARCH_NOCASE)
1460 if (strcasecmp(match, kv->str))
1465 if (strcmp(match, kv->str))
1470 if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1474 if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
1485 dataiterator_match_int(Dataiterator *di)
1487 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1488 return dataiterator_match_int_real(di, di->flags, &di->regex);
1490 return dataiterator_match_int_real(di, di->flags, di->match);
1494 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1496 return dataiterator_match_int_real(di, flags, vmatch);
1500 dataiterator_step(Dataiterator *di)
1507 /* we're stepping through solvable data, 1 -> SOLVABLE_NAME... */
1510 /* we're stepping through an id array */
1516 di->kv.eof = idp[1] ? 0 : 1;
1522 Solvable *s = di->repo->pool->solvables + di->solvid;
1523 int state = di->state;
1524 di->key = solvablekeys + state - 1;
1526 di->state = RPM_RPMDBID;
1533 state = di->keyname - 1;
1540 di->kv.id = s->name;
1546 di->kv.id = s->arch;
1555 case SOLVABLE_VENDOR:
1558 di->kv.id = s->vendor;
1561 case SOLVABLE_PROVIDES:
1562 di->idp = s->provides
1563 ? di->repo->idarraydata + s->provides : 0;
1565 case SOLVABLE_OBSOLETES:
1566 di->idp = s->obsoletes
1567 ? di->repo->idarraydata + s->obsoletes : 0;
1569 case SOLVABLE_CONFLICTS:
1570 di->idp = s->conflicts
1571 ? di->repo->idarraydata + s->conflicts : 0;
1573 case SOLVABLE_REQUIRES:
1574 di->idp = s->requires
1575 ? di->repo->idarraydata + s->requires : 0;
1577 case SOLVABLE_RECOMMENDS:
1578 di->idp = s->recommends
1579 ? di->repo->idarraydata + s->recommends : 0;
1581 case SOLVABLE_SUPPLEMENTS:
1582 di->idp = s->supplements
1583 ? di->repo->idarraydata + s->supplements : 0;
1585 case SOLVABLE_SUGGESTS:
1586 di->idp = s->suggests
1587 ? di->repo->idarraydata + s->suggests : 0;
1589 case SOLVABLE_ENHANCES:
1590 di->idp = s->enhances
1591 ? di->repo->idarraydata + s->enhances : 0;
1594 if (!di->repo->rpmdbid)
1596 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
1600 di->data = di->repo->repodata - 1;
1606 else if (di->subkeyp)
1611 /* Send end-of-substruct. We are here only when we saw a
1612 _COUNTED key one level up. Since then we didn't increment
1613 ->keyp, so it still can be found at keyp[-1]. */
1615 di->key = di->data->keys + di->keyp[-1];
1618 else if (!(keyid = *di->subkeyp++))
1620 /* Send end-of-element. See above for keyp[-1]. */
1622 di->key = di->data->keys + di->keyp[-1];
1624 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1627 di->dp = data_read_id(di->dp, &di->subschema);
1628 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1635 di->key = di->data->keys + keyid;
1636 di->dp = data_fetch(di->dp, &di->kv, di->key);
1646 di->dp = data_fetch(di->dp, &di->kv, di->key);
1651 if (di->keyname || !(keyid = *di->keyp++))
1655 Repo *repo = di->repo;
1656 Repodata *data = ++di->data;
1657 if (data >= repo->repodata + repo->nrepodata)
1659 if (di->flags & __SEARCH_ONESOLVABLE)
1661 if (di->solvid >= 0)
1663 while (++di->solvid < repo->end)
1664 if (repo->pool->solvables[di->solvid].repo == repo)
1666 if (di->solvid >= repo->end)
1668 if (!(di->flags & SEARCH_EXTRA))
1677 Pool *pool = di->repo->pool;
1678 if (!(di->flags & SEARCH_ALL_REPOS)
1679 || di->repo == pool->repos[pool->nrepos - 1])
1682 for (i = 0; i < pool->nrepos; i++)
1683 if (di->repo == pool->repos[i])
1685 di->repo = pool->repos[i + 1];
1686 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
1690 di->data = repo->repodata - 1;
1691 if ((di->flags & SEARCH_NO_STORAGE_SOLVABLE))
1693 static Id zeroid = 0;
1698 if ((di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
1700 dataiterator_newdata(di);
1708 di->key = di->data->keys + keyid;
1709 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1711 di->dp = data_fetch(di->dp, &di->kv, di->key);
1713 if (di->key->type == REPOKEY_TYPE_FIXARRAY)
1715 di->subnum = di->kv.num;
1716 di->subschema = di->kv.id;
1718 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1720 if (di->key->type == REPOKEY_TYPE_FLEXARRAY)
1722 di->subnum = di->kv.num;
1724 di->dp = data_read_id(di->dp, &di->subschema);
1725 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1731 || dataiterator_match_int(di))
1738 dataiterator_skip_attribute(Dataiterator *di)
1742 /* This will make the next _step call to retrieve the next field. */
1747 dataiterator_skip_solvable(Dataiterator *di)
1749 /* We're done with this field. */
1751 /* And with solvable data. */
1753 /* And with all keys for this repodata and thing. */
1754 static Id zeroid = 0;
1756 /* And with all repodatas for this thing. */
1757 di->data = di->repo->repodata + di->repo->nrepodata - 1;
1758 /* Hence the next call to _step will retrieve the next thing. */
1762 dataiterator_skip_repo(Dataiterator *di)
1764 dataiterator_skip_solvable(di);
1765 /* We're done with all solvables and all extra things for this repo. */
1770 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1773 /* Simulate us being done with the solvable before the requested one. */
1774 dataiterator_skip_solvable(di);
1775 di->solvid = s - s->repo->pool->solvables;
1780 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1783 dataiterator_skip_solvable(di);
1784 di->solvid = repo->start - 1;
1789 /************************************************************************
1790 * data modify functions
1793 /* extend repodata so that it includes solvables p */
1795 repodata_extend(Repodata *data, Id p)
1797 if (data->start == data->end)
1798 data->start = data->end = p;
1801 int old = data->end - data->start;
1802 int new = p - data->end + 1;
1805 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id), REPODATA_BLOCK);
1806 memset(data->attrs + old, 0, new * sizeof(Id));
1808 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1809 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1812 if (p < data->start)
1814 int old = data->end - data->start;
1815 int new = data->start - p;
1818 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id), REPODATA_BLOCK);
1819 memmove(data->attrs + new, data->attrs, old * sizeof(Id));
1820 memset(data->attrs, 0, new * sizeof(Id));
1822 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1823 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1824 memset(data->incoreoffset, 0, new * sizeof(Id));
1830 repodata_extend_block(Repodata *data, Id start, Id num)
1834 if (!data->incoreoffset)
1836 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1837 data->start = start;
1838 data->end = start + num;
1841 repodata_extend(data, start);
1843 repodata_extend(data, start + num - 1);
1846 /**********************************************************************/
1848 #define REPODATA_ATTRS_BLOCK 63
1849 #define REPODATA_ATTRDATA_BLOCK 1023
1850 #define REPODATA_ATTRIDDATA_BLOCK 63
1854 repodata_new_handle(Repodata *data)
1858 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1861 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1862 data->xattrs[data->nxattrs] = 0;
1863 return -(data->nxattrs++);
1867 repodata_get_attrp(Repodata *data, Id handle)
1869 if (handle == REPOENTRY_META)
1873 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1878 return data->xattrs - handle;
1879 if (handle < data->start || handle >= data->end)
1880 repodata_extend(data, handle);
1882 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1883 return data->attrs + (handle - data->start);
1887 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1893 app = repodata_get_attrp(data, handle);
1898 for (pp = ap; *pp; pp += 2)
1899 /* Determine equality based on the name only, allows us to change
1900 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1901 if (data->keys[*pp].name == data->keys[keyid].name)
1914 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1924 repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
1928 keyid = repodata_key2id(data, key, 1);
1929 repodata_insert_keyid(data, handle, keyid, val, 1);
1933 repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
1937 key.type = REPOKEY_TYPE_ID;
1939 key.storage = KEY_STORAGE_INCORE;
1940 repodata_set(data, handle, &key, id);
1944 repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
1948 key.type = REPOKEY_TYPE_NUM;
1950 key.storage = KEY_STORAGE_INCORE;
1951 repodata_set(data, handle, &key, (Id)num);
1955 repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
1959 if (data->localpool)
1960 id = stringpool_str2id(&data->spool, str, 1);
1962 id = str2id(data->repo->pool, str, 1);
1964 key.type = REPOKEY_TYPE_ID;
1966 key.storage = KEY_STORAGE_INCORE;
1967 repodata_set(data, handle, &key, id);
1971 repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
1975 key.type = REPOKEY_TYPE_CONSTANT;
1976 key.size = constant;
1977 key.storage = KEY_STORAGE_INCORE;
1978 repodata_set(data, handle, &key, 0);
1982 repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
1986 key.type = REPOKEY_TYPE_CONSTANTID;
1988 key.storage = KEY_STORAGE_INCORE;
1989 repodata_set(data, handle, &key, 0);
1993 repodata_set_void(Repodata *data, Id handle, Id keyname)
1997 key.type = REPOKEY_TYPE_VOID;
1999 key.storage = KEY_STORAGE_INCORE;
2000 repodata_set(data, handle, &key, 0);
2004 repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
2009 l = strlen(str) + 1;
2011 key.type = REPOKEY_TYPE_STR;
2013 key.storage = KEY_STORAGE_INCORE;
2014 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2015 memcpy(data->attrdata + data->attrdatalen, str, l);
2016 repodata_set(data, handle, &key, data->attrdatalen);
2017 data->attrdatalen += l;
2021 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2024 Id *ida, *pp, **ppp;
2026 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2028 /* great! just append the new data */
2029 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2030 data->attriddatalen--; /* overwrite terminating 0 */
2031 data->lastdatalen += entrysize;
2034 ppp = repodata_get_attrp(data, handle);
2037 for (; *pp; pp += 2)
2038 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
2042 /* not found. allocate new key */
2047 key.storage = KEY_STORAGE_INCORE;
2048 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2049 repodata_set(data, handle, &key, data->attriddatalen);
2050 data->lasthandle = 0; /* next time... */
2054 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2055 oldsize += entrysize;
2056 if (ida + 1 == data->attriddata + data->attriddatalen)
2058 /* this was the last entry, just append it */
2059 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2060 data->attriddatalen--; /* overwrite terminating 0 */
2064 /* too bad. move to back. */
2065 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2066 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2067 pp[1] = data->attriddatalen;
2068 data->attriddatalen += oldsize;
2070 data->lasthandle = handle;
2071 data->lastkey = *pp;
2072 data->lastdatalen = data->attriddatalen + entrysize + 1;
2076 checksumtype2len(Id type)
2080 case REPOKEY_TYPE_MD5:
2082 case REPOKEY_TYPE_SHA1:
2084 case REPOKEY_TYPE_SHA256:
2085 return SIZEOF_SHA256;
2092 repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
2093 const unsigned char *str)
2096 int l = checksumtype2len(type);
2103 key.storage = KEY_STORAGE_INCORE;
2104 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2105 memcpy(data->attrdata + data->attrdatalen, str, l);
2106 repodata_set(data, handle, &key, data->attrdatalen);
2107 data->attrdatalen += l;
2111 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2114 for (i = 0; i < buflen; i++)
2116 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2117 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
2118 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
2129 buf[i] = (buf[i] << 4) | v;
2136 repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
2139 unsigned char buf[64];
2140 int l = checksumtype2len(type);
2144 if (hexstr2bytes(buf, str, l) != l)
2146 fprintf(stderr, "Invalid hex character in '%s'\n", str);
2149 repodata_set_bin_checksum(data, handle, keyname, type, buf);
2153 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2158 l = checksumtype2len(type);
2161 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2162 for (i = 0; i < l; i++)
2164 unsigned char v = buf[i];
2165 unsigned char w = v >> 4;
2166 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2168 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2175 repodata_globalize_id(Repodata *data, Id id)
2177 if (!data || !data->localpool)
2179 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
2183 repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
2187 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
2189 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2190 data->attriddata[data->attriddatalen++] = dir;
2191 data->attriddata[data->attriddatalen++] = num;
2192 data->attriddata[data->attriddatalen++] = num2;
2193 data->attriddata[data->attriddatalen++] = 0;
2197 repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
2203 l = strlen(str) + 1;
2204 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2205 memcpy(data->attrdata + data->attrdatalen, str, l);
2206 stroff = data->attrdatalen;
2207 data->attrdatalen += l;
2210 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
2212 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2213 data->attriddata[data->attriddatalen++] = dir;
2214 data->attriddata[data->attriddatalen++] = stroff;
2215 data->attriddata[data->attriddatalen++] = 0;
2219 repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
2222 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
2224 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
2225 data->attriddata[data->attriddatalen++] = id;
2226 data->attriddata[data->attriddatalen++] = 0;
2230 repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
2234 if (data->localpool)
2235 id = stringpool_str2id(&data->spool, str, 1);
2237 id = str2id(data->repo->pool, str, 1);
2238 repodata_add_idarray(data, handle, keyname, id);
2242 repodata_add_fixarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2244 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2245 data->attriddata[data->attriddatalen++] = ghandle;
2246 data->attriddata[data->attriddatalen++] = 0;
2250 repodata_add_flexarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2252 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2253 data->attriddata[data->attriddatalen++] = ghandle;
2254 data->attriddata[data->attriddatalen++] = 0;
2258 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2261 if (dest == src || !(keyp = data->attrs[src]))
2263 for (; *keyp; keyp += 2)
2264 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2270 /**********************************************************************/
2272 /* unify with repo_write! */
2274 #define EXTDATA_BLOCK 1023
2282 data_addid(struct extdata *xd, Id x)
2285 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2286 dp = xd->buf + xd->len;
2291 *dp++ = (x >> 28) | 128;
2293 *dp++ = (x >> 21) | 128;
2294 *dp++ = (x >> 14) | 128;
2297 *dp++ = (x >> 7) | 128;
2299 xd->len = dp - xd->buf;
2303 data_addideof(struct extdata *xd, Id x, int eof)
2306 x = (x & 63) | ((x & ~63) << 1);
2307 data_addid(xd, (eof ? x: x | 64));
2311 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2313 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2314 memcpy(xd->buf + xd->len, blob, len);
2318 /*********************************/
2321 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2322 struct extdata *newvincore,
2324 Repokey *key, Id val)
2326 /* Otherwise we have a new value. Parse it into the internal
2330 unsigned int oldvincorelen = 0;
2334 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2337 oldvincorelen = xd->len;
2341 case REPOKEY_TYPE_VOID:
2342 case REPOKEY_TYPE_CONSTANT:
2343 case REPOKEY_TYPE_CONSTANTID:
2345 case REPOKEY_TYPE_STR:
2346 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2348 case REPOKEY_TYPE_MD5:
2349 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2351 case REPOKEY_TYPE_SHA1:
2352 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2354 case REPOKEY_TYPE_SHA256:
2355 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2357 case REPOKEY_TYPE_ID:
2358 case REPOKEY_TYPE_NUM:
2359 case REPOKEY_TYPE_DIR:
2360 data_addid(xd, val);
2362 case REPOKEY_TYPE_IDARRAY:
2363 for (ida = data->attriddata + val; *ida; ida++)
2364 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2366 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2367 for (ida = data->attriddata + val; *ida; ida += 3)
2369 data_addid(xd, ida[0]);
2370 data_addid(xd, ida[1]);
2371 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2374 case REPOKEY_TYPE_DIRSTRARRAY:
2375 for (ida = data->attriddata + val; *ida; ida += 2)
2377 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2378 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2381 case REPOKEY_TYPE_FIXARRAY:
2385 for (ida = data->attriddata + val; *ida; ida++)
2388 fprintf(stderr, "serialize struct %d\n", *ida);
2391 Id *kp = data->xattrs[-*ida];
2398 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2404 schemaid = repodata_schema2id(data, schema, 1);
2405 else if (schemaid != repodata_schema2id(data, schema, 0))
2407 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
2411 fprintf(stderr, " schema %d\n", schemaid);
2416 data_addid(xd, num);
2417 data_addid(xd, schemaid);
2418 for (ida = data->attriddata + val; *ida; ida++)
2420 Id *kp = data->xattrs[-*ida];
2425 repodata_serialize_key(data, newincore, newvincore,
2426 schema, data->keys + *kp, kp[1]);
2431 case REPOKEY_TYPE_FLEXARRAY:
2434 for (ida = data->attriddata + val; *ida; ida++)
2436 data_addid(xd, num);
2437 for (ida = data->attriddata + val; *ida; ida++)
2439 Id *kp = data->xattrs[-*ida];
2442 data_addid(xd, 0); /* XXX */
2449 schemaid = repodata_schema2id(data, schema, 1);
2450 data_addid(xd, schemaid);
2451 kp = data->xattrs[-*ida];
2454 repodata_serialize_key(data, newincore, newvincore,
2455 schema, data->keys + *kp, kp[1]);
2461 fprintf(stderr, "don't know how to handle type %d\n", key->type);
2464 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2466 /* put offset/len in incore */
2467 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2468 oldvincorelen = xd->len - oldvincorelen;
2469 data_addid(newincore, oldvincorelen);
2474 repodata_internalize(Repodata *data)
2476 Repokey *key, solvkey;
2478 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2479 unsigned char *dp, *ndp;
2480 int newschema, oldcount;
2481 struct extdata newincore;
2482 struct extdata newvincore;
2485 if (!data->attrs && !data->xattrs)
2488 newvincore.buf = data->vincore;
2489 newvincore.len = data->vincorelen;
2491 /* find the solvables key, create if needed */
2492 memset(&solvkey, 0, sizeof(solvkey));
2493 solvkey.name = REPOSITORY_SOLVABLES;
2494 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2496 solvkey.storage = KEY_STORAGE_INCORE;
2497 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2499 schema = sat_malloc2(data->nkeys, sizeof(Id));
2500 seen = sat_malloc2(data->nkeys, sizeof(Id));
2502 /* Merge the data already existing (in data->schemata, ->incoredata and
2503 friends) with the new attributes in data->attrs[]. */
2504 nentry = data->end - data->start;
2505 memset(&newincore, 0, sizeof(newincore));
2506 data_addid(&newincore, 0); /* start data at offset 1 */
2508 data->mainschema = 0;
2509 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2511 /* join entry data */
2512 /* we start with the meta data, entry -1 */
2513 for (entry = -1; entry < nentry; entry++)
2515 memset(seen, 0, data->nkeys * sizeof(Id));
2517 dp = data->incoredata;
2520 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2521 dp = data_read_id(dp, &oldschema);
2524 fprintf(stderr, "oldschema %d\n", oldschema);
2525 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2526 fprintf(stderr, "schemadata %p\n", data->schemadata);
2528 /* seen: -1: old data 0: skipped >0: id + 1 */
2532 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2536 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2544 keyp = data->attrs ? data->attrs[entry] : 0;
2547 /* strip solvables key */
2549 for (sp = keyp = schema; *sp; sp++)
2550 if (*sp != solvkeyid)
2555 seen[solvkeyid] = 0;
2556 keyp = data->xattrs ? data->xattrs[1] : 0;
2559 for (; *keyp; keyp += 2)
2566 seen[*keyp] = keyp[1] + 1;
2568 if (entry < 0 && data->end != data->start)
2575 /* Ideally we'd like to sort the new schema here, to ensure
2576 schema equality independend of the ordering. We can't do that
2577 yet. For once see below (old ids need to come before new ids).
2578 An additional difficulty is that we also need to move
2579 the values with the keys. */
2580 schemaid = repodata_schema2id(data, schema, 1);
2582 schemaid = oldschema;
2585 /* Now create data blob. We walk through the (possibly new) schema
2586 and either copy over old data, or insert the new. */
2587 /* XXX Here we rely on the fact that the (new) schema has the form
2588 o1 o2 o3 o4 ... | n1 n2 n3 ...
2589 (oX being the old keyids (possibly overwritten), and nX being
2590 the new keyids). This rules out sorting the keyids in order
2591 to ensure a small schema count. */
2593 data->incoreoffset[entry] = newincore.len;
2594 data_addid(&newincore, schemaid);
2597 data->mainschema = schemaid;
2598 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2600 keypstart = data->schemadata + data->schemata[schemaid];
2601 for (keyp = keypstart; *keyp; keyp++)
2604 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2605 if (*keyp == solvkeyid)
2607 /* add flexarray entry count */
2608 data_addid(&newincore, data->end - data->start);
2611 key = data->keys + *keyp;
2613 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2618 /* Skip the data associated with this old key. */
2619 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2621 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2622 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2624 else if (key->storage == KEY_STORAGE_INCORE)
2625 ndp = data_skip_key(data, dp, key);
2628 if (seen[*keyp] == -1)
2630 /* If this key was an old one _and_ was not overwritten with
2631 a different value copy over the old value (we skipped it
2634 data_addblob(&newincore, dp, ndp - dp);
2637 else if (seen[*keyp])
2639 /* Otherwise we have a new value. Parse it into the internal
2641 repodata_serialize_key(data, &newincore, &newvincore,
2642 schema, key, seen[*keyp] - 1);
2646 if (entry >= 0 && data->attrs && data->attrs[entry])
2647 data->attrs[entry] = sat_free(data->attrs[entry]);
2649 /* free all xattrs */
2650 for (entry = 0; entry < data->nxattrs; entry++)
2651 if (data->xattrs[entry])
2652 sat_free(data->xattrs[entry]);
2653 data->xattrs = sat_free(data->xattrs);
2656 data->lasthandle = 0;
2658 data->lastdatalen = 0;
2661 repodata_free_schemahash(data);
2663 sat_free(data->incoredata);
2664 data->incoredata = newincore.buf;
2665 data->incoredatalen = newincore.len;
2666 data->incoredatafree = 0;
2668 sat_free(data->vincore);
2669 data->vincore = newvincore.buf;
2670 data->vincorelen = newvincore.len;
2672 data->attrs = sat_free(data->attrs);
2673 data->attrdata = sat_free(data->attrdata);
2674 data->attriddata = sat_free(data->attriddata);
2675 data->attrdatalen = 0;
2676 data->attriddatalen = 0;
2680 repodata_disable_paging(Repodata *data)
2682 if (maybe_load_repodata(data, 0)
2684 repodata_load_page_range(data, 0, data->num_pages - 1);
2688 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: