2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
27 #include "poolid_private.h"
33 extern unsigned int compress_buf (const unsigned char *in, unsigned int in_len,
34 unsigned char *out, unsigned int out_len);
35 extern unsigned int unchecked_decompress_buf (const unsigned char *in,
38 unsigned int out_len);
40 #define REPODATA_BLOCK 255
44 repodata_init(Repodata *data, Repo *repo, int localpool)
46 memset(data, 0, sizeof (*data));
48 data->localpool = localpool;
50 stringpool_init_empty(&data->spool);
51 data->keys = sat_calloc(1, sizeof(Repokey));
53 data->schemata = sat_calloc(1, sizeof(Id));
54 data->schemadata = sat_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_free(Repodata *data)
67 sat_free(data->schemata);
68 sat_free(data->schemadata);
69 sat_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 sat_free(data->mainschemaoffsets);
75 sat_free(data->incoredata);
76 sat_free(data->incoreoffset);
77 sat_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 sat_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 sat_free(data->attrs[i]);
86 sat_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 sat_free(data->xattrs[i]);
90 sat_free(data->xattrs);
92 sat_free(data->attrdata);
93 sat_free(data->attriddata);
97 /***************************************************************
101 /* this is not so time critical that we need a hash, so we do a simple
104 repodata_key2id(Repodata *data, Repokey *key, int create)
108 for (keyid = 1; keyid < data->nkeys; keyid++)
109 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
111 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
115 if (keyid == data->nkeys)
119 /* allocate new key */
120 data->keys = sat_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
121 data->keys[data->nkeys++] = *key;
122 if (data->verticaloffset)
124 data->verticaloffset = sat_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
125 data->verticaloffset[data->nkeys - 1] = 0;
127 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
133 /***************************************************************
134 * schema pool management
137 #define SCHEMATA_BLOCK 31
138 #define SCHEMATADATA_BLOCK 255
141 repodata_schema2id(Repodata *data, Id *schema, int create)
147 if ((schematahash = data->schematahash) == 0)
149 data->schematahash = schematahash = sat_calloc(256, sizeof(Id));
150 for (i = 0; i < data->nschemata; i++)
152 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
155 schematahash[h] = i + 1;
157 data->schemadata = sat_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
158 data->schemata = sat_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
161 for (sp = schema, len = 0, h = 0; *sp; len++)
166 cid = schematahash[h];
170 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
173 for (cid = 0; cid < data->nschemata; cid++)
174 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
180 data->schemadata = sat_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
181 data->schemata = sat_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
183 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
184 data->schemata[data->nschemata] = data->schemadatalen;
185 data->schemadatalen += len;
186 schematahash[h] = data->nschemata + 1;
188 fprintf(stderr, "schema2id: new schema\n");
190 return data->nschemata++;
194 repodata_free_schemahash(Repodata *data)
196 data->schematahash = sat_free(data->schematahash);
198 data->schemata = sat_realloc2(data->schemata, data->nschemata, sizeof(Id));
199 data->schemadata = sat_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
203 /***************************************************************
204 * dir pool management
208 repodata_str2dir(Repodata *data, const char *dir, int create)
214 while (*dir == '/' && dir[1] == '/')
216 if (*dir == '/' && !dir[1])
220 dire = strchrnul(dir, '/');
222 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
224 id = strn2id(data->repo->pool, dir, dire - dir, create);
227 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
240 repodata_dir2str(Repodata *data, Id did, const char *suf)
242 Pool *pool = data->repo->pool;
249 return suf ? suf : "";
253 comp = dirpool_compid(&data->dirpool, parent);
254 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
256 parent = dirpool_parent(&data->dirpool, parent);
261 l += strlen(suf) + 1;
262 p = pool_alloctmpspace(pool, l + 1) + l;
273 comp = dirpool_compid(&data->dirpool, parent);
274 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
277 strncpy(p, comps, l);
278 parent = dirpool_parent(&data->dirpool, parent);
286 /***************************************************************
290 static inline unsigned char *
291 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
293 Id *keyp = data->schemadata + data->schemata[schema];
294 for (; *keyp; keyp++)
295 dp = data_skip_key(data, dp, data->keys + *keyp);
300 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
302 int nentries, schema;
305 case REPOKEY_TYPE_FIXARRAY:
306 dp = data_read_id(dp, &nentries);
309 dp = data_read_id(dp, &schema);
311 dp = data_skip_schema(data, dp, schema);
313 case REPOKEY_TYPE_FLEXARRAY:
314 dp = data_read_id(dp, &nentries);
317 dp = data_read_id(dp, &schema);
318 dp = data_skip_schema(data, dp, schema);
322 if (key->storage == KEY_STORAGE_INCORE)
323 dp = data_skip(dp, key->type);
324 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
326 dp = data_skip(dp, REPOKEY_TYPE_ID);
327 dp = data_skip(dp, REPOKEY_TYPE_ID);
333 static unsigned char *
334 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
340 while ((k = *keyp++) != 0)
344 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
346 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
347 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
350 if (data->keys[k].storage != KEY_STORAGE_INCORE)
352 dp = data_skip_key(data, dp, data->keys + k);
357 static unsigned char *
358 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
363 if (off >= data->lastverticaloffset)
365 off -= data->lastverticaloffset;
366 if (off + len > data->vincorelen)
368 return data->vincore + off;
370 if (off + len > key->size)
372 /* we now have the offset, go into vertical */
373 off += data->verticaloffset[key - data->keys];
374 /* fprintf(stderr, "key %d page %d\n", key->name, off / BLOB_PAGESIZE); */
375 dp = repopagestore_load_page_range(&data->store, off / BLOB_PAGESIZE, (off + len - 1) / BLOB_PAGESIZE);
377 dp += off % BLOB_PAGESIZE;
381 static inline unsigned char *
382 get_data(Repodata *data, Repokey *key, unsigned char **dpp)
384 unsigned char *dp = *dpp;
388 if (key->storage == KEY_STORAGE_INCORE)
390 /* hmm, this is a bit expensive */
391 *dpp = data_skip_key(data, dp, key);
394 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
397 dp = data_read_id(dp, &off);
398 dp = data_read_id(dp, &len);
400 return get_vertical_data(data, key, off, len);
406 load_repodata(Repodata *data)
408 if (data->loadcallback)
410 data->loadcallback(data);
411 if (data->state == REPODATA_AVAILABLE)
414 data->state = REPODATA_ERROR;
419 maybe_load_repodata(Repodata *data, Id keyname)
421 if (keyname && !repodata_precheck_keyname(data, keyname))
422 return 0; /* do not bother... */
429 for (i = 0; i < data->nkeys; i++)
430 if (keyname == data->keys[i].name)
432 if (i == data->nkeys)
435 return load_repodata(data);
438 case REPODATA_AVAILABLE:
441 data->state = REPODATA_ERROR;
446 static inline unsigned char*
447 entry2data(Repodata *data, Id entry, Id *schemap)
449 unsigned char *dp = data->incoredata;
452 if (entry == SOLVID_META) /* META */
454 else if (entry == SOLVID_POS) /* META */
456 Pool *pool = data->repo->pool;
457 if (data->repo != pool->pos.repo)
459 if (data != data->repo->repodata + pool->pos.repodataid)
461 *schemap = pool->pos.schema;
462 return data->incoredata + pool->pos.dp;
466 if (entry < data->start || entry >= data->end)
468 dp += data->incoreoffset[entry - data->start];
470 return data_read_id(dp, schemap);
473 /************************************************************************
478 find_schema_key(Repodata *data, Id schema, Id keyname)
481 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
482 if (data->keys[*keyp].name == keyname)
487 static inline unsigned char *
488 find_key_data(Repodata *data, Id entry, Id keyname, Repokey **keyp)
490 unsigned char *dp, *ddp;
494 if (!maybe_load_repodata(data, keyname))
496 dp = entry2data(data, entry, &schema);
499 keyid = find_schema_key(data, schema, keyname);
502 key = data->keys + keyid;
504 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
506 dp = forward_to_key(data, keyid, data->schemadata + data->schemata[schema], dp);
509 ddp = get_data(data, key, &dp);
515 repodata_lookup_id(Repodata *data, Id entry, Id keyname)
521 dp = find_key_data(data, entry, keyname, &key);
524 if (key->type == REPOKEY_TYPE_CONSTANTID)
526 if (key->type != REPOKEY_TYPE_ID)
528 dp = data_read_id(dp, &id);
533 repodata_lookup_str(Repodata *data, Id entry, Id keyname)
539 dp = find_key_data(data, entry, keyname, &key);
542 if (key->type == REPOKEY_TYPE_STR)
543 return (const char *)dp;
544 if (key->type == REPOKEY_TYPE_CONSTANTID)
545 return id2str(data->repo->pool, key->size);
546 if (key->type == REPOKEY_TYPE_ID)
547 dp = data_read_id(dp, &id);
551 return data->spool.stringspace + data->spool.strings[id];
552 return id2str(data->repo->pool, id);
556 repodata_lookup_num(Repodata *data, Id entry, Id keyname, unsigned int *value)
563 dp = find_key_data(data, entry, keyname, &key);
566 if (key->type == REPOKEY_TYPE_NUM
567 || key->type == REPOKEY_TYPE_U32
568 || key->type == REPOKEY_TYPE_CONSTANT)
570 dp = data_fetch(dp, &kv, key);
578 repodata_lookup_void(Repodata *data, Id entry, Id keyname)
584 if (!maybe_load_repodata(data, keyname))
586 dp = entry2data(data, entry, &schema);
589 /* can't use find_schema_key as we need to test the type */
590 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
591 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
596 const unsigned char *
597 repodata_lookup_bin_checksum(Repodata *data, Id entry, Id keyname, Id *typep)
602 dp = find_key_data(data, entry, keyname, &key);
610 /************************************************************************
614 struct subschema_data {
620 /* search in a specific entry */
622 repodata_search(Repodata *data, Id entry, Id keyname, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
626 Id k, keyid, *kp, *keyp;
627 unsigned char *dp, *ddp;
633 if (!maybe_load_repodata(data, keyname))
635 if (entry == SOLVID_SUBSCHEMA)
637 struct subschema_data *subd = cbdata;
638 cbdata = subd->cbdata;
640 schema = subd->parent->id;
641 dp = (unsigned char *)subd->parent->str;
642 kv.parent = subd->parent;
647 dp = entry2data(data, entry, &schema);
650 s = data->repo->pool->solvables + entry;
653 keyp = data->schemadata + data->schemata[schema];
656 /* search for a specific key */
657 for (kp = keyp; (k = *kp++) != 0; )
658 if (data->keys[k].name == keyname)
662 dp = forward_to_key(data, k, data->schemadata + data->schemata[schema], dp);
668 while ((keyid = *keyp++) != 0)
671 key = data->keys + keyid;
672 ddp = get_data(data, key, &dp);
674 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
676 struct subschema_data subd;
680 subd.cbdata = cbdata;
683 ddp = data_read_id(ddp, &nentries);
687 while (ddp && nentries > 0)
689 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
690 ddp = data_read_id(ddp, &schema);
692 kv.str = (char *)ddp;
693 stop = callback(cbdata, s, data, key, &kv);
694 if (stop > SEARCH_NEXT_KEY)
699 repodata_search(data, SOLVID_SUBSCHEMA, 0, callback, &subd);
700 ddp = data_skip_schema(data, ddp, schema);
708 kv.str = (char *)ddp;
709 stop = callback(cbdata, s, data, key, &kv);
710 if (stop > SEARCH_NEXT_KEY)
720 ddp = data_fetch(ddp, &kv, key);
723 stop = callback(cbdata, s, data, key, &kv);
726 while (!kv.eof && !stop);
727 if (onekey || stop > SEARCH_NEXT_KEY)
733 repodata_setpos_kv(Repodata *data, KeyValue *kv)
735 Pool *pool = data->repo->pool;
739 pool->pos.repodataid = 0;
741 pool->pos.schema = 0;
746 pool->pos.repodataid = data - data->repo->repodata;
747 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
748 pool->pos.schema = kv->id;
752 /************************************************************************/
754 static Repokey solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1] = {
755 { SOLVABLE_NAME, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
756 { SOLVABLE_ARCH, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
757 { SOLVABLE_EVR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
758 { SOLVABLE_VENDOR, REPOKEY_TYPE_ID, 0, KEY_STORAGE_SOLVABLE },
759 { SOLVABLE_PROVIDES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
760 { SOLVABLE_OBSOLETES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
761 { SOLVABLE_CONFLICTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
762 { SOLVABLE_REQUIRES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
763 { SOLVABLE_RECOMMENDS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
764 { SOLVABLE_SUGGESTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
765 { SOLVABLE_SUPPLEMENTS, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
766 { SOLVABLE_ENHANCES, REPOKEY_TYPE_IDARRAY, 0, KEY_STORAGE_SOLVABLE },
767 { RPM_RPMDBID, REPOKEY_TYPE_U32, 0, KEY_STORAGE_SOLVABLE },
772 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
786 case SOLVABLE_VENDOR:
789 case SOLVABLE_PROVIDES:
791 return s->provides ? s->repo->idarraydata + s->provides : 0;
792 case SOLVABLE_OBSOLETES:
794 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
795 case SOLVABLE_CONFLICTS:
797 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
798 case SOLVABLE_REQUIRES:
800 return s->requires ? s->repo->idarraydata + s->requires : 0;
801 case SOLVABLE_RECOMMENDS:
803 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
804 case SOLVABLE_SUPPLEMENTS:
806 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
807 case SOLVABLE_SUGGESTS:
809 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
810 case SOLVABLE_ENHANCES:
812 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
815 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
822 datamatcher_init(Datamatcher *ma, Pool *pool, const char *match, int flags)
825 ma->match = (void *)match;
828 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
830 ma->match = sat_calloc(1, sizeof(regex_t));
831 ma->error = regcomp((regex_t *)ma->match, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
835 ma->match = (void *)match;
836 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
842 datamatcher_free(Datamatcher *ma)
844 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->match)
847 ma->match = sat_free(ma->match);
852 datamatcher_match(Datamatcher *ma, Repodata *data, Repokey *key, KeyValue *kv)
856 case REPOKEY_TYPE_ID:
857 case REPOKEY_TYPE_IDARRAY:
858 if (data && data->localpool)
859 kv->str = stringpool_id2str(&data->spool, kv->id);
861 kv->str = id2str(ma->pool, kv->id);
863 case REPOKEY_TYPE_STR:
865 case REPOKEY_TYPE_DIRSTRARRAY:
866 if (!(ma->flags & SEARCH_FILES))
868 /* Put the full filename into kv->str. */
869 kv->str = repodata_dir2str(data, kv->id, kv->str);
870 /* And to compensate for that put the "empty" directory into
871 kv->id, so that later calls to repodata_dir2str on this data
872 come up with the same filename again. */
878 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
879 for the others we can't know if a colon separates a kind or not. */
880 if ((ma->flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
882 const char *s = strchr(kv->str, ':');
886 switch ((ma->flags & SEARCH_STRINGMASK))
888 case SEARCH_SUBSTRING:
889 if (ma->flags & SEARCH_NOCASE)
891 if (!strcasestr(kv->str, (const char *)ma->match))
896 if (!strstr(kv->str, (const char *)ma->match))
901 if (ma->flags & SEARCH_NOCASE)
903 if (strcasecmp((const char *)ma->match, kv->str))
908 if (strcmp((const char *)ma->match, kv->str))
913 if (fnmatch((const char *)ma->match, kv->str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
917 if (regexec((const regex_t *)ma->match, kv->str, 0, NULL, 0))
950 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname, const char *match, int flags)
952 memset(di, 0, sizeof(*di));
954 di->keyname = keyname;
956 di->pool = repo->pool;
958 flags |= SEARCH_THISSOLVID;
963 datamatcher_init(&di->matcher, di->pool, match, flags);
966 di->repo = di->pool->pos.repo;
967 di->data = di->repo->repodata + di->pool->pos.repodataid;
971 di->state = di_enterrepo;
975 dataiterator_free(Dataiterator *di)
977 if (di->matcher.match)
978 datamatcher_free(&di->matcher);
982 dataiterator_step(Dataiterator *di)
990 case di_nextattr: di_nextattr:
992 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
994 di->state = di_nextkey;
996 di->state = di_nextattr;
999 case di_nextkey: di_nextkey:
1005 else if ((di->flags & SEARCH_SUB) != 0)
1007 Id *keyp = di->keyp;
1008 for (keyp++; *keyp; keyp++)
1009 if (di->data->keys[*keyp].name == di->keyname ||
1010 di->data->keys[*keyp].type == REPOKEY_TYPE_FIXARRAY ||
1011 di->data->keys[*keyp].type == REPOKEY_TYPE_FLEXARRAY)
1013 if (*keyp && (di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp)) != 0)
1024 case di_nextrepodata: di_nextrepodata:
1025 if (di->repodataid >= 0 && ++di->repodataid < di->repo->nrepodata)
1026 goto di_enterrepodata;
1029 case di_nextsolvable:
1030 if (!(di->flags & SEARCH_THISSOLVID))
1033 di->solvid = di->repo->start;
1036 for (; di->solvid < di->repo->end; di->solvid++)
1038 if (di->pool->solvables[di->solvid].repo == di->repo)
1039 goto di_entersolvable;
1045 if (di->repoid >= 0)
1048 if (di->repoid < di->pool->nrepos)
1050 di->repo = di->pool->repos[di->repoid];
1060 case di_enterrepo: di_enterrepo:
1061 if (!(di->flags & SEARCH_THISSOLVID))
1062 di->solvid = di->repo->start;
1065 case di_entersolvable: di_entersolvable:
1066 if (di->repodataid >= 0)
1069 if (di->solvid > 0 && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)))
1071 di->key = solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1073 goto di_entersolvablekey;
1077 case di_enterrepodata: di_enterrepodata:
1078 if (di->repodataid >= 0)
1079 di->data = di->repo->repodata + di->repodataid;
1080 if (!maybe_load_repodata(di->data, di->keyname))
1081 goto di_nextrepodata;
1082 di->dp = entry2data(di->data, di->solvid, &schema);
1084 goto di_nextrepodata;
1085 di->keyp = di->data->schemadata + di->data->schemata[schema];
1089 if ((di->flags & SEARCH_SUB) != 0)
1094 for (keyp = di->keyp; *keyp; keyp++)
1095 if (di->data->keys[*keyp].name == di->keyname)
1098 goto di_nextrepodata;
1099 di->dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1102 goto di_nextrepodata;
1105 case di_enterkey: di_enterkey:
1107 di->key = di->data->keys + *di->keyp;
1108 di->ddp = get_data(di->data, di->key, &di->dp);
1111 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1113 di->ddp = data_read_id(di->ddp, &di->kv.num);
1116 goto di_nextarrayelement;
1120 case di_nextarrayelement: di_nextarrayelement:
1123 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1124 if (di->kv.entry == di->kv.num)
1126 if (di->keyname && di->key->name != di->keyname)
1128 di->kv.str = (char *)di->ddp;
1130 di->state = di_nextkey;
1133 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1134 di->ddp = data_read_id(di->ddp, &di->kv.id);
1135 di->kv.str = (char *)di->ddp;
1136 if (di->keyname && di->key->name != di->keyname)
1138 if ((di->flags & SEARCH_SUB) != 0)
1139 di->state = di_entersub;
1141 di->state = di_nextarrayelement;
1144 case di_entersub: di_entersub:
1145 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1146 goto di_nextarrayelement; /* sorry, full */
1147 di->parents[di->nparents].kv = di->kv;
1148 di->parents[di->nparents].dp = di->dp;
1149 di->parents[di->nparents].keyp = di->keyp;
1150 di->dp = (unsigned char *)di->kv.str;
1151 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1152 memset(&di->kv, 0, sizeof(di->kv));
1153 di->kv.parent = &di->parents[di->nparents].kv;
1158 case di_leavesub: di_leavesub:
1160 di->dp = di->parents[di->nparents].dp;
1161 di->kv = di->parents[di->nparents].kv;
1162 di->keyp = di->parents[di->nparents].keyp;
1163 di->key = di->data->keys + *di->keyp;
1164 di->ddp = (unsigned char *)di->kv.str;
1165 goto di_nextarrayelement;
1167 /* special solvable attr handling follows */
1169 case di_nextsolvableattr:
1170 di->kv.id = *di->idp++;
1175 di->state = di_nextsolvablekey;
1179 case di_nextsolvablekey: di_nextsolvablekey:
1180 if (di->keyname || di->key->name == RPM_RPMDBID)
1181 goto di_enterrepodata;
1185 case di_entersolvablekey: di_entersolvablekey:
1186 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1187 if (!di->idp || !di->idp[0])
1188 goto di_nextsolvablekey;
1189 di->kv.id = di->idp[0];
1190 di->kv.num = di->idp[0];
1191 if (!di->kv.eof && !di->idp[1])
1195 di->state = di_nextsolvablekey;
1197 di->state = di_nextsolvableattr;
1201 if (di->matcher.match)
1202 if (!datamatcher_match(&di->matcher, di->data, di->key, &di->kv))
1204 /* found something! */
1210 dataiterator_setpos(Dataiterator *di)
1212 di->pool->pos.repo = di->repo;
1213 di->pool->pos.repodataid = di->data - di->repo->repodata;
1214 di->pool->pos.schema = di->kv.id;
1215 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1219 dataiterator_skip_attribute(Dataiterator *di)
1221 if (di->state == di_nextsolvableattr)
1222 di->state = di_nextsolvablekey;
1224 di->state = di_nextkey;
1228 dataiterator_skip_solvable(Dataiterator *di)
1230 di->state = di_nextsolvable;
1234 dataiterator_skip_repo(Dataiterator *di)
1236 di->state = di_nextrepo;
1240 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1244 di->solvid = s - di->pool->solvables;
1245 di->state = di_entersolvable;
1249 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1253 di->state = di_enterrepo;
1257 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1259 Datamatcher matcher = di->matcher;
1260 matcher.flags = flags;
1261 matcher.match = (void *)vmatch;
1262 return datamatcher_match(&matcher, di->data, di->key, &di->kv);
1267 /************************************************************************
1268 * data search iterator
1272 dataiterator_newdata(Dataiterator *di)
1274 Id keyname = di->keyname;
1275 Repodata *data = di->data;
1278 if (data->state == REPODATA_STUB)
1283 for (j = 1; j < data->nkeys; j++)
1284 if (keyname == data->keys[j].name)
1286 if (j == data->nkeys)
1290 if (data->loadcallback)
1291 data->loadcallback(data);
1293 data->state = REPODATA_ERROR;
1295 if (data->state == REPODATA_ERROR)
1299 unsigned char *dp = data->incoredata;
1302 if (di->solvid >= 0)
1303 dp += data->incoreoffset[di->solvid - data->start];
1304 dp = data_read_id(dp, &schema);
1305 Id *keyp = data->schemadata + data->schemata[schema];
1309 /* search in a specific key */
1310 for (kp = keyp; (k = *kp++) != 0; )
1311 if (data->keys[k].name == keyname)
1315 dp = forward_to_key(data, k, keyp, dp);
1325 di->key = di->data->keys + keyid;
1330 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1335 dataiterator_init(Dataiterator *di, Repo *repo, Id p, Id keyname,
1336 const char *match, int flags)
1342 di->flags |= __SEARCH_ONESOLVABLE;
1343 di->data = repo->repodata - 1;
1344 if (flags & SEARCH_NO_STORAGE_SOLVABLE)
1351 di->solvid = repo->start - 1;
1354 fprintf(stderr, "A repo contains the NULL solvable!\n");
1357 di->data = repo->repodata + repo->nrepodata - 1;
1362 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1366 /* We feed multiple lines eventually (e.g. authors or descriptions),
1367 so set REG_NEWLINE. */
1369 regcomp(&di->regex, di->match,
1370 REG_EXTENDED | REG_NOSUB | REG_NEWLINE
1371 | ((di->flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1373 if (di->regex_err != 0)
1375 fprintf(stderr, "Given regex failed to compile: %s\n", di->match);
1376 fprintf(stderr, "regcomp error code: %d\n", di->regex_err);
1383 di->flags |= (di->flags & SEARCH_STRINGMASK) | SEARCH_STRING;
1389 di->keyname = keyname;
1390 static Id zeroid = 0;
1398 /* FIXME factor and merge with repo_matchvalue */
1400 dataiterator_match_int_real(Dataiterator *di, int flags, const void *vmatch)
1402 KeyValue *kv = &di->kv;
1403 const char *match = vmatch;
1404 if ((flags & SEARCH_STRINGMASK) != 0)
1406 switch (di->key->type)
1408 case REPOKEY_TYPE_ID:
1409 case REPOKEY_TYPE_IDARRAY:
1410 if (di->data && di->data->localpool)
1411 kv->str = stringpool_id2str(&di->data->spool, kv->id);
1413 kv->str = id2str(di->repo->pool, kv->id);
1415 case REPOKEY_TYPE_STR:
1417 case REPOKEY_TYPE_DIRSTRARRAY:
1418 if (!(flags & SEARCH_FILES))
1420 /* Put the full filename into kv->str. */
1421 kv->str = repodata_dir2str(di->data, kv->id, kv->str);
1422 /* And to compensate for that put the "empty" directory into
1423 kv->id, so that later calls to repodata_dir2str on this data
1424 come up with the same filename again. */
1430 /* Maybe skip the kind specifier. Do this only for SOLVABLE attributes,
1431 for the others we can't know if a colon separates a kind or not. */
1432 if ((flags & SEARCH_SKIP_KIND)
1433 && di->key->storage == KEY_STORAGE_SOLVABLE)
1435 const char *s = strchr(kv->str, ':');
1439 switch ((flags & SEARCH_STRINGMASK))
1441 case SEARCH_SUBSTRING:
1442 if (flags & SEARCH_NOCASE)
1444 if (!strcasestr(kv->str, match))
1449 if (!strstr(kv->str, match))
1454 if (flags & SEARCH_NOCASE)
1456 if (strcasecmp(match, kv->str))
1461 if (strcmp(match, kv->str))
1466 if (fnmatch(match, kv->str, (flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1470 if (regexec((const regex_t *)vmatch, kv->str, 0, NULL, 0))
1481 dataiterator_match_int(Dataiterator *di)
1483 if ((di->flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1484 return dataiterator_match_int_real(di, di->flags, &di->regex);
1486 return dataiterator_match_int_real(di, di->flags, di->match);
1490 dataiterator_match(Dataiterator *di, int flags, const void *vmatch)
1492 return dataiterator_match_int_real(di, flags, vmatch);
1496 dataiterator_step(Dataiterator *di)
1503 /* we're stepping through solvable data, 1 -> SOLVABLE_NAME... */
1506 /* we're stepping through an id array */
1512 di->kv.eof = idp[1] ? 0 : 1;
1518 Solvable *s = di->repo->pool->solvables + di->solvid;
1519 int state = di->state;
1520 di->key = solvablekeys + state - 1;
1522 di->state = RPM_RPMDBID;
1529 state = di->keyname - 1;
1536 di->kv.id = s->name;
1542 di->kv.id = s->arch;
1551 case SOLVABLE_VENDOR:
1554 di->kv.id = s->vendor;
1557 case SOLVABLE_PROVIDES:
1558 di->idp = s->provides
1559 ? di->repo->idarraydata + s->provides : 0;
1561 case SOLVABLE_OBSOLETES:
1562 di->idp = s->obsoletes
1563 ? di->repo->idarraydata + s->obsoletes : 0;
1565 case SOLVABLE_CONFLICTS:
1566 di->idp = s->conflicts
1567 ? di->repo->idarraydata + s->conflicts : 0;
1569 case SOLVABLE_REQUIRES:
1570 di->idp = s->requires
1571 ? di->repo->idarraydata + s->requires : 0;
1573 case SOLVABLE_RECOMMENDS:
1574 di->idp = s->recommends
1575 ? di->repo->idarraydata + s->recommends : 0;
1577 case SOLVABLE_SUPPLEMENTS:
1578 di->idp = s->supplements
1579 ? di->repo->idarraydata + s->supplements : 0;
1581 case SOLVABLE_SUGGESTS:
1582 di->idp = s->suggests
1583 ? di->repo->idarraydata + s->suggests : 0;
1585 case SOLVABLE_ENHANCES:
1586 di->idp = s->enhances
1587 ? di->repo->idarraydata + s->enhances : 0;
1590 if (!di->repo->rpmdbid)
1592 di->kv.num = di->repo->rpmdbid[di->solvid - di->repo->start];
1596 di->data = di->repo->repodata - 1;
1602 else if (di->subkeyp)
1607 /* Send end-of-substruct. We are here only when we saw a
1608 _COUNTED key one level up. Since then we didn't increment
1609 ->keyp, so it still can be found at keyp[-1]. */
1611 di->key = di->data->keys + di->keyp[-1];
1614 else if (!(keyid = *di->subkeyp++))
1616 /* Send end-of-element. See above for keyp[-1]. */
1618 di->key = di->data->keys + di->keyp[-1];
1620 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1623 di->dp = data_read_id(di->dp, &di->subschema);
1624 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1631 di->key = di->data->keys + keyid;
1632 di->dp = data_fetch(di->dp, &di->kv, di->key);
1642 di->dp = data_fetch(di->dp, &di->kv, di->key);
1647 if (di->keyname || !(keyid = *di->keyp++))
1651 Repo *repo = di->repo;
1652 Repodata *data = ++di->data;
1653 if (data >= repo->repodata + repo->nrepodata)
1655 if (di->flags & __SEARCH_ONESOLVABLE)
1657 if (di->solvid >= 0)
1659 while (++di->solvid < repo->end)
1660 if (repo->pool->solvables[di->solvid].repo == repo)
1662 if (di->solvid >= repo->end)
1664 if (!(di->flags & SEARCH_EXTRA))
1673 Pool *pool = di->repo->pool;
1674 if (!(di->flags & SEARCH_ALL_REPOS)
1675 || di->repo == pool->repos[pool->nrepos - 1])
1678 for (i = 0; i < pool->nrepos; i++)
1679 if (di->repo == pool->repos[i])
1681 di->repo = pool->repos[i + 1];
1682 dataiterator_init(di, di->repo, 0, di->keyname, di->match, di->flags);
1686 di->data = repo->repodata - 1;
1687 if ((di->flags & SEARCH_NO_STORAGE_SOLVABLE))
1689 static Id zeroid = 0;
1694 if ((di->solvid >= 0 && di->solvid >= data->start && di->solvid < data->end))
1696 dataiterator_newdata(di);
1704 di->key = di->data->keys + keyid;
1705 di->dp = get_data(di->data, di->key, &di->nextkeydp);
1707 di->dp = data_fetch(di->dp, &di->kv, di->key);
1709 if (di->key->type == REPOKEY_TYPE_FIXARRAY)
1711 di->subnum = di->kv.num;
1712 di->subschema = di->kv.id;
1714 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1716 if (di->key->type == REPOKEY_TYPE_FLEXARRAY)
1718 di->subnum = di->kv.num;
1720 di->dp = data_read_id(di->dp, &di->subschema);
1721 di->subkeyp = di->data->schemadata + di->data->schemata[di->subschema];
1727 || dataiterator_match_int(di))
1734 dataiterator_skip_attribute(Dataiterator *di)
1738 /* This will make the next _step call to retrieve the next field. */
1743 dataiterator_skip_solvable(Dataiterator *di)
1745 /* We're done with this field. */
1747 /* And with solvable data. */
1749 /* And with all keys for this repodata and thing. */
1750 static Id zeroid = 0;
1752 /* And with all repodatas for this thing. */
1753 di->data = di->repo->repodata + di->repo->nrepodata - 1;
1754 /* Hence the next call to _step will retrieve the next thing. */
1758 dataiterator_skip_repo(Dataiterator *di)
1760 dataiterator_skip_solvable(di);
1761 /* We're done with all solvables and all extra things for this repo. */
1766 dataiterator_jump_to_solvable(Dataiterator *di, Solvable *s)
1769 /* Simulate us being done with the solvable before the requested one. */
1770 dataiterator_skip_solvable(di);
1771 di->solvid = s - s->repo->pool->solvables;
1776 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1779 dataiterator_skip_solvable(di);
1780 di->solvid = repo->start - 1;
1785 /************************************************************************
1786 * data modify functions
1789 /* extend repodata so that it includes solvables p */
1791 repodata_extend(Repodata *data, Id p)
1793 if (data->start == data->end)
1794 data->start = data->end = p;
1797 int old = data->end - data->start;
1798 int new = p - data->end + 1;
1801 data->attrs = sat_extend(data->attrs, old, new, sizeof(Id), REPODATA_BLOCK);
1802 memset(data->attrs + old, 0, new * sizeof(Id));
1804 data->incoreoffset = sat_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1805 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1808 if (p < data->start)
1810 int old = data->end - data->start;
1811 int new = data->start - p;
1814 data->attrs = sat_extend_resize(data->attrs, old + new, sizeof(Id), REPODATA_BLOCK);
1815 memmove(data->attrs + new, data->attrs, old * sizeof(Id));
1816 memset(data->attrs, 0, new * sizeof(Id));
1818 data->incoreoffset = sat_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1819 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1820 memset(data->incoreoffset, 0, new * sizeof(Id));
1826 repodata_extend_block(Repodata *data, Id start, Id num)
1830 if (!data->incoreoffset)
1832 data->incoreoffset = sat_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1833 data->start = start;
1834 data->end = start + num;
1837 repodata_extend(data, start);
1839 repodata_extend(data, start + num - 1);
1842 /**********************************************************************/
1844 #define REPODATA_ATTRS_BLOCK 63
1845 #define REPODATA_ATTRDATA_BLOCK 1023
1846 #define REPODATA_ATTRIDDATA_BLOCK 63
1850 repodata_new_handle(Repodata *data)
1854 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1857 data->xattrs = sat_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1858 data->xattrs[data->nxattrs] = 0;
1859 return -(data->nxattrs++);
1863 repodata_get_attrp(Repodata *data, Id handle)
1865 if (handle == SOLVID_META)
1869 data->xattrs = sat_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1874 return data->xattrs - handle;
1875 if (handle < data->start || handle >= data->end)
1876 repodata_extend(data, handle);
1878 data->attrs = sat_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1879 return data->attrs + (handle - data->start);
1883 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1889 app = repodata_get_attrp(data, handle);
1894 for (pp = ap; *pp; pp += 2)
1895 /* Determine equality based on the name only, allows us to change
1896 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1897 if (data->keys[*pp].name == data->keys[keyid].name)
1910 ap = sat_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1920 repodata_set(Repodata *data, Id handle, Repokey *key, Id val)
1924 keyid = repodata_key2id(data, key, 1);
1925 repodata_insert_keyid(data, handle, keyid, val, 1);
1929 repodata_set_id(Repodata *data, Id handle, Id keyname, Id id)
1933 key.type = REPOKEY_TYPE_ID;
1935 key.storage = KEY_STORAGE_INCORE;
1936 repodata_set(data, handle, &key, id);
1940 repodata_set_num(Repodata *data, Id handle, Id keyname, unsigned int num)
1944 key.type = REPOKEY_TYPE_NUM;
1946 key.storage = KEY_STORAGE_INCORE;
1947 repodata_set(data, handle, &key, (Id)num);
1951 repodata_set_poolstr(Repodata *data, Id handle, Id keyname, const char *str)
1955 if (data->localpool)
1956 id = stringpool_str2id(&data->spool, str, 1);
1958 id = str2id(data->repo->pool, str, 1);
1960 key.type = REPOKEY_TYPE_ID;
1962 key.storage = KEY_STORAGE_INCORE;
1963 repodata_set(data, handle, &key, id);
1967 repodata_set_constant(Repodata *data, Id handle, Id keyname, unsigned int constant)
1971 key.type = REPOKEY_TYPE_CONSTANT;
1972 key.size = constant;
1973 key.storage = KEY_STORAGE_INCORE;
1974 repodata_set(data, handle, &key, 0);
1978 repodata_set_constantid(Repodata *data, Id handle, Id keyname, Id id)
1982 key.type = REPOKEY_TYPE_CONSTANTID;
1984 key.storage = KEY_STORAGE_INCORE;
1985 repodata_set(data, handle, &key, 0);
1989 repodata_set_void(Repodata *data, Id handle, Id keyname)
1993 key.type = REPOKEY_TYPE_VOID;
1995 key.storage = KEY_STORAGE_INCORE;
1996 repodata_set(data, handle, &key, 0);
2000 repodata_set_str(Repodata *data, Id handle, Id keyname, const char *str)
2005 l = strlen(str) + 1;
2007 key.type = REPOKEY_TYPE_STR;
2009 key.storage = KEY_STORAGE_INCORE;
2010 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2011 memcpy(data->attrdata + data->attrdatalen, str, l);
2012 repodata_set(data, handle, &key, data->attrdatalen);
2013 data->attrdatalen += l;
2017 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2020 Id *ida, *pp, **ppp;
2022 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2024 /* great! just append the new data */
2025 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2026 data->attriddatalen--; /* overwrite terminating 0 */
2027 data->lastdatalen += entrysize;
2030 ppp = repodata_get_attrp(data, handle);
2033 for (; *pp; pp += 2)
2034 if (data->keys[*pp].name == keyname && data->keys[*pp].type == keytype)
2038 /* not found. allocate new key */
2043 key.storage = KEY_STORAGE_INCORE;
2044 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2045 repodata_set(data, handle, &key, data->attriddatalen);
2046 data->lasthandle = 0; /* next time... */
2050 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2051 oldsize += entrysize;
2052 if (ida + 1 == data->attriddata + data->attriddatalen)
2054 /* this was the last entry, just append it */
2055 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2056 data->attriddatalen--; /* overwrite terminating 0 */
2060 /* too bad. move to back. */
2061 data->attriddata = sat_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2062 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2063 pp[1] = data->attriddatalen;
2064 data->attriddatalen += oldsize;
2066 data->lasthandle = handle;
2067 data->lastkey = *pp;
2068 data->lastdatalen = data->attriddatalen + entrysize + 1;
2072 checksumtype2len(Id type)
2076 case REPOKEY_TYPE_MD5:
2078 case REPOKEY_TYPE_SHA1:
2080 case REPOKEY_TYPE_SHA256:
2081 return SIZEOF_SHA256;
2088 repodata_set_bin_checksum(Repodata *data, Id handle, Id keyname, Id type,
2089 const unsigned char *str)
2092 int l = checksumtype2len(type);
2099 key.storage = KEY_STORAGE_INCORE;
2100 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2101 memcpy(data->attrdata + data->attrdatalen, str, l);
2102 repodata_set(data, handle, &key, data->attrdatalen);
2103 data->attrdatalen += l;
2107 hexstr2bytes(unsigned char *buf, const char *str, int buflen)
2110 for (i = 0; i < buflen; i++)
2112 #define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0') \
2113 : ((c)>='a' && (c)<='f') ? ((c)-'a'+10) \
2114 : ((c)>='A' && (c)<='F') ? ((c)-'A'+10) \
2125 buf[i] = (buf[i] << 4) | v;
2132 repodata_set_checksum(Repodata *data, Id handle, Id keyname, Id type,
2135 unsigned char buf[64];
2136 int l = checksumtype2len(type);
2140 if (hexstr2bytes(buf, str, l) != l)
2142 fprintf(stderr, "Invalid hex character in '%s'\n", str);
2145 repodata_set_bin_checksum(data, handle, keyname, type, buf);
2149 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2154 l = checksumtype2len(type);
2157 s = str = pool_alloctmpspace(data->repo->pool, 2 * l + 1);
2158 for (i = 0; i < l; i++)
2160 unsigned char v = buf[i];
2161 unsigned char w = v >> 4;
2162 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2164 *s++ = w >= 10 ? w + ('a' - 10) : w + '0';
2171 repodata_globalize_id(Repodata *data, Id id)
2173 if (!data || !data->localpool)
2175 return str2id(data->repo->pool, stringpool_id2str(&data->spool, id), 1);
2179 repodata_add_dirnumnum(Repodata *data, Id handle, Id keyname, Id dir, Id num, Id num2)
2183 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", handle, dir, num, num2, data->attriddatalen);
2185 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2186 data->attriddata[data->attriddatalen++] = dir;
2187 data->attriddata[data->attriddatalen++] = num;
2188 data->attriddata[data->attriddatalen++] = num2;
2189 data->attriddata[data->attriddatalen++] = 0;
2193 repodata_add_dirstr(Repodata *data, Id handle, Id keyname, Id dir, const char *str)
2199 l = strlen(str) + 1;
2200 data->attrdata = sat_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2201 memcpy(data->attrdata + data->attrdatalen, str, l);
2202 stroff = data->attrdatalen;
2203 data->attrdatalen += l;
2206 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", handle, dir, str, data->attriddatalen);
2208 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2209 data->attriddata[data->attriddatalen++] = dir;
2210 data->attriddata[data->attriddatalen++] = stroff;
2211 data->attriddata[data->attriddatalen++] = 0;
2215 repodata_add_idarray(Repodata *data, Id handle, Id keyname, Id id)
2218 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", handle, id, data->attriddatalen);
2220 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_IDARRAY, 1);
2221 data->attriddata[data->attriddatalen++] = id;
2222 data->attriddata[data->attriddatalen++] = 0;
2226 repodata_add_poolstr_array(Repodata *data, Id handle, Id keyname,
2230 if (data->localpool)
2231 id = stringpool_str2id(&data->spool, str, 1);
2233 id = str2id(data->repo->pool, str, 1);
2234 repodata_add_idarray(data, handle, keyname, id);
2238 repodata_add_fixarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2240 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2241 data->attriddata[data->attriddatalen++] = ghandle;
2242 data->attriddata[data->attriddatalen++] = 0;
2246 repodata_add_flexarray(Repodata *data, Id handle, Id keyname, Id ghandle)
2248 repodata_add_array(data, handle, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2249 data->attriddata[data->attriddatalen++] = ghandle;
2250 data->attriddata[data->attriddatalen++] = 0;
2254 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2257 if (dest == src || !(keyp = data->attrs[src]))
2259 for (; *keyp; keyp += 2)
2260 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2266 /**********************************************************************/
2268 /* unify with repo_write! */
2270 #define EXTDATA_BLOCK 1023
2278 data_addid(struct extdata *xd, Id x)
2281 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2282 dp = xd->buf + xd->len;
2287 *dp++ = (x >> 28) | 128;
2289 *dp++ = (x >> 21) | 128;
2290 *dp++ = (x >> 14) | 128;
2293 *dp++ = (x >> 7) | 128;
2295 xd->len = dp - xd->buf;
2299 data_addideof(struct extdata *xd, Id x, int eof)
2302 x = (x & 63) | ((x & ~63) << 1);
2303 data_addid(xd, (eof ? x: x | 64));
2307 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2309 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2310 memcpy(xd->buf + xd->len, blob, len);
2314 /*********************************/
2317 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2318 struct extdata *newvincore,
2320 Repokey *key, Id val)
2322 /* Otherwise we have a new value. Parse it into the internal
2326 unsigned int oldvincorelen = 0;
2330 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2333 oldvincorelen = xd->len;
2337 case REPOKEY_TYPE_VOID:
2338 case REPOKEY_TYPE_CONSTANT:
2339 case REPOKEY_TYPE_CONSTANTID:
2341 case REPOKEY_TYPE_STR:
2342 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2344 case REPOKEY_TYPE_MD5:
2345 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2347 case REPOKEY_TYPE_SHA1:
2348 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2350 case REPOKEY_TYPE_SHA256:
2351 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2353 case REPOKEY_TYPE_ID:
2354 case REPOKEY_TYPE_NUM:
2355 case REPOKEY_TYPE_DIR:
2356 data_addid(xd, val);
2358 case REPOKEY_TYPE_IDARRAY:
2359 for (ida = data->attriddata + val; *ida; ida++)
2360 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2362 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2363 for (ida = data->attriddata + val; *ida; ida += 3)
2365 data_addid(xd, ida[0]);
2366 data_addid(xd, ida[1]);
2367 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2370 case REPOKEY_TYPE_DIRSTRARRAY:
2371 for (ida = data->attriddata + val; *ida; ida += 2)
2373 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2374 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2377 case REPOKEY_TYPE_FIXARRAY:
2381 for (ida = data->attriddata + val; *ida; ida++)
2384 fprintf(stderr, "serialize struct %d\n", *ida);
2387 Id *kp = data->xattrs[-*ida];
2394 fprintf(stderr, " %s:%d\n", id2str(data->repo->pool, data->keys[*kp].name), kp[1]);
2400 schemaid = repodata_schema2id(data, schema, 1);
2401 else if (schemaid != repodata_schema2id(data, schema, 0))
2403 fprintf(stderr, " not yet implemented: substructs with different schemas\n");
2407 fprintf(stderr, " schema %d\n", schemaid);
2412 data_addid(xd, num);
2413 data_addid(xd, schemaid);
2414 for (ida = data->attriddata + val; *ida; ida++)
2416 Id *kp = data->xattrs[-*ida];
2421 repodata_serialize_key(data, newincore, newvincore,
2422 schema, data->keys + *kp, kp[1]);
2427 case REPOKEY_TYPE_FLEXARRAY:
2430 for (ida = data->attriddata + val; *ida; ida++)
2432 data_addid(xd, num);
2433 for (ida = data->attriddata + val; *ida; ida++)
2435 Id *kp = data->xattrs[-*ida];
2438 data_addid(xd, 0); /* XXX */
2445 schemaid = repodata_schema2id(data, schema, 1);
2446 data_addid(xd, schemaid);
2447 kp = data->xattrs[-*ida];
2450 repodata_serialize_key(data, newincore, newvincore,
2451 schema, data->keys + *kp, kp[1]);
2457 fprintf(stderr, "don't know how to handle type %d\n", key->type);
2460 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2462 /* put offset/len in incore */
2463 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2464 oldvincorelen = xd->len - oldvincorelen;
2465 data_addid(newincore, oldvincorelen);
2470 repodata_internalize(Repodata *data)
2472 Repokey *key, solvkey;
2474 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2475 unsigned char *dp, *ndp;
2476 int newschema, oldcount;
2477 struct extdata newincore;
2478 struct extdata newvincore;
2481 if (!data->attrs && !data->xattrs)
2484 newvincore.buf = data->vincore;
2485 newvincore.len = data->vincorelen;
2487 /* find the solvables key, create if needed */
2488 memset(&solvkey, 0, sizeof(solvkey));
2489 solvkey.name = REPOSITORY_SOLVABLES;
2490 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2492 solvkey.storage = KEY_STORAGE_INCORE;
2493 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2495 schema = sat_malloc2(data->nkeys, sizeof(Id));
2496 seen = sat_malloc2(data->nkeys, sizeof(Id));
2498 /* Merge the data already existing (in data->schemata, ->incoredata and
2499 friends) with the new attributes in data->attrs[]. */
2500 nentry = data->end - data->start;
2501 memset(&newincore, 0, sizeof(newincore));
2502 data_addid(&newincore, 0); /* start data at offset 1 */
2504 data->mainschema = 0;
2505 data->mainschemaoffsets = sat_free(data->mainschemaoffsets);
2507 /* join entry data */
2508 /* we start with the meta data, entry -1 */
2509 for (entry = -1; entry < nentry; entry++)
2511 memset(seen, 0, data->nkeys * sizeof(Id));
2513 dp = data->incoredata;
2516 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2517 dp = data_read_id(dp, &oldschema);
2520 fprintf(stderr, "oldschema %d\n", oldschema);
2521 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2522 fprintf(stderr, "schemadata %p\n", data->schemadata);
2524 /* seen: -1: old data 0: skipped >0: id + 1 */
2528 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2532 fprintf(stderr, "Inconsistent old data (key occured twice).\n");
2540 keyp = data->attrs ? data->attrs[entry] : 0;
2543 /* strip solvables key */
2545 for (sp = keyp = schema; *sp; sp++)
2546 if (*sp != solvkeyid)
2551 seen[solvkeyid] = 0;
2552 keyp = data->xattrs ? data->xattrs[1] : 0;
2555 for (; *keyp; keyp += 2)
2562 seen[*keyp] = keyp[1] + 1;
2564 if (entry < 0 && data->end != data->start)
2571 /* Ideally we'd like to sort the new schema here, to ensure
2572 schema equality independend of the ordering. We can't do that
2573 yet. For once see below (old ids need to come before new ids).
2574 An additional difficulty is that we also need to move
2575 the values with the keys. */
2576 schemaid = repodata_schema2id(data, schema, 1);
2578 schemaid = oldschema;
2581 /* Now create data blob. We walk through the (possibly new) schema
2582 and either copy over old data, or insert the new. */
2583 /* XXX Here we rely on the fact that the (new) schema has the form
2584 o1 o2 o3 o4 ... | n1 n2 n3 ...
2585 (oX being the old keyids (possibly overwritten), and nX being
2586 the new keyids). This rules out sorting the keyids in order
2587 to ensure a small schema count. */
2589 data->incoreoffset[entry] = newincore.len;
2590 data_addid(&newincore, schemaid);
2593 data->mainschema = schemaid;
2594 data->mainschemaoffsets = sat_calloc(sp - schema, sizeof(Id));
2596 keypstart = data->schemadata + data->schemata[schemaid];
2597 for (keyp = keypstart; *keyp; keyp++)
2600 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2601 if (*keyp == solvkeyid)
2603 /* add flexarray entry count */
2604 data_addid(&newincore, data->end - data->start);
2607 key = data->keys + *keyp;
2609 fprintf(stderr, "internalize %d:%s:%s\n", entry, id2str(data->repo->pool, key->name), id2str(data->repo->pool, key->type));
2614 /* Skip the data associated with this old key. */
2615 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2617 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2618 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2620 else if (key->storage == KEY_STORAGE_INCORE)
2621 ndp = data_skip_key(data, dp, key);
2624 if (seen[*keyp] == -1)
2626 /* If this key was an old one _and_ was not overwritten with
2627 a different value copy over the old value (we skipped it
2630 data_addblob(&newincore, dp, ndp - dp);
2633 else if (seen[*keyp])
2635 /* Otherwise we have a new value. Parse it into the internal
2637 repodata_serialize_key(data, &newincore, &newvincore,
2638 schema, key, seen[*keyp] - 1);
2642 if (entry >= 0 && data->attrs && data->attrs[entry])
2643 data->attrs[entry] = sat_free(data->attrs[entry]);
2645 /* free all xattrs */
2646 for (entry = 0; entry < data->nxattrs; entry++)
2647 if (data->xattrs[entry])
2648 sat_free(data->xattrs[entry]);
2649 data->xattrs = sat_free(data->xattrs);
2652 data->lasthandle = 0;
2654 data->lastdatalen = 0;
2657 repodata_free_schemahash(data);
2659 sat_free(data->incoredata);
2660 data->incoredata = newincore.buf;
2661 data->incoredatalen = newincore.len;
2662 data->incoredatafree = 0;
2664 sat_free(data->vincore);
2665 data->vincore = newvincore.buf;
2666 data->vincorelen = newvincore.len;
2668 data->attrs = sat_free(data->attrs);
2669 data->attrdata = sat_free(data->attrdata);
2670 data->attriddata = sat_free(data->attriddata);
2671 data->attrdatalen = 0;
2672 data->attriddatalen = 0;
2676 repodata_disable_paging(Repodata *data)
2678 if (maybe_load_repodata(data, 0))
2679 repopagestore_disable_paging(&data->store);
2683 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: