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 && key->type != REPOKEY_TYPE_REL_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)
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)
1111 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1113 regfree(ma->matchdata);
1114 solv_free(ma->matchdata);
1120 datamatcher_match(Datamatcher *ma, const char *str)
1123 switch ((ma->flags & SEARCH_STRINGMASK))
1125 case SEARCH_SUBSTRING:
1126 if (ma->flags & SEARCH_NOCASE)
1127 return strcasestr(str, ma->match) != 0;
1129 return strstr(str, ma->match) != 0;
1131 if (ma->flags & SEARCH_NOCASE)
1132 return !strcasecmp(ma->match, str);
1134 return !strcmp(ma->match, str);
1135 case SEARCH_STRINGSTART:
1136 if (ma->flags & SEARCH_NOCASE)
1137 return !strncasecmp(ma->match, str, strlen(ma->match));
1139 return !strncmp(ma->match, str, strlen(ma->match));
1140 case SEARCH_STRINGEND:
1141 l = strlen(str) - strlen(ma->match);
1144 if (ma->flags & SEARCH_NOCASE)
1145 return !strcasecmp(ma->match, str + l);
1147 return !strcmp(ma->match, str + l);
1149 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1151 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1157 /* check if the matcher can match the provides basename */
1160 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1163 const char *match = ma->matchdata;
1166 switch (ma->flags & SEARCH_STRINGMASK)
1170 case SEARCH_STRINGEND:
1171 if (match != ma->match)
1172 break; /* had slash, do exact match on basename */
1175 /* check if the basename ends with match */
1176 l = strlen(basename) - strlen(match);
1182 return 1; /* maybe matches */
1184 if ((ma->flags & SEARCH_NOCASE) != 0)
1185 return !strcasecmp(match, basename);
1187 return !strcmp(match, basename);
1191 repodata_filelistfilter_matches(Repodata *data, const char *str)
1193 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1194 /* for now hardcoded */
1195 if (strstr(str, "bin/"))
1197 if (!strncmp(str, "/etc/", 5))
1199 if (!strcmp(str, "/usr/lib/sendmail"))
1221 di_nextarrayelement,
1227 di_entersolvablekey,
1231 /* see dataiterator.h for documentation */
1233 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1235 memset(di, 0, sizeof(*di));
1237 di->flags = flags & ~SEARCH_THISSOLVID;
1238 if (!pool || (repo && repo->pool != pool))
1246 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1252 di->keyname = keyname;
1253 di->keynames[0] = keyname;
1254 dataiterator_set_search(di, repo, p);
1259 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1264 if (di->dupstr == di->kv.str)
1266 di->dupstr = solv_malloc(di->dupstrn);
1267 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1275 memset(&di->matcher, 0, sizeof(di->matcher));
1276 if (from->matcher.match)
1277 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1282 for (i = 1; i < di->nparents; i++)
1283 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1284 di->kv.parent = &di->parents[di->nparents - 1].kv;
1289 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1291 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1292 datamatcher_free(&di->matcher);
1293 memset(&di->matcher, 0, sizeof(di->matcher));
1297 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1307 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1311 di->flags &= ~SEARCH_THISSOLVID;
1315 if (!di->pool->urepos)
1323 di->repo = di->pool->repos[di->repoid];
1325 di->state = di_enterrepo;
1327 dataiterator_jump_to_solvid(di, p);
1331 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1334 di->keyname = keyname;
1335 di->keynames[0] = keyname;
1339 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1343 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1345 di->state = di_bye; /* sorry */
1348 for (i = di->nkeynames + 1; i > 0; i--)
1349 di->keynames[i] = di->keynames[i - 1];
1350 di->keynames[0] = di->keyname = keyname;
1355 dataiterator_free(Dataiterator *di)
1357 if (di->matcher.match)
1358 datamatcher_free(&di->matcher);
1360 solv_free(di->dupstr);
1363 static inline unsigned char *
1364 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1366 Id *keyp = di->keyp;
1367 Repokey *keys = di->data->keys;
1370 for (keyp = di->keyp; *keyp; keyp++)
1371 if (keys[*keyp].name == keyname)
1375 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1383 dataiterator_filelistcheck(Dataiterator *di)
1386 int needcomplete = 0;
1387 Repodata *data = di->data;
1389 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1390 if (!di->matcher.match
1391 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1392 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1393 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1395 if (data->state != REPODATA_AVAILABLE)
1396 return needcomplete ? 1 : 0;
1397 for (j = 1; j < data->nkeys; j++)
1398 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1400 return j == data->nkeys && !needcomplete ? 0 : 1;
1404 dataiterator_step(Dataiterator *di)
1408 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1409 unsigned int ddpoff = di->ddp - di->vert_ddp;
1410 di->vert_off += ddpoff;
1411 di->vert_len -= ddpoff;
1412 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1413 di->vert_storestate = di->data->storestate;
1415 di->state = di_nextkey;
1421 case di_enterrepo: di_enterrepo:
1422 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1424 if (!(di->flags & SEARCH_THISSOLVID))
1426 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1427 goto di_nextsolvable;
1431 case di_entersolvable: di_entersolvable:
1434 di->repodataid = 1; /* reset repodata iterator */
1435 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)
1437 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1439 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1441 goto di_entersolvablekey;
1446 case di_enterrepodata: di_enterrepodata:
1449 if (di->repodataid >= di->repo->nrepodata)
1450 goto di_nextsolvable;
1451 di->data = di->repo->repodata + di->repodataid;
1453 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1454 goto di_nextrepodata;
1455 if (!maybe_load_repodata(di->data, di->keyname))
1456 goto di_nextrepodata;
1457 di->dp = solvid2data(di->data, di->solvid, &schema);
1459 goto di_nextrepodata;
1460 if (di->solvid == SOLVID_POS)
1461 di->solvid = di->pool->pos.solvid;
1462 /* reset key iterator */
1463 di->keyp = di->data->schemadata + di->data->schemata[schema];
1466 case di_enterschema: di_enterschema:
1468 di->dp = dataiterator_find_keyname(di, di->keyname);
1469 if (!di->dp || !*di->keyp)
1473 goto di_nextrepodata;
1477 case di_enterkey: di_enterkey:
1479 di->key = di->data->keys + *di->keyp;
1482 /* this is get_data() modified to store vert_ data */
1483 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1486 di->dp = data_read_id(di->dp, &off);
1487 di->dp = data_read_id(di->dp, &len);
1488 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1491 di->vert_storestate = di->data->storestate;
1493 else if (di->key->storage == KEY_STORAGE_INCORE)
1496 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1497 di->dp = data_skip_key(di->data, di->dp, di->key);
1503 if (di->key->type == REPOKEY_TYPE_DELETED)
1505 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1507 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1513 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1515 di->state = di_nextkey;
1517 di->state = di_nextattr;
1520 case di_nextkey: di_nextkey:
1521 if (!di->keyname && *++di->keyp)
1527 case di_nextrepodata: di_nextrepodata:
1528 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1529 goto di_enterrepodata;
1532 case di_nextsolvable: di_nextsolvable:
1533 if (!(di->flags & SEARCH_THISSOLVID))
1536 di->solvid = di->repo->start;
1539 for (; di->solvid < di->repo->end; di->solvid++)
1541 if (di->pool->solvables[di->solvid].repo == di->repo)
1542 goto di_entersolvable;
1547 case di_nextrepo: di_nextrepo:
1552 if (di->repoid < di->pool->nrepos)
1554 di->repo = di->pool->repos[di->repoid];
1560 case di_bye: di_bye:
1564 case di_enterarray: di_enterarray:
1565 if (di->key->name == REPOSITORY_SOLVABLES)
1567 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1572 case di_nextarrayelement: di_nextarrayelement:
1575 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1576 if (di->kv.entry == di->kv.num)
1578 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1580 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1582 di->kv.str = (char *)di->ddp;
1584 di->state = di_nextkey;
1587 if (di->kv.entry == di->kv.num - 1)
1589 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1590 di->ddp = data_read_id(di->ddp, &di->kv.id);
1591 di->kv.str = (char *)di->ddp;
1592 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1594 if ((di->flags & SEARCH_SUB) != 0)
1595 di->state = di_entersub;
1597 di->state = di_nextarrayelement;
1600 case di_entersub: di_entersub:
1601 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1602 goto di_nextarrayelement; /* sorry, full */
1603 di->parents[di->nparents].kv = di->kv;
1604 di->parents[di->nparents].dp = di->dp;
1605 di->parents[di->nparents].keyp = di->keyp;
1606 di->dp = (unsigned char *)di->kv.str;
1607 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1608 memset(&di->kv, 0, sizeof(di->kv));
1609 di->kv.parent = &di->parents[di->nparents].kv;
1611 di->keyname = di->keynames[di->nparents - di->rootlevel];
1612 goto di_enterschema;
1614 case di_leavesub: di_leavesub:
1615 if (di->nparents - 1 < di->rootlevel)
1618 di->dp = di->parents[di->nparents].dp;
1619 di->kv = di->parents[di->nparents].kv;
1620 di->keyp = di->parents[di->nparents].keyp;
1621 di->key = di->data->keys + *di->keyp;
1622 di->ddp = (unsigned char *)di->kv.str;
1623 di->keyname = di->keynames[di->nparents - di->rootlevel];
1624 goto di_nextarrayelement;
1626 /* special solvable attr handling follows */
1628 case di_nextsolvablekey: di_nextsolvablekey:
1629 if (di->keyname || di->key->name == RPM_RPMDBID)
1630 goto di_enterrepodata;
1634 case di_entersolvablekey: di_entersolvablekey:
1635 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1636 if (!di->idp || !*di->idp)
1637 goto di_nextsolvablekey;
1641 di->kv.id = *di->idp;
1642 di->kv.num = *di->idp; /* for rpmdbid */
1643 di->kv.num2 = 0; /* for rpmdbid */
1645 di->state = di_nextsolvablekey;
1651 case di_nextsolvableattr:
1652 di->state = di_nextsolvableattr;
1653 di->kv.id = *di->idp++;
1658 di->state = di_nextsolvablekey;
1664 if (di->matcher.match)
1666 /* simple pre-check so that we don't need to stringify */
1667 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1668 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1670 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1672 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1676 if (!datamatcher_match(&di->matcher, di->kv.str))
1681 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1682 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1684 /* found something! */
1690 dataiterator_entersub(Dataiterator *di)
1692 if (di->state == di_nextarrayelement)
1693 di->state = di_entersub;
1697 dataiterator_setpos(Dataiterator *di)
1699 if (di->kv.eof == 2)
1701 pool_clear_pos(di->pool);
1704 di->pool->pos.solvid = di->solvid;
1705 di->pool->pos.repo = di->repo;
1706 di->pool->pos.repodataid = di->data - di->repo->repodata;
1707 di->pool->pos.schema = di->kv.id;
1708 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1712 dataiterator_setpos_parent(Dataiterator *di)
1714 if (!di->kv.parent || di->kv.parent->eof == 2)
1716 pool_clear_pos(di->pool);
1719 di->pool->pos.solvid = di->solvid;
1720 di->pool->pos.repo = di->repo;
1721 di->pool->pos.repodataid = di->data - di->repo->repodata;
1722 di->pool->pos.schema = di->kv.parent->id;
1723 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1726 /* clones just the position, not the search keys/matcher */
1728 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1730 di->state = from->state;
1731 di->flags &= ~SEARCH_THISSOLVID;
1732 di->flags |= (from->flags & SEARCH_THISSOLVID);
1733 di->repo = from->repo;
1734 di->data = from->data;
1736 di->ddp = from->ddp;
1737 di->idp = from->idp;
1738 di->keyp = from->keyp;
1739 di->key = from->key;
1741 di->repodataid = from->repodataid;
1742 di->solvid = from->solvid;
1743 di->repoid = from->repoid;
1744 di->rootlevel = from->rootlevel;
1745 memcpy(di->parents, from->parents, sizeof(from->parents));
1746 di->nparents = from->nparents;
1750 for (i = 1; i < di->nparents; i++)
1751 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1752 di->kv.parent = &di->parents[di->nparents - 1].kv;
1756 if (from->dupstr && from->dupstr == from->kv.str)
1758 di->dupstrn = from->dupstrn;
1759 di->dupstr = solv_malloc(from->dupstrn);
1760 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1765 dataiterator_seek(Dataiterator *di, int whence)
1767 if ((whence & DI_SEEK_STAY) != 0)
1768 di->rootlevel = di->nparents;
1769 switch (whence & ~DI_SEEK_STAY)
1772 if (di->state != di_nextarrayelement)
1774 if ((whence & DI_SEEK_STAY) != 0)
1775 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1776 di->state = di_entersub;
1778 case DI_SEEK_PARENT:
1785 if (di->rootlevel > di->nparents)
1786 di->rootlevel = di->nparents;
1787 di->dp = di->parents[di->nparents].dp;
1788 di->kv = di->parents[di->nparents].kv;
1789 di->keyp = di->parents[di->nparents].keyp;
1790 di->key = di->data->keys + *di->keyp;
1791 di->ddp = (unsigned char *)di->kv.str;
1792 di->keyname = di->keynames[di->nparents - di->rootlevel];
1793 di->state = di_nextarrayelement;
1795 case DI_SEEK_REWIND:
1801 di->dp = (unsigned char *)di->kv.parent->str;
1802 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1803 di->state = di_enterschema;
1811 dataiterator_skip_attribute(Dataiterator *di)
1813 if (di->state == di_nextsolvableattr)
1814 di->state = di_nextsolvablekey;
1816 di->state = di_nextkey;
1820 dataiterator_skip_solvable(Dataiterator *di)
1825 di->keyname = di->keynames[0];
1826 di->state = di_nextsolvable;
1830 dataiterator_skip_repo(Dataiterator *di)
1835 di->keyname = di->keynames[0];
1836 di->state = di_nextrepo;
1840 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1845 di->keyname = di->keynames[0];
1846 if (solvid == SOLVID_POS)
1848 di->repo = di->pool->pos.repo;
1855 di->data = di->repo->repodata + di->pool->pos.repodataid;
1857 di->solvid = solvid;
1858 di->state = di_enterrepo;
1859 di->flags |= SEARCH_THISSOLVID;
1864 di->repo = di->pool->solvables[solvid].repo;
1867 else if (di->repoid > 0)
1869 if (!di->pool->urepos)
1875 di->repo = di->pool->repos[di->repoid];
1878 di->solvid = solvid;
1880 di->flags |= SEARCH_THISSOLVID;
1881 di->state = di_enterrepo;
1885 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1891 di->repoid = 0; /* 0 means stay at repo */
1894 di->flags &= ~SEARCH_THISSOLVID;
1895 di->state = di_enterrepo;
1899 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1901 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1905 return datamatcher_match(ma, di->kv.str);
1909 dataiterator_strdup(Dataiterator *di)
1913 if (!di->kv.str || di->kv.str == di->dupstr)
1915 switch (di->key->type)
1917 case REPOKEY_TYPE_MD5:
1918 case REPOKEY_TYPE_SHA1:
1919 case REPOKEY_TYPE_SHA256:
1920 case REPOKEY_TYPE_DIRSTRARRAY:
1921 if (di->kv.num) /* was it stringified into tmp space? */
1922 l = strlen(di->kv.str) + 1;
1927 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1929 switch (di->key->type)
1931 case REPOKEY_TYPE_STR:
1932 case REPOKEY_TYPE_DIRSTRARRAY:
1933 l = strlen(di->kv.str) + 1;
1935 case REPOKEY_TYPE_MD5:
1938 case REPOKEY_TYPE_SHA1:
1941 case REPOKEY_TYPE_SHA256:
1944 case REPOKEY_TYPE_BINARY:
1951 if (!di->dupstrn || di->dupstrn < l)
1953 di->dupstrn = l + 16;
1954 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
1957 memcpy(di->dupstr, di->kv.str, l);
1958 di->kv.str = di->dupstr;
1962 /************************************************************************
1963 * data modify functions
1966 /* extend repodata so that it includes solvables p */
1968 repodata_extend(Repodata *data, Id p)
1970 if (data->start == data->end)
1971 data->start = data->end = p;
1974 int old = data->end - data->start;
1975 int new = p - data->end + 1;
1978 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1979 memset(data->attrs + old, 0, new * sizeof(Id *));
1981 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1982 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1985 if (p < data->start)
1987 int old = data->end - data->start;
1988 int new = data->start - p;
1991 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1992 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1993 memset(data->attrs, 0, new * sizeof(Id *));
1995 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1996 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1997 memset(data->incoreoffset, 0, new * sizeof(Id));
2002 /* shrink end of repodata */
2004 repodata_shrink(Repodata *data, int end)
2008 if (data->end <= end)
2010 if (data->start >= end)
2014 for (i = 0; i < data->end - data->start; i++)
2015 solv_free(data->attrs[i]);
2016 data->attrs = solv_free(data->attrs);
2018 data->incoreoffset = solv_free(data->incoreoffset);
2019 data->start = data->end = 0;
2024 for (i = end; i < data->end; i++)
2025 solv_free(data->attrs[i - data->start]);
2026 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2028 if (data->incoreoffset)
2029 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2033 /* extend repodata so that it includes solvables from start to start + num - 1 */
2035 repodata_extend_block(Repodata *data, Id start, Id num)
2039 if (!data->incoreoffset)
2041 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2042 data->start = start;
2043 data->end = start + num;
2046 repodata_extend(data, start);
2048 repodata_extend(data, start + num - 1);
2051 /**********************************************************************/
2054 #define REPODATA_ATTRS_BLOCK 31
2055 #define REPODATA_ATTRDATA_BLOCK 1023
2056 #define REPODATA_ATTRIDDATA_BLOCK 63
2057 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2061 repodata_new_handle(Repodata *data)
2065 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2066 data->nxattrs = 2; /* -1: SOLVID_META */
2068 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2069 data->xattrs[data->nxattrs] = 0;
2070 return -(data->nxattrs++);
2074 repodata_get_attrp(Repodata *data, Id handle)
2078 if (handle == SOLVID_META && !data->xattrs)
2080 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2083 return data->xattrs - handle;
2085 if (handle < data->start || handle >= data->end)
2086 repodata_extend(data, handle);
2088 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2089 return data->attrs + (handle - data->start);
2093 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2099 app = repodata_get_attrp(data, handle);
2104 /* Determine equality based on the name only, allows us to change
2105 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2106 for (pp = ap; *pp; pp += 2)
2107 if (data->keys[*pp].name == data->keys[keyid].name)
2111 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2120 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2130 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2134 keyid = repodata_key2id(data, key, 1);
2135 repodata_insert_keyid(data, solvid, keyid, val, 1);
2139 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2143 key.type = REPOKEY_TYPE_ID;
2145 key.storage = KEY_STORAGE_INCORE;
2146 repodata_set(data, solvid, &key, id);
2150 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2154 key.type = REPOKEY_TYPE_NUM;
2156 key.storage = KEY_STORAGE_INCORE;
2157 if (num >= 0x80000000)
2159 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2160 data->attrnum64data[data->attrnum64datalen] = num;
2161 num = 0x80000000 | data->attrnum64datalen++;
2163 repodata_set(data, solvid, &key, (Id)num);
2167 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2171 if (data->localpool)
2172 id = stringpool_str2id(&data->spool, str, 1);
2174 id = pool_str2id(data->repo->pool, str, 1);
2176 key.type = REPOKEY_TYPE_ID;
2178 key.storage = KEY_STORAGE_INCORE;
2179 repodata_set(data, solvid, &key, id);
2183 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2187 key.type = REPOKEY_TYPE_CONSTANT;
2188 key.size = constant;
2189 key.storage = KEY_STORAGE_INCORE;
2190 repodata_set(data, solvid, &key, 0);
2194 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2198 key.type = REPOKEY_TYPE_CONSTANTID;
2200 key.storage = KEY_STORAGE_INCORE;
2201 repodata_set(data, solvid, &key, 0);
2205 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2209 key.type = REPOKEY_TYPE_VOID;
2211 key.storage = KEY_STORAGE_INCORE;
2212 repodata_set(data, solvid, &key, 0);
2216 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2221 l = strlen(str) + 1;
2223 key.type = REPOKEY_TYPE_STR;
2225 key.storage = KEY_STORAGE_INCORE;
2226 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2227 memcpy(data->attrdata + data->attrdatalen, str, l);
2228 repodata_set(data, solvid, &key, data->attrdatalen);
2229 data->attrdatalen += l;
2233 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2241 key.type = REPOKEY_TYPE_BINARY;
2243 key.storage = KEY_STORAGE_INCORE;
2244 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2245 dp = data->attrdata + data->attrdatalen;
2246 if (len >= (1 << 14))
2248 if (len >= (1 << 28))
2249 *dp++ = (len >> 28) | 128;
2250 if (len >= (1 << 21))
2251 *dp++ = (len >> 21) | 128;
2252 *dp++ = (len >> 14) | 128;
2254 if (len >= (1 << 7))
2255 *dp++ = (len >> 7) | 128;
2258 memcpy(dp, buf, len);
2259 repodata_set(data, solvid, &key, data->attrdatalen);
2260 data->attrdatalen = dp + len - data->attrdata;
2263 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2264 * so that the caller can append entrysize new elements plus the termination zero there */
2266 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2269 Id *ida, *pp, **ppp;
2271 /* check if it is the same as last time, this speeds things up a lot */
2272 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2274 /* great! just append the new data */
2275 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2276 data->attriddatalen--; /* overwrite terminating 0 */
2277 data->lastdatalen += entrysize;
2281 ppp = repodata_get_attrp(data, handle);
2285 for (; *pp; pp += 2)
2286 if (data->keys[*pp].name == keyname)
2289 if (!pp || !*pp || data->keys[*pp].type != keytype)
2291 /* not found. allocate new key */
2297 key.storage = KEY_STORAGE_INCORE;
2298 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2299 keyid = repodata_key2id(data, &key, 1);
2300 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2301 data->lasthandle = handle;
2302 data->lastkey = keyid;
2303 data->lastdatalen = data->attriddatalen + entrysize + 1;
2307 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2308 oldsize += entrysize;
2309 if (ida + 1 == data->attriddata + data->attriddatalen)
2311 /* this was the last entry, just append it */
2312 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2313 data->attriddatalen--; /* overwrite terminating 0 */
2317 /* too bad. move to back. */
2318 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2319 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2320 pp[1] = data->attriddatalen;
2321 data->attriddatalen += oldsize;
2323 data->lasthandle = handle;
2324 data->lastkey = *pp;
2325 data->lastdatalen = data->attriddatalen + entrysize + 1;
2329 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2330 const unsigned char *str)
2335 if (!(l = solv_chksum_len(type)))
2340 key.storage = KEY_STORAGE_INCORE;
2341 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2342 memcpy(data->attrdata + data->attrdatalen, str, l);
2343 repodata_set(data, solvid, &key, data->attrdatalen);
2344 data->attrdatalen += l;
2348 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2351 unsigned char buf[64];
2354 if (!(l = solv_chksum_len(type)))
2356 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2358 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2362 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2366 if (!(l = solv_chksum_len(type)))
2368 return pool_bin2hex(data->repo->pool, buf, l);
2371 /* rpm filenames don't contain the epoch, so strip it */
2372 static inline const char *
2373 evrid2vrstr(Pool *pool, Id evrid)
2375 const char *p, *evr = pool_id2str(pool, evrid);
2378 for (p = evr; *p >= '0' && *p <= '9'; p++)
2380 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2384 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2387 if (data->localpool)
2388 id = stringpool_strn2id(&data->spool, str, l, 1);
2390 id = pool_strn2id(data->repo->pool, str, l, 1);
2391 repodata_set_id(data, solvid, keyname, id);
2395 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2398 repodata_set_str(data, solvid, keyname, str);
2401 char *s = solv_strdup(str);
2403 repodata_set_str(data, solvid, keyname, s);
2409 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2411 Pool *pool = data->repo->pool;
2413 const char *str, *fp;
2417 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2420 if ((dir = strrchr(file, '/')) != 0)
2431 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2436 if (l == 1 && dir[0] == '.')
2438 s = pool->solvables + solvid;
2441 str = pool_id2str(pool, s->arch);
2442 if (!strncmp(dir, str, l) && !str[l])
2443 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2445 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2448 str = pool_id2str(pool, s->name);
2450 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2453 str = evrid2vrstr(pool, s->evr);
2455 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2458 str = pool_id2str(pool, s->arch);
2460 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2462 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2467 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2470 /* XXX: medianr is currently not stored */
2472 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2475 const char *evr, *suf, *s;
2479 if ((dir = strrchr(file, '/')) != 0)
2490 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2495 if (l == 1 && dir[0] == '.')
2498 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2499 evr = strchr(file, '-');
2502 for (s = evr - 1; s > file; s--)
2509 suf = strrchr(file, '.');
2512 for (s = suf - 1; s > file; s--)
2518 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2520 /* We accept one more item as suffix. */
2521 for (s = suf - 1; s > file; s--)
2531 if (suf && evr && suf < evr)
2533 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2535 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2537 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2541 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2543 Pool *pool = data->repo->pool;
2544 Solvable *s = pool->solvables + solvid;
2545 const char *p, *sevr, *sarch, *name, *evr;
2547 p = strrchr(sourcepkg, '.');
2548 if (!p || strcmp(p, ".rpm") != 0)
2551 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2555 while (p > sourcepkg && *p != '.')
2557 if (*p != '.' || p == sourcepkg)
2560 while (p > sourcepkg && *p != '-')
2562 if (*p != '-' || p == sourcepkg)
2565 while (p > sourcepkg && *p != '-')
2567 if (*p != '-' || p == sourcepkg)
2570 pool = s->repo->pool;
2572 name = pool_id2str(pool, s->name);
2573 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2574 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2576 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2578 evr = evrid2vrstr(pool, s->evr);
2579 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2580 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2582 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2584 if (!strcmp(sarch, "src.rpm"))
2585 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2586 else if (!strcmp(sarch, "nosrc.rpm"))
2587 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2589 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2593 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2599 key.type = REPOKEY_TYPE_IDARRAY;
2601 key.storage = KEY_STORAGE_INCORE;
2602 repodata_set(data, solvid, &key, data->attriddatalen);
2603 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2604 for (i = 0; i < q->count; i++)
2605 data->attriddata[data->attriddatalen++] = q->elements[i];
2606 data->attriddata[data->attriddatalen++] = 0;
2610 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2614 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2616 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2617 data->attriddata[data->attriddatalen++] = dir;
2618 data->attriddata[data->attriddatalen++] = num;
2619 data->attriddata[data->attriddatalen++] = num2;
2620 data->attriddata[data->attriddatalen++] = 0;
2624 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2630 l = strlen(str) + 1;
2631 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2632 memcpy(data->attrdata + data->attrdatalen, str, l);
2633 stroff = data->attrdatalen;
2634 data->attrdatalen += l;
2637 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2639 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2640 data->attriddata[data->attriddatalen++] = dir;
2641 data->attriddata[data->attriddatalen++] = stroff;
2642 data->attriddata[data->attriddatalen++] = 0;
2646 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2649 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2651 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2652 data->attriddata[data->attriddatalen++] = id;
2653 data->attriddata[data->attriddatalen++] = 0;
2657 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2661 if (data->localpool)
2662 id = stringpool_str2id(&data->spool, str, 1);
2664 id = pool_str2id(data->repo->pool, str, 1);
2665 repodata_add_idarray(data, solvid, keyname, id);
2669 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2671 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2672 data->attriddata[data->attriddatalen++] = ghandle;
2673 data->attriddata[data->attriddatalen++] = 0;
2677 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2679 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2680 data->attriddata[data->attriddatalen++] = ghandle;
2681 data->attriddata[data->attriddatalen++] = 0;
2685 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2688 app = repodata_get_attrp(data, solvid);
2692 for (; *ap; ap += 2)
2693 if (data->keys[*ap].name == keyname)
2699 for (; *ap; ap += 2)
2701 if (data->keys[*ap].name == keyname)
2709 /* XXX: does not work correctly, needs fix in iterators! */
2711 repodata_unset(Repodata *data, Id solvid, Id keyname)
2715 key.type = REPOKEY_TYPE_DELETED;
2717 key.storage = KEY_STORAGE_INCORE;
2718 repodata_set(data, solvid, &key, 0);
2721 /* add all (uninternalized) attrs from src to dest */
2723 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2726 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2728 for (; *keyp; keyp += 2)
2729 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2732 /* add some (uninternalized) attrs from src to dest */
2734 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2737 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2739 for (; *keyp; keyp += 2)
2740 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2741 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2744 /* swap (uninternalized) attrs from src and dest */
2746 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2749 if (!data->attrs || dest == src)
2751 tmpattrs = data->attrs[dest - data->start];
2752 data->attrs[dest - data->start] = data->attrs[src - data->start];
2753 data->attrs[src - data->start] = tmpattrs;
2757 /**********************************************************************/
2759 /* TODO: unify with repo_write and repo_solv! */
2761 #define EXTDATA_BLOCK 1023
2769 data_addid(struct extdata *xd, Id sx)
2771 unsigned int x = (unsigned int)sx;
2774 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2775 dp = xd->buf + xd->len;
2780 *dp++ = (x >> 28) | 128;
2782 *dp++ = (x >> 21) | 128;
2783 *dp++ = (x >> 14) | 128;
2786 *dp++ = (x >> 7) | 128;
2788 xd->len = dp - xd->buf;
2792 data_addid64(struct extdata *xd, unsigned long long x)
2794 if (x >= 0x100000000)
2798 data_addid(xd, (Id)(x >> 35));
2799 xd->buf[xd->len - 1] |= 128;
2801 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2802 xd->buf[xd->len - 5] = (x >> 28) | 128;
2805 data_addid(xd, (Id)x);
2809 data_addideof(struct extdata *xd, Id sx, int eof)
2811 unsigned int x = (unsigned int)sx;
2814 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2815 dp = xd->buf + xd->len;
2820 *dp++ = (x >> 27) | 128;
2822 *dp++ = (x >> 20) | 128;
2823 *dp++ = (x >> 13) | 128;
2826 *dp++ = (x >> 6) | 128;
2827 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2828 xd->len = dp - xd->buf;
2832 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2834 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2835 memcpy(xd->buf + xd->len, blob, len);
2839 /*********************************/
2841 /* internalalize some key into incore/vincore data */
2844 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2845 struct extdata *newvincore,
2847 Repokey *key, Id val)
2851 unsigned int oldvincorelen = 0;
2855 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2858 oldvincorelen = xd->len;
2862 case REPOKEY_TYPE_VOID:
2863 case REPOKEY_TYPE_CONSTANT:
2864 case REPOKEY_TYPE_CONSTANTID:
2866 case REPOKEY_TYPE_STR:
2867 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2869 case REPOKEY_TYPE_MD5:
2870 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2872 case REPOKEY_TYPE_SHA1:
2873 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2875 case REPOKEY_TYPE_SHA256:
2876 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2878 case REPOKEY_TYPE_NUM:
2879 if (val & 0x80000000)
2881 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2885 case REPOKEY_TYPE_ID:
2886 case REPOKEY_TYPE_DIR:
2887 data_addid(xd, val);
2889 case REPOKEY_TYPE_BINARY:
2892 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2893 dp += (unsigned int)len;
2894 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2897 case REPOKEY_TYPE_IDARRAY:
2898 for (ida = data->attriddata + val; *ida; ida++)
2899 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2901 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2902 for (ida = data->attriddata + val; *ida; ida += 3)
2904 data_addid(xd, ida[0]);
2905 data_addid(xd, ida[1]);
2906 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2909 case REPOKEY_TYPE_DIRSTRARRAY:
2910 for (ida = data->attriddata + val; *ida; ida += 2)
2912 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2913 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2916 case REPOKEY_TYPE_FIXARRAY:
2920 for (ida = data->attriddata + val; *ida; ida++)
2924 kp = data->xattrs[-*ida];
2932 schemaid = repodata_schema2id(data, schema, 1);
2933 else if (schemaid != repodata_schema2id(data, schema, 0))
2935 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2941 data_addid(xd, num);
2942 data_addid(xd, schemaid);
2943 for (ida = data->attriddata + val; *ida; ida++)
2945 Id *kp = data->xattrs[-*ida];
2949 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2953 case REPOKEY_TYPE_FLEXARRAY:
2956 for (ida = data->attriddata + val; *ida; ida++)
2958 data_addid(xd, num);
2959 for (ida = data->attriddata + val; *ida; ida++)
2961 Id *kp = data->xattrs[-*ida];
2964 data_addid(xd, 0); /* XXX */
2971 schemaid = repodata_schema2id(data, schema, 1);
2972 data_addid(xd, schemaid);
2973 kp = data->xattrs[-*ida];
2975 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2980 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2983 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2985 /* put offset/len in incore */
2986 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2987 oldvincorelen = xd->len - oldvincorelen;
2988 data_addid(newincore, oldvincorelen);
2993 repodata_internalize(Repodata *data)
2995 Repokey *key, solvkey;
2997 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2998 unsigned char *dp, *ndp;
2999 int newschema, oldcount;
3000 struct extdata newincore;
3001 struct extdata newvincore;
3004 if (!data->attrs && !data->xattrs)
3007 newvincore.buf = data->vincore;
3008 newvincore.len = data->vincorelen;
3010 /* find the solvables key, create if needed */
3011 memset(&solvkey, 0, sizeof(solvkey));
3012 solvkey.name = REPOSITORY_SOLVABLES;
3013 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3015 solvkey.storage = KEY_STORAGE_INCORE;
3016 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3018 schema = solv_malloc2(data->nkeys, sizeof(Id));
3019 seen = solv_malloc2(data->nkeys, sizeof(Id));
3021 /* Merge the data already existing (in data->schemata, ->incoredata and
3022 friends) with the new attributes in data->attrs[]. */
3023 nentry = data->end - data->start;
3024 memset(&newincore, 0, sizeof(newincore));
3025 data_addid(&newincore, 0); /* start data at offset 1 */
3027 data->mainschema = 0;
3028 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3030 /* join entry data */
3031 /* we start with the meta data, entry -1 */
3032 for (entry = -1; entry < nentry; entry++)
3034 memset(seen, 0, data->nkeys * sizeof(Id));
3036 dp = data->incoredata;
3039 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3040 dp = data_read_id(dp, &oldschema);
3043 fprintf(stderr, "oldschema %d\n", oldschema);
3044 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3045 fprintf(stderr, "schemadata %p\n", data->schemadata);
3047 /* seen: -1: old data 0: skipped >0: id + 1 */
3051 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3055 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3063 keyp = data->attrs ? data->attrs[entry] : 0;
3066 /* strip solvables key */
3068 for (sp = keyp = schema; *sp; sp++)
3069 if (*sp != solvkeyid)
3074 seen[solvkeyid] = 0;
3075 keyp = data->xattrs ? data->xattrs[1] : 0;
3078 for (; *keyp; keyp += 2)
3085 seen[*keyp] = keyp[1] + 1;
3087 if (entry < 0 && data->end != data->start)
3094 /* Ideally we'd like to sort the new schema here, to ensure
3095 schema equality independend of the ordering. We can't do that
3096 yet. For once see below (old ids need to come before new ids).
3097 An additional difficulty is that we also need to move
3098 the values with the keys. */
3099 schemaid = repodata_schema2id(data, schema, 1);
3101 schemaid = oldschema;
3104 /* Now create data blob. We walk through the (possibly new) schema
3105 and either copy over old data, or insert the new. */
3106 /* XXX Here we rely on the fact that the (new) schema has the form
3107 o1 o2 o3 o4 ... | n1 n2 n3 ...
3108 (oX being the old keyids (possibly overwritten), and nX being
3109 the new keyids). This rules out sorting the keyids in order
3110 to ensure a small schema count. */
3112 data->incoreoffset[entry] = newincore.len;
3113 data_addid(&newincore, schemaid);
3116 data->mainschema = schemaid;
3117 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3119 keypstart = data->schemadata + data->schemata[schemaid];
3120 for (keyp = keypstart; *keyp; keyp++)
3123 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3124 if (*keyp == solvkeyid)
3126 /* add flexarray entry count */
3127 data_addid(&newincore, data->end - data->start);
3130 key = data->keys + *keyp;
3132 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));
3137 /* Skip the data associated with this old key. */
3138 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3140 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3141 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3143 else if (key->storage == KEY_STORAGE_INCORE)
3144 ndp = data_skip_key(data, dp, key);
3147 if (seen[*keyp] == -1)
3149 /* If this key was an old one _and_ was not overwritten with
3150 a different value copy over the old value (we skipped it
3153 data_addblob(&newincore, dp, ndp - dp);
3156 else if (seen[*keyp])
3158 /* Otherwise we have a new value. Parse it into the internal
3160 repodata_serialize_key(data, &newincore, &newvincore,
3161 schema, key, seen[*keyp] - 1);
3165 if (entry >= 0 && data->attrs && data->attrs[entry])
3166 data->attrs[entry] = solv_free(data->attrs[entry]);
3168 /* free all xattrs */
3169 for (entry = 0; entry < data->nxattrs; entry++)
3170 if (data->xattrs[entry])
3171 solv_free(data->xattrs[entry]);
3172 data->xattrs = solv_free(data->xattrs);
3175 data->lasthandle = 0;
3177 data->lastdatalen = 0;
3180 repodata_free_schemahash(data);
3182 solv_free(data->incoredata);
3183 data->incoredata = newincore.buf;
3184 data->incoredatalen = newincore.len;
3185 data->incoredatafree = 0;
3187 solv_free(data->vincore);
3188 data->vincore = newvincore.buf;
3189 data->vincorelen = newvincore.len;
3191 data->attrs = solv_free(data->attrs);
3192 data->attrdata = solv_free(data->attrdata);
3193 data->attriddata = solv_free(data->attriddata);
3194 data->attrnum64data = solv_free(data->attrnum64data);
3195 data->attrdatalen = 0;
3196 data->attriddatalen = 0;
3197 data->attrnum64datalen = 0;
3201 repodata_disable_paging(Repodata *data)
3203 if (maybe_load_repodata(data, 0))
3205 repopagestore_disable_paging(&data->store);
3211 repodata_load_stub(Repodata *data)
3213 Repo *repo = data->repo;
3214 Pool *pool = repo->pool;
3216 struct _Pool_tmpspace oldtmpspace;
3218 if (!pool->loadcallback)
3220 data->state = REPODATA_ERROR;
3223 data->state = REPODATA_LOADING;
3225 /* save tmp space */
3226 oldtmpspace = pool->tmpspace;
3227 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3229 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3231 /* restore tmp space */
3232 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3233 solv_free(pool->tmpspace.buf[i]);
3234 pool->tmpspace = oldtmpspace;
3236 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3240 repodata_create_stubs(Repodata *data)
3242 Repo *repo = data->repo;
3243 Pool *pool = repo->pool;
3250 int datastart, dataend;
3252 repodataid = data - repo->repodata;
3253 datastart = data->start;
3254 dataend = data->end;
3255 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3256 while (dataiterator_step(&di))
3258 if (di.data - repo->repodata != repodataid)
3262 dataiterator_free(&di);
3265 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3266 for (i = 0; i < cnt; i++)
3268 sdata = repo_add_repodata(repo, 0);
3269 if (dataend > datastart)
3270 repodata_extend_block(sdata, datastart, dataend - datastart);
3271 stubdataids[i] = sdata - repo->repodata;
3272 sdata->state = REPODATA_STUB;
3273 sdata->loadcallback = repodata_load_stub;
3276 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3278 while (dataiterator_step(&di))
3280 if (di.data - repo->repodata != repodataid)
3282 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3284 dataiterator_entersub(&di);
3285 sdata = repo->repodata + stubdataids[i++];
3289 switch (di.key->type)
3291 case REPOKEY_TYPE_ID:
3292 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3294 case REPOKEY_TYPE_CONSTANTID:
3295 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3297 case REPOKEY_TYPE_STR:
3298 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3300 case REPOKEY_TYPE_VOID:
3301 repodata_set_void(sdata, SOLVID_META, di.key->name);
3303 case REPOKEY_TYPE_NUM:
3304 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3306 case REPOKEY_TYPE_MD5:
3307 case REPOKEY_TYPE_SHA1:
3308 case REPOKEY_TYPE_SHA256:
3309 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3311 case REPOKEY_TYPE_IDARRAY:
3312 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3313 if (di.key->name == REPOSITORY_KEYS)
3320 xkeyname = di.kv.id;
3323 xkey.name = xkeyname;
3324 xkey.type = di.kv.id;
3325 xkey.storage = KEY_STORAGE_INCORE;
3327 repodata_key2id(sdata, &xkey, 1);
3334 dataiterator_free(&di);
3335 for (i = 0; i < cnt; i++)
3336 repodata_internalize(repo->repodata + stubdataids[i]);
3337 solv_free(stubdataids);
3341 repodata_memused(Repodata *data)
3343 return data->incoredatalen + data->vincorelen;
3347 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: