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; len++)
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) /* META */
573 else if (solvid == SOLVID_POS) /* META */
575 Pool *pool = data->repo->pool;
576 if (data->repo != pool->pos.repo)
578 if (data != data->repo->repodata + pool->pos.repodataid)
580 *schemap = pool->pos.schema;
581 return data->incoredata + pool->pos.dp;
585 if (solvid < data->start || solvid >= data->end)
587 dp += data->incoreoffset[solvid - data->start];
589 return data_read_id(dp, schemap);
592 /************************************************************************
596 static inline unsigned char *
597 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
600 Id schema, *keyp, *kp;
603 if (!maybe_load_repodata(data, keyname))
605 dp = solvid2data(data, solvid, &schema);
608 keyp = data->schemadata + data->schemata[schema];
609 for (kp = keyp; *kp; kp++)
610 if (data->keys[*kp].name == keyname)
614 *keypp = key = data->keys + *kp;
615 if (key->type == REPOKEY_TYPE_DELETED)
617 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
618 return dp; /* no need to forward... */
619 dp = forward_to_key(data, *kp, keyp, dp);
622 return get_data(data, key, &dp, 0);
626 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
628 Id schema, *keyp, *kp;
629 if (!maybe_load_repodata(data, keyname))
631 if (!solvid2data(data, solvid, &schema))
633 keyp = data->schemadata + data->schemata[schema];
634 for (kp = keyp; *kp; kp++)
635 if (data->keys[*kp].name == keyname)
636 return data->keys[*kp].type;
641 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
647 dp = find_key_data(data, solvid, keyname, &key);
650 if (key->type == REPOKEY_TYPE_CONSTANTID)
652 if (key->type != REPOKEY_TYPE_ID)
654 dp = data_read_id(dp, &id);
659 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
665 dp = find_key_data(data, solvid, keyname, &key);
668 if (key->type == REPOKEY_TYPE_STR)
669 return (const char *)dp;
670 if (key->type == REPOKEY_TYPE_CONSTANTID)
672 else if (key->type == REPOKEY_TYPE_ID)
673 dp = data_read_id(dp, &id);
677 return stringpool_id2str(&data->spool, id);
678 return pool_id2str(data->repo->pool, id);
682 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
686 unsigned int high, low;
689 dp = find_key_data(data, solvid, keyname, &key);
694 case REPOKEY_TYPE_NUM:
695 data_read_num64(dp, &low, &high);
696 *value = (unsigned long long)high << 32 | low;
698 case REPOKEY_TYPE_U32:
699 data_read_u32(dp, &low);
702 case REPOKEY_TYPE_CONSTANT:
711 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
717 if (!maybe_load_repodata(data, keyname))
719 dp = solvid2data(data, solvid, &schema);
722 /* can't use find_key_data as we need to test the type */
723 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
724 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
729 const unsigned char *
730 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
735 dp = find_key_data(data, solvid, keyname, &key);
738 if (!(key->type == REPOKEY_TYPE_MD5 || key->type == REPOKEY_TYPE_SHA1 || key->type == REPOKEY_TYPE_SHA256))
745 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
753 dp = find_key_data(data, solvid, keyname, &key);
756 if (key->type != REPOKEY_TYPE_IDARRAY && key->type != REPOKEY_TYPE_REL_IDARRAY)
760 dp = data_read_ideof(dp, &id, &eof);
769 repodata_globalize_id(Repodata *data, Id id, int create)
771 if (!id || !data || !data->localpool)
773 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
777 repodata_localize_id(Repodata *data, Id id, int create)
779 if (!id || !data || !data->localpool)
781 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
785 repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
787 if (!id || !data || !fromdata)
789 if (!data->localpool || !fromdata->localpool)
791 if (fromdata->localpool)
792 id = repodata_globalize_id(fromdata, id, create);
794 id = repodata_localize_id(data, id, create);
797 /* localpool is set in both data and fromdata */
798 return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create);
802 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
807 ap = data->attrs[solvid - data->start];
812 if (data->keys[*ap].name != keyname)
814 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
816 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
824 /************************************************************************
830 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
834 case REPOKEY_TYPE_ID:
835 case REPOKEY_TYPE_CONSTANTID:
836 case REPOKEY_TYPE_IDARRAY:
837 if (data && data->localpool)
838 kv->str = stringpool_id2str(&data->spool, kv->id);
840 kv->str = pool_id2str(pool, kv->id);
841 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
844 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
846 if (*s == ':' && s > kv->str)
850 case REPOKEY_TYPE_STR:
852 case REPOKEY_TYPE_DIRSTRARRAY:
853 if (!(flags & SEARCH_FILES))
854 return 1; /* match just the basename */
856 return 1; /* already stringified */
857 /* Put the full filename into kv->str. */
858 kv->str = repodata_dir2str(data, kv->id, kv->str);
859 kv->num = 1; /* mark stringification */
861 case REPOKEY_TYPE_MD5:
862 case REPOKEY_TYPE_SHA1:
863 case REPOKEY_TYPE_SHA256:
864 if (!(flags & SEARCH_CHECKSUMS))
865 return 0; /* skip em */
867 return 1; /* already stringified */
868 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
869 kv->num = 1; /* mark stringification */
877 struct subschema_data {
883 /* search a specific repodata */
885 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
889 Id keyid, *kp, *keyp;
890 unsigned char *dp, *ddp;
896 if (!maybe_load_repodata(data, keyname))
898 if (solvid == SOLVID_SUBSCHEMA)
900 struct subschema_data *subd = cbdata;
901 cbdata = subd->cbdata;
903 schema = subd->parent->id;
904 dp = (unsigned char *)subd->parent->str;
905 kv.parent = subd->parent;
910 dp = solvid2data(data, solvid, &schema);
913 s = data->repo->pool->solvables + solvid;
916 keyp = data->schemadata + data->schemata[schema];
919 /* search for a specific key */
920 for (kp = keyp; *kp; kp++)
921 if (data->keys[*kp].name == keyname)
925 dp = forward_to_key(data, *kp, keyp, dp);
931 while ((keyid = *keyp++) != 0)
934 key = data->keys + keyid;
935 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
937 if (key->type == REPOKEY_TYPE_DELETED)
939 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
941 struct subschema_data subd;
945 subd.cbdata = cbdata;
948 ddp = data_read_id(ddp, &nentries);
952 while (ddp && nentries > 0)
956 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
957 ddp = data_read_id(ddp, &schema);
959 kv.str = (char *)ddp;
960 stop = callback(cbdata, s, data, key, &kv);
961 if (stop > SEARCH_NEXT_KEY)
963 if (stop && stop != SEARCH_ENTERSUB)
965 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
966 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
967 ddp = data_skip_schema(data, ddp, schema);
970 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
974 kv.str = (char *)ddp;
975 stop = callback(cbdata, s, data, key, &kv);
976 if (stop > SEARCH_NEXT_KEY)
986 ddp = data_fetch(ddp, &kv, key);
989 stop = callback(cbdata, s, data, key, &kv);
992 while (!kv.eof && !stop);
993 if (onekey || stop > SEARCH_NEXT_KEY)
999 repodata_setpos_kv(Repodata *data, KeyValue *kv)
1001 Pool *pool = data->repo->pool;
1003 pool_clear_pos(pool);
1006 pool->pos.repo = data->repo;
1007 pool->pos.repodataid = data - data->repo->repodata;
1008 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
1009 pool->pos.schema = kv->id;
1013 /************************************************************************
1014 * data iterator functions
1018 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1032 case SOLVABLE_VENDOR:
1035 case SOLVABLE_PROVIDES:
1037 return s->provides ? s->repo->idarraydata + s->provides : 0;
1038 case SOLVABLE_OBSOLETES:
1040 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1041 case SOLVABLE_CONFLICTS:
1043 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1044 case SOLVABLE_REQUIRES:
1046 return s->requires ? s->repo->idarraydata + s->requires : 0;
1047 case SOLVABLE_RECOMMENDS:
1049 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1050 case SOLVABLE_SUPPLEMENTS:
1052 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1053 case SOLVABLE_SUGGESTS:
1055 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1056 case SOLVABLE_ENHANCES:
1058 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1061 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1068 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1074 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1076 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1077 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1080 solv_free(ma->matchdata);
1081 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1084 if ((flags & SEARCH_FILES) != 0 && match)
1086 /* prepare basename check */
1087 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1089 const char *p = strrchr(match, '/');
1090 ma->matchdata = (void *)(p ? p + 1 : match);
1092 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1095 for (p = match + strlen(match) - 1; p >= match; p--)
1096 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1098 ma->matchdata = (void *)(p + 1);
1105 datamatcher_free(Datamatcher *ma)
1107 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1109 regfree(ma->matchdata);
1110 solv_free(ma->matchdata);
1116 datamatcher_match(Datamatcher *ma, const char *str)
1119 switch ((ma->flags & SEARCH_STRINGMASK))
1121 case SEARCH_SUBSTRING:
1122 if (ma->flags & SEARCH_NOCASE)
1123 return strcasestr(str, ma->match) != 0;
1125 return strstr(str, ma->match) != 0;
1127 if (ma->flags & SEARCH_NOCASE)
1128 return !strcasecmp(ma->match, str);
1130 return !strcmp(ma->match, str);
1131 case SEARCH_STRINGSTART:
1132 if (ma->flags & SEARCH_NOCASE)
1133 return !strncasecmp(ma->match, str, strlen(ma->match));
1135 return !strncmp(ma->match, str, strlen(ma->match));
1136 case SEARCH_STRINGEND:
1137 l = strlen(str) - strlen(ma->match);
1140 if (ma->flags & SEARCH_NOCASE)
1141 return !strcasecmp(ma->match, str + l);
1143 return !strcmp(ma->match, str + l);
1145 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1147 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1153 /* check if the matcher can match the provides basename */
1156 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1159 const char *match = ma->matchdata;
1162 switch (ma->flags & SEARCH_STRINGMASK)
1166 case SEARCH_STRINGEND:
1167 if (match != ma->match)
1168 break; /* had slash, do exact match on basename */
1171 /* check if the basename ends with match */
1172 l = strlen(basename) - strlen(match);
1178 return 1; /* maybe matches */
1180 if ((ma->flags & SEARCH_NOCASE) != 0)
1181 return !strcasecmp(match, basename);
1183 return !strcmp(match, basename);
1187 repodata_filelistfilter_matches(Repodata *data, const char *str)
1189 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1190 /* for now hardcoded */
1191 if (strstr(str, "bin/"))
1193 if (!strncmp(str, "/etc/", 5))
1195 if (!strcmp(str, "/usr/lib/sendmail"))
1217 di_nextarrayelement,
1223 di_entersolvablekey,
1227 /* see dataiterator.h for documentation */
1229 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1231 memset(di, 0, sizeof(*di));
1233 di->flags = flags & ~SEARCH_THISSOLVID;
1234 if (!pool || (repo && repo->pool != pool))
1242 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1248 di->keyname = keyname;
1249 di->keynames[0] = keyname;
1250 dataiterator_set_search(di, repo, p);
1255 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1260 if (di->dupstr == di->kv.str)
1262 di->dupstr = solv_malloc(di->dupstrn);
1263 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1271 memset(&di->matcher, 0, sizeof(di->matcher));
1272 if (from->matcher.match)
1273 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1278 for (i = 1; i < di->nparents; i++)
1279 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1280 di->kv.parent = &di->parents[di->nparents - 1].kv;
1285 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1287 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1288 datamatcher_free(&di->matcher);
1289 memset(&di->matcher, 0, sizeof(di->matcher));
1293 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1303 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1307 di->flags &= ~SEARCH_THISSOLVID;
1311 if (!di->pool->urepos)
1319 di->repo = di->pool->repos[di->repoid];
1321 di->state = di_enterrepo;
1323 dataiterator_jump_to_solvid(di, p);
1327 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1330 di->keyname = keyname;
1331 di->keynames[0] = keyname;
1335 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1339 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1341 di->state = di_bye; /* sorry */
1344 for (i = di->nkeynames + 1; i > 0; i--)
1345 di->keynames[i] = di->keynames[i - 1];
1346 di->keynames[0] = di->keyname = keyname;
1351 dataiterator_free(Dataiterator *di)
1353 if (di->matcher.match)
1354 datamatcher_free(&di->matcher);
1356 solv_free(di->dupstr);
1359 static inline unsigned char *
1360 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1362 Id *keyp = di->keyp;
1363 Repokey *keys = di->data->keys;
1366 for (keyp = di->keyp; *keyp; keyp++)
1367 if (keys[*keyp].name == keyname)
1371 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1379 dataiterator_filelistcheck(Dataiterator *di)
1382 int needcomplete = 0;
1383 Repodata *data = di->data;
1385 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1386 if (!di->matcher.match
1387 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1388 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1389 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1391 if (data->state != REPODATA_AVAILABLE)
1392 return needcomplete ? 1 : 0;
1393 for (j = 1; j < data->nkeys; j++)
1394 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1396 return j == data->nkeys && !needcomplete ? 0 : 1;
1400 dataiterator_step(Dataiterator *di)
1404 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1405 unsigned int ddpoff = di->ddp - di->vert_ddp;
1406 di->vert_off += ddpoff;
1407 di->vert_len -= ddpoff;
1408 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1409 di->vert_storestate = di->data->storestate;
1411 di->state = di_nextkey;
1417 case di_enterrepo: di_enterrepo:
1418 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1420 if (!(di->flags & SEARCH_THISSOLVID))
1422 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1423 goto di_nextsolvable;
1427 case di_entersolvable: di_entersolvable:
1430 di->repodataid = 1; /* reset repodata iterator */
1431 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)
1433 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1435 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1437 goto di_entersolvablekey;
1442 case di_enterrepodata: di_enterrepodata:
1445 if (di->repodataid >= di->repo->nrepodata)
1446 goto di_nextsolvable;
1447 di->data = di->repo->repodata + di->repodataid;
1449 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1450 goto di_nextrepodata;
1451 if (!maybe_load_repodata(di->data, di->keyname))
1452 goto di_nextrepodata;
1453 di->dp = solvid2data(di->data, di->solvid, &schema);
1455 goto di_nextrepodata;
1456 if (di->solvid == SOLVID_POS)
1457 di->solvid = di->pool->pos.solvid;
1458 /* reset key iterator */
1459 di->keyp = di->data->schemadata + di->data->schemata[schema];
1462 case di_enterschema: di_enterschema:
1464 di->dp = dataiterator_find_keyname(di, di->keyname);
1465 if (!di->dp || !*di->keyp)
1469 goto di_nextrepodata;
1473 case di_enterkey: di_enterkey:
1475 di->key = di->data->keys + *di->keyp;
1478 /* this is get_data() modified to store vert_ data */
1479 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1482 di->dp = data_read_id(di->dp, &off);
1483 di->dp = data_read_id(di->dp, &len);
1484 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1487 di->vert_storestate = di->data->storestate;
1489 else if (di->key->storage == KEY_STORAGE_INCORE)
1492 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1493 di->dp = data_skip_key(di->data, di->dp, di->key);
1499 if (di->key->type == REPOKEY_TYPE_DELETED)
1501 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1503 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1509 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1511 di->state = di_nextkey;
1513 di->state = di_nextattr;
1516 case di_nextkey: di_nextkey:
1517 if (!di->keyname && *++di->keyp)
1523 case di_nextrepodata: di_nextrepodata:
1524 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1525 goto di_enterrepodata;
1528 case di_nextsolvable: di_nextsolvable:
1529 if (!(di->flags & SEARCH_THISSOLVID))
1532 di->solvid = di->repo->start;
1535 for (; di->solvid < di->repo->end; di->solvid++)
1537 if (di->pool->solvables[di->solvid].repo == di->repo)
1538 goto di_entersolvable;
1543 case di_nextrepo: di_nextrepo:
1548 if (di->repoid < di->pool->nrepos)
1550 di->repo = di->pool->repos[di->repoid];
1556 case di_bye: di_bye:
1560 case di_enterarray: di_enterarray:
1561 if (di->key->name == REPOSITORY_SOLVABLES)
1563 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1568 case di_nextarrayelement: di_nextarrayelement:
1571 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1572 if (di->kv.entry == di->kv.num)
1574 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1576 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1578 di->kv.str = (char *)di->ddp;
1580 di->state = di_nextkey;
1583 if (di->kv.entry == di->kv.num - 1)
1585 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1586 di->ddp = data_read_id(di->ddp, &di->kv.id);
1587 di->kv.str = (char *)di->ddp;
1588 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1590 if ((di->flags & SEARCH_SUB) != 0)
1591 di->state = di_entersub;
1593 di->state = di_nextarrayelement;
1596 case di_entersub: di_entersub:
1597 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1598 goto di_nextarrayelement; /* sorry, full */
1599 di->parents[di->nparents].kv = di->kv;
1600 di->parents[di->nparents].dp = di->dp;
1601 di->parents[di->nparents].keyp = di->keyp;
1602 di->dp = (unsigned char *)di->kv.str;
1603 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1604 memset(&di->kv, 0, sizeof(di->kv));
1605 di->kv.parent = &di->parents[di->nparents].kv;
1607 di->keyname = di->keynames[di->nparents - di->rootlevel];
1608 goto di_enterschema;
1610 case di_leavesub: di_leavesub:
1611 if (di->nparents - 1 < di->rootlevel)
1614 di->dp = di->parents[di->nparents].dp;
1615 di->kv = di->parents[di->nparents].kv;
1616 di->keyp = di->parents[di->nparents].keyp;
1617 di->key = di->data->keys + *di->keyp;
1618 di->ddp = (unsigned char *)di->kv.str;
1619 di->keyname = di->keynames[di->nparents - di->rootlevel];
1620 goto di_nextarrayelement;
1622 /* special solvable attr handling follows */
1624 case di_nextsolvablekey: di_nextsolvablekey:
1625 if (di->keyname || di->key->name == RPM_RPMDBID)
1626 goto di_enterrepodata;
1630 case di_entersolvablekey: di_entersolvablekey:
1631 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1632 if (!di->idp || !*di->idp)
1633 goto di_nextsolvablekey;
1637 di->kv.id = *di->idp;
1638 di->kv.num = *di->idp; /* for rpmdbid */
1639 di->kv.num2 = 0; /* for rpmdbid */
1641 di->state = di_nextsolvablekey;
1647 case di_nextsolvableattr:
1648 di->state = di_nextsolvableattr;
1649 di->kv.id = *di->idp++;
1654 di->state = di_nextsolvablekey;
1660 if (di->matcher.match)
1662 /* simple pre-check so that we don't need to stringify */
1663 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1664 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1666 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1668 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1672 if (!datamatcher_match(&di->matcher, di->kv.str))
1677 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1678 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1680 /* found something! */
1686 dataiterator_entersub(Dataiterator *di)
1688 if (di->state == di_nextarrayelement)
1689 di->state = di_entersub;
1693 dataiterator_setpos(Dataiterator *di)
1695 if (di->kv.eof == 2)
1697 pool_clear_pos(di->pool);
1700 di->pool->pos.solvid = di->solvid;
1701 di->pool->pos.repo = di->repo;
1702 di->pool->pos.repodataid = di->data - di->repo->repodata;
1703 di->pool->pos.schema = di->kv.id;
1704 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1708 dataiterator_setpos_parent(Dataiterator *di)
1710 if (!di->kv.parent || di->kv.parent->eof == 2)
1712 pool_clear_pos(di->pool);
1715 di->pool->pos.solvid = di->solvid;
1716 di->pool->pos.repo = di->repo;
1717 di->pool->pos.repodataid = di->data - di->repo->repodata;
1718 di->pool->pos.schema = di->kv.parent->id;
1719 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1722 /* clones just the position, not the search keys/matcher */
1724 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1726 di->state = from->state;
1727 di->flags &= ~SEARCH_THISSOLVID;
1728 di->flags |= (from->flags & SEARCH_THISSOLVID);
1729 di->repo = from->repo;
1730 di->data = from->data;
1732 di->ddp = from->ddp;
1733 di->idp = from->idp;
1734 di->keyp = from->keyp;
1735 di->key = from->key;
1737 di->repodataid = from->repodataid;
1738 di->solvid = from->solvid;
1739 di->repoid = from->repoid;
1740 di->rootlevel = from->rootlevel;
1741 memcpy(di->parents, from->parents, sizeof(from->parents));
1742 di->nparents = from->nparents;
1746 for (i = 1; i < di->nparents; i++)
1747 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1748 di->kv.parent = &di->parents[di->nparents - 1].kv;
1752 if (from->dupstr && from->dupstr == from->kv.str)
1754 di->dupstrn = from->dupstrn;
1755 di->dupstr = solv_malloc(from->dupstrn);
1756 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1761 dataiterator_seek(Dataiterator *di, int whence)
1763 if ((whence & DI_SEEK_STAY) != 0)
1764 di->rootlevel = di->nparents;
1765 switch (whence & ~DI_SEEK_STAY)
1768 if (di->state != di_nextarrayelement)
1770 if ((whence & DI_SEEK_STAY) != 0)
1771 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1772 di->state = di_entersub;
1774 case DI_SEEK_PARENT:
1781 if (di->rootlevel > di->nparents)
1782 di->rootlevel = di->nparents;
1783 di->dp = di->parents[di->nparents].dp;
1784 di->kv = di->parents[di->nparents].kv;
1785 di->keyp = di->parents[di->nparents].keyp;
1786 di->key = di->data->keys + *di->keyp;
1787 di->ddp = (unsigned char *)di->kv.str;
1788 di->keyname = di->keynames[di->nparents - di->rootlevel];
1789 di->state = di_nextarrayelement;
1791 case DI_SEEK_REWIND:
1797 di->dp = (unsigned char *)di->kv.parent->str;
1798 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1799 di->state = di_enterschema;
1807 dataiterator_skip_attribute(Dataiterator *di)
1809 if (di->state == di_nextsolvableattr)
1810 di->state = di_nextsolvablekey;
1812 di->state = di_nextkey;
1816 dataiterator_skip_solvable(Dataiterator *di)
1821 di->keyname = di->keynames[0];
1822 di->state = di_nextsolvable;
1826 dataiterator_skip_repo(Dataiterator *di)
1831 di->keyname = di->keynames[0];
1832 di->state = di_nextrepo;
1836 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1841 di->keyname = di->keynames[0];
1842 if (solvid == SOLVID_POS)
1844 di->repo = di->pool->pos.repo;
1851 di->data = di->repo->repodata + di->pool->pos.repodataid;
1853 di->solvid = solvid;
1854 di->state = di_enterrepo;
1855 di->flags |= SEARCH_THISSOLVID;
1860 di->repo = di->pool->solvables[solvid].repo;
1863 else if (di->repoid > 0)
1865 if (!di->pool->urepos)
1871 di->repo = di->pool->repos[di->repoid];
1874 di->solvid = solvid;
1876 di->flags |= SEARCH_THISSOLVID;
1877 di->state = di_enterrepo;
1881 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1887 di->repoid = 0; /* 0 means stay at repo */
1890 di->flags &= ~SEARCH_THISSOLVID;
1891 di->state = di_enterrepo;
1895 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1897 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1901 return datamatcher_match(ma, di->kv.str);
1905 dataiterator_strdup(Dataiterator *di)
1909 if (!di->kv.str || di->kv.str == di->dupstr)
1911 switch (di->key->type)
1913 case REPOKEY_TYPE_MD5:
1914 case REPOKEY_TYPE_SHA1:
1915 case REPOKEY_TYPE_SHA256:
1916 case REPOKEY_TYPE_DIRSTRARRAY:
1917 if (di->kv.num) /* was it stringified into tmp space? */
1918 l = strlen(di->kv.str) + 1;
1923 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1925 switch (di->key->type)
1927 case REPOKEY_TYPE_STR:
1928 case REPOKEY_TYPE_DIRSTRARRAY:
1929 l = strlen(di->kv.str) + 1;
1931 case REPOKEY_TYPE_MD5:
1934 case REPOKEY_TYPE_SHA1:
1937 case REPOKEY_TYPE_SHA256:
1940 case REPOKEY_TYPE_BINARY:
1947 if (!di->dupstrn || di->dupstrn < l)
1949 di->dupstrn = l + 16;
1950 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
1953 memcpy(di->dupstr, di->kv.str, l);
1954 di->kv.str = di->dupstr;
1958 /************************************************************************
1959 * data modify functions
1962 /* extend repodata so that it includes solvables p */
1964 repodata_extend(Repodata *data, Id p)
1966 if (data->start == data->end)
1967 data->start = data->end = p;
1970 int old = data->end - data->start;
1971 int new = p - data->end + 1;
1974 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1975 memset(data->attrs + old, 0, new * sizeof(Id *));
1977 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1978 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1981 if (p < data->start)
1983 int old = data->end - data->start;
1984 int new = data->start - p;
1987 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1988 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1989 memset(data->attrs, 0, new * sizeof(Id *));
1991 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1992 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1993 memset(data->incoreoffset, 0, new * sizeof(Id));
1998 /* shrink end of repodata */
2000 repodata_shrink(Repodata *data, int end)
2004 if (data->end <= end)
2006 if (data->start >= end)
2010 for (i = 0; i < data->end - data->start; i++)
2011 solv_free(data->attrs[i]);
2012 data->attrs = solv_free(data->attrs);
2014 data->incoreoffset = solv_free(data->incoreoffset);
2015 data->start = data->end = 0;
2020 for (i = end; i < data->end; i++)
2021 solv_free(data->attrs[i - data->start]);
2022 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2024 if (data->incoreoffset)
2025 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2029 /* extend repodata so that it includes solvables from start to start + num - 1 */
2031 repodata_extend_block(Repodata *data, Id start, Id num)
2035 if (!data->incoreoffset)
2037 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2038 data->start = start;
2039 data->end = start + num;
2042 repodata_extend(data, start);
2044 repodata_extend(data, start + num - 1);
2047 /**********************************************************************/
2050 #define REPODATA_ATTRS_BLOCK 31
2051 #define REPODATA_ATTRDATA_BLOCK 1023
2052 #define REPODATA_ATTRIDDATA_BLOCK 63
2053 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2057 repodata_new_handle(Repodata *data)
2061 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2062 data->nxattrs = 2; /* -1: SOLVID_META */
2064 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2065 data->xattrs[data->nxattrs] = 0;
2066 return -(data->nxattrs++);
2070 repodata_get_attrp(Repodata *data, Id handle)
2074 if (handle == SOLVID_META && !data->xattrs)
2076 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2079 return data->xattrs - handle;
2081 if (handle < data->start || handle >= data->end)
2082 repodata_extend(data, handle);
2084 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2085 return data->attrs + (handle - data->start);
2089 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2095 app = repodata_get_attrp(data, handle);
2100 /* Determine equality based on the name only, allows us to change
2101 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2102 for (pp = ap; *pp; pp += 2)
2103 if (data->keys[*pp].name == data->keys[keyid].name)
2107 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2116 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2126 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2130 keyid = repodata_key2id(data, key, 1);
2131 repodata_insert_keyid(data, solvid, keyid, val, 1);
2135 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2139 key.type = REPOKEY_TYPE_ID;
2141 key.storage = KEY_STORAGE_INCORE;
2142 repodata_set(data, solvid, &key, id);
2146 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2150 key.type = REPOKEY_TYPE_NUM;
2152 key.storage = KEY_STORAGE_INCORE;
2153 if (num >= 0x80000000)
2155 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2156 data->attrnum64data[data->attrnum64datalen] = num;
2157 num = 0x80000000 | data->attrnum64datalen++;
2159 repodata_set(data, solvid, &key, (Id)num);
2163 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2167 if (data->localpool)
2168 id = stringpool_str2id(&data->spool, str, 1);
2170 id = pool_str2id(data->repo->pool, str, 1);
2172 key.type = REPOKEY_TYPE_ID;
2174 key.storage = KEY_STORAGE_INCORE;
2175 repodata_set(data, solvid, &key, id);
2179 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2183 key.type = REPOKEY_TYPE_CONSTANT;
2184 key.size = constant;
2185 key.storage = KEY_STORAGE_INCORE;
2186 repodata_set(data, solvid, &key, 0);
2190 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2194 key.type = REPOKEY_TYPE_CONSTANTID;
2196 key.storage = KEY_STORAGE_INCORE;
2197 repodata_set(data, solvid, &key, 0);
2201 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2205 key.type = REPOKEY_TYPE_VOID;
2207 key.storage = KEY_STORAGE_INCORE;
2208 repodata_set(data, solvid, &key, 0);
2212 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2217 l = strlen(str) + 1;
2219 key.type = REPOKEY_TYPE_STR;
2221 key.storage = KEY_STORAGE_INCORE;
2222 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2223 memcpy(data->attrdata + data->attrdatalen, str, l);
2224 repodata_set(data, solvid, &key, data->attrdatalen);
2225 data->attrdatalen += l;
2229 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2237 key.type = REPOKEY_TYPE_BINARY;
2239 key.storage = KEY_STORAGE_INCORE;
2240 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2241 dp = data->attrdata + data->attrdatalen;
2242 if (len >= (1 << 14))
2244 if (len >= (1 << 28))
2245 *dp++ = (len >> 28) | 128;
2246 if (len >= (1 << 21))
2247 *dp++ = (len >> 21) | 128;
2248 *dp++ = (len >> 14) | 128;
2250 if (len >= (1 << 7))
2251 *dp++ = (len >> 7) | 128;
2254 memcpy(dp, buf, len);
2255 repodata_set(data, solvid, &key, data->attrdatalen);
2256 data->attrdatalen = dp + len - data->attrdata;
2259 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2260 * so that the caller can append entrysize new elements plus the termination zero there */
2262 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2265 Id *ida, *pp, **ppp;
2267 /* check if it is the same as last time, this speeds things up a lot */
2268 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2270 /* great! just append the new data */
2271 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2272 data->attriddatalen--; /* overwrite terminating 0 */
2273 data->lastdatalen += entrysize;
2277 ppp = repodata_get_attrp(data, handle);
2281 for (; *pp; pp += 2)
2282 if (data->keys[*pp].name == keyname)
2285 if (!pp || !*pp || data->keys[*pp].type != keytype)
2287 /* not found. allocate new key */
2293 key.storage = KEY_STORAGE_INCORE;
2294 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2295 keyid = repodata_key2id(data, &key, 1);
2296 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2297 data->lasthandle = handle;
2298 data->lastkey = keyid;
2299 data->lastdatalen = data->attriddatalen + entrysize + 1;
2303 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2304 oldsize += entrysize;
2305 if (ida + 1 == data->attriddata + data->attriddatalen)
2307 /* this was the last entry, just append it */
2308 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2309 data->attriddatalen--; /* overwrite terminating 0 */
2313 /* too bad. move to back. */
2314 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2315 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2316 pp[1] = data->attriddatalen;
2317 data->attriddatalen += oldsize;
2319 data->lasthandle = handle;
2320 data->lastkey = *pp;
2321 data->lastdatalen = data->attriddatalen + entrysize + 1;
2325 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2326 const unsigned char *str)
2331 if (!(l = solv_chksum_len(type)))
2336 key.storage = KEY_STORAGE_INCORE;
2337 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2338 memcpy(data->attrdata + data->attrdatalen, str, l);
2339 repodata_set(data, solvid, &key, data->attrdatalen);
2340 data->attrdatalen += l;
2344 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2347 unsigned char buf[64];
2350 if (!(l = solv_chksum_len(type)))
2352 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2354 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2358 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2362 if (!(l = solv_chksum_len(type)))
2364 return pool_bin2hex(data->repo->pool, buf, l);
2367 /* rpm filenames don't contain the epoch, so strip it */
2368 static inline const char *
2369 evrid2vrstr(Pool *pool, Id evrid)
2371 const char *p, *evr = pool_id2str(pool, evrid);
2374 for (p = evr; *p >= '0' && *p <= '9'; p++)
2376 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2380 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2383 if (data->localpool)
2384 id = stringpool_strn2id(&data->spool, str, l, 1);
2386 id = pool_strn2id(data->repo->pool, str, l, 1);
2387 repodata_set_id(data, solvid, keyname, id);
2391 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2394 repodata_set_str(data, solvid, keyname, str);
2397 char *s = solv_strdup(str);
2399 repodata_set_str(data, solvid, keyname, s);
2405 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2407 Pool *pool = data->repo->pool;
2409 const char *str, *fp;
2413 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2416 if ((dir = strrchr(file, '/')) != 0)
2427 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2432 if (l == 1 && dir[0] == '.')
2434 s = pool->solvables + solvid;
2437 str = pool_id2str(pool, s->arch);
2438 if (!strncmp(dir, str, l) && !str[l])
2439 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2441 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2444 str = pool_id2str(pool, s->name);
2446 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2449 str = evrid2vrstr(pool, s->evr);
2451 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2454 str = pool_id2str(pool, s->arch);
2456 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2458 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2463 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2466 /* XXX: medianr is currently not stored */
2468 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2471 const char *evr, *suf, *s;
2475 if ((dir = strrchr(file, '/')) != 0)
2486 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2491 if (l == 1 && dir[0] == '.')
2494 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2495 evr = strchr(file, '-');
2498 for (s = evr - 1; s > file; s--)
2505 suf = strrchr(file, '.');
2508 for (s = suf - 1; s > file; s--)
2514 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2516 /* We accept one more item as suffix. */
2517 for (s = suf - 1; s > file; s--)
2527 if (suf && evr && suf < evr)
2529 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2531 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2533 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2537 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2539 Pool *pool = data->repo->pool;
2540 Solvable *s = pool->solvables + solvid;
2541 const char *p, *sevr, *sarch, *name, *evr;
2543 p = strrchr(sourcepkg, '.');
2544 if (!p || strcmp(p, ".rpm") != 0)
2547 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2551 while (p > sourcepkg && *p != '.')
2553 if (*p != '.' || p == sourcepkg)
2556 while (p > sourcepkg && *p != '-')
2558 if (*p != '-' || p == sourcepkg)
2561 while (p > sourcepkg && *p != '-')
2563 if (*p != '-' || p == sourcepkg)
2566 pool = s->repo->pool;
2568 name = pool_id2str(pool, s->name);
2569 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2570 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2572 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2574 evr = evrid2vrstr(pool, s->evr);
2575 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2576 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2578 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2580 if (!strcmp(sarch, "src.rpm"))
2581 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2582 else if (!strcmp(sarch, "nosrc.rpm"))
2583 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2585 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2589 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2595 key.type = REPOKEY_TYPE_IDARRAY;
2597 key.storage = KEY_STORAGE_INCORE;
2598 repodata_set(data, solvid, &key, data->attriddatalen);
2599 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2600 for (i = 0; i < q->count; i++)
2601 data->attriddata[data->attriddatalen++] = q->elements[i];
2602 data->attriddata[data->attriddatalen++] = 0;
2606 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2610 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2612 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2613 data->attriddata[data->attriddatalen++] = dir;
2614 data->attriddata[data->attriddatalen++] = num;
2615 data->attriddata[data->attriddatalen++] = num2;
2616 data->attriddata[data->attriddatalen++] = 0;
2620 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2626 l = strlen(str) + 1;
2627 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2628 memcpy(data->attrdata + data->attrdatalen, str, l);
2629 stroff = data->attrdatalen;
2630 data->attrdatalen += l;
2633 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2635 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2636 data->attriddata[data->attriddatalen++] = dir;
2637 data->attriddata[data->attriddatalen++] = stroff;
2638 data->attriddata[data->attriddatalen++] = 0;
2642 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2645 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2647 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2648 data->attriddata[data->attriddatalen++] = id;
2649 data->attriddata[data->attriddatalen++] = 0;
2653 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2657 if (data->localpool)
2658 id = stringpool_str2id(&data->spool, str, 1);
2660 id = pool_str2id(data->repo->pool, str, 1);
2661 repodata_add_idarray(data, solvid, keyname, id);
2665 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2667 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2668 data->attriddata[data->attriddatalen++] = ghandle;
2669 data->attriddata[data->attriddatalen++] = 0;
2673 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2675 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2676 data->attriddata[data->attriddatalen++] = ghandle;
2677 data->attriddata[data->attriddatalen++] = 0;
2681 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2684 app = repodata_get_attrp(data, solvid);
2688 for (; *ap; ap += 2)
2689 if (data->keys[*ap].name == keyname)
2695 for (; *ap; ap += 2)
2697 if (data->keys[*ap].name == keyname)
2705 /* XXX: does not work correctly, needs fix in iterators! */
2707 repodata_unset(Repodata *data, Id solvid, Id keyname)
2711 key.type = REPOKEY_TYPE_DELETED;
2713 key.storage = KEY_STORAGE_INCORE;
2714 repodata_set(data, solvid, &key, 0);
2717 /* add all (uninternalized) attrs from src to dest */
2719 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2722 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2724 for (; *keyp; keyp += 2)
2725 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2728 /* add some (uninternalized) attrs from src to dest */
2730 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2733 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2735 for (; *keyp; keyp += 2)
2736 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2737 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2740 /* swap (uninternalized) attrs from src and dest */
2742 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2745 if (!data->attrs || dest == src)
2747 tmpattrs = data->attrs[dest - data->start];
2748 data->attrs[dest - data->start] = data->attrs[src - data->start];
2749 data->attrs[src - data->start] = tmpattrs;
2753 /**********************************************************************/
2755 /* TODO: unify with repo_write and repo_solv! */
2757 #define EXTDATA_BLOCK 1023
2765 data_addid(struct extdata *xd, Id sx)
2767 unsigned int x = (unsigned int)sx;
2770 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2771 dp = xd->buf + xd->len;
2776 *dp++ = (x >> 28) | 128;
2778 *dp++ = (x >> 21) | 128;
2779 *dp++ = (x >> 14) | 128;
2782 *dp++ = (x >> 7) | 128;
2784 xd->len = dp - xd->buf;
2788 data_addid64(struct extdata *xd, unsigned long long x)
2790 if (x >= 0x100000000)
2794 data_addid(xd, (Id)(x >> 35));
2795 xd->buf[xd->len - 1] |= 128;
2797 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2798 xd->buf[xd->len - 5] = (x >> 28) | 128;
2801 data_addid(xd, (Id)x);
2805 data_addideof(struct extdata *xd, Id sx, int eof)
2807 unsigned int x = (unsigned int)sx;
2810 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2811 dp = xd->buf + xd->len;
2816 *dp++ = (x >> 27) | 128;
2818 *dp++ = (x >> 20) | 128;
2819 *dp++ = (x >> 13) | 128;
2822 *dp++ = (x >> 6) | 128;
2823 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2824 xd->len = dp - xd->buf;
2828 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2830 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2831 memcpy(xd->buf + xd->len, blob, len);
2835 /*********************************/
2837 /* internalalize some key into incore/vincore data */
2840 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2841 struct extdata *newvincore,
2843 Repokey *key, Id val)
2847 unsigned int oldvincorelen = 0;
2851 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2854 oldvincorelen = xd->len;
2858 case REPOKEY_TYPE_VOID:
2859 case REPOKEY_TYPE_CONSTANT:
2860 case REPOKEY_TYPE_CONSTANTID:
2862 case REPOKEY_TYPE_STR:
2863 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2865 case REPOKEY_TYPE_MD5:
2866 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2868 case REPOKEY_TYPE_SHA1:
2869 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2871 case REPOKEY_TYPE_SHA256:
2872 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2874 case REPOKEY_TYPE_NUM:
2875 if (val & 0x80000000)
2877 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2881 case REPOKEY_TYPE_ID:
2882 case REPOKEY_TYPE_DIR:
2883 data_addid(xd, val);
2885 case REPOKEY_TYPE_BINARY:
2888 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2889 dp += (unsigned int)len;
2890 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2893 case REPOKEY_TYPE_IDARRAY:
2894 for (ida = data->attriddata + val; *ida; ida++)
2895 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2897 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2898 for (ida = data->attriddata + val; *ida; ida += 3)
2900 data_addid(xd, ida[0]);
2901 data_addid(xd, ida[1]);
2902 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2905 case REPOKEY_TYPE_DIRSTRARRAY:
2906 for (ida = data->attriddata + val; *ida; ida += 2)
2908 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2909 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2912 case REPOKEY_TYPE_FIXARRAY:
2916 for (ida = data->attriddata + val; *ida; ida++)
2920 kp = data->xattrs[-*ida];
2928 schemaid = repodata_schema2id(data, schema, 1);
2929 else if (schemaid != repodata_schema2id(data, schema, 0))
2931 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2937 data_addid(xd, num);
2938 data_addid(xd, schemaid);
2939 for (ida = data->attriddata + val; *ida; ida++)
2941 Id *kp = data->xattrs[-*ida];
2945 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2949 case REPOKEY_TYPE_FLEXARRAY:
2952 for (ida = data->attriddata + val; *ida; ida++)
2954 data_addid(xd, num);
2955 for (ida = data->attriddata + val; *ida; ida++)
2957 Id *kp = data->xattrs[-*ida];
2960 data_addid(xd, 0); /* XXX */
2967 schemaid = repodata_schema2id(data, schema, 1);
2968 data_addid(xd, schemaid);
2969 kp = data->xattrs[-*ida];
2971 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2976 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2979 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2981 /* put offset/len in incore */
2982 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2983 oldvincorelen = xd->len - oldvincorelen;
2984 data_addid(newincore, oldvincorelen);
2989 repodata_internalize(Repodata *data)
2991 Repokey *key, solvkey;
2993 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2994 unsigned char *dp, *ndp;
2995 int newschema, oldcount;
2996 struct extdata newincore;
2997 struct extdata newvincore;
3000 if (!data->attrs && !data->xattrs)
3003 newvincore.buf = data->vincore;
3004 newvincore.len = data->vincorelen;
3006 /* find the solvables key, create if needed */
3007 memset(&solvkey, 0, sizeof(solvkey));
3008 solvkey.name = REPOSITORY_SOLVABLES;
3009 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3011 solvkey.storage = KEY_STORAGE_INCORE;
3012 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3014 schema = solv_malloc2(data->nkeys, sizeof(Id));
3015 seen = solv_malloc2(data->nkeys, sizeof(Id));
3017 /* Merge the data already existing (in data->schemata, ->incoredata and
3018 friends) with the new attributes in data->attrs[]. */
3019 nentry = data->end - data->start;
3020 memset(&newincore, 0, sizeof(newincore));
3021 data_addid(&newincore, 0); /* start data at offset 1 */
3023 data->mainschema = 0;
3024 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3026 /* join entry data */
3027 /* we start with the meta data, entry -1 */
3028 for (entry = -1; entry < nentry; entry++)
3030 memset(seen, 0, data->nkeys * sizeof(Id));
3032 dp = data->incoredata;
3035 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3036 dp = data_read_id(dp, &oldschema);
3039 fprintf(stderr, "oldschema %d\n", oldschema);
3040 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3041 fprintf(stderr, "schemadata %p\n", data->schemadata);
3043 /* seen: -1: old data 0: skipped >0: id + 1 */
3047 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3051 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3059 keyp = data->attrs ? data->attrs[entry] : 0;
3062 /* strip solvables key */
3064 for (sp = keyp = schema; *sp; sp++)
3065 if (*sp != solvkeyid)
3070 seen[solvkeyid] = 0;
3071 keyp = data->xattrs ? data->xattrs[1] : 0;
3074 for (; *keyp; keyp += 2)
3081 seen[*keyp] = keyp[1] + 1;
3083 if (entry < 0 && data->end != data->start)
3090 /* Ideally we'd like to sort the new schema here, to ensure
3091 schema equality independend of the ordering. We can't do that
3092 yet. For once see below (old ids need to come before new ids).
3093 An additional difficulty is that we also need to move
3094 the values with the keys. */
3095 schemaid = repodata_schema2id(data, schema, 1);
3097 schemaid = oldschema;
3100 /* Now create data blob. We walk through the (possibly new) schema
3101 and either copy over old data, or insert the new. */
3102 /* XXX Here we rely on the fact that the (new) schema has the form
3103 o1 o2 o3 o4 ... | n1 n2 n3 ...
3104 (oX being the old keyids (possibly overwritten), and nX being
3105 the new keyids). This rules out sorting the keyids in order
3106 to ensure a small schema count. */
3108 data->incoreoffset[entry] = newincore.len;
3109 data_addid(&newincore, schemaid);
3112 data->mainschema = schemaid;
3113 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3115 keypstart = data->schemadata + data->schemata[schemaid];
3116 for (keyp = keypstart; *keyp; keyp++)
3119 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3120 if (*keyp == solvkeyid)
3122 /* add flexarray entry count */
3123 data_addid(&newincore, data->end - data->start);
3126 key = data->keys + *keyp;
3128 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));
3133 /* Skip the data associated with this old key. */
3134 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3136 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3137 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3139 else if (key->storage == KEY_STORAGE_INCORE)
3140 ndp = data_skip_key(data, dp, key);
3143 if (seen[*keyp] == -1)
3145 /* If this key was an old one _and_ was not overwritten with
3146 a different value copy over the old value (we skipped it
3149 data_addblob(&newincore, dp, ndp - dp);
3152 else if (seen[*keyp])
3154 /* Otherwise we have a new value. Parse it into the internal
3156 repodata_serialize_key(data, &newincore, &newvincore,
3157 schema, key, seen[*keyp] - 1);
3161 if (entry >= 0 && data->attrs && data->attrs[entry])
3162 data->attrs[entry] = solv_free(data->attrs[entry]);
3164 /* free all xattrs */
3165 for (entry = 0; entry < data->nxattrs; entry++)
3166 if (data->xattrs[entry])
3167 solv_free(data->xattrs[entry]);
3168 data->xattrs = solv_free(data->xattrs);
3171 data->lasthandle = 0;
3173 data->lastdatalen = 0;
3176 repodata_free_schemahash(data);
3178 solv_free(data->incoredata);
3179 data->incoredata = newincore.buf;
3180 data->incoredatalen = newincore.len;
3181 data->incoredatafree = 0;
3183 solv_free(data->vincore);
3184 data->vincore = newvincore.buf;
3185 data->vincorelen = newvincore.len;
3187 data->attrs = solv_free(data->attrs);
3188 data->attrdata = solv_free(data->attrdata);
3189 data->attriddata = solv_free(data->attriddata);
3190 data->attrnum64data = solv_free(data->attrnum64data);
3191 data->attrdatalen = 0;
3192 data->attriddatalen = 0;
3193 data->attrnum64datalen = 0;
3197 repodata_disable_paging(Repodata *data)
3199 if (maybe_load_repodata(data, 0))
3201 repopagestore_disable_paging(&data->store);
3207 repodata_load_stub(Repodata *data)
3209 Repo *repo = data->repo;
3210 Pool *pool = repo->pool;
3212 struct _Pool_tmpspace oldtmpspace;
3214 if (!pool->loadcallback)
3216 data->state = REPODATA_ERROR;
3219 data->state = REPODATA_LOADING;
3221 /* save tmp space */
3222 oldtmpspace = pool->tmpspace;
3223 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3225 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3227 /* restore tmp space */
3228 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3229 solv_free(pool->tmpspace.buf[i]);
3230 pool->tmpspace = oldtmpspace;
3232 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3236 repodata_create_stubs(Repodata *data)
3238 Repo *repo = data->repo;
3239 Pool *pool = repo->pool;
3246 int datastart, dataend;
3248 repodataid = data - repo->repodata;
3249 datastart = data->start;
3250 dataend = data->end;
3251 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3252 while (dataiterator_step(&di))
3254 if (di.data - repo->repodata != repodataid)
3258 dataiterator_free(&di);
3261 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3262 for (i = 0; i < cnt; i++)
3264 sdata = repo_add_repodata(repo, 0);
3265 if (dataend > datastart)
3266 repodata_extend_block(sdata, datastart, dataend - datastart);
3267 stubdataids[i] = sdata - repo->repodata;
3268 sdata->state = REPODATA_STUB;
3269 sdata->loadcallback = repodata_load_stub;
3272 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3274 while (dataiterator_step(&di))
3276 if (di.data - repo->repodata != repodataid)
3278 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3280 dataiterator_entersub(&di);
3281 sdata = repo->repodata + stubdataids[i++];
3285 switch (di.key->type)
3287 case REPOKEY_TYPE_ID:
3288 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3290 case REPOKEY_TYPE_CONSTANTID:
3291 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3293 case REPOKEY_TYPE_STR:
3294 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3296 case REPOKEY_TYPE_VOID:
3297 repodata_set_void(sdata, SOLVID_META, di.key->name);
3299 case REPOKEY_TYPE_NUM:
3300 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3302 case REPOKEY_TYPE_MD5:
3303 case REPOKEY_TYPE_SHA1:
3304 case REPOKEY_TYPE_SHA256:
3305 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3307 case REPOKEY_TYPE_IDARRAY:
3308 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3309 if (di.key->name == REPOSITORY_KEYS)
3316 xkeyname = di.kv.id;
3319 xkey.name = xkeyname;
3320 xkey.type = di.kv.id;
3321 xkey.storage = KEY_STORAGE_INCORE;
3323 repodata_key2id(sdata, &xkey, 1);
3330 dataiterator_free(&di);
3331 for (i = 0; i < cnt; i++)
3332 repodata_internalize(repo->repodata + stubdataids[i]);
3333 solv_free(stubdataids);
3337 repodata_memused(Repodata *data)
3339 return data->incoredatalen + data->vincorelen;
3343 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: