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);
690 while (ddp && nentries > 0)
692 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
693 ddp = data_read_id(ddp, &schema);
695 kv.str = (char *)ddp;
696 stop = callback(cbdata, s, data, key, &kv);
697 if (stop > SEARCH_NEXT_KEY)
702 repodata_search(data, REPOENTRY_SUBSCHEMA, 0, callback, &subd);
703 ddp = data_skip_schema(data, ddp, schema);
711 kv.str = (char *)ddp;
712 stop = callback(cbdata, s, data, key, &kv);
713 if (stop > SEARCH_NEXT_KEY)
723 ddp = data_fetch(ddp, &kv, key);
726 stop = callback(cbdata, s, data, key, &kv);
729 while (!kv.eof && !stop);
730 if (onekey || stop > SEARCH_NEXT_KEY)
736 repodata_setpos_kv(Repodata *data, KeyValue *kv)
738 Pool *pool = data->repo->pool;
742 pool->pos.repodataid = 0;
744 pool->pos.schema = 0;
749 pool->pos.repodataid = data - data->repo->repodata;
750 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
751 pool->pos.schema = kv->id;
755 /************************************************************************/
757 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
758 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
759 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
760 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
761 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
762 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
763 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
764 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
765 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
766 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
767 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
768 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
769 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
770 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
775 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
789 case SOLVABLE_VENDOR:
792 case SOLVABLE_PROVIDES:
794 return s->provides ? s->repo->idarraydata + s->provides : 0;
795 case SOLVABLE_OBSOLETES:
797 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
798 case SOLVABLE_CONFLICTS:
800 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
801 case SOLVABLE_REQUIRES:
803 return s->requires ? s->repo->idarraydata + s->requires : 0;
804 case SOLVABLE_RECOMMENDS:
806 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
807 case SOLVABLE_SUPPLEMENTS:
809 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
810 case SOLVABLE_SUGGESTS:
812 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
813 case SOLVABLE_ENHANCES:
815 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
818 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
825 datamatcher_init(Datamatcher *ma, Pool *pool, const char *match, int flags)
828 ma->match = (void *)match;
831 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
833 ma->match = sat_calloc(1, sizeof(regex_t));
834 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
838 ma->match = (void *)match;
839 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
845 datamatcher_free(Datamatcher *ma)
847 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
850 ma->match = sat_free(ma->match);
855 datamatcher_match(Datamatcher *ma, Repodata *data, Repokey *key, KeyValue *kv)
859 case REPOKEY_TYPE_ID:
860 case REPOKEY_TYPE_IDARRAY:
861 if (data && data->localpool)
862 kv->str = stringpool_id2str(&data->spool, kv->id);
864 kv->str = id2str(ma->pool, kv->id);
866 case REPOKEY_TYPE_STR:
868 case REPOKEY_TYPE_DIRSTRARRAY:
869 if (!(ma->flags & SEARCH_FILES))
871 /* Put the full filename into kv->str. */
872 kv->str = repodata_dir2str(data, kv->id, kv->str);
873 /* And to compensate for that put the "empty" directory into
874 kv->id, so that later calls to repodata_dir2str on this data
875 come up with the same filename again. */
881 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
882 for the others we can't know if a colon separates a kind or not. */
883 if ((ma->flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
885 const char *s = strchr(kv->str, ':');
889 switch ((ma->flags & SEARCH_STRINGMASK))
891 case SEARCH_SUBSTRING:
892 if (ma->flags & SEARCH_NOCASE)
894 if (!strcasestr(kv->str, (const char *)ma->match))
899 if (!strstr(kv->str, (const char *)ma->match))
904 if (ma->flags & SEARCH_NOCASE)
906 if (strcasecmp((const char *)ma->match, kv->str))
911 if (strcmp((const char *)ma->match, kv->str))
916 if (fnmatch((const char *)ma->match, kv->str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
920 if (regexec((const regex_t *)ma->match, kv->str, 0, NULL, 0))
953 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname, const char *match, int flags)
955 memset(di, 0, sizeof(*di));
957 di->keyname = keyname;
959 di->pool = repo->pool;
961 flags |= SEARCH_THISENTRY;
966 datamatcher_init(&di->matcher, di->pool, match, flags);
967 di->state = di_enterrepo;
971 dataiterator_free(Dataiterator *di)
973 if (di->matcher.match)
974 datamatcher_free(&di->matcher);
978 dataiterator_step(Dataiterator *di)
986 case di_nextattr: di_nextattr:
988 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
990 di->state = di_nextkey;
992 di->state = di_nextattr;
995 case di_nextkey: di_nextkey:
1001 else if ((di->flags & SEARCH_SUB) != 0)
1003 Id *keyp = di->keyp;
1004 for (keyp++; *keyp; keyp++)
1005 if (di->data->keys[*keyp].name == di->keyname ||
1006 di->data->keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
1007 di->data->keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
1009 if (*keyp && (di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp)) != 0)
1020 case di_nextrepodata: di_nextrepodata:
1021 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1022 goto di_enterrepodata;
1025 case di_nextsolvable:
1026 if (!(di->flags & SEARCH_THISENTRY))
1029 di->entry = di->repo->start;
1032 for (; di->entry < di->repo->end; di->entry++)
1034 if (di->pool->solvables[di->entry].repo == di->repo)
1035 goto di_entersolvable;
1041 if (di->repoid >= 0)
1044 if (di->repoid < di->pool->nrepos)
1046 di->repo = di->pool->repos[di->repoid];
1056 case di_enterrepo: di_enterrepo:
1057 if (!(di->flags & SEARCH_THISENTRY))
1058 di->entry = di->repo->start;
1061 case di_entersolvable: di_entersolvable:
1062 if (di->repodataid >= 0)
1065 if (di->entry > 0 && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1067 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1069 goto di_entersolvablekey;
1073 case di_enterrepodata: di_enterrepodata:
1074 if (di->repodataid >= 0)
1075 di->data = di->repo->repodata + di->repodataid;
1076 if (!maybe_load_repodata(di->data, di->keyname))
1077 goto di_nextrepodata;
1078 di->dp = entry2data(di->data, di->entry, &schema);
1080 goto di_nextrepodata;
1081 di->keyp = di->data->schemadata + di->data->schemata[schema];
1085 if ((di->flags & SEARCH_SUB) != 0)
1090 for (keyp = di->keyp; *keyp; keyp++)
1091 if (di->data->keys[*keyp].name == di->keyname)
1094 goto di_nextrepodata;
1095 di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1098 goto di_nextrepodata;
1101 case di_enterkey: di_enterkey:
1103 di->key = di->data->keys + *di->keyp;
1104 di->ddp = get_data(di->data, di->key, &di->dp);
1107 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1109 di->ddp = data_read_id(di->ddp, &di->kv.num);
1112 goto di_nextarrayelement;
1116 case di_nextarrayelement: di_nextarrayelement:
1119 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1120 if (di->kv.entry == di->kv.num)
1122 if (di->keyname && di->key->name != di->keyname)
1124 di->kv.str = (char *)di->ddp;
1126 di->state = di_nextkey;
1129 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1130 di->ddp = data_read_id(di->ddp, &di->kv.id);
1131 di->kv.str = (char *)di->ddp;
1132 if (di->keyname && di->key->name != di->keyname)
1134 if ((di->flags & SEARCH_SUB) != 0)
1135 di->state = di_entersub;
1137 di->state = di_nextarrayelement;
1140 case di_entersub: di_entersub:
1141 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1142 goto di_nextarrayelement; /* sorry, full */
1143 di->parents[di->nparents].kv = di->kv;
1144 di->parents[di->nparents].dp = di->dp;
1145 di->parents[di->nparents].keyp = di->keyp;
1146 di->dp = (unsigned char *)di->kv.str;
1147 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1148 memset(&di->kv, 0, sizeof(di->kv));
1149 di->kv.parent = &di->parents[di->nparents].kv;
1154 case di_leavesub: di_leavesub:
1156 di->dp = di->parents[di->nparents].dp;
1157 di->kv = di->parents[di->nparents].kv;
1158 di->keyp = di->parents[di->nparents].keyp;
1159 di->key = di->data->keys + *di->keyp;
1160 di->ddp = (unsigned char *)di->kv.str;
1161 goto di_nextarrayelement;
1163 /* special solvable attr handling follows */
1165 case di_nextsolvableattr:
1166 di->kv.id = *di->idp++;
1171 di->state = di_nextsolvablekey;
1175 case di_nextsolvablekey: di_nextsolvablekey:
1176 if (di->keyname || di->key->name == RPM_RPMDBID)
1177 goto di_enterrepodata;
1181 case di_entersolvablekey: di_entersolvablekey:
1182 di->idp = solvabledata_fetch(di->pool->solvables + di->entry, &di->kv, di->key->name);
1183 if (!di->idp || !di->idp[0])
1184 goto di_nextsolvablekey;
1185 di->kv.id = di->idp[0];
1186 di->kv.num = di->idp[0];
1187 if (!di->kv.eof && !di->idp[1])
1191 di->state = di_nextsolvablekey;
1193 di->state = di_nextsolvableattr;
1197 if (di->matcher.match)
1198 if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
1200 /* found something! */
1206 dataiterator_setpos(Dataiterator *di)
1208 di->pool->pos.repo = di->repo;
1209 di->pool->pos.repodataid = di->data - di->repo->repodata;
1210 di->pool->pos.schema = di->kv.id;
1211 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1215 dataiterator_skip_attribute(Dataiterator *di)
1217 if (di->state == di_nextsolvableattr)
1218 di->state = di_nextsolvablekey;
1220 di->state = di_nextkey;
1224 dataiterator_skip_solvable(Dataiterator *di)
1226 di->state = di_nextsolvable;
1230 dataiterator_skip_repo(Dataiterator *di)
1232 di->state = di_nextrepo;
1236 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1240 di->entry = s - di->pool->solvables;
1241 di->state = di_entersolvable;
1245 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1249 di->state = di_enterrepo;
1254 /************************************************************************
1255 * data search iterator
1259 dataiterator_newdata(Dataiterator *di)
1261 Id keyname = di->keyname;
1262 Repodata *data = di->data;
1265 if (data->state == REPODATA_STUB)
1270 for (j = 1; j < data->nkeys; j++)
1271 if (keyname == data->keys[j].name)
1273 if (j == data->nkeys)
1277 if (data->loadcallback)
1278 data->loadcallback(data);
1280 data->state = REPODATA_ERROR;
1282 if (data->state == REPODATA_ERROR)
1286 unsigned char *dp = data->incoredata;
1289 if (di->solvid >= 0)
1290 dp += data->incoreoffset[di->solvid - data->start];
1291 dp = data_read_id(dp, &schema);
1292 Id *keyp = data->schemadata + data->schemata[schema];
1296 /* search in a specific key */
1297 for (kp = keyp; (k = *kp++) != 0; )
1298 if (data->keys[k].name == keyname)
1302 dp = forward_to_key(data, k, keyp, dp);
1312 di->key = di->data->keys + keyid;
1317 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1322 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
1323 const char *match, int flags)
1329 di->flags |= __SEARCH_ONESOLVABLE;
1330 di->data = repo->repodata - 1;
1331 if (flags & SEARCH_NO_STORAGE_SOLVABLE)
1338 di->solvid = repo->start - 1;
1341 fprintf(stderr, "A repo contains the NULL solvable!\n");
1344 di->data = repo->repodata + repo->nrepodata - 1;
1349 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1353 /* We feed multiple lines eventually (e.g. authors or descriptions),
1354 so set REG_NEWLINE. */
1356 regcomp(&di->regex, di->match,
1357 REG_EXTENDED | REG_NOSUB | REG_NEWLINE
1358 | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1360 if (di->regex_err != 0)
1362 fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
1363 fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
1370 di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
1376 di->keyname = keyname;
1377 static Id zeroid = 0;
1385 /* FIXME factor and merge with repo_matchvalue */
1387 dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
1389 KeyValue *kv = &di->kv;
1390 const char *match = vmatch;
1391 if ((flags & SEARCH_STRINGMASK) != 0)
1393 switch (di->key->type)
1395 case REPOKEY_TYPE_ID:
1396 case REPOKEY_TYPE_IDARRAY:
1397 if (di->data && di->data->localpool)
1398 kv->str = stringpool_id2str(&di->data->spool, kv->id);
1400 kv->str = id2str(di->repo->pool, kv->id);
1402 case REPOKEY_TYPE_STR:
1404 case REPOKEY_TYPE_DIRSTRARRAY:
1405 if (!(flags & SEARCH_FILES))
1407 /* Put the full filename into kv->str. */
1408 kv->str = repodata_dir2str(di->data, kv->id, kv->str);
1409 /* And to compensate for that put the "empty" directory into
1410 kv->id, so that later calls to repodata_dir2str on this data
1411 come up with the same filename again. */
1417 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
1418 for the others we can't know if a colon separates a kind or not. */
1419 if ((flags & SEARCH_SKIP_KIND)
1420 && di->key->storage == KEY_STORAGE_SOLVABLE)
1422 const char *s = strchr(kv->str, ':');
1426 switch ((flags & SEARCH_STRINGMASK))
1428 case SEARCH_SUBSTRING:
1429 if (flags & SEARCH_NOCASE)
1431 if (!strcasestr(kv->str, match))
1436 if (!strstr(kv->str, match))
1441 if (flags & SEARCH_NOCASE)
1443 if (strcasecmp(match, kv->str))
1448 if (strcmp(match, kv->str))
1453 if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1457 if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
1468 dataiterator_match_int(Dataiterator *di)
1470 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1471 return dataiterator_match_int_real(di, di->flags, &di->regex);
1473 return dataiterator_match_int_real(di, di->flags, di->match);
1477 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1479 return dataiterator_match_int_real(di, flags, vmatch);
1483 dataiterator_step(Dataiterator *di)
1490 /* we're stepping through solvable data, 1 -> SOLVABLE_NAME... */
1493 /* we're stepping through an id array */
1499 di->kv.eof = idp[1] ? 0 : 1;
1505 Solvable *s = di->repo->pool->solvables + di->solvid;
1506 int state = di->state;
1507 di->key = solvablekeys + state - 1;
1509 di->state = RPM_RPMDBID;
1516 state = di->keyname - 1;
1523 di->kv.id = s->name;
1529 di->kv.id = s->arch;
1538 case SOLVABLE_VENDOR:
1541 di->kv.id = s->vendor;
1544 case SOLVABLE_PROVIDES:
1545 di->idp = s->provides
1546 ? di->repo->idarraydata + s->provides : 0;
1548 case SOLVABLE_OBSOLETES:
1549 di->idp = s->obsoletes
1550 ? di->repo->idarraydata + s->obsoletes : 0;
1552 case SOLVABLE_CONFLICTS:
1553 di->idp = s->conflicts
1554 ? di->repo->idarraydata + s->conflicts : 0;
1556 case SOLVABLE_REQUIRES:
1557 di->idp = s->requires
1558 ? di->repo->idarraydata + s->requires : 0;
1560 case SOLVABLE_RECOMMENDS:
1561 di->idp = s->recommends
1562 ? di->repo->idarraydata + s->recommends : 0;
1564 case SOLVABLE_SUPPLEMENTS:
1565 di->idp = s->supplements
1566 ? di->repo->idarraydata + s->supplements : 0;
1568 case SOLVABLE_SUGGESTS:
1569 di->idp = s->suggests
1570 ? di->repo->idarraydata + s->suggests : 0;
1572 case SOLVABLE_ENHANCES:
1573 di->idp = s->enhances
1574 ? di->repo->idarraydata + s->enhances : 0;
1577 if (!di->repo->rpmdbid)
1579 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
1583 di->data = di->repo->repodata - 1;
1589 else if (di->subkeyp)
1594 /* Send end-of-substruct. We are here only when we saw a
1595 _COUNTED key one level up. Since then we didn't increment
1596 ->keyp, so it still can be found at keyp[-1]. */
1598 di->key = di->data->keys + di->keyp[-1];
1601 else if (!(keyid = *di->subkeyp++))
1603 /* Send end-of-element. See above for keyp[-1]. */
1605 di->key = di->data->keys + di->keyp[-1];
1607 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1610 di->dp = data_read_id(di->dp, &di->subschema);
1611 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1618 di->key = di->data->keys + keyid;
1619 di->dp = data_fetch(di->dp, &di->kv, di->key);
1629 di->dp = data_fetch(di->dp, &di->kv, di->key);
1634 if (di->keyname || !(keyid = *di->keyp++))
1638 Repo *repo = di->repo;
1639 Repodata *data = ++di->data;
1640 if (data >= repo->repodata + repo->nrepodata)
1642 if (di->flags & __SEARCH_ONESOLVABLE)
1644 if (di->solvid >= 0)
1646 while (++di->solvid < repo->end)
1647 if (repo->pool->solvables[di->solvid].repo == repo)
1649 if (di->solvid >= repo->end)
1651 if (!(di->flags & SEARCH_EXTRA))
1660 Pool *pool = di->repo->pool;
1661 if (!(di->flags & SEARCH_ALL_REPOS)
1662 || di->repo == pool->repos[pool->nrepos - 1])
1665 for (i = 0; i < pool->nrepos; i++)
1666 if (di->repo == pool->repos[i])
1668 di->repo = pool->repos[i + 1];
1669 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
1673 di->data = repo->repodata - 1;
1674 if ((di->flags & SEARCH_NO_STORAGE_SOLVABLE))
1676 static Id zeroid = 0;
1681 if ((di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
1683 dataiterator_newdata(di);
1691 di->key = di->data->keys + keyid;
1692 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1694 di->dp = data_fetch(di->dp, &di->kv, di->key);
1696 if (di->key->type == REPOKEY_TYPE_FIXARRAY)
1698 di->subnum = di->kv.num;
1699 di->subschema = di->kv.id;
1701 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1703 if (di->key->type == REPOKEY_TYPE_FLEXARRAY)
1705 di->subnum = di->kv.num;
1707 di->dp = data_read_id(di->dp, &di->subschema);
1708 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1714 || dataiterator_match_int(di))
1721 dataiterator_skip_attribute(Dataiterator *di)
1725 /* This will make the next _step call to retrieve the next field. */
1730 dataiterator_skip_solvable(Dataiterator *di)
1732 /* We're done with this field. */
1734 /* And with solvable data. */
1736 /* And with all keys for this repodata and thing. */
1737 static Id zeroid = 0;
1739 /* And with all repodatas for this thing. */
1740 di->data = di->repo->repodata + di->repo->nrepodata - 1;
1741 /* Hence the next call to _step will retrieve the next thing. */
1745 dataiterator_skip_repo(Dataiterator *di)
1747 dataiterator_skip_solvable(di);
1748 /* We're done with all solvables and all extra things for this repo. */
1753 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1756 /* Simulate us being done with the solvable before the requested one. */
1757 dataiterator_skip_solvable(di);
1758 di->solvid = s - s->repo->pool->solvables;
1763 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1766 dataiterator_skip_solvable(di);
1767 di->solvid = repo->start - 1;
1772 /************************************************************************
1773 * data modify functions
1776 /* extend repodata so that it includes solvables p */
1778 repodata_extend(Repodata *data, Id p)
1780 if (data->start == data->end)
1781 data->start = data->end = p;
1784 int old = data->end - data->start;
1785 int new = p - data->end + 1;
1788 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id), REPODATA_BLOCK);
1789 memset(data->attrs + old, 0, new * sizeof(Id));
1791 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1792 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1795 if (p < data->start)
1797 int old = data->end - data->start;
1798 int new = data->start - p;
1801 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id), REPODATA_BLOCK);
1802 memmove(data->attrs + new, data->attrs, old * sizeof(Id));
1803 memset(data->attrs, 0, new * sizeof(Id));
1805 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1806 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1807 memset(data->incoreoffset, 0, new * sizeof(Id));
1813 repodata_extend_block(Repodata *data, Id start, Id num)
1817 if (!data->incoreoffset)
1819 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1820 data->start = start;
1821 data->end = start + num;
1824 repodata_extend(data, start);
1826 repodata_extend(data, start + num - 1);
1829 /**********************************************************************/
1831 #define REPODATA_ATTRS_BLOCK 63
1832 #define REPODATA_ATTRDATA_BLOCK 1023
1833 #define REPODATA_ATTRIDDATA_BLOCK 63
1837 repodata_new_handle(Repodata *data)
1841 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1844 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1845 data->xattrs[data->nxattrs] = 0;
1846 return -(data->nxattrs++);
1850 repodata_get_attrp(Repodata *data, Id handle)
1852 if (handle == REPOENTRY_META)
1856 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1861 return data->xattrs - handle;
1862 if (handle < data->start || handle >= data->end)
1863 repodata_extend(data, handle);
1865 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1866 return data->attrs + (handle - data->start);
1870 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1876 app = repodata_get_attrp(data, handle);
1881 for (pp = ap; *pp; pp += 2)
1882 /* Determine equality based on the name only, allows us to change
1883 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1884 if (data->keys[*pp].name == data->keys[keyid].name)
1897 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1907 repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
1911 keyid = repodata_key2id(data, key, 1);
1912 repodata_insert_keyid(data, handle, keyid, val, 1);
1916 repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
1920 key.type = REPOKEY_TYPE_ID;
1922 key.storage = KEY_STORAGE_INCORE;
1923 repodata_set(data, handle, &key, id);
1927 repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
1931 key.type = REPOKEY_TYPE_NUM;
1933 key.storage = KEY_STORAGE_INCORE;
1934 repodata_set(data, handle, &key, (Id)num);
1938 repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
1942 if (data->localpool)
1943 id = stringpool_str2id(&data->spool, str, 1);
1945 id = str2id(data->repo->pool, str, 1);
1947 key.type = REPOKEY_TYPE_ID;
1949 key.storage = KEY_STORAGE_INCORE;
1950 repodata_set(data, handle, &key, id);
1954 repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
1958 key.type = REPOKEY_TYPE_CONSTANT;
1959 key.size = constant;
1960 key.storage = KEY_STORAGE_INCORE;
1961 repodata_set(data, handle, &key, 0);
1965 repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
1969 key.type = REPOKEY_TYPE_CONSTANTID;
1971 key.storage = KEY_STORAGE_INCORE;
1972 repodata_set(data, handle, &key, 0);
1976 repodata_set_void(Repodata *data, Id handle, Id keyname)
1980 key.type = REPOKEY_TYPE_VOID;
1982 key.storage = KEY_STORAGE_INCORE;
1983 repodata_set(data, handle, &key, 0);
1987 repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
1992 l = strlen(str) + 1;
1994 key.type = REPOKEY_TYPE_STR;
1996 key.storage = KEY_STORAGE_INCORE;
1997 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
1998 memcpy(data->attrdata + data->attrdatalen, str, l);
1999 repodata_set(data, handle, &key, data->attrdatalen);
2000 data->attrdatalen += l;
2004 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2007 Id *ida, *pp, **ppp;
2009 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2011 /* great! just append the new data */
2012 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2013 data->attriddatalen--; /* overwrite terminating 0 */
2014 data->lastdatalen += entrysize;
2017 ppp = repodata_get_attrp(data, handle);
2020 for (; *pp; pp += 2)
2021 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
2025 /* not found. allocate new key */
2030 key.storage = KEY_STORAGE_INCORE;
2031 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2032 repodata_set(data, handle, &key, data->attriddatalen);
2033 data->lasthandle = 0; /* next time... */
2037 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2038 oldsize += entrysize;
2039 if (ida + 1 == data->attriddata + data->attriddatalen)
2041 /* this was the last entry, just append it */
2042 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2043 data->attriddatalen--; /* overwrite terminating 0 */
2047 /* too bad. move to back. */
2048 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2049 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2050 pp[1] = data->attriddatalen;
2051 data->attriddatalen += oldsize;
2053 data->lasthandle = handle;
2054 data->lastkey = *pp;
2055 data->lastdatalen = data->attriddatalen + entrysize + 1;
2059 checksumtype2len(Id type)
2063 case REPOKEY_TYPE_MD5:
2065 case REPOKEY_TYPE_SHA1:
2067 case REPOKEY_TYPE_SHA256:
2068 return SIZEOF_SHA256;
2075 repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
2076 const unsigned char *str)
2079 int l = checksumtype2len(type);
2086 key.storage = KEY_STORAGE_INCORE;
2087 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2088 memcpy(data->attrdata + data->attrdatalen, str, l);
2089 repodata_set(data, handle, &key, data->attrdatalen);
2090 data->attrdatalen += l;
2094 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2097 for (i = 0; i < buflen; i++)
2099 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2100 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
2101 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
2112 buf[i] = (buf[i] << 4) | v;
2119 repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
2122 unsigned char buf[64];
2123 int l = checksumtype2len(type);
2127 if (hexstr2bytes(buf, str, l) != l)
2129 fprintf(stderr, "Invalid hex character in '%s'\n", str);
2132 repodata_set_bin_checksum(data, handle, keyname, type, buf);
2136 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2141 l = checksumtype2len(type);
2144 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2145 for (i = 0; i < l; i++)
2147 unsigned char v = buf[i];
2148 unsigned char w = v >> 4;
2149 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2151 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2158 repodata_globalize_id(Repodata *data, Id id)
2160 if (!data || !data->localpool)
2162 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
2166 repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
2170 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
2172 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2173 data->attriddata[data->attriddatalen++] = dir;
2174 data->attriddata[data->attriddatalen++] = num;
2175 data->attriddata[data->attriddatalen++] = num2;
2176 data->attriddata[data->attriddatalen++] = 0;
2180 repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
2186 l = strlen(str) + 1;
2187 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2188 memcpy(data->attrdata + data->attrdatalen, str, l);
2189 stroff = data->attrdatalen;
2190 data->attrdatalen += l;
2193 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
2195 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2196 data->attriddata[data->attriddatalen++] = dir;
2197 data->attriddata[data->attriddatalen++] = stroff;
2198 data->attriddata[data->attriddatalen++] = 0;
2202 repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
2205 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
2207 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
2208 data->attriddata[data->attriddatalen++] = id;
2209 data->attriddata[data->attriddatalen++] = 0;
2213 repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
2217 if (data->localpool)
2218 id = stringpool_str2id(&data->spool, str, 1);
2220 id = str2id(data->repo->pool, str, 1);
2221 repodata_add_idarray(data, handle, keyname, id);
2225 repodata_add_fixarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2227 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2228 data->attriddata[data->attriddatalen++] = ghandle;
2229 data->attriddata[data->attriddatalen++] = 0;
2233 repodata_add_flexarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2235 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2236 data->attriddata[data->attriddatalen++] = ghandle;
2237 data->attriddata[data->attriddatalen++] = 0;
2241 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2244 if (dest == src || !(keyp = data->attrs[src]))
2246 for (; *keyp; keyp += 2)
2247 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2253 /**********************************************************************/
2255 /* unify with repo_write! */
2257 #define EXTDATA_BLOCK 1023
2265 data_addid(struct extdata *xd, Id x)
2268 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2269 dp = xd->buf + xd->len;
2274 *dp++ = (x >> 28) | 128;
2276 *dp++ = (x >> 21) | 128;
2277 *dp++ = (x >> 14) | 128;
2280 *dp++ = (x >> 7) | 128;
2282 xd->len = dp - xd->buf;
2286 data_addideof(struct extdata *xd, Id x, int eof)
2289 x = (x & 63) | ((x & ~63) << 1);
2290 data_addid(xd, (eof ? x: x | 64));
2294 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2296 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2297 memcpy(xd->buf + xd->len, blob, len);
2301 /*********************************/
2304 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2305 struct extdata *newvincore,
2307 Repokey *key, Id val)
2309 /* Otherwise we have a new value. Parse it into the internal
2313 unsigned int oldvincorelen = 0;
2317 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2320 oldvincorelen = xd->len;
2324 case REPOKEY_TYPE_VOID:
2325 case REPOKEY_TYPE_CONSTANT:
2326 case REPOKEY_TYPE_CONSTANTID:
2328 case REPOKEY_TYPE_STR:
2329 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2331 case REPOKEY_TYPE_MD5:
2332 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2334 case REPOKEY_TYPE_SHA1:
2335 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2337 case REPOKEY_TYPE_SHA256:
2338 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2340 case REPOKEY_TYPE_ID:
2341 case REPOKEY_TYPE_NUM:
2342 case REPOKEY_TYPE_DIR:
2343 data_addid(xd, val);
2345 case REPOKEY_TYPE_IDARRAY:
2346 for (ida = data->attriddata + val; *ida; ida++)
2347 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2349 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2350 for (ida = data->attriddata + val; *ida; ida += 3)
2352 data_addid(xd, ida[0]);
2353 data_addid(xd, ida[1]);
2354 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2357 case REPOKEY_TYPE_DIRSTRARRAY:
2358 for (ida = data->attriddata + val; *ida; ida += 2)
2360 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2361 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2364 case REPOKEY_TYPE_FIXARRAY:
2368 for (ida = data->attriddata + val; *ida; ida++)
2371 fprintf(stderr, "serialize struct %d\n", *ida);
2374 Id *kp = data->xattrs[-*ida];
2381 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2387 schemaid = repodata_schema2id(data, schema, 1);
2388 else if (schemaid != repodata_schema2id(data, schema, 0))
2390 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
2394 fprintf(stderr, " schema %d\n", schemaid);
2399 data_addid(xd, num);
2400 data_addid(xd, schemaid);
2401 for (ida = data->attriddata + val; *ida; ida++)
2403 Id *kp = data->xattrs[-*ida];
2408 repodata_serialize_key(data, newincore, newvincore,
2409 schema, data->keys + *kp, kp[1]);
2414 case REPOKEY_TYPE_FLEXARRAY:
2417 for (ida = data->attriddata + val; *ida; ida++)
2419 data_addid(xd, num);
2420 for (ida = data->attriddata + val; *ida; ida++)
2422 Id *kp = data->xattrs[-*ida];
2425 data_addid(xd, 0); /* XXX */
2432 schemaid = repodata_schema2id(data, schema, 1);
2433 data_addid(xd, schemaid);
2434 kp = data->xattrs[-*ida];
2437 repodata_serialize_key(data, newincore, newvincore,
2438 schema, data->keys + *kp, kp[1]);
2444 fprintf(stderr, "don't know how to handle type %d\n", key->type);
2447 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2449 /* put offset/len in incore */
2450 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2451 oldvincorelen = xd->len - oldvincorelen;
2452 data_addid(newincore, oldvincorelen);
2457 repodata_internalize(Repodata *data)
2459 Repokey *key, solvkey;
2461 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2462 unsigned char *dp, *ndp;
2463 int newschema, oldcount;
2464 struct extdata newincore;
2465 struct extdata newvincore;
2468 if (!data->attrs && !data->xattrs)
2471 newvincore.buf = data->vincore;
2472 newvincore.len = data->vincorelen;
2474 /* find the solvables key, create if needed */
2475 memset(&solvkey, 0, sizeof(solvkey));
2476 solvkey.name = REPOSITORY_SOLVABLES;
2477 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2479 solvkey.storage = KEY_STORAGE_INCORE;
2480 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2482 schema = sat_malloc2(data->nkeys, sizeof(Id));
2483 seen = sat_malloc2(data->nkeys, sizeof(Id));
2485 /* Merge the data already existing (in data->schemata, ->incoredata and
2486 friends) with the new attributes in data->attrs[]. */
2487 nentry = data->end - data->start;
2488 memset(&newincore, 0, sizeof(newincore));
2489 data_addid(&newincore, 0); /* start data at offset 1 */
2491 data->mainschema = 0;
2492 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2494 /* join entry data */
2495 /* we start with the meta data, entry -1 */
2496 for (entry = -1; entry < nentry; entry++)
2498 memset(seen, 0, data->nkeys * sizeof(Id));
2500 dp = data->incoredata;
2503 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2504 dp = data_read_id(dp, &oldschema);
2507 fprintf(stderr, "oldschema %d\n", oldschema);
2508 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2509 fprintf(stderr, "schemadata %p\n", data->schemadata);
2511 /* seen: -1: old data 0: skipped >0: id + 1 */
2515 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2519 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2527 keyp = data->attrs ? data->attrs[entry] : 0;
2530 /* strip solvables key */
2532 for (sp = keyp = schema; *sp; sp++)
2533 if (*sp != solvkeyid)
2538 seen[solvkeyid] = 0;
2539 keyp = data->xattrs ? data->xattrs[1] : 0;
2542 for (; *keyp; keyp += 2)
2549 seen[*keyp] = keyp[1] + 1;
2551 if (entry < 0 && data->end != data->start)
2558 /* Ideally we'd like to sort the new schema here, to ensure
2559 schema equality independend of the ordering. We can't do that
2560 yet. For once see below (old ids need to come before new ids).
2561 An additional difficulty is that we also need to move
2562 the values with the keys. */
2563 schemaid = repodata_schema2id(data, schema, 1);
2565 schemaid = oldschema;
2568 /* Now create data blob. We walk through the (possibly new) schema
2569 and either copy over old data, or insert the new. */
2570 /* XXX Here we rely on the fact that the (new) schema has the form
2571 o1 o2 o3 o4 ... | n1 n2 n3 ...
2572 (oX being the old keyids (possibly overwritten), and nX being
2573 the new keyids). This rules out sorting the keyids in order
2574 to ensure a small schema count. */
2576 data->incoreoffset[entry] = newincore.len;
2577 data_addid(&newincore, schemaid);
2580 data->mainschema = schemaid;
2581 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2583 keypstart = data->schemadata + data->schemata[schemaid];
2584 for (keyp = keypstart; *keyp; keyp++)
2587 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2588 if (*keyp == solvkeyid)
2590 /* add flexarray entry count */
2591 data_addid(&newincore, data->end - data->start);
2594 key = data->keys + *keyp;
2596 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2601 /* Skip the data associated with this old key. */
2602 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2604 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2605 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2607 else if (key->storage == KEY_STORAGE_INCORE)
2608 ndp = data_skip_key(data, dp, key);
2611 if (seen[*keyp] == -1)
2613 /* If this key was an old one _and_ was not overwritten with
2614 a different value copy over the old value (we skipped it
2617 data_addblob(&newincore, dp, ndp - dp);
2620 else if (seen[*keyp])
2622 /* Otherwise we have a new value. Parse it into the internal
2624 repodata_serialize_key(data, &newincore, &newvincore,
2625 schema, key, seen[*keyp] - 1);
2629 if (entry >= 0 && data->attrs && data->attrs[entry])
2630 data->attrs[entry] = sat_free(data->attrs[entry]);
2632 /* free all xattrs */
2633 for (entry = 0; entry < data->nxattrs; entry++)
2634 if (data->xattrs[entry])
2635 sat_free(data->xattrs[entry]);
2636 data->xattrs = sat_free(data->xattrs);
2639 data->lasthandle = 0;
2641 data->lastdatalen = 0;
2644 repodata_free_schemahash(data);
2646 sat_free(data->incoredata);
2647 data->incoredata = newincore.buf;
2648 data->incoredatalen = newincore.len;
2649 data->incoredatafree = 0;
2651 sat_free(data->vincore);
2652 data->vincore = newvincore.buf;
2653 data->vincorelen = newvincore.len;
2655 data->attrs = sat_free(data->attrs);
2656 data->attrdata = sat_free(data->attrdata);
2657 data->attriddata = sat_free(data->attriddata);
2658 data->attrdatalen = 0;
2659 data->attriddatalen = 0;
2663 repodata_disable_paging(Repodata *data)
2665 if (maybe_load_repodata(data, 0)
2667 repodata_load_page_range(data, 0, data->num_pages - 1);
2671 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: