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)
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_globalize_id(Repodata *data, Id id, int create)
775 if (!id || !data || !data->localpool)
777 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
781 repodata_localize_id(Repodata *data, Id id, int create)
783 if (!id || !data || !data->localpool)
785 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
789 repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
791 if (!id || !data || !fromdata)
793 if (!data->localpool || !fromdata->localpool)
795 if (fromdata->localpool)
796 id = repodata_globalize_id(fromdata, id, create);
798 id = repodata_localize_id(data, id, create);
801 /* localpool is set in both data and fromdata */
802 return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create);
806 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
811 ap = data->attrs[solvid - data->start];
816 if (data->keys[*ap].name != keyname)
818 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
820 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
828 /************************************************************************
834 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
838 case REPOKEY_TYPE_ID:
839 case REPOKEY_TYPE_CONSTANTID:
840 case REPOKEY_TYPE_IDARRAY:
841 if (data && data->localpool)
842 kv->str = stringpool_id2str(&data->spool, kv->id);
844 kv->str = pool_id2str(pool, kv->id);
845 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
848 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
850 if (*s == ':' && s > kv->str)
854 case REPOKEY_TYPE_STR:
856 case REPOKEY_TYPE_DIRSTRARRAY:
857 if (!(flags & SEARCH_FILES))
858 return 1; /* match just the basename */
860 return 1; /* already stringified */
861 /* Put the full filename into kv->str. */
862 kv->str = repodata_dir2str(data, kv->id, kv->str);
863 kv->num = 1; /* mark stringification */
865 case REPOKEY_TYPE_MD5:
866 case REPOKEY_TYPE_SHA1:
867 case REPOKEY_TYPE_SHA256:
868 if (!(flags & SEARCH_CHECKSUMS))
869 return 0; /* skip em */
871 return 1; /* already stringified */
872 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
873 kv->num = 1; /* mark stringification */
881 struct subschema_data {
887 /* search a specific repodata */
889 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
893 Id keyid, *kp, *keyp;
894 unsigned char *dp, *ddp;
900 if (!maybe_load_repodata(data, keyname))
902 if (solvid == SOLVID_SUBSCHEMA)
904 struct subschema_data *subd = cbdata;
905 cbdata = subd->cbdata;
907 schema = subd->parent->id;
908 dp = (unsigned char *)subd->parent->str;
909 kv.parent = subd->parent;
914 dp = solvid2data(data, solvid, &schema);
917 s = data->repo->pool->solvables + solvid;
920 keyp = data->schemadata + data->schemata[schema];
923 /* search for a specific key */
924 for (kp = keyp; *kp; kp++)
925 if (data->keys[*kp].name == keyname)
929 dp = forward_to_key(data, *kp, keyp, dp);
935 while ((keyid = *keyp++) != 0)
938 key = data->keys + keyid;
939 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
941 if (key->type == REPOKEY_TYPE_DELETED)
943 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
945 struct subschema_data subd;
949 subd.cbdata = cbdata;
952 ddp = data_read_id(ddp, &nentries);
956 while (ddp && nentries > 0)
960 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
961 ddp = data_read_id(ddp, &schema);
963 kv.str = (char *)ddp;
964 stop = callback(cbdata, s, data, key, &kv);
965 if (stop > SEARCH_NEXT_KEY)
967 if (stop && stop != SEARCH_ENTERSUB)
969 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
970 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
971 ddp = data_skip_schema(data, ddp, schema);
974 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
978 kv.str = (char *)ddp;
979 stop = callback(cbdata, s, data, key, &kv);
980 if (stop > SEARCH_NEXT_KEY)
990 ddp = data_fetch(ddp, &kv, key);
993 stop = callback(cbdata, s, data, key, &kv);
996 while (!kv.eof && !stop);
997 if (onekey || stop > SEARCH_NEXT_KEY)
1003 repodata_setpos_kv(Repodata *data, KeyValue *kv)
1005 Pool *pool = data->repo->pool;
1007 pool_clear_pos(pool);
1010 pool->pos.repo = data->repo;
1011 pool->pos.repodataid = data - data->repo->repodata;
1012 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
1013 pool->pos.schema = kv->id;
1017 /************************************************************************
1018 * data iterator functions
1022 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1036 case SOLVABLE_VENDOR:
1039 case SOLVABLE_PROVIDES:
1041 return s->provides ? s->repo->idarraydata + s->provides : 0;
1042 case SOLVABLE_OBSOLETES:
1044 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1045 case SOLVABLE_CONFLICTS:
1047 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1048 case SOLVABLE_REQUIRES:
1050 return s->requires ? s->repo->idarraydata + s->requires : 0;
1051 case SOLVABLE_RECOMMENDS:
1053 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1054 case SOLVABLE_SUPPLEMENTS:
1056 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1057 case SOLVABLE_SUGGESTS:
1059 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1060 case SOLVABLE_ENHANCES:
1062 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1065 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1072 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1074 ma->match = match ? solv_strdup(match) : 0;
1078 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1080 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1081 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1084 solv_free(ma->matchdata);
1085 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1088 if ((flags & SEARCH_FILES) != 0 && match)
1090 /* prepare basename check */
1091 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1093 const char *p = strrchr(match, '/');
1094 ma->matchdata = (void *)(p ? p + 1 : match);
1096 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1099 for (p = match + strlen(match) - 1; p >= match; p--)
1100 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1102 ma->matchdata = (void *)(p + 1);
1109 datamatcher_free(Datamatcher *ma)
1112 ma->match = solv_free((char *)ma->match);
1113 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1115 regfree(ma->matchdata);
1116 solv_free(ma->matchdata);
1122 datamatcher_match(Datamatcher *ma, const char *str)
1125 switch ((ma->flags & SEARCH_STRINGMASK))
1127 case SEARCH_SUBSTRING:
1128 if (ma->flags & SEARCH_NOCASE)
1129 return strcasestr(str, ma->match) != 0;
1131 return strstr(str, ma->match) != 0;
1133 if (ma->flags & SEARCH_NOCASE)
1134 return !strcasecmp(ma->match, str);
1136 return !strcmp(ma->match, str);
1137 case SEARCH_STRINGSTART:
1138 if (ma->flags & SEARCH_NOCASE)
1139 return !strncasecmp(ma->match, str, strlen(ma->match));
1141 return !strncmp(ma->match, str, strlen(ma->match));
1142 case SEARCH_STRINGEND:
1143 l = strlen(str) - strlen(ma->match);
1146 if (ma->flags & SEARCH_NOCASE)
1147 return !strcasecmp(ma->match, str + l);
1149 return !strcmp(ma->match, str + l);
1151 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1153 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1159 /* check if the matcher can match the provides basename */
1162 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1165 const char *match = ma->matchdata;
1168 switch (ma->flags & SEARCH_STRINGMASK)
1172 case SEARCH_STRINGEND:
1173 if (match != ma->match)
1174 break; /* had slash, do exact match on basename */
1177 /* check if the basename ends with match */
1178 l = strlen(basename) - strlen(match);
1184 return 1; /* maybe matches */
1186 if ((ma->flags & SEARCH_NOCASE) != 0)
1187 return !strcasecmp(match, basename);
1189 return !strcmp(match, basename);
1193 repodata_filelistfilter_matches(Repodata *data, const char *str)
1195 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1196 /* for now hardcoded */
1197 if (strstr(str, "bin/"))
1199 if (!strncmp(str, "/etc/", 5))
1201 if (!strcmp(str, "/usr/lib/sendmail"))
1223 di_nextarrayelement,
1229 di_entersolvablekey,
1233 /* see dataiterator.h for documentation */
1235 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1237 memset(di, 0, sizeof(*di));
1239 di->flags = flags & ~SEARCH_THISSOLVID;
1240 if (!pool || (repo && repo->pool != pool))
1248 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1254 di->keyname = keyname;
1255 di->keynames[0] = keyname;
1256 dataiterator_set_search(di, repo, p);
1261 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1266 if (di->dupstr == di->kv.str)
1268 di->dupstr = solv_malloc(di->dupstrn);
1269 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1277 memset(&di->matcher, 0, sizeof(di->matcher));
1278 if (from->matcher.match)
1279 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1284 for (i = 1; i < di->nparents; i++)
1285 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1286 di->kv.parent = &di->parents[di->nparents - 1].kv;
1291 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1293 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1294 datamatcher_free(&di->matcher);
1295 memset(&di->matcher, 0, sizeof(di->matcher));
1299 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1309 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1313 di->flags &= ~SEARCH_THISSOLVID;
1317 if (!di->pool->urepos)
1325 di->repo = di->pool->repos[di->repoid];
1327 di->state = di_enterrepo;
1329 dataiterator_jump_to_solvid(di, p);
1333 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1336 di->keyname = keyname;
1337 di->keynames[0] = keyname;
1341 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1345 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1347 di->state = di_bye; /* sorry */
1350 for (i = di->nkeynames + 1; i > 0; i--)
1351 di->keynames[i] = di->keynames[i - 1];
1352 di->keynames[0] = di->keyname = keyname;
1357 dataiterator_free(Dataiterator *di)
1359 if (di->matcher.match)
1360 datamatcher_free(&di->matcher);
1362 solv_free(di->dupstr);
1365 static inline unsigned char *
1366 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1368 Id *keyp = di->keyp;
1369 Repokey *keys = di->data->keys;
1372 for (keyp = di->keyp; *keyp; keyp++)
1373 if (keys[*keyp].name == keyname)
1377 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1385 is_filelist_extension(Repodata *data)
1388 if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
1390 for (j = 1; j < data->nkeys; j++)
1391 if (data->keys[j].name == SOLVABLE_FILELIST)
1393 if (j == data->nkeys)
1395 if (data->state != REPODATA_AVAILABLE)
1397 for (j = 1; j < data->nkeys; j++)
1398 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1404 dataiterator_filelistcheck(Dataiterator *di)
1407 int needcomplete = 0;
1408 Repodata *data = di->data;
1410 if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
1411 if (!di->matcher.match
1412 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1413 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1414 || !repodata_filelistfilter_matches(data, di->matcher.match))
1416 if (data->state != REPODATA_AVAILABLE)
1417 return needcomplete ? 1 : 0;
1420 /* we don't need the complete filelist, so ignore all stubs */
1421 for (j = 1; j < data->nkeys; j++)
1422 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1428 /* we need the complete filelist. check if we habe a filtered filelist and there's
1429 * a extension with the complete filelist later on */
1430 for (j = 1; j < data->nkeys; j++)
1431 if (data->keys[j].name == SOLVABLE_FILELIST)
1433 if (j == data->nkeys)
1434 return 0; /* does not have filelist */
1435 for (j = 1; j < data->nkeys; j++)
1436 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1438 if (j == data->nkeys)
1439 return 1; /* this is the externsion */
1440 while (data - data->repo->repodata + 1 < data->repo->nrepodata)
1443 if (is_filelist_extension(data))
1451 dataiterator_step(Dataiterator *di)
1455 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1456 unsigned int ddpoff = di->ddp - di->vert_ddp;
1457 di->vert_off += ddpoff;
1458 di->vert_len -= ddpoff;
1459 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1460 di->vert_storestate = di->data->storestate;
1462 di->state = di_nextkey;
1468 case di_enterrepo: di_enterrepo:
1469 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1471 if (!(di->flags & SEARCH_THISSOLVID))
1473 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1474 goto di_nextsolvable;
1478 case di_entersolvable: di_entersolvable:
1481 di->repodataid = 1; /* reset repodata iterator */
1482 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)
1484 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1486 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1488 goto di_entersolvablekey;
1493 case di_enterrepodata: di_enterrepodata:
1496 if (di->repodataid >= di->repo->nrepodata)
1497 goto di_nextsolvable;
1498 di->data = di->repo->repodata + di->repodataid;
1500 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1501 goto di_nextrepodata;
1502 if (!maybe_load_repodata(di->data, di->keyname))
1503 goto di_nextrepodata;
1504 di->dp = solvid2data(di->data, di->solvid, &schema);
1506 goto di_nextrepodata;
1507 if (di->solvid == SOLVID_POS)
1508 di->solvid = di->pool->pos.solvid;
1509 /* reset key iterator */
1510 di->keyp = di->data->schemadata + di->data->schemata[schema];
1513 case di_enterschema: di_enterschema:
1515 di->dp = dataiterator_find_keyname(di, di->keyname);
1516 if (!di->dp || !*di->keyp)
1520 goto di_nextrepodata;
1524 case di_enterkey: di_enterkey:
1526 di->key = di->data->keys + *di->keyp;
1529 /* this is get_data() modified to store vert_ data */
1530 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1533 di->dp = data_read_id(di->dp, &off);
1534 di->dp = data_read_id(di->dp, &len);
1535 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1538 di->vert_storestate = di->data->storestate;
1540 else if (di->key->storage == KEY_STORAGE_INCORE)
1543 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1544 di->dp = data_skip_key(di->data, di->dp, di->key);
1550 if (di->key->type == REPOKEY_TYPE_DELETED)
1552 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1554 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1560 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1562 di->state = di_nextkey;
1564 di->state = di_nextattr;
1567 case di_nextkey: di_nextkey:
1568 if (!di->keyname && *++di->keyp)
1574 case di_nextrepodata: di_nextrepodata:
1575 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1576 goto di_enterrepodata;
1579 case di_nextsolvable: di_nextsolvable:
1580 if (!(di->flags & SEARCH_THISSOLVID))
1583 di->solvid = di->repo->start;
1586 for (; di->solvid < di->repo->end; di->solvid++)
1588 if (di->pool->solvables[di->solvid].repo == di->repo)
1589 goto di_entersolvable;
1594 case di_nextrepo: di_nextrepo:
1599 if (di->repoid < di->pool->nrepos)
1601 di->repo = di->pool->repos[di->repoid];
1607 case di_bye: di_bye:
1611 case di_enterarray: di_enterarray:
1612 if (di->key->name == REPOSITORY_SOLVABLES)
1614 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1619 case di_nextarrayelement: di_nextarrayelement:
1622 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1623 if (di->kv.entry == di->kv.num)
1625 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1627 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1629 di->kv.str = (char *)di->ddp;
1631 di->state = di_nextkey;
1634 if (di->kv.entry == di->kv.num - 1)
1636 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1637 di->ddp = data_read_id(di->ddp, &di->kv.id);
1638 di->kv.str = (char *)di->ddp;
1639 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1641 if ((di->flags & SEARCH_SUB) != 0)
1642 di->state = di_entersub;
1644 di->state = di_nextarrayelement;
1647 case di_entersub: di_entersub:
1648 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1649 goto di_nextarrayelement; /* sorry, full */
1650 di->parents[di->nparents].kv = di->kv;
1651 di->parents[di->nparents].dp = di->dp;
1652 di->parents[di->nparents].keyp = di->keyp;
1653 di->dp = (unsigned char *)di->kv.str;
1654 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1655 memset(&di->kv, 0, sizeof(di->kv));
1656 di->kv.parent = &di->parents[di->nparents].kv;
1658 di->keyname = di->keynames[di->nparents - di->rootlevel];
1659 goto di_enterschema;
1661 case di_leavesub: di_leavesub:
1662 if (di->nparents - 1 < di->rootlevel)
1665 di->dp = di->parents[di->nparents].dp;
1666 di->kv = di->parents[di->nparents].kv;
1667 di->keyp = di->parents[di->nparents].keyp;
1668 di->key = di->data->keys + *di->keyp;
1669 di->ddp = (unsigned char *)di->kv.str;
1670 di->keyname = di->keynames[di->nparents - di->rootlevel];
1671 goto di_nextarrayelement;
1673 /* special solvable attr handling follows */
1675 case di_nextsolvablekey: di_nextsolvablekey:
1676 if (di->keyname || di->key->name == RPM_RPMDBID)
1677 goto di_enterrepodata;
1681 case di_entersolvablekey: di_entersolvablekey:
1682 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1683 if (!di->idp || !*di->idp)
1684 goto di_nextsolvablekey;
1688 di->kv.id = *di->idp;
1689 di->kv.num = *di->idp; /* for rpmdbid */
1690 di->kv.num2 = 0; /* for rpmdbid */
1692 di->state = di_nextsolvablekey;
1698 case di_nextsolvableattr:
1699 di->state = di_nextsolvableattr;
1700 di->kv.id = *di->idp++;
1705 di->state = di_nextsolvablekey;
1711 if (di->matcher.match)
1713 /* simple pre-check so that we don't need to stringify */
1714 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1715 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1717 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1719 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1723 if (!datamatcher_match(&di->matcher, di->kv.str))
1728 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1729 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1731 /* found something! */
1737 dataiterator_entersub(Dataiterator *di)
1739 if (di->state == di_nextarrayelement)
1740 di->state = di_entersub;
1744 dataiterator_setpos(Dataiterator *di)
1746 if (di->kv.eof == 2)
1748 pool_clear_pos(di->pool);
1751 di->pool->pos.solvid = di->solvid;
1752 di->pool->pos.repo = di->repo;
1753 di->pool->pos.repodataid = di->data - di->repo->repodata;
1754 di->pool->pos.schema = di->kv.id;
1755 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1759 dataiterator_setpos_parent(Dataiterator *di)
1761 if (!di->kv.parent || di->kv.parent->eof == 2)
1763 pool_clear_pos(di->pool);
1766 di->pool->pos.solvid = di->solvid;
1767 di->pool->pos.repo = di->repo;
1768 di->pool->pos.repodataid = di->data - di->repo->repodata;
1769 di->pool->pos.schema = di->kv.parent->id;
1770 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1773 /* clones just the position, not the search keys/matcher */
1775 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1777 di->state = from->state;
1778 di->flags &= ~SEARCH_THISSOLVID;
1779 di->flags |= (from->flags & SEARCH_THISSOLVID);
1780 di->repo = from->repo;
1781 di->data = from->data;
1783 di->ddp = from->ddp;
1784 di->idp = from->idp;
1785 di->keyp = from->keyp;
1786 di->key = from->key;
1788 di->repodataid = from->repodataid;
1789 di->solvid = from->solvid;
1790 di->repoid = from->repoid;
1791 di->rootlevel = from->rootlevel;
1792 memcpy(di->parents, from->parents, sizeof(from->parents));
1793 di->nparents = from->nparents;
1797 for (i = 1; i < di->nparents; i++)
1798 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1799 di->kv.parent = &di->parents[di->nparents - 1].kv;
1803 if (from->dupstr && from->dupstr == from->kv.str)
1805 di->dupstrn = from->dupstrn;
1806 di->dupstr = solv_malloc(from->dupstrn);
1807 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1812 dataiterator_seek(Dataiterator *di, int whence)
1814 if ((whence & DI_SEEK_STAY) != 0)
1815 di->rootlevel = di->nparents;
1816 switch (whence & ~DI_SEEK_STAY)
1819 if (di->state != di_nextarrayelement)
1821 if ((whence & DI_SEEK_STAY) != 0)
1822 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1823 di->state = di_entersub;
1825 case DI_SEEK_PARENT:
1832 if (di->rootlevel > di->nparents)
1833 di->rootlevel = di->nparents;
1834 di->dp = di->parents[di->nparents].dp;
1835 di->kv = di->parents[di->nparents].kv;
1836 di->keyp = di->parents[di->nparents].keyp;
1837 di->key = di->data->keys + *di->keyp;
1838 di->ddp = (unsigned char *)di->kv.str;
1839 di->keyname = di->keynames[di->nparents - di->rootlevel];
1840 di->state = di_nextarrayelement;
1842 case DI_SEEK_REWIND:
1848 di->dp = (unsigned char *)di->kv.parent->str;
1849 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1850 di->state = di_enterschema;
1858 dataiterator_skip_attribute(Dataiterator *di)
1860 if (di->state == di_nextsolvableattr)
1861 di->state = di_nextsolvablekey;
1863 di->state = di_nextkey;
1867 dataiterator_skip_solvable(Dataiterator *di)
1872 di->keyname = di->keynames[0];
1873 di->state = di_nextsolvable;
1877 dataiterator_skip_repo(Dataiterator *di)
1882 di->keyname = di->keynames[0];
1883 di->state = di_nextrepo;
1887 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1892 di->keyname = di->keynames[0];
1893 if (solvid == SOLVID_POS)
1895 di->repo = di->pool->pos.repo;
1902 di->data = di->repo->repodata + di->pool->pos.repodataid;
1904 di->solvid = solvid;
1905 di->state = di_enterrepo;
1906 di->flags |= SEARCH_THISSOLVID;
1911 di->repo = di->pool->solvables[solvid].repo;
1914 else if (di->repoid > 0)
1916 if (!di->pool->urepos)
1922 di->repo = di->pool->repos[di->repoid];
1925 di->solvid = solvid;
1927 di->flags |= SEARCH_THISSOLVID;
1928 di->state = di_enterrepo;
1932 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1938 di->repoid = 0; /* 0 means stay at repo */
1941 di->flags &= ~SEARCH_THISSOLVID;
1942 di->state = di_enterrepo;
1946 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1948 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1952 return datamatcher_match(ma, di->kv.str);
1956 dataiterator_strdup(Dataiterator *di)
1960 if (!di->kv.str || di->kv.str == di->dupstr)
1962 switch (di->key->type)
1964 case REPOKEY_TYPE_MD5:
1965 case REPOKEY_TYPE_SHA1:
1966 case REPOKEY_TYPE_SHA256:
1967 case REPOKEY_TYPE_DIRSTRARRAY:
1968 if (di->kv.num) /* was it stringified into tmp space? */
1969 l = strlen(di->kv.str) + 1;
1974 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1976 switch (di->key->type)
1978 case REPOKEY_TYPE_STR:
1979 case REPOKEY_TYPE_DIRSTRARRAY:
1980 l = strlen(di->kv.str) + 1;
1982 case REPOKEY_TYPE_MD5:
1985 case REPOKEY_TYPE_SHA1:
1988 case REPOKEY_TYPE_SHA256:
1991 case REPOKEY_TYPE_BINARY:
1998 if (!di->dupstrn || di->dupstrn < l)
2000 di->dupstrn = l + 16;
2001 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
2004 memcpy(di->dupstr, di->kv.str, l);
2005 di->kv.str = di->dupstr;
2009 /************************************************************************
2010 * data modify functions
2013 /* extend repodata so that it includes solvables p */
2015 repodata_extend(Repodata *data, Id p)
2017 if (data->start == data->end)
2018 data->start = data->end = p;
2021 int old = data->end - data->start;
2022 int new = p - data->end + 1;
2025 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
2026 memset(data->attrs + old, 0, new * sizeof(Id *));
2028 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
2029 memset(data->incoreoffset + old, 0, new * sizeof(Id));
2032 if (p < data->start)
2034 int old = data->end - data->start;
2035 int new = data->start - p;
2038 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
2039 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
2040 memset(data->attrs, 0, new * sizeof(Id *));
2042 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
2043 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
2044 memset(data->incoreoffset, 0, new * sizeof(Id));
2049 /* shrink end of repodata */
2051 repodata_shrink(Repodata *data, int end)
2055 if (data->end <= end)
2057 if (data->start >= end)
2061 for (i = 0; i < data->end - data->start; i++)
2062 solv_free(data->attrs[i]);
2063 data->attrs = solv_free(data->attrs);
2065 data->incoreoffset = solv_free(data->incoreoffset);
2066 data->start = data->end = 0;
2071 for (i = end; i < data->end; i++)
2072 solv_free(data->attrs[i - data->start]);
2073 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2075 if (data->incoreoffset)
2076 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2080 /* extend repodata so that it includes solvables from start to start + num - 1 */
2082 repodata_extend_block(Repodata *data, Id start, Id num)
2086 if (!data->incoreoffset)
2088 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2089 data->start = start;
2090 data->end = start + num;
2093 repodata_extend(data, start);
2095 repodata_extend(data, start + num - 1);
2098 /**********************************************************************/
2101 #define REPODATA_ATTRS_BLOCK 31
2102 #define REPODATA_ATTRDATA_BLOCK 1023
2103 #define REPODATA_ATTRIDDATA_BLOCK 63
2104 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2108 repodata_new_handle(Repodata *data)
2112 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2113 data->nxattrs = 2; /* -1: SOLVID_META */
2115 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2116 data->xattrs[data->nxattrs] = 0;
2117 return -(data->nxattrs++);
2121 repodata_get_attrp(Repodata *data, Id handle)
2125 if (handle == SOLVID_META && !data->xattrs)
2127 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2130 return data->xattrs - handle;
2132 if (handle < data->start || handle >= data->end)
2133 repodata_extend(data, handle);
2135 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2136 return data->attrs + (handle - data->start);
2140 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2146 app = repodata_get_attrp(data, handle);
2151 /* Determine equality based on the name only, allows us to change
2152 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2153 for (pp = ap; *pp; pp += 2)
2154 if (data->keys[*pp].name == data->keys[keyid].name)
2158 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2167 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2177 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2181 keyid = repodata_key2id(data, key, 1);
2182 repodata_insert_keyid(data, solvid, keyid, val, 1);
2186 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2190 key.type = REPOKEY_TYPE_ID;
2192 key.storage = KEY_STORAGE_INCORE;
2193 repodata_set(data, solvid, &key, id);
2197 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2201 key.type = REPOKEY_TYPE_NUM;
2203 key.storage = KEY_STORAGE_INCORE;
2204 if (num >= 0x80000000)
2206 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2207 data->attrnum64data[data->attrnum64datalen] = num;
2208 num = 0x80000000 | data->attrnum64datalen++;
2210 repodata_set(data, solvid, &key, (Id)num);
2214 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2218 if (data->localpool)
2219 id = stringpool_str2id(&data->spool, str, 1);
2221 id = pool_str2id(data->repo->pool, str, 1);
2223 key.type = REPOKEY_TYPE_ID;
2225 key.storage = KEY_STORAGE_INCORE;
2226 repodata_set(data, solvid, &key, id);
2230 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2234 key.type = REPOKEY_TYPE_CONSTANT;
2235 key.size = constant;
2236 key.storage = KEY_STORAGE_INCORE;
2237 repodata_set(data, solvid, &key, 0);
2241 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2245 key.type = REPOKEY_TYPE_CONSTANTID;
2247 key.storage = KEY_STORAGE_INCORE;
2248 repodata_set(data, solvid, &key, 0);
2252 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2256 key.type = REPOKEY_TYPE_VOID;
2258 key.storage = KEY_STORAGE_INCORE;
2259 repodata_set(data, solvid, &key, 0);
2263 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2268 l = strlen(str) + 1;
2270 key.type = REPOKEY_TYPE_STR;
2272 key.storage = KEY_STORAGE_INCORE;
2273 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2274 memcpy(data->attrdata + data->attrdatalen, str, l);
2275 repodata_set(data, solvid, &key, data->attrdatalen);
2276 data->attrdatalen += l;
2280 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2288 key.type = REPOKEY_TYPE_BINARY;
2290 key.storage = KEY_STORAGE_INCORE;
2291 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2292 dp = data->attrdata + data->attrdatalen;
2293 if (len >= (1 << 14))
2295 if (len >= (1 << 28))
2296 *dp++ = (len >> 28) | 128;
2297 if (len >= (1 << 21))
2298 *dp++ = (len >> 21) | 128;
2299 *dp++ = (len >> 14) | 128;
2301 if (len >= (1 << 7))
2302 *dp++ = (len >> 7) | 128;
2305 memcpy(dp, buf, len);
2306 repodata_set(data, solvid, &key, data->attrdatalen);
2307 data->attrdatalen = dp + len - data->attrdata;
2310 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2311 * so that the caller can append entrysize new elements plus the termination zero there */
2313 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2316 Id *ida, *pp, **ppp;
2318 /* check if it is the same as last time, this speeds things up a lot */
2319 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2321 /* great! just append the new data */
2322 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2323 data->attriddatalen--; /* overwrite terminating 0 */
2324 data->lastdatalen += entrysize;
2328 ppp = repodata_get_attrp(data, handle);
2332 for (; *pp; pp += 2)
2333 if (data->keys[*pp].name == keyname)
2336 if (!pp || !*pp || data->keys[*pp].type != keytype)
2338 /* not found. allocate new key */
2344 key.storage = KEY_STORAGE_INCORE;
2345 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2346 keyid = repodata_key2id(data, &key, 1);
2347 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2348 data->lasthandle = handle;
2349 data->lastkey = keyid;
2350 data->lastdatalen = data->attriddatalen + entrysize + 1;
2354 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2355 oldsize += entrysize;
2356 if (ida + 1 == data->attriddata + data->attriddatalen)
2358 /* this was the last entry, just append it */
2359 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2360 data->attriddatalen--; /* overwrite terminating 0 */
2364 /* too bad. move to back. */
2365 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2366 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2367 pp[1] = data->attriddatalen;
2368 data->attriddatalen += oldsize;
2370 data->lasthandle = handle;
2371 data->lastkey = *pp;
2372 data->lastdatalen = data->attriddatalen + entrysize + 1;
2376 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2377 const unsigned char *str)
2382 if (!(l = solv_chksum_len(type)))
2387 key.storage = KEY_STORAGE_INCORE;
2388 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2389 memcpy(data->attrdata + data->attrdatalen, str, l);
2390 repodata_set(data, solvid, &key, data->attrdatalen);
2391 data->attrdatalen += l;
2395 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2398 unsigned char buf[64];
2401 if (!(l = solv_chksum_len(type)))
2403 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2405 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2409 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2413 if (!(l = solv_chksum_len(type)))
2415 return pool_bin2hex(data->repo->pool, buf, l);
2418 /* rpm filenames don't contain the epoch, so strip it */
2419 static inline const char *
2420 evrid2vrstr(Pool *pool, Id evrid)
2422 const char *p, *evr = pool_id2str(pool, evrid);
2425 for (p = evr; *p >= '0' && *p <= '9'; p++)
2427 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2431 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2434 if (data->localpool)
2435 id = stringpool_strn2id(&data->spool, str, l, 1);
2437 id = pool_strn2id(data->repo->pool, str, l, 1);
2438 repodata_set_id(data, solvid, keyname, id);
2442 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2445 repodata_set_str(data, solvid, keyname, str);
2448 char *s = solv_strdup(str);
2450 repodata_set_str(data, solvid, keyname, s);
2456 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2458 Pool *pool = data->repo->pool;
2460 const char *str, *fp;
2464 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2467 if ((dir = strrchr(file, '/')) != 0)
2478 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2483 if (l == 1 && dir[0] == '.')
2485 s = pool->solvables + solvid;
2488 str = pool_id2str(pool, s->arch);
2489 if (!strncmp(dir, str, l) && !str[l])
2490 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2492 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2495 str = pool_id2str(pool, s->name);
2497 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2500 str = evrid2vrstr(pool, s->evr);
2502 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2505 str = pool_id2str(pool, s->arch);
2507 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2509 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2514 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2517 /* XXX: medianr is currently not stored */
2519 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2522 const char *evr, *suf, *s;
2526 if ((dir = strrchr(file, '/')) != 0)
2537 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2542 if (l == 1 && dir[0] == '.')
2545 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2546 evr = strchr(file, '-');
2549 for (s = evr - 1; s > file; s--)
2556 suf = strrchr(file, '.');
2559 for (s = suf - 1; s > file; s--)
2565 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2567 /* We accept one more item as suffix. */
2568 for (s = suf - 1; s > file; s--)
2578 if (suf && evr && suf < evr)
2580 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2582 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2584 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2588 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2590 Pool *pool = data->repo->pool;
2591 Solvable *s = pool->solvables + solvid;
2592 const char *p, *sevr, *sarch, *name, *evr;
2594 p = strrchr(sourcepkg, '.');
2595 if (!p || strcmp(p, ".rpm") != 0)
2598 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2602 while (p > sourcepkg && *p != '.')
2604 if (*p != '.' || p == sourcepkg)
2607 while (p > sourcepkg && *p != '-')
2609 if (*p != '-' || p == sourcepkg)
2612 while (p > sourcepkg && *p != '-')
2614 if (*p != '-' || p == sourcepkg)
2617 pool = s->repo->pool;
2619 name = pool_id2str(pool, s->name);
2620 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2621 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2623 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2625 evr = evrid2vrstr(pool, s->evr);
2626 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2627 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2629 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2631 if (!strcmp(sarch, "src.rpm"))
2632 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2633 else if (!strcmp(sarch, "nosrc.rpm"))
2634 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2636 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2640 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2646 key.type = REPOKEY_TYPE_IDARRAY;
2648 key.storage = KEY_STORAGE_INCORE;
2649 repodata_set(data, solvid, &key, data->attriddatalen);
2650 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2651 for (i = 0; i < q->count; i++)
2652 data->attriddata[data->attriddatalen++] = q->elements[i];
2653 data->attriddata[data->attriddatalen++] = 0;
2657 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2661 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2663 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2664 data->attriddata[data->attriddatalen++] = dir;
2665 data->attriddata[data->attriddatalen++] = num;
2666 data->attriddata[data->attriddatalen++] = num2;
2667 data->attriddata[data->attriddatalen++] = 0;
2671 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2677 l = strlen(str) + 1;
2678 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2679 memcpy(data->attrdata + data->attrdatalen, str, l);
2680 stroff = data->attrdatalen;
2681 data->attrdatalen += l;
2684 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2686 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2687 data->attriddata[data->attriddatalen++] = dir;
2688 data->attriddata[data->attriddatalen++] = stroff;
2689 data->attriddata[data->attriddatalen++] = 0;
2693 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2696 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2698 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2699 data->attriddata[data->attriddatalen++] = id;
2700 data->attriddata[data->attriddatalen++] = 0;
2704 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2708 if (data->localpool)
2709 id = stringpool_str2id(&data->spool, str, 1);
2711 id = pool_str2id(data->repo->pool, str, 1);
2712 repodata_add_idarray(data, solvid, keyname, id);
2716 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2718 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2719 data->attriddata[data->attriddatalen++] = ghandle;
2720 data->attriddata[data->attriddatalen++] = 0;
2724 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2726 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2727 data->attriddata[data->attriddatalen++] = ghandle;
2728 data->attriddata[data->attriddatalen++] = 0;
2732 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2735 app = repodata_get_attrp(data, solvid);
2739 for (; *ap; ap += 2)
2740 if (data->keys[*ap].name == keyname)
2746 for (; *ap; ap += 2)
2748 if (data->keys[*ap].name == keyname)
2756 /* XXX: does not work correctly, needs fix in iterators! */
2758 repodata_unset(Repodata *data, Id solvid, Id keyname)
2762 key.type = REPOKEY_TYPE_DELETED;
2764 key.storage = KEY_STORAGE_INCORE;
2765 repodata_set(data, solvid, &key, 0);
2768 /* add all (uninternalized) attrs from src to dest */
2770 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2773 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2775 for (; *keyp; keyp += 2)
2776 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2779 /* add some (uninternalized) attrs from src to dest */
2781 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2784 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2786 for (; *keyp; keyp += 2)
2787 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2788 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2791 /* swap (uninternalized) attrs from src and dest */
2793 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2796 if (!data->attrs || dest == src)
2798 tmpattrs = data->attrs[dest - data->start];
2799 data->attrs[dest - data->start] = data->attrs[src - data->start];
2800 data->attrs[src - data->start] = tmpattrs;
2804 /**********************************************************************/
2806 /* TODO: unify with repo_write and repo_solv! */
2808 #define EXTDATA_BLOCK 1023
2816 data_addid(struct extdata *xd, Id sx)
2818 unsigned int x = (unsigned int)sx;
2821 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2822 dp = xd->buf + xd->len;
2827 *dp++ = (x >> 28) | 128;
2829 *dp++ = (x >> 21) | 128;
2830 *dp++ = (x >> 14) | 128;
2833 *dp++ = (x >> 7) | 128;
2835 xd->len = dp - xd->buf;
2839 data_addid64(struct extdata *xd, unsigned long long x)
2841 if (x >= 0x100000000)
2845 data_addid(xd, (Id)(x >> 35));
2846 xd->buf[xd->len - 1] |= 128;
2848 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2849 xd->buf[xd->len - 5] = (x >> 28) | 128;
2852 data_addid(xd, (Id)x);
2856 data_addideof(struct extdata *xd, Id sx, int eof)
2858 unsigned int x = (unsigned int)sx;
2861 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2862 dp = xd->buf + xd->len;
2867 *dp++ = (x >> 27) | 128;
2869 *dp++ = (x >> 20) | 128;
2870 *dp++ = (x >> 13) | 128;
2873 *dp++ = (x >> 6) | 128;
2874 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2875 xd->len = dp - xd->buf;
2879 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2881 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2882 memcpy(xd->buf + xd->len, blob, len);
2886 /*********************************/
2888 /* internalalize some key into incore/vincore data */
2891 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2892 struct extdata *newvincore,
2894 Repokey *key, Id val)
2898 unsigned int oldvincorelen = 0;
2902 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2905 oldvincorelen = xd->len;
2909 case REPOKEY_TYPE_VOID:
2910 case REPOKEY_TYPE_CONSTANT:
2911 case REPOKEY_TYPE_CONSTANTID:
2913 case REPOKEY_TYPE_STR:
2914 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2916 case REPOKEY_TYPE_MD5:
2917 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2919 case REPOKEY_TYPE_SHA1:
2920 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2922 case REPOKEY_TYPE_SHA256:
2923 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2925 case REPOKEY_TYPE_NUM:
2926 if (val & 0x80000000)
2928 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2932 case REPOKEY_TYPE_ID:
2933 case REPOKEY_TYPE_DIR:
2934 data_addid(xd, val);
2936 case REPOKEY_TYPE_BINARY:
2939 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2940 dp += (unsigned int)len;
2941 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2944 case REPOKEY_TYPE_IDARRAY:
2945 for (ida = data->attriddata + val; *ida; ida++)
2946 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2948 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2949 for (ida = data->attriddata + val; *ida; ida += 3)
2951 data_addid(xd, ida[0]);
2952 data_addid(xd, ida[1]);
2953 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2956 case REPOKEY_TYPE_DIRSTRARRAY:
2957 for (ida = data->attriddata + val; *ida; ida += 2)
2959 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2960 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2963 case REPOKEY_TYPE_FIXARRAY:
2967 for (ida = data->attriddata + val; *ida; ida++)
2971 kp = data->xattrs[-*ida];
2979 schemaid = repodata_schema2id(data, schema, 1);
2980 else if (schemaid != repodata_schema2id(data, schema, 0))
2982 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2988 data_addid(xd, num);
2989 data_addid(xd, schemaid);
2990 for (ida = data->attriddata + val; *ida; ida++)
2992 Id *kp = data->xattrs[-*ida];
2996 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3000 case REPOKEY_TYPE_FLEXARRAY:
3003 for (ida = data->attriddata + val; *ida; ida++)
3005 data_addid(xd, num);
3006 for (ida = data->attriddata + val; *ida; ida++)
3008 Id *kp = data->xattrs[-*ida];
3011 data_addid(xd, 0); /* XXX */
3018 schemaid = repodata_schema2id(data, schema, 1);
3019 data_addid(xd, schemaid);
3020 kp = data->xattrs[-*ida];
3022 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3027 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
3030 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3032 /* put offset/len in incore */
3033 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
3034 oldvincorelen = xd->len - oldvincorelen;
3035 data_addid(newincore, oldvincorelen);
3040 repodata_internalize(Repodata *data)
3042 Repokey *key, solvkey;
3044 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
3045 unsigned char *dp, *ndp;
3046 int newschema, oldcount;
3047 struct extdata newincore;
3048 struct extdata newvincore;
3051 if (!data->attrs && !data->xattrs)
3054 newvincore.buf = data->vincore;
3055 newvincore.len = data->vincorelen;
3057 /* find the solvables key, create if needed */
3058 memset(&solvkey, 0, sizeof(solvkey));
3059 solvkey.name = REPOSITORY_SOLVABLES;
3060 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3062 solvkey.storage = KEY_STORAGE_INCORE;
3063 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3065 schema = solv_malloc2(data->nkeys, sizeof(Id));
3066 seen = solv_malloc2(data->nkeys, sizeof(Id));
3068 /* Merge the data already existing (in data->schemata, ->incoredata and
3069 friends) with the new attributes in data->attrs[]. */
3070 nentry = data->end - data->start;
3071 memset(&newincore, 0, sizeof(newincore));
3072 data_addid(&newincore, 0); /* start data at offset 1 */
3074 data->mainschema = 0;
3075 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3077 /* join entry data */
3078 /* we start with the meta data, entry -1 */
3079 for (entry = -1; entry < nentry; entry++)
3081 memset(seen, 0, data->nkeys * sizeof(Id));
3083 dp = data->incoredata;
3086 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3087 dp = data_read_id(dp, &oldschema);
3090 fprintf(stderr, "oldschema %d\n", oldschema);
3091 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3092 fprintf(stderr, "schemadata %p\n", data->schemadata);
3094 /* seen: -1: old data 0: skipped >0: id + 1 */
3098 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3102 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3110 keyp = data->attrs ? data->attrs[entry] : 0;
3113 /* strip solvables key */
3115 for (sp = keyp = schema; *sp; sp++)
3116 if (*sp != solvkeyid)
3121 seen[solvkeyid] = 0;
3122 keyp = data->xattrs ? data->xattrs[1] : 0;
3125 for (; *keyp; keyp += 2)
3132 seen[*keyp] = keyp[1] + 1;
3134 if (entry < 0 && data->end != data->start)
3141 /* Ideally we'd like to sort the new schema here, to ensure
3142 schema equality independend of the ordering. We can't do that
3143 yet. For once see below (old ids need to come before new ids).
3144 An additional difficulty is that we also need to move
3145 the values with the keys. */
3146 schemaid = repodata_schema2id(data, schema, 1);
3148 schemaid = oldschema;
3151 /* Now create data blob. We walk through the (possibly new) schema
3152 and either copy over old data, or insert the new. */
3153 /* XXX Here we rely on the fact that the (new) schema has the form
3154 o1 o2 o3 o4 ... | n1 n2 n3 ...
3155 (oX being the old keyids (possibly overwritten), and nX being
3156 the new keyids). This rules out sorting the keyids in order
3157 to ensure a small schema count. */
3159 data->incoreoffset[entry] = newincore.len;
3160 data_addid(&newincore, schemaid);
3163 data->mainschema = schemaid;
3164 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3166 keypstart = data->schemadata + data->schemata[schemaid];
3167 for (keyp = keypstart; *keyp; keyp++)
3170 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3171 if (*keyp == solvkeyid)
3173 /* add flexarray entry count */
3174 data_addid(&newincore, data->end - data->start);
3177 key = data->keys + *keyp;
3179 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));
3184 /* Skip the data associated with this old key. */
3185 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3187 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3188 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3190 else if (key->storage == KEY_STORAGE_INCORE)
3191 ndp = data_skip_key(data, dp, key);
3194 if (seen[*keyp] == -1)
3196 /* If this key was an old one _and_ was not overwritten with
3197 a different value copy over the old value (we skipped it
3200 data_addblob(&newincore, dp, ndp - dp);
3203 else if (seen[*keyp])
3205 /* Otherwise we have a new value. Parse it into the internal
3207 repodata_serialize_key(data, &newincore, &newvincore,
3208 schema, key, seen[*keyp] - 1);
3212 if (entry >= 0 && data->attrs && data->attrs[entry])
3213 data->attrs[entry] = solv_free(data->attrs[entry]);
3215 /* free all xattrs */
3216 for (entry = 0; entry < data->nxattrs; entry++)
3217 if (data->xattrs[entry])
3218 solv_free(data->xattrs[entry]);
3219 data->xattrs = solv_free(data->xattrs);
3222 data->lasthandle = 0;
3224 data->lastdatalen = 0;
3227 repodata_free_schemahash(data);
3229 solv_free(data->incoredata);
3230 data->incoredata = newincore.buf;
3231 data->incoredatalen = newincore.len;
3232 data->incoredatafree = 0;
3234 solv_free(data->vincore);
3235 data->vincore = newvincore.buf;
3236 data->vincorelen = newvincore.len;
3238 data->attrs = solv_free(data->attrs);
3239 data->attrdata = solv_free(data->attrdata);
3240 data->attriddata = solv_free(data->attriddata);
3241 data->attrnum64data = solv_free(data->attrnum64data);
3242 data->attrdatalen = 0;
3243 data->attriddatalen = 0;
3244 data->attrnum64datalen = 0;
3248 repodata_disable_paging(Repodata *data)
3250 if (maybe_load_repodata(data, 0))
3252 repopagestore_disable_paging(&data->store);
3258 repodata_load_stub(Repodata *data)
3260 Repo *repo = data->repo;
3261 Pool *pool = repo->pool;
3263 struct _Pool_tmpspace oldtmpspace;
3265 if (!pool->loadcallback)
3267 data->state = REPODATA_ERROR;
3270 data->state = REPODATA_LOADING;
3272 /* save tmp space */
3273 oldtmpspace = pool->tmpspace;
3274 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3276 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3278 /* restore tmp space */
3279 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3280 solv_free(pool->tmpspace.buf[i]);
3281 pool->tmpspace = oldtmpspace;
3283 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3287 repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
3291 xkey.name = keyname;
3292 xkey.type = keytype;
3293 xkey.storage = KEY_STORAGE_INCORE;
3295 repodata_key2id(data, &xkey, 1);
3299 repodata_add_stub(Repodata **datap)
3301 Repodata *data = *datap;
3302 Repo *repo = data->repo;
3303 Id repodataid = data - repo->repodata;
3304 Repodata *sdata = repo_add_repodata(repo, 0);
3305 data = repo->repodata + repodataid;
3306 if (data->end > data->start)
3307 repodata_extend_block(sdata, data->start, data->end - data->start);
3308 sdata->state = REPODATA_STUB;
3309 sdata->loadcallback = repodata_load_stub;
3315 repodata_create_stubs(Repodata *data)
3317 Repo *repo = data->repo;
3318 Pool *pool = repo->pool;
3325 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3326 while (dataiterator_step(&di))
3327 if (di.data == data)
3329 dataiterator_free(&di);
3332 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3333 for (i = 0; i < cnt; i++)
3335 sdata = repodata_add_stub(&data);
3336 stubdataids[i] = sdata - repo->repodata;
3339 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3341 while (dataiterator_step(&di))
3343 if (di.data != data)
3345 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3347 dataiterator_entersub(&di);
3348 sdata = repo->repodata + stubdataids[i++];
3352 switch (di.key->type)
3354 case REPOKEY_TYPE_ID:
3355 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3357 case REPOKEY_TYPE_CONSTANTID:
3358 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3360 case REPOKEY_TYPE_STR:
3361 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3363 case REPOKEY_TYPE_VOID:
3364 repodata_set_void(sdata, SOLVID_META, di.key->name);
3366 case REPOKEY_TYPE_NUM:
3367 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3369 case REPOKEY_TYPE_MD5:
3370 case REPOKEY_TYPE_SHA1:
3371 case REPOKEY_TYPE_SHA256:
3372 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3374 case REPOKEY_TYPE_IDARRAY:
3375 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3376 if (di.key->name == REPOSITORY_KEYS)
3381 xkeyname = di.kv.id;
3385 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
3394 dataiterator_free(&di);
3395 for (i = 0; i < cnt; i++)
3396 repodata_internalize(repo->repodata + stubdataids[i]);
3397 solv_free(stubdataids);
3402 repodata_memused(Repodata *data)
3404 return data->incoredatalen + data->vincorelen;
3408 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: