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)
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 dataiterator_filelistcheck(Dataiterator *di)
1388 int needcomplete = 0;
1389 Repodata *data = di->data;
1391 if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
1392 if (!di->matcher.match
1393 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1394 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1395 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1397 if (data->state != REPODATA_AVAILABLE)
1398 return needcomplete ? 1 : 0;
1399 for (j = 1; j < data->nkeys; j++)
1400 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1402 return j == data->nkeys && !needcomplete ? 0 : 1;
1406 dataiterator_step(Dataiterator *di)
1410 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1411 unsigned int ddpoff = di->ddp - di->vert_ddp;
1412 di->vert_off += ddpoff;
1413 di->vert_len -= ddpoff;
1414 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1415 di->vert_storestate = di->data->storestate;
1417 di->state = di_nextkey;
1423 case di_enterrepo: di_enterrepo:
1424 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1426 if (!(di->flags & SEARCH_THISSOLVID))
1428 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1429 goto di_nextsolvable;
1433 case di_entersolvable: di_entersolvable:
1436 di->repodataid = 1; /* reset repodata iterator */
1437 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)
1439 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1441 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1443 goto di_entersolvablekey;
1448 case di_enterrepodata: di_enterrepodata:
1451 if (di->repodataid >= di->repo->nrepodata)
1452 goto di_nextsolvable;
1453 di->data = di->repo->repodata + di->repodataid;
1455 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1456 goto di_nextrepodata;
1457 if (!maybe_load_repodata(di->data, di->keyname))
1458 goto di_nextrepodata;
1459 di->dp = solvid2data(di->data, di->solvid, &schema);
1461 goto di_nextrepodata;
1462 if (di->solvid == SOLVID_POS)
1463 di->solvid = di->pool->pos.solvid;
1464 /* reset key iterator */
1465 di->keyp = di->data->schemadata + di->data->schemata[schema];
1468 case di_enterschema: di_enterschema:
1470 di->dp = dataiterator_find_keyname(di, di->keyname);
1471 if (!di->dp || !*di->keyp)
1475 goto di_nextrepodata;
1479 case di_enterkey: di_enterkey:
1481 di->key = di->data->keys + *di->keyp;
1484 /* this is get_data() modified to store vert_ data */
1485 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1488 di->dp = data_read_id(di->dp, &off);
1489 di->dp = data_read_id(di->dp, &len);
1490 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1493 di->vert_storestate = di->data->storestate;
1495 else if (di->key->storage == KEY_STORAGE_INCORE)
1498 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1499 di->dp = data_skip_key(di->data, di->dp, di->key);
1505 if (di->key->type == REPOKEY_TYPE_DELETED)
1507 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1509 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1515 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1517 di->state = di_nextkey;
1519 di->state = di_nextattr;
1522 case di_nextkey: di_nextkey:
1523 if (!di->keyname && *++di->keyp)
1529 case di_nextrepodata: di_nextrepodata:
1530 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1531 goto di_enterrepodata;
1534 case di_nextsolvable: di_nextsolvable:
1535 if (!(di->flags & SEARCH_THISSOLVID))
1538 di->solvid = di->repo->start;
1541 for (; di->solvid < di->repo->end; di->solvid++)
1543 if (di->pool->solvables[di->solvid].repo == di->repo)
1544 goto di_entersolvable;
1549 case di_nextrepo: di_nextrepo:
1554 if (di->repoid < di->pool->nrepos)
1556 di->repo = di->pool->repos[di->repoid];
1562 case di_bye: di_bye:
1566 case di_enterarray: di_enterarray:
1567 if (di->key->name == REPOSITORY_SOLVABLES)
1569 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1574 case di_nextarrayelement: di_nextarrayelement:
1577 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1578 if (di->kv.entry == di->kv.num)
1580 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1582 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1584 di->kv.str = (char *)di->ddp;
1586 di->state = di_nextkey;
1589 if (di->kv.entry == di->kv.num - 1)
1591 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1592 di->ddp = data_read_id(di->ddp, &di->kv.id);
1593 di->kv.str = (char *)di->ddp;
1594 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1596 if ((di->flags & SEARCH_SUB) != 0)
1597 di->state = di_entersub;
1599 di->state = di_nextarrayelement;
1602 case di_entersub: di_entersub:
1603 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1604 goto di_nextarrayelement; /* sorry, full */
1605 di->parents[di->nparents].kv = di->kv;
1606 di->parents[di->nparents].dp = di->dp;
1607 di->parents[di->nparents].keyp = di->keyp;
1608 di->dp = (unsigned char *)di->kv.str;
1609 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1610 memset(&di->kv, 0, sizeof(di->kv));
1611 di->kv.parent = &di->parents[di->nparents].kv;
1613 di->keyname = di->keynames[di->nparents - di->rootlevel];
1614 goto di_enterschema;
1616 case di_leavesub: di_leavesub:
1617 if (di->nparents - 1 < di->rootlevel)
1620 di->dp = di->parents[di->nparents].dp;
1621 di->kv = di->parents[di->nparents].kv;
1622 di->keyp = di->parents[di->nparents].keyp;
1623 di->key = di->data->keys + *di->keyp;
1624 di->ddp = (unsigned char *)di->kv.str;
1625 di->keyname = di->keynames[di->nparents - di->rootlevel];
1626 goto di_nextarrayelement;
1628 /* special solvable attr handling follows */
1630 case di_nextsolvablekey: di_nextsolvablekey:
1631 if (di->keyname || di->key->name == RPM_RPMDBID)
1632 goto di_enterrepodata;
1636 case di_entersolvablekey: di_entersolvablekey:
1637 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1638 if (!di->idp || !*di->idp)
1639 goto di_nextsolvablekey;
1643 di->kv.id = *di->idp;
1644 di->kv.num = *di->idp; /* for rpmdbid */
1645 di->kv.num2 = 0; /* for rpmdbid */
1647 di->state = di_nextsolvablekey;
1653 case di_nextsolvableattr:
1654 di->state = di_nextsolvableattr;
1655 di->kv.id = *di->idp++;
1660 di->state = di_nextsolvablekey;
1666 if (di->matcher.match)
1668 /* simple pre-check so that we don't need to stringify */
1669 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1670 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1672 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1674 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1678 if (!datamatcher_match(&di->matcher, di->kv.str))
1683 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1684 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1686 /* found something! */
1692 dataiterator_entersub(Dataiterator *di)
1694 if (di->state == di_nextarrayelement)
1695 di->state = di_entersub;
1699 dataiterator_setpos(Dataiterator *di)
1701 if (di->kv.eof == 2)
1703 pool_clear_pos(di->pool);
1706 di->pool->pos.solvid = di->solvid;
1707 di->pool->pos.repo = di->repo;
1708 di->pool->pos.repodataid = di->data - di->repo->repodata;
1709 di->pool->pos.schema = di->kv.id;
1710 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1714 dataiterator_setpos_parent(Dataiterator *di)
1716 if (!di->kv.parent || di->kv.parent->eof == 2)
1718 pool_clear_pos(di->pool);
1721 di->pool->pos.solvid = di->solvid;
1722 di->pool->pos.repo = di->repo;
1723 di->pool->pos.repodataid = di->data - di->repo->repodata;
1724 di->pool->pos.schema = di->kv.parent->id;
1725 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1728 /* clones just the position, not the search keys/matcher */
1730 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1732 di->state = from->state;
1733 di->flags &= ~SEARCH_THISSOLVID;
1734 di->flags |= (from->flags & SEARCH_THISSOLVID);
1735 di->repo = from->repo;
1736 di->data = from->data;
1738 di->ddp = from->ddp;
1739 di->idp = from->idp;
1740 di->keyp = from->keyp;
1741 di->key = from->key;
1743 di->repodataid = from->repodataid;
1744 di->solvid = from->solvid;
1745 di->repoid = from->repoid;
1746 di->rootlevel = from->rootlevel;
1747 memcpy(di->parents, from->parents, sizeof(from->parents));
1748 di->nparents = from->nparents;
1752 for (i = 1; i < di->nparents; i++)
1753 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1754 di->kv.parent = &di->parents[di->nparents - 1].kv;
1758 if (from->dupstr && from->dupstr == from->kv.str)
1760 di->dupstrn = from->dupstrn;
1761 di->dupstr = solv_malloc(from->dupstrn);
1762 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1767 dataiterator_seek(Dataiterator *di, int whence)
1769 if ((whence & DI_SEEK_STAY) != 0)
1770 di->rootlevel = di->nparents;
1771 switch (whence & ~DI_SEEK_STAY)
1774 if (di->state != di_nextarrayelement)
1776 if ((whence & DI_SEEK_STAY) != 0)
1777 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1778 di->state = di_entersub;
1780 case DI_SEEK_PARENT:
1787 if (di->rootlevel > di->nparents)
1788 di->rootlevel = di->nparents;
1789 di->dp = di->parents[di->nparents].dp;
1790 di->kv = di->parents[di->nparents].kv;
1791 di->keyp = di->parents[di->nparents].keyp;
1792 di->key = di->data->keys + *di->keyp;
1793 di->ddp = (unsigned char *)di->kv.str;
1794 di->keyname = di->keynames[di->nparents - di->rootlevel];
1795 di->state = di_nextarrayelement;
1797 case DI_SEEK_REWIND:
1803 di->dp = (unsigned char *)di->kv.parent->str;
1804 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1805 di->state = di_enterschema;
1813 dataiterator_skip_attribute(Dataiterator *di)
1815 if (di->state == di_nextsolvableattr)
1816 di->state = di_nextsolvablekey;
1818 di->state = di_nextkey;
1822 dataiterator_skip_solvable(Dataiterator *di)
1827 di->keyname = di->keynames[0];
1828 di->state = di_nextsolvable;
1832 dataiterator_skip_repo(Dataiterator *di)
1837 di->keyname = di->keynames[0];
1838 di->state = di_nextrepo;
1842 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1847 di->keyname = di->keynames[0];
1848 if (solvid == SOLVID_POS)
1850 di->repo = di->pool->pos.repo;
1857 di->data = di->repo->repodata + di->pool->pos.repodataid;
1859 di->solvid = solvid;
1860 di->state = di_enterrepo;
1861 di->flags |= SEARCH_THISSOLVID;
1866 di->repo = di->pool->solvables[solvid].repo;
1869 else if (di->repoid > 0)
1871 if (!di->pool->urepos)
1877 di->repo = di->pool->repos[di->repoid];
1880 di->solvid = solvid;
1882 di->flags |= SEARCH_THISSOLVID;
1883 di->state = di_enterrepo;
1887 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1893 di->repoid = 0; /* 0 means stay at repo */
1896 di->flags &= ~SEARCH_THISSOLVID;
1897 di->state = di_enterrepo;
1901 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1903 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1907 return datamatcher_match(ma, di->kv.str);
1911 dataiterator_strdup(Dataiterator *di)
1915 if (!di->kv.str || di->kv.str == di->dupstr)
1917 switch (di->key->type)
1919 case REPOKEY_TYPE_MD5:
1920 case REPOKEY_TYPE_SHA1:
1921 case REPOKEY_TYPE_SHA256:
1922 case REPOKEY_TYPE_DIRSTRARRAY:
1923 if (di->kv.num) /* was it stringified into tmp space? */
1924 l = strlen(di->kv.str) + 1;
1929 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1931 switch (di->key->type)
1933 case REPOKEY_TYPE_STR:
1934 case REPOKEY_TYPE_DIRSTRARRAY:
1935 l = strlen(di->kv.str) + 1;
1937 case REPOKEY_TYPE_MD5:
1940 case REPOKEY_TYPE_SHA1:
1943 case REPOKEY_TYPE_SHA256:
1946 case REPOKEY_TYPE_BINARY:
1953 if (!di->dupstrn || di->dupstrn < l)
1955 di->dupstrn = l + 16;
1956 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
1959 memcpy(di->dupstr, di->kv.str, l);
1960 di->kv.str = di->dupstr;
1964 /************************************************************************
1965 * data modify functions
1968 /* extend repodata so that it includes solvables p */
1970 repodata_extend(Repodata *data, Id p)
1972 if (data->start == data->end)
1973 data->start = data->end = p;
1976 int old = data->end - data->start;
1977 int new = p - data->end + 1;
1980 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1981 memset(data->attrs + old, 0, new * sizeof(Id *));
1983 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1984 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1987 if (p < data->start)
1989 int old = data->end - data->start;
1990 int new = data->start - p;
1993 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1994 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1995 memset(data->attrs, 0, new * sizeof(Id *));
1997 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1998 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1999 memset(data->incoreoffset, 0, new * sizeof(Id));
2004 /* shrink end of repodata */
2006 repodata_shrink(Repodata *data, int end)
2010 if (data->end <= end)
2012 if (data->start >= end)
2016 for (i = 0; i < data->end - data->start; i++)
2017 solv_free(data->attrs[i]);
2018 data->attrs = solv_free(data->attrs);
2020 data->incoreoffset = solv_free(data->incoreoffset);
2021 data->start = data->end = 0;
2026 for (i = end; i < data->end; i++)
2027 solv_free(data->attrs[i - data->start]);
2028 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2030 if (data->incoreoffset)
2031 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2035 /* extend repodata so that it includes solvables from start to start + num - 1 */
2037 repodata_extend_block(Repodata *data, Id start, Id num)
2041 if (!data->incoreoffset)
2043 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2044 data->start = start;
2045 data->end = start + num;
2048 repodata_extend(data, start);
2050 repodata_extend(data, start + num - 1);
2053 /**********************************************************************/
2056 #define REPODATA_ATTRS_BLOCK 31
2057 #define REPODATA_ATTRDATA_BLOCK 1023
2058 #define REPODATA_ATTRIDDATA_BLOCK 63
2059 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2063 repodata_new_handle(Repodata *data)
2067 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2068 data->nxattrs = 2; /* -1: SOLVID_META */
2070 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2071 data->xattrs[data->nxattrs] = 0;
2072 return -(data->nxattrs++);
2076 repodata_get_attrp(Repodata *data, Id handle)
2080 if (handle == SOLVID_META && !data->xattrs)
2082 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2085 return data->xattrs - handle;
2087 if (handle < data->start || handle >= data->end)
2088 repodata_extend(data, handle);
2090 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2091 return data->attrs + (handle - data->start);
2095 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2101 app = repodata_get_attrp(data, handle);
2106 /* Determine equality based on the name only, allows us to change
2107 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2108 for (pp = ap; *pp; pp += 2)
2109 if (data->keys[*pp].name == data->keys[keyid].name)
2113 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2122 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2132 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2136 keyid = repodata_key2id(data, key, 1);
2137 repodata_insert_keyid(data, solvid, keyid, val, 1);
2141 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2145 key.type = REPOKEY_TYPE_ID;
2147 key.storage = KEY_STORAGE_INCORE;
2148 repodata_set(data, solvid, &key, id);
2152 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2156 key.type = REPOKEY_TYPE_NUM;
2158 key.storage = KEY_STORAGE_INCORE;
2159 if (num >= 0x80000000)
2161 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2162 data->attrnum64data[data->attrnum64datalen] = num;
2163 num = 0x80000000 | data->attrnum64datalen++;
2165 repodata_set(data, solvid, &key, (Id)num);
2169 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2173 if (data->localpool)
2174 id = stringpool_str2id(&data->spool, str, 1);
2176 id = pool_str2id(data->repo->pool, str, 1);
2178 key.type = REPOKEY_TYPE_ID;
2180 key.storage = KEY_STORAGE_INCORE;
2181 repodata_set(data, solvid, &key, id);
2185 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2189 key.type = REPOKEY_TYPE_CONSTANT;
2190 key.size = constant;
2191 key.storage = KEY_STORAGE_INCORE;
2192 repodata_set(data, solvid, &key, 0);
2196 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2200 key.type = REPOKEY_TYPE_CONSTANTID;
2202 key.storage = KEY_STORAGE_INCORE;
2203 repodata_set(data, solvid, &key, 0);
2207 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2211 key.type = REPOKEY_TYPE_VOID;
2213 key.storage = KEY_STORAGE_INCORE;
2214 repodata_set(data, solvid, &key, 0);
2218 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2223 l = strlen(str) + 1;
2225 key.type = REPOKEY_TYPE_STR;
2227 key.storage = KEY_STORAGE_INCORE;
2228 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2229 memcpy(data->attrdata + data->attrdatalen, str, l);
2230 repodata_set(data, solvid, &key, data->attrdatalen);
2231 data->attrdatalen += l;
2235 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2243 key.type = REPOKEY_TYPE_BINARY;
2245 key.storage = KEY_STORAGE_INCORE;
2246 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2247 dp = data->attrdata + data->attrdatalen;
2248 if (len >= (1 << 14))
2250 if (len >= (1 << 28))
2251 *dp++ = (len >> 28) | 128;
2252 if (len >= (1 << 21))
2253 *dp++ = (len >> 21) | 128;
2254 *dp++ = (len >> 14) | 128;
2256 if (len >= (1 << 7))
2257 *dp++ = (len >> 7) | 128;
2260 memcpy(dp, buf, len);
2261 repodata_set(data, solvid, &key, data->attrdatalen);
2262 data->attrdatalen = dp + len - data->attrdata;
2265 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2266 * so that the caller can append entrysize new elements plus the termination zero there */
2268 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2271 Id *ida, *pp, **ppp;
2273 /* check if it is the same as last time, this speeds things up a lot */
2274 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2276 /* great! just append the new data */
2277 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2278 data->attriddatalen--; /* overwrite terminating 0 */
2279 data->lastdatalen += entrysize;
2283 ppp = repodata_get_attrp(data, handle);
2287 for (; *pp; pp += 2)
2288 if (data->keys[*pp].name == keyname)
2291 if (!pp || !*pp || data->keys[*pp].type != keytype)
2293 /* not found. allocate new key */
2299 key.storage = KEY_STORAGE_INCORE;
2300 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2301 keyid = repodata_key2id(data, &key, 1);
2302 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2303 data->lasthandle = handle;
2304 data->lastkey = keyid;
2305 data->lastdatalen = data->attriddatalen + entrysize + 1;
2309 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2310 oldsize += entrysize;
2311 if (ida + 1 == data->attriddata + data->attriddatalen)
2313 /* this was the last entry, just append it */
2314 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2315 data->attriddatalen--; /* overwrite terminating 0 */
2319 /* too bad. move to back. */
2320 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2321 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2322 pp[1] = data->attriddatalen;
2323 data->attriddatalen += oldsize;
2325 data->lasthandle = handle;
2326 data->lastkey = *pp;
2327 data->lastdatalen = data->attriddatalen + entrysize + 1;
2331 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2332 const unsigned char *str)
2337 if (!(l = solv_chksum_len(type)))
2342 key.storage = KEY_STORAGE_INCORE;
2343 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2344 memcpy(data->attrdata + data->attrdatalen, str, l);
2345 repodata_set(data, solvid, &key, data->attrdatalen);
2346 data->attrdatalen += l;
2350 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2353 unsigned char buf[64];
2356 if (!(l = solv_chksum_len(type)))
2358 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2360 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2364 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2368 if (!(l = solv_chksum_len(type)))
2370 return pool_bin2hex(data->repo->pool, buf, l);
2373 /* rpm filenames don't contain the epoch, so strip it */
2374 static inline const char *
2375 evrid2vrstr(Pool *pool, Id evrid)
2377 const char *p, *evr = pool_id2str(pool, evrid);
2380 for (p = evr; *p >= '0' && *p <= '9'; p++)
2382 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2386 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2389 if (data->localpool)
2390 id = stringpool_strn2id(&data->spool, str, l, 1);
2392 id = pool_strn2id(data->repo->pool, str, l, 1);
2393 repodata_set_id(data, solvid, keyname, id);
2397 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2400 repodata_set_str(data, solvid, keyname, str);
2403 char *s = solv_strdup(str);
2405 repodata_set_str(data, solvid, keyname, s);
2411 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2413 Pool *pool = data->repo->pool;
2415 const char *str, *fp;
2419 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2422 if ((dir = strrchr(file, '/')) != 0)
2433 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2438 if (l == 1 && dir[0] == '.')
2440 s = pool->solvables + solvid;
2443 str = pool_id2str(pool, s->arch);
2444 if (!strncmp(dir, str, l) && !str[l])
2445 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2447 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2450 str = pool_id2str(pool, s->name);
2452 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2455 str = evrid2vrstr(pool, s->evr);
2457 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2460 str = pool_id2str(pool, s->arch);
2462 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2464 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2469 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2472 /* XXX: medianr is currently not stored */
2474 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2477 const char *evr, *suf, *s;
2481 if ((dir = strrchr(file, '/')) != 0)
2492 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2497 if (l == 1 && dir[0] == '.')
2500 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2501 evr = strchr(file, '-');
2504 for (s = evr - 1; s > file; s--)
2511 suf = strrchr(file, '.');
2514 for (s = suf - 1; s > file; s--)
2520 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2522 /* We accept one more item as suffix. */
2523 for (s = suf - 1; s > file; s--)
2533 if (suf && evr && suf < evr)
2535 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2537 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2539 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2543 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2545 Pool *pool = data->repo->pool;
2546 Solvable *s = pool->solvables + solvid;
2547 const char *p, *sevr, *sarch, *name, *evr;
2549 p = strrchr(sourcepkg, '.');
2550 if (!p || strcmp(p, ".rpm") != 0)
2553 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2557 while (p > sourcepkg && *p != '.')
2559 if (*p != '.' || p == sourcepkg)
2562 while (p > sourcepkg && *p != '-')
2564 if (*p != '-' || p == sourcepkg)
2567 while (p > sourcepkg && *p != '-')
2569 if (*p != '-' || p == sourcepkg)
2572 pool = s->repo->pool;
2574 name = pool_id2str(pool, s->name);
2575 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2576 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2578 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2580 evr = evrid2vrstr(pool, s->evr);
2581 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2582 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2584 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2586 if (!strcmp(sarch, "src.rpm"))
2587 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2588 else if (!strcmp(sarch, "nosrc.rpm"))
2589 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2591 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2595 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2601 key.type = REPOKEY_TYPE_IDARRAY;
2603 key.storage = KEY_STORAGE_INCORE;
2604 repodata_set(data, solvid, &key, data->attriddatalen);
2605 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2606 for (i = 0; i < q->count; i++)
2607 data->attriddata[data->attriddatalen++] = q->elements[i];
2608 data->attriddata[data->attriddatalen++] = 0;
2612 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2616 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2618 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2619 data->attriddata[data->attriddatalen++] = dir;
2620 data->attriddata[data->attriddatalen++] = num;
2621 data->attriddata[data->attriddatalen++] = num2;
2622 data->attriddata[data->attriddatalen++] = 0;
2626 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2632 l = strlen(str) + 1;
2633 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2634 memcpy(data->attrdata + data->attrdatalen, str, l);
2635 stroff = data->attrdatalen;
2636 data->attrdatalen += l;
2639 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2641 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2642 data->attriddata[data->attriddatalen++] = dir;
2643 data->attriddata[data->attriddatalen++] = stroff;
2644 data->attriddata[data->attriddatalen++] = 0;
2648 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2651 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2653 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2654 data->attriddata[data->attriddatalen++] = id;
2655 data->attriddata[data->attriddatalen++] = 0;
2659 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2663 if (data->localpool)
2664 id = stringpool_str2id(&data->spool, str, 1);
2666 id = pool_str2id(data->repo->pool, str, 1);
2667 repodata_add_idarray(data, solvid, keyname, id);
2671 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2673 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2674 data->attriddata[data->attriddatalen++] = ghandle;
2675 data->attriddata[data->attriddatalen++] = 0;
2679 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2681 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2682 data->attriddata[data->attriddatalen++] = ghandle;
2683 data->attriddata[data->attriddatalen++] = 0;
2687 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2690 app = repodata_get_attrp(data, solvid);
2694 for (; *ap; ap += 2)
2695 if (data->keys[*ap].name == keyname)
2701 for (; *ap; ap += 2)
2703 if (data->keys[*ap].name == keyname)
2711 /* XXX: does not work correctly, needs fix in iterators! */
2713 repodata_unset(Repodata *data, Id solvid, Id keyname)
2717 key.type = REPOKEY_TYPE_DELETED;
2719 key.storage = KEY_STORAGE_INCORE;
2720 repodata_set(data, solvid, &key, 0);
2723 /* add all (uninternalized) attrs from src to dest */
2725 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2728 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2730 for (; *keyp; keyp += 2)
2731 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2734 /* add some (uninternalized) attrs from src to dest */
2736 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2739 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2741 for (; *keyp; keyp += 2)
2742 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2743 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2746 /* swap (uninternalized) attrs from src and dest */
2748 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2751 if (!data->attrs || dest == src)
2753 tmpattrs = data->attrs[dest - data->start];
2754 data->attrs[dest - data->start] = data->attrs[src - data->start];
2755 data->attrs[src - data->start] = tmpattrs;
2759 /**********************************************************************/
2761 /* TODO: unify with repo_write and repo_solv! */
2763 #define EXTDATA_BLOCK 1023
2771 data_addid(struct extdata *xd, Id sx)
2773 unsigned int x = (unsigned int)sx;
2776 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2777 dp = xd->buf + xd->len;
2782 *dp++ = (x >> 28) | 128;
2784 *dp++ = (x >> 21) | 128;
2785 *dp++ = (x >> 14) | 128;
2788 *dp++ = (x >> 7) | 128;
2790 xd->len = dp - xd->buf;
2794 data_addid64(struct extdata *xd, unsigned long long x)
2796 if (x >= 0x100000000)
2800 data_addid(xd, (Id)(x >> 35));
2801 xd->buf[xd->len - 1] |= 128;
2803 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2804 xd->buf[xd->len - 5] = (x >> 28) | 128;
2807 data_addid(xd, (Id)x);
2811 data_addideof(struct extdata *xd, Id sx, int eof)
2813 unsigned int x = (unsigned int)sx;
2816 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2817 dp = xd->buf + xd->len;
2822 *dp++ = (x >> 27) | 128;
2824 *dp++ = (x >> 20) | 128;
2825 *dp++ = (x >> 13) | 128;
2828 *dp++ = (x >> 6) | 128;
2829 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2830 xd->len = dp - xd->buf;
2834 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2836 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2837 memcpy(xd->buf + xd->len, blob, len);
2841 /*********************************/
2843 /* internalalize some key into incore/vincore data */
2846 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2847 struct extdata *newvincore,
2849 Repokey *key, Id val)
2853 unsigned int oldvincorelen = 0;
2857 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2860 oldvincorelen = xd->len;
2864 case REPOKEY_TYPE_VOID:
2865 case REPOKEY_TYPE_CONSTANT:
2866 case REPOKEY_TYPE_CONSTANTID:
2868 case REPOKEY_TYPE_STR:
2869 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2871 case REPOKEY_TYPE_MD5:
2872 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2874 case REPOKEY_TYPE_SHA1:
2875 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2877 case REPOKEY_TYPE_SHA256:
2878 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2880 case REPOKEY_TYPE_NUM:
2881 if (val & 0x80000000)
2883 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2887 case REPOKEY_TYPE_ID:
2888 case REPOKEY_TYPE_DIR:
2889 data_addid(xd, val);
2891 case REPOKEY_TYPE_BINARY:
2894 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2895 dp += (unsigned int)len;
2896 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2899 case REPOKEY_TYPE_IDARRAY:
2900 for (ida = data->attriddata + val; *ida; ida++)
2901 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2903 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2904 for (ida = data->attriddata + val; *ida; ida += 3)
2906 data_addid(xd, ida[0]);
2907 data_addid(xd, ida[1]);
2908 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2911 case REPOKEY_TYPE_DIRSTRARRAY:
2912 for (ida = data->attriddata + val; *ida; ida += 2)
2914 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2915 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2918 case REPOKEY_TYPE_FIXARRAY:
2922 for (ida = data->attriddata + val; *ida; ida++)
2926 kp = data->xattrs[-*ida];
2934 schemaid = repodata_schema2id(data, schema, 1);
2935 else if (schemaid != repodata_schema2id(data, schema, 0))
2937 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2943 data_addid(xd, num);
2944 data_addid(xd, schemaid);
2945 for (ida = data->attriddata + val; *ida; ida++)
2947 Id *kp = data->xattrs[-*ida];
2951 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2955 case REPOKEY_TYPE_FLEXARRAY:
2958 for (ida = data->attriddata + val; *ida; ida++)
2960 data_addid(xd, num);
2961 for (ida = data->attriddata + val; *ida; ida++)
2963 Id *kp = data->xattrs[-*ida];
2966 data_addid(xd, 0); /* XXX */
2973 schemaid = repodata_schema2id(data, schema, 1);
2974 data_addid(xd, schemaid);
2975 kp = data->xattrs[-*ida];
2977 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2982 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2985 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2987 /* put offset/len in incore */
2988 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2989 oldvincorelen = xd->len - oldvincorelen;
2990 data_addid(newincore, oldvincorelen);
2995 repodata_internalize(Repodata *data)
2997 Repokey *key, solvkey;
2999 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
3000 unsigned char *dp, *ndp;
3001 int newschema, oldcount;
3002 struct extdata newincore;
3003 struct extdata newvincore;
3006 if (!data->attrs && !data->xattrs)
3009 newvincore.buf = data->vincore;
3010 newvincore.len = data->vincorelen;
3012 /* find the solvables key, create if needed */
3013 memset(&solvkey, 0, sizeof(solvkey));
3014 solvkey.name = REPOSITORY_SOLVABLES;
3015 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3017 solvkey.storage = KEY_STORAGE_INCORE;
3018 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3020 schema = solv_malloc2(data->nkeys, sizeof(Id));
3021 seen = solv_malloc2(data->nkeys, sizeof(Id));
3023 /* Merge the data already existing (in data->schemata, ->incoredata and
3024 friends) with the new attributes in data->attrs[]. */
3025 nentry = data->end - data->start;
3026 memset(&newincore, 0, sizeof(newincore));
3027 data_addid(&newincore, 0); /* start data at offset 1 */
3029 data->mainschema = 0;
3030 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3032 /* join entry data */
3033 /* we start with the meta data, entry -1 */
3034 for (entry = -1; entry < nentry; entry++)
3036 memset(seen, 0, data->nkeys * sizeof(Id));
3038 dp = data->incoredata;
3041 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3042 dp = data_read_id(dp, &oldschema);
3045 fprintf(stderr, "oldschema %d\n", oldschema);
3046 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3047 fprintf(stderr, "schemadata %p\n", data->schemadata);
3049 /* seen: -1: old data 0: skipped >0: id + 1 */
3053 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3057 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3065 keyp = data->attrs ? data->attrs[entry] : 0;
3068 /* strip solvables key */
3070 for (sp = keyp = schema; *sp; sp++)
3071 if (*sp != solvkeyid)
3076 seen[solvkeyid] = 0;
3077 keyp = data->xattrs ? data->xattrs[1] : 0;
3080 for (; *keyp; keyp += 2)
3087 seen[*keyp] = keyp[1] + 1;
3089 if (entry < 0 && data->end != data->start)
3096 /* Ideally we'd like to sort the new schema here, to ensure
3097 schema equality independend of the ordering. We can't do that
3098 yet. For once see below (old ids need to come before new ids).
3099 An additional difficulty is that we also need to move
3100 the values with the keys. */
3101 schemaid = repodata_schema2id(data, schema, 1);
3103 schemaid = oldschema;
3106 /* Now create data blob. We walk through the (possibly new) schema
3107 and either copy over old data, or insert the new. */
3108 /* XXX Here we rely on the fact that the (new) schema has the form
3109 o1 o2 o3 o4 ... | n1 n2 n3 ...
3110 (oX being the old keyids (possibly overwritten), and nX being
3111 the new keyids). This rules out sorting the keyids in order
3112 to ensure a small schema count. */
3114 data->incoreoffset[entry] = newincore.len;
3115 data_addid(&newincore, schemaid);
3118 data->mainschema = schemaid;
3119 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3121 keypstart = data->schemadata + data->schemata[schemaid];
3122 for (keyp = keypstart; *keyp; keyp++)
3125 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3126 if (*keyp == solvkeyid)
3128 /* add flexarray entry count */
3129 data_addid(&newincore, data->end - data->start);
3132 key = data->keys + *keyp;
3134 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));
3139 /* Skip the data associated with this old key. */
3140 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3142 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3143 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3145 else if (key->storage == KEY_STORAGE_INCORE)
3146 ndp = data_skip_key(data, dp, key);
3149 if (seen[*keyp] == -1)
3151 /* If this key was an old one _and_ was not overwritten with
3152 a different value copy over the old value (we skipped it
3155 data_addblob(&newincore, dp, ndp - dp);
3158 else if (seen[*keyp])
3160 /* Otherwise we have a new value. Parse it into the internal
3162 repodata_serialize_key(data, &newincore, &newvincore,
3163 schema, key, seen[*keyp] - 1);
3167 if (entry >= 0 && data->attrs && data->attrs[entry])
3168 data->attrs[entry] = solv_free(data->attrs[entry]);
3170 /* free all xattrs */
3171 for (entry = 0; entry < data->nxattrs; entry++)
3172 if (data->xattrs[entry])
3173 solv_free(data->xattrs[entry]);
3174 data->xattrs = solv_free(data->xattrs);
3177 data->lasthandle = 0;
3179 data->lastdatalen = 0;
3182 repodata_free_schemahash(data);
3184 solv_free(data->incoredata);
3185 data->incoredata = newincore.buf;
3186 data->incoredatalen = newincore.len;
3187 data->incoredatafree = 0;
3189 solv_free(data->vincore);
3190 data->vincore = newvincore.buf;
3191 data->vincorelen = newvincore.len;
3193 data->attrs = solv_free(data->attrs);
3194 data->attrdata = solv_free(data->attrdata);
3195 data->attriddata = solv_free(data->attriddata);
3196 data->attrnum64data = solv_free(data->attrnum64data);
3197 data->attrdatalen = 0;
3198 data->attriddatalen = 0;
3199 data->attrnum64datalen = 0;
3203 repodata_disable_paging(Repodata *data)
3205 if (maybe_load_repodata(data, 0))
3207 repopagestore_disable_paging(&data->store);
3213 repodata_load_stub(Repodata *data)
3215 Repo *repo = data->repo;
3216 Pool *pool = repo->pool;
3218 struct _Pool_tmpspace oldtmpspace;
3220 if (!pool->loadcallback)
3222 data->state = REPODATA_ERROR;
3225 data->state = REPODATA_LOADING;
3227 /* save tmp space */
3228 oldtmpspace = pool->tmpspace;
3229 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3231 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3233 /* restore tmp space */
3234 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3235 solv_free(pool->tmpspace.buf[i]);
3236 pool->tmpspace = oldtmpspace;
3238 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3242 repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
3246 xkey.name = keyname;
3247 xkey.type = keytype;
3248 xkey.storage = KEY_STORAGE_INCORE;
3250 repodata_key2id(data, &xkey, 1);
3254 repodata_add_stub(Repodata **datap)
3256 Repodata *data = *datap;
3257 Repo *repo = data->repo;
3258 Id repodataid = data - repo->repodata;
3259 Repodata *sdata = repo_add_repodata(repo, 0);
3260 data = repo->repodata + repodataid;
3261 if (data->end > data->start)
3262 repodata_extend_block(sdata, data->start, data->end - data->start);
3263 sdata->state = REPODATA_STUB;
3264 sdata->loadcallback = repodata_load_stub;
3270 repodata_create_stubs(Repodata *data)
3272 Repo *repo = data->repo;
3273 Pool *pool = repo->pool;
3280 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3281 while (dataiterator_step(&di))
3282 if (di.data == data)
3284 dataiterator_free(&di);
3287 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3288 for (i = 0; i < cnt; i++)
3290 sdata = repodata_add_stub(&data);
3291 stubdataids[i] = sdata - repo->repodata;
3294 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3296 while (dataiterator_step(&di))
3298 if (di.data != data)
3300 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3302 dataiterator_entersub(&di);
3303 sdata = repo->repodata + stubdataids[i++];
3307 switch (di.key->type)
3309 case REPOKEY_TYPE_ID:
3310 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3312 case REPOKEY_TYPE_CONSTANTID:
3313 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3315 case REPOKEY_TYPE_STR:
3316 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3318 case REPOKEY_TYPE_VOID:
3319 repodata_set_void(sdata, SOLVID_META, di.key->name);
3321 case REPOKEY_TYPE_NUM:
3322 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3324 case REPOKEY_TYPE_MD5:
3325 case REPOKEY_TYPE_SHA1:
3326 case REPOKEY_TYPE_SHA256:
3327 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3329 case REPOKEY_TYPE_IDARRAY:
3330 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3331 if (di.key->name == REPOSITORY_KEYS)
3336 xkeyname = di.kv.id;
3340 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
3349 dataiterator_free(&di);
3350 for (i = 0; i < cnt; i++)
3351 repodata_internalize(repo->repodata + stubdataids[i]);
3352 solv_free(stubdataids);
3357 repodata_memused(Repodata *data)
3359 return data->incoredatalen + data->vincorelen;
3363 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: