2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
37 #define REPODATA_BLOCK 255
39 static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
42 repodata_initdata(Repodata *data, Repo *repo, int localpool)
44 memset(data, 0, sizeof (*data));
45 data->repodataid = data - repo->repodata;
47 data->localpool = localpool;
49 stringpool_init_empty(&data->spool);
50 /* dirpool_init(&data->dirpool); just zeros out again */
51 data->keys = solv_calloc(1, sizeof(Repokey));
53 data->schemata = solv_calloc(1, sizeof(Id));
54 data->schemadata = solv_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_freedata(Repodata *data)
65 solv_free(data->keys);
67 solv_free(data->schemata);
68 solv_free(data->schemadata);
69 solv_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 solv_free(data->mainschemaoffsets);
75 solv_free(data->incoredata);
76 solv_free(data->incoreoffset);
77 solv_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 solv_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 solv_free(data->attrs[i]);
86 solv_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 solv_free(data->xattrs[i]);
90 solv_free(data->xattrs);
92 solv_free(data->attrdata);
93 solv_free(data->attriddata);
94 solv_free(data->attrnum64data);
96 solv_free(data->dircache);
100 repodata_free(Repodata *data)
102 Repo *repo = data->repo;
103 int i = data - repo->repodata;
106 repodata_freedata(data);
107 if (i < repo->nrepodata - 1)
109 /* whoa! this changes the repodataids! */
110 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
111 for (; i < repo->nrepodata - 1; i++)
112 repo->repodata[i].repodataid = i;
115 if (repo->nrepodata == 1)
117 repo->repodata = solv_free(repo->repodata);
123 repodata_empty(Repodata *data, int localpool)
125 void (*loadcallback)(Repodata *) = data->loadcallback;
126 int state = data->state;
127 repodata_freedata(data);
128 repodata_initdata(data, data->repo, localpool);
130 data->loadcallback = loadcallback;
134 /***************************************************************
135 * key pool management
138 /* this is not so time critical that we need a hash, so we do a simple
141 repodata_key2id(Repodata *data, Repokey *key, int create)
145 for (keyid = 1; keyid < data->nkeys; keyid++)
146 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
148 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
152 if (keyid == data->nkeys)
156 /* allocate new key */
157 data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
158 data->keys[data->nkeys++] = *key;
159 if (data->verticaloffset)
161 data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
162 data->verticaloffset[data->nkeys - 1] = 0;
164 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
170 /***************************************************************
171 * schema pool management
174 #define SCHEMATA_BLOCK 31
175 #define SCHEMATADATA_BLOCK 255
178 repodata_schema2id(Repodata *data, Id *schema, int create)
185 return 0; /* XXX: allow empty schema? */
186 if ((schematahash = data->schematahash) == 0)
188 data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
189 for (i = 1; i < data->nschemata; i++)
191 for (sp = data->schemadata + data->schemata[i], h = 0; *sp;)
196 data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
197 data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
200 for (sp = schema, len = 0, h = 0; *sp; len++)
205 cid = schematahash[h];
208 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
210 /* cache conflict, do a slow search */
211 for (cid = 1; cid < data->nschemata; cid++)
212 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
218 data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
219 data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
221 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
222 data->schemata[data->nschemata] = data->schemadatalen;
223 data->schemadatalen += len;
224 schematahash[h] = data->nschemata;
226 fprintf(stderr, "schema2id: new schema\n");
228 return data->nschemata++;
232 repodata_free_schemahash(Repodata *data)
234 data->schematahash = solv_free(data->schematahash);
236 data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
237 data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
241 /***************************************************************
242 * dir pool management
245 #ifndef HAVE_STRCHRNUL
246 static inline const char *strchrnul(const char *str, char x)
248 const char *p = strchr(str, x);
249 return p ? p : str + strlen(str);
253 #define DIRCACHE_SIZE 41 /* < 1k */
257 Id ids[DIRCACHE_SIZE];
258 char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
263 repodata_str2dir(Repodata *data, const char *dir, int create)
274 while (*dir == '/' && dir[1] == '/')
276 if (*dir == '/' && !dir[1])
278 if (data->dirpool.ndirs)
280 return dirpool_add_dir(&data->dirpool, 0, 1, create);
287 struct dircache *dircache = data->dircache;
291 if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
293 parent = dircache->ids[l];
309 dire = strchrnul(dir, '/');
311 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
313 id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
316 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
321 data->dircache = solv_calloc(1, sizeof(struct dircache));
325 if (l < DIRCACHE_SIZE)
327 data->dircache->ids[l] = parent;
328 memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
342 repodata_free_dircache(Repodata *data)
344 data->dircache = solv_free(data->dircache);
348 repodata_dir2str(Repodata *data, Id did, const char *suf)
350 Pool *pool = data->repo->pool;
357 return suf ? suf : "";
361 comp = dirpool_compid(&data->dirpool, parent);
362 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
364 parent = dirpool_parent(&data->dirpool, parent);
369 l += strlen(suf) + 1;
370 p = pool_alloctmpspace(pool, l + 1) + l;
381 comp = dirpool_compid(&data->dirpool, parent);
382 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
385 strncpy(p, comps, l);
386 parent = dirpool_parent(&data->dirpool, parent);
394 /***************************************************************
398 static inline unsigned char *
399 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
401 Id *keyp = data->schemadata + data->schemata[schema];
402 for (; *keyp; keyp++)
403 dp = data_skip_key(data, dp, data->keys + *keyp);
407 static unsigned char *
408 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
410 int nentries, schema;
413 case REPOKEY_TYPE_FIXARRAY:
414 dp = data_read_id(dp, &nentries);
417 dp = data_read_id(dp, &schema);
419 dp = data_skip_schema(data, dp, schema);
421 case REPOKEY_TYPE_FLEXARRAY:
422 dp = data_read_id(dp, &nentries);
425 dp = data_read_id(dp, &schema);
426 dp = data_skip_schema(data, dp, schema);
430 if (key->storage == KEY_STORAGE_INCORE)
431 dp = data_skip(dp, key->type);
432 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
434 dp = data_skip(dp, REPOKEY_TYPE_ID);
435 dp = data_skip(dp, REPOKEY_TYPE_ID);
441 static unsigned char *
442 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
448 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
451 for (i = 0; (k = *keyp++) != 0; i++)
453 return data->incoredata + data->mainschemaoffsets[i];
456 while ((k = *keyp++) != 0)
460 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
462 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
463 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
466 if (data->keys[k].storage != KEY_STORAGE_INCORE)
468 dp = data_skip_key(data, dp, data->keys + k);
473 static unsigned char *
474 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
479 if (off >= data->lastverticaloffset)
481 off -= data->lastverticaloffset;
482 if (off + len > data->vincorelen)
484 return data->vincore + off;
486 if (off + len > key->size)
488 /* we now have the offset, go into vertical */
489 off += data->verticaloffset[key - data->keys];
490 /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
491 dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
494 dp += off % REPOPAGE_BLOBSIZE;
498 static inline unsigned char *
499 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
501 unsigned char *dp = *dpp;
505 if (key->storage == KEY_STORAGE_INCORE)
508 *dpp = data_skip_key(data, dp, key);
511 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
514 dp = data_read_id(dp, &off);
515 dp = data_read_id(dp, &len);
518 return get_vertical_data(data, key, off, len);
524 load_repodata(Repodata *data)
526 if (data->loadcallback)
528 data->loadcallback(data);
529 if (data->state == REPODATA_AVAILABLE)
532 data->state = REPODATA_ERROR;
537 maybe_load_repodata(Repodata *data, Id keyname)
539 if (keyname && !repodata_precheck_keyname(data, keyname))
540 return 0; /* do not bother... */
547 for (i = 1; i < data->nkeys; i++)
548 if (keyname == data->keys[i].name)
550 if (i == data->nkeys)
553 return load_repodata(data);
556 case REPODATA_AVAILABLE:
557 case REPODATA_LOADING:
560 data->state = REPODATA_ERROR;
565 static inline unsigned char *
566 solvid2data(Repodata *data, Id solvid, Id *schemap)
568 unsigned char *dp = data->incoredata;
571 if (solvid == SOLVID_META)
572 dp += 1; /* offset of "meta" solvable */
573 else if (solvid == SOLVID_POS)
575 Pool *pool = data->repo->pool;
576 if (data->repo != pool->pos.repo)
578 if (data != data->repo->repodata + pool->pos.repodataid)
581 if (pool->pos.dp != 1)
583 *schemap = pool->pos.schema;
589 if (solvid < data->start || solvid >= data->end)
591 dp += data->incoreoffset[solvid - data->start];
593 return data_read_id(dp, schemap);
596 /************************************************************************
600 static inline unsigned char *
601 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
604 Id schema, *keyp, *kp;
607 if (!maybe_load_repodata(data, keyname))
609 dp = solvid2data(data, solvid, &schema);
612 keyp = data->schemadata + data->schemata[schema];
613 for (kp = keyp; *kp; kp++)
614 if (data->keys[*kp].name == keyname)
618 *keypp = key = data->keys + *kp;
619 if (key->type == REPOKEY_TYPE_DELETED)
621 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
622 return dp; /* no need to forward... */
623 dp = forward_to_key(data, *kp, keyp, dp);
626 return get_data(data, key, &dp, 0);
630 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
632 Id schema, *keyp, *kp;
633 if (!maybe_load_repodata(data, keyname))
635 if (!solvid2data(data, solvid, &schema))
637 keyp = data->schemadata + data->schemata[schema];
638 for (kp = keyp; *kp; kp++)
639 if (data->keys[*kp].name == keyname)
640 return data->keys[*kp].type;
645 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
651 dp = find_key_data(data, solvid, keyname, &key);
654 if (key->type == REPOKEY_TYPE_CONSTANTID)
656 if (key->type != REPOKEY_TYPE_ID)
658 dp = data_read_id(dp, &id);
663 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
669 dp = find_key_data(data, solvid, keyname, &key);
672 if (key->type == REPOKEY_TYPE_STR)
673 return (const char *)dp;
674 if (key->type == REPOKEY_TYPE_CONSTANTID)
676 else if (key->type == REPOKEY_TYPE_ID)
677 dp = data_read_id(dp, &id);
681 return stringpool_id2str(&data->spool, id);
682 return pool_id2str(data->repo->pool, id);
686 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
690 unsigned int high, low;
693 dp = find_key_data(data, solvid, keyname, &key);
698 case REPOKEY_TYPE_NUM:
699 data_read_num64(dp, &low, &high);
700 *value = (unsigned long long)high << 32 | low;
702 case REPOKEY_TYPE_U32:
703 data_read_u32(dp, &low);
706 case REPOKEY_TYPE_CONSTANT:
715 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
721 if (!maybe_load_repodata(data, keyname))
723 dp = solvid2data(data, solvid, &schema);
726 /* can't use find_key_data as we need to test the type */
727 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
728 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
733 const unsigned char *
734 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
739 dp = find_key_data(data, solvid, keyname, &key);
742 if (!(key->type == REPOKEY_TYPE_MD5 || key->type == REPOKEY_TYPE_SHA1 || key->type == REPOKEY_TYPE_SHA256))
749 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
757 dp = find_key_data(data, solvid, keyname, &key);
760 if (key->type != REPOKEY_TYPE_IDARRAY)
764 dp = data_read_ideof(dp, &id, &eof);
773 repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp)
779 dp = find_key_data(data, solvid, keyname, &key);
780 if (!dp || key->type != REPOKEY_TYPE_BINARY)
785 dp = data_read_id(dp, &len);
791 repodata_globalize_id(Repodata *data, Id id, int create)
793 if (!id || !data || !data->localpool)
795 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
799 repodata_localize_id(Repodata *data, Id id, int create)
801 if (!id || !data || !data->localpool)
803 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
807 repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
809 if (!id || !data || !fromdata)
811 if (!data->localpool || !fromdata->localpool)
813 if (fromdata->localpool)
814 id = repodata_globalize_id(fromdata, id, create);
816 id = repodata_localize_id(data, id, create);
819 /* localpool is set in both data and fromdata */
820 return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create);
824 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
829 ap = data->attrs[solvid - data->start];
834 if (data->keys[*ap].name != keyname)
836 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
838 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
846 /************************************************************************
852 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
856 case REPOKEY_TYPE_ID:
857 case REPOKEY_TYPE_CONSTANTID:
858 case REPOKEY_TYPE_IDARRAY:
859 if (data && data->localpool)
860 kv->str = stringpool_id2str(&data->spool, kv->id);
862 kv->str = pool_id2str(pool, kv->id);
863 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
866 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
868 if (*s == ':' && s > kv->str)
872 case REPOKEY_TYPE_STR:
874 case REPOKEY_TYPE_DIRSTRARRAY:
875 if (!(flags & SEARCH_FILES))
876 return 1; /* match just the basename */
878 return 1; /* already stringified */
879 /* Put the full filename into kv->str. */
880 kv->str = repodata_dir2str(data, kv->id, kv->str);
881 kv->num = 1; /* mark stringification */
883 case REPOKEY_TYPE_MD5:
884 case REPOKEY_TYPE_SHA1:
885 case REPOKEY_TYPE_SHA256:
886 if (!(flags & SEARCH_CHECKSUMS))
887 return 0; /* skip em */
889 return 1; /* already stringified */
890 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
891 kv->num = 1; /* mark stringification */
899 struct subschema_data {
905 /* search a specific repodata */
907 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
911 Id keyid, *kp, *keyp;
912 unsigned char *dp, *ddp;
918 if (!maybe_load_repodata(data, keyname))
920 if (solvid == SOLVID_SUBSCHEMA)
922 struct subschema_data *subd = cbdata;
923 cbdata = subd->cbdata;
925 schema = subd->parent->id;
926 dp = (unsigned char *)subd->parent->str;
927 kv.parent = subd->parent;
932 dp = solvid2data(data, solvid, &schema);
935 s = data->repo->pool->solvables + solvid;
938 keyp = data->schemadata + data->schemata[schema];
941 /* search for a specific key */
942 for (kp = keyp; *kp; kp++)
943 if (data->keys[*kp].name == keyname)
947 dp = forward_to_key(data, *kp, keyp, dp);
953 while ((keyid = *keyp++) != 0)
956 key = data->keys + keyid;
957 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
959 if (key->type == REPOKEY_TYPE_DELETED)
961 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
963 struct subschema_data subd;
967 subd.cbdata = cbdata;
970 ddp = data_read_id(ddp, &nentries);
974 while (ddp && nentries > 0)
978 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
979 ddp = data_read_id(ddp, &schema);
981 kv.str = (char *)ddp;
982 stop = callback(cbdata, s, data, key, &kv);
983 if (stop > SEARCH_NEXT_KEY)
985 if (stop && stop != SEARCH_ENTERSUB)
987 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
988 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
989 ddp = data_skip_schema(data, ddp, schema);
992 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
996 kv.str = (char *)ddp;
997 stop = callback(cbdata, s, data, key, &kv);
998 if (stop > SEARCH_NEXT_KEY)
1008 ddp = data_fetch(ddp, &kv, key);
1011 stop = callback(cbdata, s, data, key, &kv);
1014 while (!kv.eof && !stop);
1015 if (onekey || stop > SEARCH_NEXT_KEY)
1021 repodata_setpos_kv(Repodata *data, KeyValue *kv)
1023 Pool *pool = data->repo->pool;
1025 pool_clear_pos(pool);
1028 pool->pos.repo = data->repo;
1029 pool->pos.repodataid = data - data->repo->repodata;
1030 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
1031 pool->pos.schema = kv->id;
1035 /************************************************************************
1036 * data iterator functions
1040 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1054 case SOLVABLE_VENDOR:
1057 case SOLVABLE_PROVIDES:
1059 return s->provides ? s->repo->idarraydata + s->provides : 0;
1060 case SOLVABLE_OBSOLETES:
1062 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1063 case SOLVABLE_CONFLICTS:
1065 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1066 case SOLVABLE_REQUIRES:
1068 return s->requires ? s->repo->idarraydata + s->requires : 0;
1069 case SOLVABLE_RECOMMENDS:
1071 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1072 case SOLVABLE_SUPPLEMENTS:
1074 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1075 case SOLVABLE_SUGGESTS:
1077 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1078 case SOLVABLE_ENHANCES:
1080 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1083 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1090 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1092 ma->match = match ? solv_strdup(match) : 0;
1096 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1098 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1099 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1102 solv_free(ma->matchdata);
1103 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1106 if ((flags & SEARCH_FILES) != 0 && match)
1108 /* prepare basename check */
1109 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1111 const char *p = strrchr(match, '/');
1112 ma->matchdata = (void *)(p ? p + 1 : match);
1114 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1117 for (p = match + strlen(match) - 1; p >= match; p--)
1118 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1120 ma->matchdata = (void *)(p + 1);
1127 datamatcher_free(Datamatcher *ma)
1130 ma->match = solv_free((char *)ma->match);
1131 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1133 regfree(ma->matchdata);
1134 solv_free(ma->matchdata);
1140 datamatcher_match(Datamatcher *ma, const char *str)
1143 switch ((ma->flags & SEARCH_STRINGMASK))
1145 case SEARCH_SUBSTRING:
1146 if (ma->flags & SEARCH_NOCASE)
1147 return strcasestr(str, ma->match) != 0;
1149 return strstr(str, ma->match) != 0;
1151 if (ma->flags & SEARCH_NOCASE)
1152 return !strcasecmp(ma->match, str);
1154 return !strcmp(ma->match, str);
1155 case SEARCH_STRINGSTART:
1156 if (ma->flags & SEARCH_NOCASE)
1157 return !strncasecmp(ma->match, str, strlen(ma->match));
1159 return !strncmp(ma->match, str, strlen(ma->match));
1160 case SEARCH_STRINGEND:
1161 l = strlen(str) - strlen(ma->match);
1164 if (ma->flags & SEARCH_NOCASE)
1165 return !strcasecmp(ma->match, str + l);
1167 return !strcmp(ma->match, str + l);
1169 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1171 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1177 /* check if the matcher can match the provides basename */
1180 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1183 const char *match = ma->matchdata;
1186 switch (ma->flags & SEARCH_STRINGMASK)
1190 case SEARCH_STRINGEND:
1191 if (match != ma->match)
1192 break; /* had slash, do exact match on basename */
1195 /* check if the basename ends with match */
1196 l = strlen(basename) - strlen(match);
1202 return 1; /* maybe matches */
1204 if ((ma->flags & SEARCH_NOCASE) != 0)
1205 return !strcasecmp(match, basename);
1207 return !strcmp(match, basename);
1211 repodata_filelistfilter_matches(Repodata *data, const char *str)
1213 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1214 /* for now hardcoded */
1215 if (strstr(str, "bin/"))
1217 if (!strncmp(str, "/etc/", 5))
1219 if (!strcmp(str, "/usr/lib/sendmail"))
1241 di_nextarrayelement,
1247 di_entersolvablekey,
1251 /* see dataiterator.h for documentation */
1253 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1255 memset(di, 0, sizeof(*di));
1257 di->flags = flags & ~SEARCH_THISSOLVID;
1258 if (!pool || (repo && repo->pool != pool))
1266 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1272 di->keyname = keyname;
1273 di->keynames[0] = keyname;
1274 dataiterator_set_search(di, repo, p);
1279 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1284 if (di->dupstr == di->kv.str)
1286 di->dupstr = solv_malloc(di->dupstrn);
1287 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1295 memset(&di->matcher, 0, sizeof(di->matcher));
1296 if (from->matcher.match)
1297 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1302 for (i = 1; i < di->nparents; i++)
1303 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1304 di->kv.parent = &di->parents[di->nparents - 1].kv;
1309 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1311 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1312 datamatcher_free(&di->matcher);
1313 memset(&di->matcher, 0, sizeof(di->matcher));
1317 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1327 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1331 di->flags &= ~SEARCH_THISSOLVID;
1335 if (!di->pool->urepos)
1343 di->repo = di->pool->repos[di->repoid];
1345 di->state = di_enterrepo;
1347 dataiterator_jump_to_solvid(di, p);
1351 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1354 di->keyname = keyname;
1355 di->keynames[0] = keyname;
1359 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1363 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1365 di->state = di_bye; /* sorry */
1368 for (i = di->nkeynames + 1; i > 0; i--)
1369 di->keynames[i] = di->keynames[i - 1];
1370 di->keynames[0] = di->keyname = keyname;
1375 dataiterator_free(Dataiterator *di)
1377 if (di->matcher.match)
1378 datamatcher_free(&di->matcher);
1380 solv_free(di->dupstr);
1383 static inline unsigned char *
1384 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1386 Id *keyp = di->keyp;
1387 Repokey *keys = di->data->keys;
1390 for (keyp = di->keyp; *keyp; keyp++)
1391 if (keys[*keyp].name == keyname)
1395 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1403 is_filelist_extension(Repodata *data)
1406 if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
1408 for (j = 1; j < data->nkeys; j++)
1409 if (data->keys[j].name == SOLVABLE_FILELIST)
1411 if (j == data->nkeys)
1413 if (data->state != REPODATA_AVAILABLE)
1415 for (j = 1; j < data->nkeys; j++)
1416 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1422 dataiterator_filelistcheck(Dataiterator *di)
1425 int needcomplete = 0;
1426 Repodata *data = di->data;
1428 if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
1429 if (!di->matcher.match
1430 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1431 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1432 || !repodata_filelistfilter_matches(data, di->matcher.match))
1434 if (data->state != REPODATA_AVAILABLE)
1435 return needcomplete ? 1 : 0;
1438 /* we don't need the complete filelist, so ignore all stubs */
1439 for (j = 1; j < data->nkeys; j++)
1440 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1446 /* we need the complete filelist. check if we habe a filtered filelist and there's
1447 * a extension with the complete filelist later on */
1448 for (j = 1; j < data->nkeys; j++)
1449 if (data->keys[j].name == SOLVABLE_FILELIST)
1451 if (j == data->nkeys)
1452 return 0; /* does not have filelist */
1453 for (j = 1; j < data->nkeys; j++)
1454 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1456 if (j == data->nkeys)
1457 return 1; /* this is the externsion */
1458 while (data - data->repo->repodata + 1 < data->repo->nrepodata)
1461 if (is_filelist_extension(data))
1469 dataiterator_step(Dataiterator *di)
1473 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1474 unsigned int ddpoff = di->ddp - di->vert_ddp;
1475 di->vert_off += ddpoff;
1476 di->vert_len -= ddpoff;
1477 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1478 di->vert_storestate = di->data->storestate;
1480 di->state = di_nextkey;
1486 case di_enterrepo: di_enterrepo:
1487 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1489 if (!(di->flags & SEARCH_THISSOLVID))
1491 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1492 goto di_nextsolvable;
1496 case di_entersolvable: di_entersolvable:
1499 di->repodataid = 1; /* reset repodata iterator */
1500 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
1502 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1504 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1506 goto di_entersolvablekey;
1511 case di_enterrepodata: di_enterrepodata:
1514 if (di->repodataid >= di->repo->nrepodata)
1515 goto di_nextsolvable;
1516 di->data = di->repo->repodata + di->repodataid;
1518 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1519 goto di_nextrepodata;
1520 if (!maybe_load_repodata(di->data, di->keyname))
1521 goto di_nextrepodata;
1522 di->dp = solvid2data(di->data, di->solvid, &schema);
1524 goto di_nextrepodata;
1525 if (di->solvid == SOLVID_POS)
1526 di->solvid = di->pool->pos.solvid;
1527 /* reset key iterator */
1528 di->keyp = di->data->schemadata + di->data->schemata[schema];
1531 case di_enterschema: di_enterschema:
1533 di->dp = dataiterator_find_keyname(di, di->keyname);
1534 if (!di->dp || !*di->keyp)
1538 goto di_nextrepodata;
1542 case di_enterkey: di_enterkey:
1544 di->key = di->data->keys + *di->keyp;
1547 /* this is get_data() modified to store vert_ data */
1548 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1551 di->dp = data_read_id(di->dp, &off);
1552 di->dp = data_read_id(di->dp, &len);
1553 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1556 di->vert_storestate = di->data->storestate;
1558 else if (di->key->storage == KEY_STORAGE_INCORE)
1561 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1562 di->dp = data_skip_key(di->data, di->dp, di->key);
1568 if (di->key->type == REPOKEY_TYPE_DELETED)
1570 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1572 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1578 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1580 di->state = di_nextkey;
1582 di->state = di_nextattr;
1585 case di_nextkey: di_nextkey:
1586 if (!di->keyname && *++di->keyp)
1592 case di_nextrepodata: di_nextrepodata:
1593 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1594 goto di_enterrepodata;
1597 case di_nextsolvable: di_nextsolvable:
1598 if (!(di->flags & SEARCH_THISSOLVID))
1601 di->solvid = di->repo->start;
1604 for (; di->solvid < di->repo->end; di->solvid++)
1606 if (di->pool->solvables[di->solvid].repo == di->repo)
1607 goto di_entersolvable;
1612 case di_nextrepo: di_nextrepo:
1617 if (di->repoid < di->pool->nrepos)
1619 di->repo = di->pool->repos[di->repoid];
1625 case di_bye: di_bye:
1629 case di_enterarray: di_enterarray:
1630 if (di->key->name == REPOSITORY_SOLVABLES)
1632 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1637 case di_nextarrayelement: di_nextarrayelement:
1640 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1641 if (di->kv.entry == di->kv.num)
1643 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1645 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1647 di->kv.str = (char *)di->ddp;
1649 di->state = di_nextkey;
1652 if (di->kv.entry == di->kv.num - 1)
1654 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1655 di->ddp = data_read_id(di->ddp, &di->kv.id);
1656 di->kv.str = (char *)di->ddp;
1657 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1659 if ((di->flags & SEARCH_SUB) != 0)
1660 di->state = di_entersub;
1662 di->state = di_nextarrayelement;
1665 case di_entersub: di_entersub:
1666 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1667 goto di_nextarrayelement; /* sorry, full */
1668 di->parents[di->nparents].kv = di->kv;
1669 di->parents[di->nparents].dp = di->dp;
1670 di->parents[di->nparents].keyp = di->keyp;
1671 di->dp = (unsigned char *)di->kv.str;
1672 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1673 memset(&di->kv, 0, sizeof(di->kv));
1674 di->kv.parent = &di->parents[di->nparents].kv;
1676 di->keyname = di->keynames[di->nparents - di->rootlevel];
1677 goto di_enterschema;
1679 case di_leavesub: di_leavesub:
1680 if (di->nparents - 1 < di->rootlevel)
1683 di->dp = di->parents[di->nparents].dp;
1684 di->kv = di->parents[di->nparents].kv;
1685 di->keyp = di->parents[di->nparents].keyp;
1686 di->key = di->data->keys + *di->keyp;
1687 di->ddp = (unsigned char *)di->kv.str;
1688 di->keyname = di->keynames[di->nparents - di->rootlevel];
1689 goto di_nextarrayelement;
1691 /* special solvable attr handling follows */
1693 case di_nextsolvablekey: di_nextsolvablekey:
1694 if (di->keyname || di->key->name == RPM_RPMDBID)
1695 goto di_enterrepodata;
1699 case di_entersolvablekey: di_entersolvablekey:
1700 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1701 if (!di->idp || !*di->idp)
1702 goto di_nextsolvablekey;
1706 di->kv.id = *di->idp;
1707 di->kv.num = *di->idp; /* for rpmdbid */
1708 di->kv.num2 = 0; /* for rpmdbid */
1710 di->state = di_nextsolvablekey;
1716 case di_nextsolvableattr:
1717 di->state = di_nextsolvableattr;
1718 di->kv.id = *di->idp++;
1723 di->state = di_nextsolvablekey;
1729 if (di->matcher.match)
1731 /* simple pre-check so that we don't need to stringify */
1732 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1733 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1735 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1737 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1741 if (!datamatcher_match(&di->matcher, di->kv.str))
1746 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1747 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1749 /* found something! */
1755 dataiterator_entersub(Dataiterator *di)
1757 if (di->state == di_nextarrayelement)
1758 di->state = di_entersub;
1762 dataiterator_setpos(Dataiterator *di)
1764 if (di->kv.eof == 2)
1766 pool_clear_pos(di->pool);
1769 di->pool->pos.solvid = di->solvid;
1770 di->pool->pos.repo = di->repo;
1771 di->pool->pos.repodataid = di->data - di->repo->repodata;
1772 di->pool->pos.schema = di->kv.id;
1773 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1777 dataiterator_setpos_parent(Dataiterator *di)
1779 if (!di->kv.parent || di->kv.parent->eof == 2)
1781 pool_clear_pos(di->pool);
1784 di->pool->pos.solvid = di->solvid;
1785 di->pool->pos.repo = di->repo;
1786 di->pool->pos.repodataid = di->data - di->repo->repodata;
1787 di->pool->pos.schema = di->kv.parent->id;
1788 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1791 /* clones just the position, not the search keys/matcher */
1793 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1795 di->state = from->state;
1796 di->flags &= ~SEARCH_THISSOLVID;
1797 di->flags |= (from->flags & SEARCH_THISSOLVID);
1798 di->repo = from->repo;
1799 di->data = from->data;
1801 di->ddp = from->ddp;
1802 di->idp = from->idp;
1803 di->keyp = from->keyp;
1804 di->key = from->key;
1806 di->repodataid = from->repodataid;
1807 di->solvid = from->solvid;
1808 di->repoid = from->repoid;
1809 di->rootlevel = from->rootlevel;
1810 memcpy(di->parents, from->parents, sizeof(from->parents));
1811 di->nparents = from->nparents;
1815 for (i = 1; i < di->nparents; i++)
1816 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1817 di->kv.parent = &di->parents[di->nparents - 1].kv;
1821 if (from->dupstr && from->dupstr == from->kv.str)
1823 di->dupstrn = from->dupstrn;
1824 di->dupstr = solv_malloc(from->dupstrn);
1825 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1830 dataiterator_seek(Dataiterator *di, int whence)
1832 if ((whence & DI_SEEK_STAY) != 0)
1833 di->rootlevel = di->nparents;
1834 switch (whence & ~DI_SEEK_STAY)
1837 if (di->state != di_nextarrayelement)
1839 if ((whence & DI_SEEK_STAY) != 0)
1840 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1841 di->state = di_entersub;
1843 case DI_SEEK_PARENT:
1850 if (di->rootlevel > di->nparents)
1851 di->rootlevel = di->nparents;
1852 di->dp = di->parents[di->nparents].dp;
1853 di->kv = di->parents[di->nparents].kv;
1854 di->keyp = di->parents[di->nparents].keyp;
1855 di->key = di->data->keys + *di->keyp;
1856 di->ddp = (unsigned char *)di->kv.str;
1857 di->keyname = di->keynames[di->nparents - di->rootlevel];
1858 di->state = di_nextarrayelement;
1860 case DI_SEEK_REWIND:
1866 di->dp = (unsigned char *)di->kv.parent->str;
1867 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1868 di->state = di_enterschema;
1876 dataiterator_skip_attribute(Dataiterator *di)
1878 if (di->state == di_nextsolvableattr)
1879 di->state = di_nextsolvablekey;
1881 di->state = di_nextkey;
1885 dataiterator_skip_solvable(Dataiterator *di)
1890 di->keyname = di->keynames[0];
1891 di->state = di_nextsolvable;
1895 dataiterator_skip_repo(Dataiterator *di)
1900 di->keyname = di->keynames[0];
1901 di->state = di_nextrepo;
1905 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1910 di->keyname = di->keynames[0];
1911 if (solvid == SOLVID_POS)
1913 di->repo = di->pool->pos.repo;
1920 di->data = di->repo->repodata + di->pool->pos.repodataid;
1922 di->solvid = solvid;
1923 di->state = di_enterrepo;
1924 di->flags |= SEARCH_THISSOLVID;
1929 di->repo = di->pool->solvables[solvid].repo;
1932 else if (di->repoid > 0)
1934 if (!di->pool->urepos)
1940 di->repo = di->pool->repos[di->repoid];
1943 di->solvid = solvid;
1945 di->flags |= SEARCH_THISSOLVID;
1946 di->state = di_enterrepo;
1950 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1956 di->repoid = 0; /* 0 means stay at repo */
1959 di->flags &= ~SEARCH_THISSOLVID;
1960 di->state = di_enterrepo;
1964 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1966 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1970 return datamatcher_match(ma, di->kv.str);
1974 dataiterator_strdup(Dataiterator *di)
1978 if (!di->kv.str || di->kv.str == di->dupstr)
1980 switch (di->key->type)
1982 case REPOKEY_TYPE_MD5:
1983 case REPOKEY_TYPE_SHA1:
1984 case REPOKEY_TYPE_SHA256:
1985 case REPOKEY_TYPE_DIRSTRARRAY:
1986 if (di->kv.num) /* was it stringified into tmp space? */
1987 l = strlen(di->kv.str) + 1;
1992 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1994 switch (di->key->type)
1996 case REPOKEY_TYPE_STR:
1997 case REPOKEY_TYPE_DIRSTRARRAY:
1998 l = strlen(di->kv.str) + 1;
2000 case REPOKEY_TYPE_MD5:
2003 case REPOKEY_TYPE_SHA1:
2006 case REPOKEY_TYPE_SHA256:
2009 case REPOKEY_TYPE_BINARY:
2016 if (!di->dupstrn || di->dupstrn < l)
2018 di->dupstrn = l + 16;
2019 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
2022 memcpy(di->dupstr, di->kv.str, l);
2023 di->kv.str = di->dupstr;
2027 /************************************************************************
2028 * data modify functions
2031 /* extend repodata so that it includes solvables p */
2033 repodata_extend(Repodata *data, Id p)
2035 if (data->start == data->end)
2036 data->start = data->end = p;
2039 int old = data->end - data->start;
2040 int new = p - data->end + 1;
2043 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
2044 memset(data->attrs + old, 0, new * sizeof(Id *));
2046 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
2047 memset(data->incoreoffset + old, 0, new * sizeof(Id));
2050 if (p < data->start)
2052 int old = data->end - data->start;
2053 int new = data->start - p;
2056 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
2057 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
2058 memset(data->attrs, 0, new * sizeof(Id *));
2060 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
2061 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
2062 memset(data->incoreoffset, 0, new * sizeof(Id));
2067 /* shrink end of repodata */
2069 repodata_shrink(Repodata *data, int end)
2073 if (data->end <= end)
2075 if (data->start >= end)
2079 for (i = 0; i < data->end - data->start; i++)
2080 solv_free(data->attrs[i]);
2081 data->attrs = solv_free(data->attrs);
2083 data->incoreoffset = solv_free(data->incoreoffset);
2084 data->start = data->end = 0;
2089 for (i = end; i < data->end; i++)
2090 solv_free(data->attrs[i - data->start]);
2091 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2093 if (data->incoreoffset)
2094 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2098 /* extend repodata so that it includes solvables from start to start + num - 1 */
2100 repodata_extend_block(Repodata *data, Id start, Id num)
2104 if (!data->incoreoffset)
2106 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2107 data->start = start;
2108 data->end = start + num;
2111 repodata_extend(data, start);
2113 repodata_extend(data, start + num - 1);
2116 /**********************************************************************/
2119 #define REPODATA_ATTRS_BLOCK 31
2120 #define REPODATA_ATTRDATA_BLOCK 1023
2121 #define REPODATA_ATTRIDDATA_BLOCK 63
2122 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2126 repodata_new_handle(Repodata *data)
2130 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2131 data->nxattrs = 2; /* -1: SOLVID_META */
2133 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2134 data->xattrs[data->nxattrs] = 0;
2135 return -(data->nxattrs++);
2139 repodata_get_attrp(Repodata *data, Id handle)
2143 if (handle == SOLVID_META && !data->xattrs)
2145 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2148 return data->xattrs - handle;
2150 if (handle < data->start || handle >= data->end)
2151 repodata_extend(data, handle);
2153 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2154 return data->attrs + (handle - data->start);
2158 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2164 app = repodata_get_attrp(data, handle);
2169 /* Determine equality based on the name only, allows us to change
2170 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2171 for (pp = ap; *pp; pp += 2)
2172 if (data->keys[*pp].name == data->keys[keyid].name)
2176 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2185 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2195 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2199 keyid = repodata_key2id(data, key, 1);
2200 repodata_insert_keyid(data, solvid, keyid, val, 1);
2204 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2208 key.type = REPOKEY_TYPE_ID;
2210 key.storage = KEY_STORAGE_INCORE;
2211 repodata_set(data, solvid, &key, id);
2215 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2219 key.type = REPOKEY_TYPE_NUM;
2221 key.storage = KEY_STORAGE_INCORE;
2222 if (num >= 0x80000000)
2224 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2225 data->attrnum64data[data->attrnum64datalen] = num;
2226 num = 0x80000000 | data->attrnum64datalen++;
2228 repodata_set(data, solvid, &key, (Id)num);
2232 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2236 if (data->localpool)
2237 id = stringpool_str2id(&data->spool, str, 1);
2239 id = pool_str2id(data->repo->pool, str, 1);
2241 key.type = REPOKEY_TYPE_ID;
2243 key.storage = KEY_STORAGE_INCORE;
2244 repodata_set(data, solvid, &key, id);
2248 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2252 key.type = REPOKEY_TYPE_CONSTANT;
2253 key.size = constant;
2254 key.storage = KEY_STORAGE_INCORE;
2255 repodata_set(data, solvid, &key, 0);
2259 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2263 key.type = REPOKEY_TYPE_CONSTANTID;
2265 key.storage = KEY_STORAGE_INCORE;
2266 repodata_set(data, solvid, &key, 0);
2270 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2274 key.type = REPOKEY_TYPE_VOID;
2276 key.storage = KEY_STORAGE_INCORE;
2277 repodata_set(data, solvid, &key, 0);
2281 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2286 l = strlen(str) + 1;
2288 key.type = REPOKEY_TYPE_STR;
2290 key.storage = KEY_STORAGE_INCORE;
2291 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2292 memcpy(data->attrdata + data->attrdatalen, str, l);
2293 repodata_set(data, solvid, &key, data->attrdatalen);
2294 data->attrdatalen += l;
2298 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2306 key.type = REPOKEY_TYPE_BINARY;
2308 key.storage = KEY_STORAGE_INCORE;
2309 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2310 dp = data->attrdata + data->attrdatalen;
2311 if (len >= (1 << 14))
2313 if (len >= (1 << 28))
2314 *dp++ = (len >> 28) | 128;
2315 if (len >= (1 << 21))
2316 *dp++ = (len >> 21) | 128;
2317 *dp++ = (len >> 14) | 128;
2319 if (len >= (1 << 7))
2320 *dp++ = (len >> 7) | 128;
2323 memcpy(dp, buf, len);
2324 repodata_set(data, solvid, &key, data->attrdatalen);
2325 data->attrdatalen = dp + len - data->attrdata;
2328 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2329 * so that the caller can append entrysize new elements plus the termination zero there */
2331 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2334 Id *ida, *pp, **ppp;
2336 /* check if it is the same as last time, this speeds things up a lot */
2337 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2339 /* great! just append the new data */
2340 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2341 data->attriddatalen--; /* overwrite terminating 0 */
2342 data->lastdatalen += entrysize;
2346 ppp = repodata_get_attrp(data, handle);
2350 for (; *pp; pp += 2)
2351 if (data->keys[*pp].name == keyname)
2354 if (!pp || !*pp || data->keys[*pp].type != keytype)
2356 /* not found. allocate new key */
2362 key.storage = KEY_STORAGE_INCORE;
2363 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2364 keyid = repodata_key2id(data, &key, 1);
2365 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2366 data->lasthandle = handle;
2367 data->lastkey = keyid;
2368 data->lastdatalen = data->attriddatalen + entrysize + 1;
2372 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2373 oldsize += entrysize;
2374 if (ida + 1 == data->attriddata + data->attriddatalen)
2376 /* this was the last entry, just append it */
2377 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2378 data->attriddatalen--; /* overwrite terminating 0 */
2382 /* too bad. move to back. */
2383 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2384 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2385 pp[1] = data->attriddatalen;
2386 data->attriddatalen += oldsize;
2388 data->lasthandle = handle;
2389 data->lastkey = *pp;
2390 data->lastdatalen = data->attriddatalen + entrysize + 1;
2394 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2395 const unsigned char *str)
2400 if (!(l = solv_chksum_len(type)))
2405 key.storage = KEY_STORAGE_INCORE;
2406 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2407 memcpy(data->attrdata + data->attrdatalen, str, l);
2408 repodata_set(data, solvid, &key, data->attrdatalen);
2409 data->attrdatalen += l;
2413 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2416 unsigned char buf[64];
2419 if (!(l = solv_chksum_len(type)))
2421 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2423 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2427 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2431 if (!(l = solv_chksum_len(type)))
2433 return pool_bin2hex(data->repo->pool, buf, l);
2436 /* rpm filenames don't contain the epoch, so strip it */
2437 static inline const char *
2438 evrid2vrstr(Pool *pool, Id evrid)
2440 const char *p, *evr = pool_id2str(pool, evrid);
2443 for (p = evr; *p >= '0' && *p <= '9'; p++)
2445 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2449 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2452 if (data->localpool)
2453 id = stringpool_strn2id(&data->spool, str, l, 1);
2455 id = pool_strn2id(data->repo->pool, str, l, 1);
2456 repodata_set_id(data, solvid, keyname, id);
2460 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2463 repodata_set_str(data, solvid, keyname, str);
2466 char *s = solv_strdup(str);
2468 repodata_set_str(data, solvid, keyname, s);
2474 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2476 Pool *pool = data->repo->pool;
2478 const char *str, *fp;
2482 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2485 if ((dir = strrchr(file, '/')) != 0)
2496 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2501 if (l == 1 && dir[0] == '.')
2503 s = pool->solvables + solvid;
2506 str = pool_id2str(pool, s->arch);
2507 if (!strncmp(dir, str, l) && !str[l])
2508 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2510 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2513 str = pool_id2str(pool, s->name);
2515 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2518 str = evrid2vrstr(pool, s->evr);
2520 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2523 str = pool_id2str(pool, s->arch);
2525 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2527 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2532 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2535 /* XXX: medianr is currently not stored */
2537 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2540 const char *evr, *suf, *s;
2544 if ((dir = strrchr(file, '/')) != 0)
2555 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2560 if (l == 1 && dir[0] == '.')
2563 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2564 evr = strchr(file, '-');
2567 for (s = evr - 1; s > file; s--)
2574 suf = strrchr(file, '.');
2577 for (s = suf - 1; s > file; s--)
2583 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2585 /* We accept one more item as suffix. */
2586 for (s = suf - 1; s > file; s--)
2596 if (suf && evr && suf < evr)
2598 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2600 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2602 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2606 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2608 Pool *pool = data->repo->pool;
2609 Solvable *s = pool->solvables + solvid;
2610 const char *p, *sevr, *sarch, *name, *evr;
2612 p = strrchr(sourcepkg, '.');
2613 if (!p || strcmp(p, ".rpm") != 0)
2616 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2620 while (p > sourcepkg && *p != '.')
2622 if (*p != '.' || p == sourcepkg)
2625 while (p > sourcepkg && *p != '-')
2627 if (*p != '-' || p == sourcepkg)
2630 while (p > sourcepkg && *p != '-')
2632 if (*p != '-' || p == sourcepkg)
2635 pool = s->repo->pool;
2637 name = pool_id2str(pool, s->name);
2638 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2639 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2641 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2643 evr = evrid2vrstr(pool, s->evr);
2644 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2645 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2647 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2649 if (!strcmp(sarch, "src.rpm"))
2650 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2651 else if (!strcmp(sarch, "nosrc.rpm"))
2652 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2654 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2658 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2664 key.type = REPOKEY_TYPE_IDARRAY;
2666 key.storage = KEY_STORAGE_INCORE;
2667 repodata_set(data, solvid, &key, data->attriddatalen);
2668 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2669 for (i = 0; i < q->count; i++)
2670 data->attriddata[data->attriddatalen++] = q->elements[i];
2671 data->attriddata[data->attriddatalen++] = 0;
2675 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2679 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2681 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2682 data->attriddata[data->attriddatalen++] = dir;
2683 data->attriddata[data->attriddatalen++] = num;
2684 data->attriddata[data->attriddatalen++] = num2;
2685 data->attriddata[data->attriddatalen++] = 0;
2689 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2695 l = strlen(str) + 1;
2696 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2697 memcpy(data->attrdata + data->attrdatalen, str, l);
2698 stroff = data->attrdatalen;
2699 data->attrdatalen += l;
2702 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2704 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2705 data->attriddata[data->attriddatalen++] = dir;
2706 data->attriddata[data->attriddatalen++] = stroff;
2707 data->attriddata[data->attriddatalen++] = 0;
2711 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2714 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2716 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2717 data->attriddata[data->attriddatalen++] = id;
2718 data->attriddata[data->attriddatalen++] = 0;
2722 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2726 if (data->localpool)
2727 id = stringpool_str2id(&data->spool, str, 1);
2729 id = pool_str2id(data->repo->pool, str, 1);
2730 repodata_add_idarray(data, solvid, keyname, id);
2734 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2736 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2737 data->attriddata[data->attriddatalen++] = ghandle;
2738 data->attriddata[data->attriddatalen++] = 0;
2742 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2744 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2745 data->attriddata[data->attriddatalen++] = ghandle;
2746 data->attriddata[data->attriddatalen++] = 0;
2750 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2753 app = repodata_get_attrp(data, solvid);
2757 for (; *ap; ap += 2)
2758 if (data->keys[*ap].name == keyname)
2764 for (; *ap; ap += 2)
2766 if (data->keys[*ap].name == keyname)
2774 /* XXX: does not work correctly, needs fix in iterators! */
2776 repodata_unset(Repodata *data, Id solvid, Id keyname)
2780 key.type = REPOKEY_TYPE_DELETED;
2782 key.storage = KEY_STORAGE_INCORE;
2783 repodata_set(data, solvid, &key, 0);
2786 /* add all (uninternalized) attrs from src to dest */
2788 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2791 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2793 for (; *keyp; keyp += 2)
2794 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2797 /* add some (uninternalized) attrs from src to dest */
2799 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2802 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2804 for (; *keyp; keyp += 2)
2805 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2806 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2809 /* swap (uninternalized) attrs from src and dest */
2811 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2814 if (!data->attrs || dest == src)
2816 tmpattrs = data->attrs[dest - data->start];
2817 data->attrs[dest - data->start] = data->attrs[src - data->start];
2818 data->attrs[src - data->start] = tmpattrs;
2822 /**********************************************************************/
2824 /* TODO: unify with repo_write and repo_solv! */
2826 #define EXTDATA_BLOCK 1023
2834 data_addid(struct extdata *xd, Id sx)
2836 unsigned int x = (unsigned int)sx;
2839 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2840 dp = xd->buf + xd->len;
2845 *dp++ = (x >> 28) | 128;
2847 *dp++ = (x >> 21) | 128;
2848 *dp++ = (x >> 14) | 128;
2851 *dp++ = (x >> 7) | 128;
2853 xd->len = dp - xd->buf;
2857 data_addid64(struct extdata *xd, unsigned long long x)
2859 if (x >= 0x100000000)
2863 data_addid(xd, (Id)(x >> 35));
2864 xd->buf[xd->len - 1] |= 128;
2866 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2867 xd->buf[xd->len - 5] = (x >> 28) | 128;
2870 data_addid(xd, (Id)x);
2874 data_addideof(struct extdata *xd, Id sx, int eof)
2876 unsigned int x = (unsigned int)sx;
2879 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2880 dp = xd->buf + xd->len;
2885 *dp++ = (x >> 27) | 128;
2887 *dp++ = (x >> 20) | 128;
2888 *dp++ = (x >> 13) | 128;
2891 *dp++ = (x >> 6) | 128;
2892 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2893 xd->len = dp - xd->buf;
2897 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2899 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2900 memcpy(xd->buf + xd->len, blob, len);
2904 /*********************************/
2906 /* internalalize some key into incore/vincore data */
2909 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2910 struct extdata *newvincore,
2912 Repokey *key, Id val)
2916 unsigned int oldvincorelen = 0;
2920 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2923 oldvincorelen = xd->len;
2927 case REPOKEY_TYPE_VOID:
2928 case REPOKEY_TYPE_CONSTANT:
2929 case REPOKEY_TYPE_CONSTANTID:
2931 case REPOKEY_TYPE_STR:
2932 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2934 case REPOKEY_TYPE_MD5:
2935 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2937 case REPOKEY_TYPE_SHA1:
2938 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2940 case REPOKEY_TYPE_SHA256:
2941 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2943 case REPOKEY_TYPE_NUM:
2944 if (val & 0x80000000)
2946 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2950 case REPOKEY_TYPE_ID:
2951 case REPOKEY_TYPE_DIR:
2952 data_addid(xd, val);
2954 case REPOKEY_TYPE_BINARY:
2957 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2958 dp += (unsigned int)len;
2959 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2962 case REPOKEY_TYPE_IDARRAY:
2963 for (ida = data->attriddata + val; *ida; ida++)
2964 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2966 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2967 for (ida = data->attriddata + val; *ida; ida += 3)
2969 data_addid(xd, ida[0]);
2970 data_addid(xd, ida[1]);
2971 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2974 case REPOKEY_TYPE_DIRSTRARRAY:
2975 for (ida = data->attriddata + val; *ida; ida += 2)
2977 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2978 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2981 case REPOKEY_TYPE_FIXARRAY:
2985 for (ida = data->attriddata + val; *ida; ida++)
2989 kp = data->xattrs[-*ida];
2997 schemaid = repodata_schema2id(data, schema, 1);
2998 else if (schemaid != repodata_schema2id(data, schema, 0))
3000 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
3006 data_addid(xd, num);
3007 data_addid(xd, schemaid);
3008 for (ida = data->attriddata + val; *ida; ida++)
3010 Id *kp = data->xattrs[-*ida];
3014 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3018 case REPOKEY_TYPE_FLEXARRAY:
3021 for (ida = data->attriddata + val; *ida; ida++)
3023 data_addid(xd, num);
3024 for (ida = data->attriddata + val; *ida; ida++)
3026 Id *kp = data->xattrs[-*ida];
3029 data_addid(xd, 0); /* XXX */
3036 schemaid = repodata_schema2id(data, schema, 1);
3037 data_addid(xd, schemaid);
3038 kp = data->xattrs[-*ida];
3040 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3045 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
3048 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3050 /* put offset/len in incore */
3051 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
3052 oldvincorelen = xd->len - oldvincorelen;
3053 data_addid(newincore, oldvincorelen);
3058 repodata_internalize(Repodata *data)
3060 Repokey *key, solvkey;
3062 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
3063 unsigned char *dp, *ndp;
3064 int newschema, oldcount;
3065 struct extdata newincore;
3066 struct extdata newvincore;
3069 if (!data->attrs && !data->xattrs)
3072 newvincore.buf = data->vincore;
3073 newvincore.len = data->vincorelen;
3075 /* find the solvables key, create if needed */
3076 memset(&solvkey, 0, sizeof(solvkey));
3077 solvkey.name = REPOSITORY_SOLVABLES;
3078 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3080 solvkey.storage = KEY_STORAGE_INCORE;
3081 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3083 schema = solv_malloc2(data->nkeys, sizeof(Id));
3084 seen = solv_malloc2(data->nkeys, sizeof(Id));
3086 /* Merge the data already existing (in data->schemata, ->incoredata and
3087 friends) with the new attributes in data->attrs[]. */
3088 nentry = data->end - data->start;
3089 memset(&newincore, 0, sizeof(newincore));
3090 data_addid(&newincore, 0); /* start data at offset 1 */
3092 data->mainschema = 0;
3093 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3095 /* join entry data */
3096 /* we start with the meta data, entry -1 */
3097 for (entry = -1; entry < nentry; entry++)
3099 memset(seen, 0, data->nkeys * sizeof(Id));
3101 dp = data->incoredata;
3104 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3105 dp = data_read_id(dp, &oldschema);
3108 fprintf(stderr, "oldschema %d\n", oldschema);
3109 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3110 fprintf(stderr, "schemadata %p\n", data->schemadata);
3112 /* seen: -1: old data 0: skipped >0: id + 1 */
3116 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3120 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3128 keyp = data->attrs ? data->attrs[entry] : 0;
3131 /* strip solvables key */
3133 for (sp = keyp = schema; *sp; sp++)
3134 if (*sp != solvkeyid)
3139 seen[solvkeyid] = 0;
3140 keyp = data->xattrs ? data->xattrs[1] : 0;
3143 for (; *keyp; keyp += 2)
3150 seen[*keyp] = keyp[1] + 1;
3152 if (entry < 0 && data->end != data->start)
3159 /* Ideally we'd like to sort the new schema here, to ensure
3160 schema equality independend of the ordering. We can't do that
3161 yet. For once see below (old ids need to come before new ids).
3162 An additional difficulty is that we also need to move
3163 the values with the keys. */
3164 schemaid = repodata_schema2id(data, schema, 1);
3166 schemaid = oldschema;
3169 /* Now create data blob. We walk through the (possibly new) schema
3170 and either copy over old data, or insert the new. */
3171 /* XXX Here we rely on the fact that the (new) schema has the form
3172 o1 o2 o3 o4 ... | n1 n2 n3 ...
3173 (oX being the old keyids (possibly overwritten), and nX being
3174 the new keyids). This rules out sorting the keyids in order
3175 to ensure a small schema count. */
3177 data->incoreoffset[entry] = newincore.len;
3178 data_addid(&newincore, schemaid);
3181 data->mainschema = schemaid;
3182 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3184 keypstart = data->schemadata + data->schemata[schemaid];
3185 for (keyp = keypstart; *keyp; keyp++)
3188 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3189 if (*keyp == solvkeyid)
3191 /* add flexarray entry count */
3192 data_addid(&newincore, data->end - data->start);
3195 key = data->keys + *keyp;
3197 fprintf(stderr, "internalize %d(%d):%s:%s\n", entry, entry + data->start, pool_id2str(data->repo->pool, key->name), pool_id2str(data->repo->pool, key->type));
3202 /* Skip the data associated with this old key. */
3203 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3205 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3206 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3208 else if (key->storage == KEY_STORAGE_INCORE)
3209 ndp = data_skip_key(data, dp, key);
3212 if (seen[*keyp] == -1)
3214 /* If this key was an old one _and_ was not overwritten with
3215 a different value copy over the old value (we skipped it
3218 data_addblob(&newincore, dp, ndp - dp);
3221 else if (seen[*keyp])
3223 /* Otherwise we have a new value. Parse it into the internal
3225 repodata_serialize_key(data, &newincore, &newvincore,
3226 schema, key, seen[*keyp] - 1);
3230 if (entry >= 0 && data->attrs && data->attrs[entry])
3231 data->attrs[entry] = solv_free(data->attrs[entry]);
3233 /* free all xattrs */
3234 for (entry = 0; entry < data->nxattrs; entry++)
3235 if (data->xattrs[entry])
3236 solv_free(data->xattrs[entry]);
3237 data->xattrs = solv_free(data->xattrs);
3240 data->lasthandle = 0;
3242 data->lastdatalen = 0;
3245 repodata_free_schemahash(data);
3247 solv_free(data->incoredata);
3248 data->incoredata = newincore.buf;
3249 data->incoredatalen = newincore.len;
3250 data->incoredatafree = 0;
3252 solv_free(data->vincore);
3253 data->vincore = newvincore.buf;
3254 data->vincorelen = newvincore.len;
3256 data->attrs = solv_free(data->attrs);
3257 data->attrdata = solv_free(data->attrdata);
3258 data->attriddata = solv_free(data->attriddata);
3259 data->attrnum64data = solv_free(data->attrnum64data);
3260 data->attrdatalen = 0;
3261 data->attriddatalen = 0;
3262 data->attrnum64datalen = 0;
3266 repodata_disable_paging(Repodata *data)
3268 if (maybe_load_repodata(data, 0))
3270 repopagestore_disable_paging(&data->store);
3276 repodata_load_stub(Repodata *data)
3278 Repo *repo = data->repo;
3279 Pool *pool = repo->pool;
3281 struct _Pool_tmpspace oldtmpspace;
3283 if (!pool->loadcallback)
3285 data->state = REPODATA_ERROR;
3288 data->state = REPODATA_LOADING;
3290 /* save tmp space */
3291 oldtmpspace = pool->tmpspace;
3292 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3294 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3296 /* restore tmp space */
3297 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3298 solv_free(pool->tmpspace.buf[i]);
3299 pool->tmpspace = oldtmpspace;
3301 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3305 repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
3309 xkey.name = keyname;
3310 xkey.type = keytype;
3311 xkey.storage = KEY_STORAGE_INCORE;
3313 repodata_key2id(data, &xkey, 1);
3317 repodata_add_stub(Repodata **datap)
3319 Repodata *data = *datap;
3320 Repo *repo = data->repo;
3321 Id repodataid = data - repo->repodata;
3322 Repodata *sdata = repo_add_repodata(repo, 0);
3323 data = repo->repodata + repodataid;
3324 if (data->end > data->start)
3325 repodata_extend_block(sdata, data->start, data->end - data->start);
3326 sdata->state = REPODATA_STUB;
3327 sdata->loadcallback = repodata_load_stub;
3333 repodata_create_stubs(Repodata *data)
3335 Repo *repo = data->repo;
3336 Pool *pool = repo->pool;
3343 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3344 while (dataiterator_step(&di))
3345 if (di.data == data)
3347 dataiterator_free(&di);
3350 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3351 for (i = 0; i < cnt; i++)
3353 sdata = repodata_add_stub(&data);
3354 stubdataids[i] = sdata - repo->repodata;
3357 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3359 while (dataiterator_step(&di))
3361 if (di.data != data)
3363 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3365 dataiterator_entersub(&di);
3366 sdata = repo->repodata + stubdataids[i++];
3370 switch (di.key->type)
3372 case REPOKEY_TYPE_ID:
3373 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3375 case REPOKEY_TYPE_CONSTANTID:
3376 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3378 case REPOKEY_TYPE_STR:
3379 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3381 case REPOKEY_TYPE_VOID:
3382 repodata_set_void(sdata, SOLVID_META, di.key->name);
3384 case REPOKEY_TYPE_NUM:
3385 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3387 case REPOKEY_TYPE_MD5:
3388 case REPOKEY_TYPE_SHA1:
3389 case REPOKEY_TYPE_SHA256:
3390 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3392 case REPOKEY_TYPE_IDARRAY:
3393 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3394 if (di.key->name == REPOSITORY_KEYS)
3399 xkeyname = di.kv.id;
3403 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
3412 dataiterator_free(&di);
3413 for (i = 0; i < cnt; i++)
3414 repodata_internalize(repo->repodata + stubdataids[i]);
3415 solv_free(stubdataids);
3420 repodata_memused(Repodata *data)
3422 return data->incoredatalen + data->vincorelen;