2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
37 #define REPODATA_BLOCK 255
39 static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
42 repodata_initdata(Repodata *data, Repo *repo, int localpool)
44 memset(data, 0, sizeof (*data));
45 data->repodataid = data - repo->repodata;
47 data->localpool = localpool;
49 stringpool_init_empty(&data->spool);
50 /* dirpool_init(&data->dirpool); just zeros out again */
51 data->keys = solv_calloc(1, sizeof(Repokey));
53 data->schemata = solv_calloc(1, sizeof(Id));
54 data->schemadata = solv_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_freedata(Repodata *data)
65 solv_free(data->keys);
67 solv_free(data->schemata);
68 solv_free(data->schemadata);
69 solv_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 solv_free(data->mainschemaoffsets);
75 solv_free(data->incoredata);
76 solv_free(data->incoreoffset);
77 solv_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 solv_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 solv_free(data->attrs[i]);
86 solv_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 solv_free(data->xattrs[i]);
90 solv_free(data->xattrs);
92 solv_free(data->attrdata);
93 solv_free(data->attriddata);
94 solv_free(data->attrnum64data);
96 solv_free(data->dircache);
100 repodata_free(Repodata *data)
102 Repo *repo = data->repo;
103 int i = data - repo->repodata;
106 repodata_freedata(data);
107 if (i < repo->nrepodata - 1)
109 /* whoa! this changes the repodataids! */
110 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
111 for (; i < repo->nrepodata - 1; i++)
112 repo->repodata[i].repodataid = i;
115 if (repo->nrepodata == 1)
117 repo->repodata = solv_free(repo->repodata);
123 repodata_empty(Repodata *data, int localpool)
125 void (*loadcallback)(Repodata *) = data->loadcallback;
126 int state = data->state;
127 repodata_freedata(data);
128 repodata_initdata(data, data->repo, localpool);
130 data->loadcallback = loadcallback;
134 /***************************************************************
135 * key pool management
138 /* this is not so time critical that we need a hash, so we do a simple
141 repodata_key2id(Repodata *data, Repokey *key, int create)
145 for (keyid = 1; keyid < data->nkeys; keyid++)
146 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
148 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
152 if (keyid == data->nkeys)
156 /* allocate new key */
157 data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
158 data->keys[data->nkeys++] = *key;
159 if (data->verticaloffset)
161 data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
162 data->verticaloffset[data->nkeys - 1] = 0;
164 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
170 /***************************************************************
171 * schema pool management
174 #define SCHEMATA_BLOCK 31
175 #define SCHEMATADATA_BLOCK 255
178 repodata_schema2id(Repodata *data, Id *schema, int create)
185 return 0; /* XXX: allow empty schema? */
186 if ((schematahash = data->schematahash) == 0)
188 data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
189 for (i = 1; i < data->nschemata; i++)
191 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
196 data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
197 data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
200 for (sp = schema, len = 0, h = 0; *sp; len++)
205 cid = schematahash[h];
208 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
210 /* cache conflict, do a slow search */
211 for (cid = 1; cid < data->nschemata; cid++)
212 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
218 data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
219 data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
221 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
222 data->schemata[data->nschemata] = data->schemadatalen;
223 data->schemadatalen += len;
224 schematahash[h] = data->nschemata;
226 fprintf(stderr, "schema2id: new schema\n");
228 return data->nschemata++;
232 repodata_free_schemahash(Repodata *data)
234 data->schematahash = solv_free(data->schematahash);
236 data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
237 data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
241 /***************************************************************
242 * dir pool management
245 #ifndef HAVE_STRCHRNUL
246 static inline const char *strchrnul(const char *str, char x)
248 const char *p = strchr(str, x);
249 return p ? p : str + strlen(str);
253 #define DIRCACHE_SIZE 41 /* < 1k */
257 Id ids[DIRCACHE_SIZE];
258 char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
263 repodata_str2dir(Repodata *data, const char *dir, int create)
274 while (*dir == '/' && dir[1] == '/')
276 if (*dir == '/' && !dir[1])
278 if (data->dirpool.ndirs)
280 return dirpool_add_dir(&data->dirpool, 0, 1, create);
287 struct dircache *dircache = data->dircache;
291 if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
293 parent = dircache->ids[l];
309 dire = strchrnul(dir, '/');
311 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
313 id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
316 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
321 data->dircache = solv_calloc(1, sizeof(struct dircache));
325 if (l < DIRCACHE_SIZE)
327 data->dircache->ids[l] = parent;
328 memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
342 repodata_free_dircache(Repodata *data)
344 data->dircache = solv_free(data->dircache);
348 repodata_dir2str(Repodata *data, Id did, const char *suf)
350 Pool *pool = data->repo->pool;
357 return suf ? suf : "";
361 comp = dirpool_compid(&data->dirpool, parent);
362 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
364 parent = dirpool_parent(&data->dirpool, parent);
369 l += strlen(suf) + 1;
370 p = pool_alloctmpspace(pool, l + 1) + l;
381 comp = dirpool_compid(&data->dirpool, parent);
382 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
385 strncpy(p, comps, l);
386 parent = dirpool_parent(&data->dirpool, parent);
394 /***************************************************************
398 static inline unsigned char *
399 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
401 Id *keyp = data->schemadata + data->schemata[schema];
402 for (; *keyp; keyp++)
403 dp = data_skip_key(data, dp, data->keys + *keyp);
407 static unsigned char *
408 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
410 int nentries, schema;
413 case REPOKEY_TYPE_FIXARRAY:
414 dp = data_read_id(dp, &nentries);
417 dp = data_read_id(dp, &schema);
419 dp = data_skip_schema(data, dp, schema);
421 case REPOKEY_TYPE_FLEXARRAY:
422 dp = data_read_id(dp, &nentries);
425 dp = data_read_id(dp, &schema);
426 dp = data_skip_schema(data, dp, schema);
430 if (key->storage == KEY_STORAGE_INCORE)
431 dp = data_skip(dp, key->type);
432 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
434 dp = data_skip(dp, REPOKEY_TYPE_ID);
435 dp = data_skip(dp, REPOKEY_TYPE_ID);
441 static unsigned char *
442 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
448 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
451 for (i = 0; (k = *keyp++) != 0; i++)
453 return data->incoredata + data->mainschemaoffsets[i];
456 while ((k = *keyp++) != 0)
460 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
462 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
463 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
466 if (data->keys[k].storage != KEY_STORAGE_INCORE)
468 dp = data_skip_key(data, dp, data->keys + k);
473 static unsigned char *
474 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
479 if (off >= data->lastverticaloffset)
481 off -= data->lastverticaloffset;
482 if (off + len > data->vincorelen)
484 return data->vincore + off;
486 if (off + len > key->size)
488 /* we now have the offset, go into vertical */
489 off += data->verticaloffset[key - data->keys];
490 /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
491 dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
494 dp += off % REPOPAGE_BLOBSIZE;
498 static inline unsigned char *
499 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
501 unsigned char *dp = *dpp;
505 if (key->storage == KEY_STORAGE_INCORE)
508 *dpp = data_skip_key(data, dp, key);
511 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
514 dp = data_read_id(dp, &off);
515 dp = data_read_id(dp, &len);
518 return get_vertical_data(data, key, off, len);
524 load_repodata(Repodata *data)
526 if (data->loadcallback)
528 data->loadcallback(data);
529 if (data->state == REPODATA_AVAILABLE)
532 data->state = REPODATA_ERROR;
537 maybe_load_repodata(Repodata *data, Id keyname)
539 if (keyname && !repodata_precheck_keyname(data, keyname))
540 return 0; /* do not bother... */
547 for (i = 1; i < data->nkeys; i++)
548 if (keyname == data->keys[i].name)
550 if (i == data->nkeys)
553 return load_repodata(data);
556 case REPODATA_AVAILABLE:
557 case REPODATA_LOADING:
560 data->state = REPODATA_ERROR;
565 static inline unsigned char *
566 solvid2data(Repodata *data, Id solvid, Id *schemap)
568 unsigned char *dp = data->incoredata;
571 if (solvid == SOLVID_META) /* META */
573 else if (solvid == SOLVID_POS) /* META */
575 Pool *pool = data->repo->pool;
576 if (data->repo != pool->pos.repo)
578 if (data != data->repo->repodata + pool->pos.repodataid)
580 *schemap = pool->pos.schema;
581 return data->incoredata + pool->pos.dp;
585 if (solvid < data->start || solvid >= data->end)
587 dp += data->incoreoffset[solvid - data->start];
589 return data_read_id(dp, schemap);
592 /************************************************************************
596 static inline unsigned char *
597 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
600 Id schema, *keyp, *kp;
603 if (!maybe_load_repodata(data, keyname))
605 dp = solvid2data(data, solvid, &schema);
608 keyp = data->schemadata + data->schemata[schema];
609 for (kp = keyp; *kp; kp++)
610 if (data->keys[*kp].name == keyname)
614 *keypp = key = data->keys + *kp;
615 if (key->type == REPOKEY_TYPE_DELETED)
617 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
618 return dp; /* no need to forward... */
619 dp = forward_to_key(data, *kp, keyp, dp);
622 return get_data(data, key, &dp, 0);
626 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
628 Id schema, *keyp, *kp;
629 if (!maybe_load_repodata(data, keyname))
631 if (!solvid2data(data, solvid, &schema))
633 keyp = data->schemadata + data->schemata[schema];
634 for (kp = keyp; *kp; kp++)
635 if (data->keys[*kp].name == keyname)
636 return data->keys[*kp].type;
641 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
647 dp = find_key_data(data, solvid, keyname, &key);
650 if (key->type == REPOKEY_TYPE_CONSTANTID)
652 if (key->type != REPOKEY_TYPE_ID)
654 dp = data_read_id(dp, &id);
659 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
665 dp = find_key_data(data, solvid, keyname, &key);
668 if (key->type == REPOKEY_TYPE_STR)
669 return (const char *)dp;
670 if (key->type == REPOKEY_TYPE_CONSTANTID)
672 else if (key->type == REPOKEY_TYPE_ID)
673 dp = data_read_id(dp, &id);
677 return stringpool_id2str(&data->spool, id);
678 return pool_id2str(data->repo->pool, id);
682 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
686 unsigned int high, low;
689 dp = find_key_data(data, solvid, keyname, &key);
694 case REPOKEY_TYPE_NUM:
695 data_read_num64(dp, &low, &high);
696 *value = (unsigned long long)high << 32 | low;
698 case REPOKEY_TYPE_U32:
699 data_read_u32(dp, &low);
702 case REPOKEY_TYPE_CONSTANT:
711 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
717 if (!maybe_load_repodata(data, keyname))
719 dp = solvid2data(data, solvid, &schema);
722 /* can't use find_key_data as we need to test the type */
723 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
724 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
729 const unsigned char *
730 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
735 dp = find_key_data(data, solvid, keyname, &key);
738 if (!(key->type == REPOKEY_TYPE_MD5 || key->type == REPOKEY_TYPE_SHA1 || key->type == REPOKEY_TYPE_SHA256))
745 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
753 dp = find_key_data(data, solvid, keyname, &key);
756 if (key->type != REPOKEY_TYPE_IDARRAY && key->type != REPOKEY_TYPE_REL_IDARRAY)
760 dp = data_read_ideof(dp, &id, &eof);
769 repodata_globalize_id(Repodata *data, Id id, int create)
771 if (!id || !data || !data->localpool)
773 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
777 repodata_localize_id(Repodata *data, Id id, int create)
779 if (!id || !data || !data->localpool)
781 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
785 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
790 ap = data->attrs[solvid - data->start];
795 if (data->keys[*ap].name != keyname)
797 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
799 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
807 /************************************************************************
813 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
817 case REPOKEY_TYPE_ID:
818 case REPOKEY_TYPE_CONSTANTID:
819 case REPOKEY_TYPE_IDARRAY:
820 if (data && data->localpool)
821 kv->str = stringpool_id2str(&data->spool, kv->id);
823 kv->str = pool_id2str(pool, kv->id);
824 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
827 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
829 if (*s == ':' && s > kv->str)
833 case REPOKEY_TYPE_STR:
835 case REPOKEY_TYPE_DIRSTRARRAY:
836 if (!(flags & SEARCH_FILES))
837 return 1; /* match just the basename */
839 return 1; /* already stringified */
840 /* Put the full filename into kv->str. */
841 kv->str = repodata_dir2str(data, kv->id, kv->str);
842 kv->num = 1; /* mark stringification */
844 case REPOKEY_TYPE_MD5:
845 case REPOKEY_TYPE_SHA1:
846 case REPOKEY_TYPE_SHA256:
847 if (!(flags & SEARCH_CHECKSUMS))
848 return 0; /* skip em */
850 return 1; /* already stringified */
851 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
852 kv->num = 1; /* mark stringification */
860 struct subschema_data {
866 /* search a specific repodata */
868 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
872 Id keyid, *kp, *keyp;
873 unsigned char *dp, *ddp;
879 if (!maybe_load_repodata(data, keyname))
881 if (solvid == SOLVID_SUBSCHEMA)
883 struct subschema_data *subd = cbdata;
884 cbdata = subd->cbdata;
886 schema = subd->parent->id;
887 dp = (unsigned char *)subd->parent->str;
888 kv.parent = subd->parent;
893 dp = solvid2data(data, solvid, &schema);
896 s = data->repo->pool->solvables + solvid;
899 keyp = data->schemadata + data->schemata[schema];
902 /* search for a specific key */
903 for (kp = keyp; *kp; kp++)
904 if (data->keys[*kp].name == keyname)
908 dp = forward_to_key(data, *kp, keyp, dp);
914 while ((keyid = *keyp++) != 0)
917 key = data->keys + keyid;
918 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
920 if (key->type == REPOKEY_TYPE_DELETED)
922 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
924 struct subschema_data subd;
928 subd.cbdata = cbdata;
931 ddp = data_read_id(ddp, &nentries);
935 while (ddp && nentries > 0)
939 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
940 ddp = data_read_id(ddp, &schema);
942 kv.str = (char *)ddp;
943 stop = callback(cbdata, s, data, key, &kv);
944 if (stop > SEARCH_NEXT_KEY)
946 if (stop && stop != SEARCH_ENTERSUB)
948 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
949 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
950 ddp = data_skip_schema(data, ddp, schema);
953 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
957 kv.str = (char *)ddp;
958 stop = callback(cbdata, s, data, key, &kv);
959 if (stop > SEARCH_NEXT_KEY)
969 ddp = data_fetch(ddp, &kv, key);
972 stop = callback(cbdata, s, data, key, &kv);
975 while (!kv.eof && !stop);
976 if (onekey || stop > SEARCH_NEXT_KEY)
982 repodata_setpos_kv(Repodata *data, KeyValue *kv)
984 Pool *pool = data->repo->pool;
986 pool_clear_pos(pool);
989 pool->pos.repo = data->repo;
990 pool->pos.repodataid = data - data->repo->repodata;
991 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
992 pool->pos.schema = kv->id;
996 /************************************************************************
997 * data iterator functions
1001 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1015 case SOLVABLE_VENDOR:
1018 case SOLVABLE_PROVIDES:
1020 return s->provides ? s->repo->idarraydata + s->provides : 0;
1021 case SOLVABLE_OBSOLETES:
1023 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1024 case SOLVABLE_CONFLICTS:
1026 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1027 case SOLVABLE_REQUIRES:
1029 return s->requires ? s->repo->idarraydata + s->requires : 0;
1030 case SOLVABLE_RECOMMENDS:
1032 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1033 case SOLVABLE_SUPPLEMENTS:
1035 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1036 case SOLVABLE_SUGGESTS:
1038 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1039 case SOLVABLE_ENHANCES:
1041 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1044 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1051 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1057 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1059 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1060 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1063 solv_free(ma->matchdata);
1064 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1067 if ((flags & SEARCH_FILES) != 0 && match)
1069 /* prepare basename check */
1070 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1072 const char *p = strrchr(match, '/');
1073 ma->matchdata = (void *)(p ? p + 1 : match);
1075 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1078 for (p = match + strlen(match) - 1; p >= match; p--)
1079 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1081 ma->matchdata = (void *)(p + 1);
1088 datamatcher_free(Datamatcher *ma)
1090 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1092 regfree(ma->matchdata);
1093 solv_free(ma->matchdata);
1099 datamatcher_match(Datamatcher *ma, const char *str)
1102 switch ((ma->flags & SEARCH_STRINGMASK))
1104 case SEARCH_SUBSTRING:
1105 if (ma->flags & SEARCH_NOCASE)
1106 return strcasestr(str, ma->match) != 0;
1108 return strstr(str, ma->match) != 0;
1110 if (ma->flags & SEARCH_NOCASE)
1111 return !strcasecmp(ma->match, str);
1113 return !strcmp(ma->match, str);
1114 case SEARCH_STRINGSTART:
1115 if (ma->flags & SEARCH_NOCASE)
1116 return !strncasecmp(ma->match, str, strlen(ma->match));
1118 return !strncmp(ma->match, str, strlen(ma->match));
1119 case SEARCH_STRINGEND:
1120 l = strlen(str) - strlen(ma->match);
1123 if (ma->flags & SEARCH_NOCASE)
1124 return !strcasecmp(ma->match, str + l);
1126 return !strcmp(ma->match, str + l);
1128 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1130 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1136 /* check if the matcher can match the provides basename */
1139 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1142 const char *match = ma->matchdata;
1145 switch (ma->flags & SEARCH_STRINGMASK)
1149 case SEARCH_STRINGEND:
1150 if (match != ma->match)
1151 break; /* had slash, do exact match on basename */
1154 /* check if the basename ends with match */
1155 l = strlen(basename) - strlen(match);
1161 return 1; /* maybe matches */
1163 if ((ma->flags & SEARCH_NOCASE) != 0)
1164 return !strcasecmp(match, basename);
1166 return !strcmp(match, basename);
1170 repodata_filelistfilter_matches(Repodata *data, const char *str)
1172 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1173 /* for now hardcoded */
1174 if (strstr(str, "bin/"))
1176 if (!strncmp(str, "/etc/", 5))
1178 if (!strcmp(str, "/usr/lib/sendmail"))
1200 di_nextarrayelement,
1206 di_entersolvablekey,
1210 /* see dataiterator.h for documentation */
1212 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1214 memset(di, 0, sizeof(*di));
1216 di->flags = flags & ~SEARCH_THISSOLVID;
1217 if (!pool || (repo && repo->pool != pool))
1225 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1231 di->keyname = keyname;
1232 di->keynames[0] = keyname;
1233 dataiterator_set_search(di, repo, p);
1238 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1243 if (di->dupstr == di->kv.str)
1245 di->dupstr = solv_malloc(di->dupstrn);
1246 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1254 memset(&di->matcher, 0, sizeof(di->matcher));
1255 if (from->matcher.match)
1256 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1261 for (i = 1; i < di->nparents; i++)
1262 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1263 di->kv.parent = &di->parents[di->nparents - 1].kv;
1268 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1270 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1271 datamatcher_free(&di->matcher);
1272 memset(&di->matcher, 0, sizeof(di->matcher));
1276 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1286 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1290 di->flags &= ~SEARCH_THISSOLVID;
1294 if (!di->pool->urepos)
1302 di->repo = di->pool->repos[di->repoid];
1304 di->state = di_enterrepo;
1306 dataiterator_jump_to_solvid(di, p);
1310 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1313 di->keyname = keyname;
1314 di->keynames[0] = keyname;
1318 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1322 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1324 di->state = di_bye; /* sorry */
1327 for (i = di->nkeynames + 1; i > 0; i--)
1328 di->keynames[i] = di->keynames[i - 1];
1329 di->keynames[0] = di->keyname = keyname;
1334 dataiterator_free(Dataiterator *di)
1336 if (di->matcher.match)
1337 datamatcher_free(&di->matcher);
1339 solv_free(di->dupstr);
1342 static inline unsigned char *
1343 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1345 Id *keyp = di->keyp;
1346 Repokey *keys = di->data->keys;
1349 for (keyp = di->keyp; *keyp; keyp++)
1350 if (keys[*keyp].name == keyname)
1354 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1362 dataiterator_filelistcheck(Dataiterator *di)
1365 int needcomplete = 0;
1366 Repodata *data = di->data;
1368 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1369 if (!di->matcher.match
1370 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1371 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1372 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1374 if (data->state != REPODATA_AVAILABLE)
1375 return needcomplete ? 1 : 0;
1376 for (j = 1; j < data->nkeys; j++)
1377 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1379 return j == data->nkeys && !needcomplete ? 0 : 1;
1383 dataiterator_step(Dataiterator *di)
1387 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1388 unsigned int ddpoff = di->ddp - di->vert_ddp;
1389 di->vert_off += ddpoff;
1390 di->vert_len -= ddpoff;
1391 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1392 di->vert_storestate = di->data->storestate;
1394 di->state = di_nextkey;
1400 case di_enterrepo: di_enterrepo:
1401 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1403 if (!(di->flags & SEARCH_THISSOLVID))
1405 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1406 goto di_nextsolvable;
1410 case di_entersolvable: di_entersolvable:
1413 di->repodataid = 1; /* reset repodata iterator */
1414 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)
1416 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1418 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1420 goto di_entersolvablekey;
1425 case di_enterrepodata: di_enterrepodata:
1428 if (di->repodataid >= di->repo->nrepodata)
1429 goto di_nextsolvable;
1430 di->data = di->repo->repodata + di->repodataid;
1432 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1433 goto di_nextrepodata;
1434 if (!maybe_load_repodata(di->data, di->keyname))
1435 goto di_nextrepodata;
1436 di->dp = solvid2data(di->data, di->solvid, &schema);
1438 goto di_nextrepodata;
1439 if (di->solvid == SOLVID_POS)
1440 di->solvid = di->pool->pos.solvid;
1441 /* reset key iterator */
1442 di->keyp = di->data->schemadata + di->data->schemata[schema];
1445 case di_enterschema: di_enterschema:
1447 di->dp = dataiterator_find_keyname(di, di->keyname);
1448 if (!di->dp || !*di->keyp)
1452 goto di_nextrepodata;
1456 case di_enterkey: di_enterkey:
1458 di->key = di->data->keys + *di->keyp;
1461 /* this is get_data() modified to store vert_ data */
1462 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1465 di->dp = data_read_id(di->dp, &off);
1466 di->dp = data_read_id(di->dp, &len);
1467 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1470 di->vert_storestate = di->data->storestate;
1472 else if (di->key->storage == KEY_STORAGE_INCORE)
1475 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1476 di->dp = data_skip_key(di->data, di->dp, di->key);
1482 if (di->key->type == REPOKEY_TYPE_DELETED)
1484 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1486 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1492 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1494 di->state = di_nextkey;
1496 di->state = di_nextattr;
1499 case di_nextkey: di_nextkey:
1500 if (!di->keyname && *++di->keyp)
1506 case di_nextrepodata: di_nextrepodata:
1507 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1508 goto di_enterrepodata;
1511 case di_nextsolvable: di_nextsolvable:
1512 if (!(di->flags & SEARCH_THISSOLVID))
1515 di->solvid = di->repo->start;
1518 for (; di->solvid < di->repo->end; di->solvid++)
1520 if (di->pool->solvables[di->solvid].repo == di->repo)
1521 goto di_entersolvable;
1526 case di_nextrepo: di_nextrepo:
1531 if (di->repoid < di->pool->nrepos)
1533 di->repo = di->pool->repos[di->repoid];
1539 case di_bye: di_bye:
1543 case di_enterarray: di_enterarray:
1544 if (di->key->name == REPOSITORY_SOLVABLES)
1546 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1551 case di_nextarrayelement: di_nextarrayelement:
1554 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1555 if (di->kv.entry == di->kv.num)
1557 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1559 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1561 di->kv.str = (char *)di->ddp;
1563 di->state = di_nextkey;
1566 if (di->kv.entry == di->kv.num - 1)
1568 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1569 di->ddp = data_read_id(di->ddp, &di->kv.id);
1570 di->kv.str = (char *)di->ddp;
1571 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1573 if ((di->flags & SEARCH_SUB) != 0)
1574 di->state = di_entersub;
1576 di->state = di_nextarrayelement;
1579 case di_entersub: di_entersub:
1580 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1581 goto di_nextarrayelement; /* sorry, full */
1582 di->parents[di->nparents].kv = di->kv;
1583 di->parents[di->nparents].dp = di->dp;
1584 di->parents[di->nparents].keyp = di->keyp;
1585 di->dp = (unsigned char *)di->kv.str;
1586 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1587 memset(&di->kv, 0, sizeof(di->kv));
1588 di->kv.parent = &di->parents[di->nparents].kv;
1590 di->keyname = di->keynames[di->nparents - di->rootlevel];
1591 goto di_enterschema;
1593 case di_leavesub: di_leavesub:
1594 if (di->nparents - 1 < di->rootlevel)
1597 di->dp = di->parents[di->nparents].dp;
1598 di->kv = di->parents[di->nparents].kv;
1599 di->keyp = di->parents[di->nparents].keyp;
1600 di->key = di->data->keys + *di->keyp;
1601 di->ddp = (unsigned char *)di->kv.str;
1602 di->keyname = di->keynames[di->nparents - di->rootlevel];
1603 goto di_nextarrayelement;
1605 /* special solvable attr handling follows */
1607 case di_nextsolvablekey: di_nextsolvablekey:
1608 if (di->keyname || di->key->name == RPM_RPMDBID)
1609 goto di_enterrepodata;
1613 case di_entersolvablekey: di_entersolvablekey:
1614 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1615 if (!di->idp || !*di->idp)
1616 goto di_nextsolvablekey;
1620 di->kv.id = *di->idp;
1621 di->kv.num = *di->idp; /* for rpmdbid */
1622 di->kv.num2 = 0; /* for rpmdbid */
1624 di->state = di_nextsolvablekey;
1630 case di_nextsolvableattr:
1631 di->state = di_nextsolvableattr;
1632 di->kv.id = *di->idp++;
1637 di->state = di_nextsolvablekey;
1643 if (di->matcher.match)
1645 /* simple pre-check so that we don't need to stringify */
1646 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1647 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1649 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1651 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1655 if (!datamatcher_match(&di->matcher, di->kv.str))
1660 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1661 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1663 /* found something! */
1669 dataiterator_entersub(Dataiterator *di)
1671 if (di->state == di_nextarrayelement)
1672 di->state = di_entersub;
1676 dataiterator_setpos(Dataiterator *di)
1678 if (di->kv.eof == 2)
1680 pool_clear_pos(di->pool);
1683 di->pool->pos.solvid = di->solvid;
1684 di->pool->pos.repo = di->repo;
1685 di->pool->pos.repodataid = di->data - di->repo->repodata;
1686 di->pool->pos.schema = di->kv.id;
1687 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1691 dataiterator_setpos_parent(Dataiterator *di)
1693 if (!di->kv.parent || di->kv.parent->eof == 2)
1695 pool_clear_pos(di->pool);
1698 di->pool->pos.solvid = di->solvid;
1699 di->pool->pos.repo = di->repo;
1700 di->pool->pos.repodataid = di->data - di->repo->repodata;
1701 di->pool->pos.schema = di->kv.parent->id;
1702 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1705 /* clones just the position, not the search keys/matcher */
1707 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1709 di->state = from->state;
1710 di->flags &= ~SEARCH_THISSOLVID;
1711 di->flags |= (from->flags & SEARCH_THISSOLVID);
1712 di->repo = from->repo;
1713 di->data = from->data;
1715 di->ddp = from->ddp;
1716 di->idp = from->idp;
1717 di->keyp = from->keyp;
1718 di->key = from->key;
1720 di->repodataid = from->repodataid;
1721 di->solvid = from->solvid;
1722 di->repoid = from->repoid;
1723 di->rootlevel = from->rootlevel;
1724 memcpy(di->parents, from->parents, sizeof(from->parents));
1725 di->nparents = from->nparents;
1729 for (i = 1; i < di->nparents; i++)
1730 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1731 di->kv.parent = &di->parents[di->nparents - 1].kv;
1735 if (from->dupstr && from->dupstr == from->kv.str)
1737 di->dupstrn = from->dupstrn;
1738 di->dupstr = solv_malloc(from->dupstrn);
1739 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1744 dataiterator_seek(Dataiterator *di, int whence)
1746 if ((whence & DI_SEEK_STAY) != 0)
1747 di->rootlevel = di->nparents;
1748 switch (whence & ~DI_SEEK_STAY)
1751 if (di->state != di_nextarrayelement)
1753 if ((whence & DI_SEEK_STAY) != 0)
1754 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1755 di->state = di_entersub;
1757 case DI_SEEK_PARENT:
1764 if (di->rootlevel > di->nparents)
1765 di->rootlevel = di->nparents;
1766 di->dp = di->parents[di->nparents].dp;
1767 di->kv = di->parents[di->nparents].kv;
1768 di->keyp = di->parents[di->nparents].keyp;
1769 di->key = di->data->keys + *di->keyp;
1770 di->ddp = (unsigned char *)di->kv.str;
1771 di->keyname = di->keynames[di->nparents - di->rootlevel];
1772 di->state = di_nextarrayelement;
1774 case DI_SEEK_REWIND:
1780 di->dp = (unsigned char *)di->kv.parent->str;
1781 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1782 di->state = di_enterschema;
1790 dataiterator_skip_attribute(Dataiterator *di)
1792 if (di->state == di_nextsolvableattr)
1793 di->state = di_nextsolvablekey;
1795 di->state = di_nextkey;
1799 dataiterator_skip_solvable(Dataiterator *di)
1804 di->keyname = di->keynames[0];
1805 di->state = di_nextsolvable;
1809 dataiterator_skip_repo(Dataiterator *di)
1814 di->keyname = di->keynames[0];
1815 di->state = di_nextrepo;
1819 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1824 di->keyname = di->keynames[0];
1825 if (solvid == SOLVID_POS)
1827 di->repo = di->pool->pos.repo;
1834 di->data = di->repo->repodata + di->pool->pos.repodataid;
1836 di->solvid = solvid;
1837 di->state = di_enterrepo;
1838 di->flags |= SEARCH_THISSOLVID;
1843 di->repo = di->pool->solvables[solvid].repo;
1846 else if (di->repoid > 0)
1848 if (!di->pool->urepos)
1854 di->repo = di->pool->repos[di->repoid];
1857 di->solvid = solvid;
1859 di->flags |= SEARCH_THISSOLVID;
1860 di->state = di_enterrepo;
1864 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1870 di->repoid = 0; /* 0 means stay at repo */
1873 di->flags &= ~SEARCH_THISSOLVID;
1874 di->state = di_enterrepo;
1878 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1880 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1884 return datamatcher_match(ma, di->kv.str);
1888 dataiterator_strdup(Dataiterator *di)
1892 if (!di->kv.str || di->kv.str == di->dupstr)
1894 switch (di->key->type)
1896 case REPOKEY_TYPE_MD5:
1897 case REPOKEY_TYPE_SHA1:
1898 case REPOKEY_TYPE_SHA256:
1899 case REPOKEY_TYPE_DIRSTRARRAY:
1900 if (di->kv.num) /* was it stringified into tmp space? */
1901 l = strlen(di->kv.str) + 1;
1906 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1908 switch (di->key->type)
1910 case REPOKEY_TYPE_STR:
1911 case REPOKEY_TYPE_DIRSTRARRAY:
1912 l = strlen(di->kv.str) + 1;
1914 case REPOKEY_TYPE_MD5:
1917 case REPOKEY_TYPE_SHA1:
1920 case REPOKEY_TYPE_SHA256:
1923 case REPOKEY_TYPE_BINARY:
1930 if (!di->dupstrn || di->dupstrn < l)
1932 di->dupstrn = l + 16;
1933 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
1936 memcpy(di->dupstr, di->kv.str, l);
1937 di->kv.str = di->dupstr;
1941 /************************************************************************
1942 * data modify functions
1945 /* extend repodata so that it includes solvables p */
1947 repodata_extend(Repodata *data, Id p)
1949 if (data->start == data->end)
1950 data->start = data->end = p;
1953 int old = data->end - data->start;
1954 int new = p - data->end + 1;
1957 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1958 memset(data->attrs + old, 0, new * sizeof(Id *));
1960 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1961 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1964 if (p < data->start)
1966 int old = data->end - data->start;
1967 int new = data->start - p;
1970 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1971 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1972 memset(data->attrs, 0, new * sizeof(Id *));
1974 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1975 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1976 memset(data->incoreoffset, 0, new * sizeof(Id));
1981 /* shrink end of repodata */
1983 repodata_shrink(Repodata *data, int end)
1987 if (data->end <= end)
1989 if (data->start >= end)
1993 for (i = 0; i < data->end - data->start; i++)
1994 solv_free(data->attrs[i]);
1995 data->attrs = solv_free(data->attrs);
1997 data->incoreoffset = solv_free(data->incoreoffset);
1998 data->start = data->end = 0;
2003 for (i = end; i < data->end; i++)
2004 solv_free(data->attrs[i - data->start]);
2005 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2007 if (data->incoreoffset)
2008 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2012 /* extend repodata so that it includes solvables from start to start + num - 1 */
2014 repodata_extend_block(Repodata *data, Id start, Id num)
2018 if (!data->incoreoffset)
2020 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2021 data->start = start;
2022 data->end = start + num;
2025 repodata_extend(data, start);
2027 repodata_extend(data, start + num - 1);
2030 /**********************************************************************/
2033 #define REPODATA_ATTRS_BLOCK 31
2034 #define REPODATA_ATTRDATA_BLOCK 1023
2035 #define REPODATA_ATTRIDDATA_BLOCK 63
2036 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2040 repodata_new_handle(Repodata *data)
2044 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2045 data->nxattrs = 2; /* -1: SOLVID_META */
2047 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2048 data->xattrs[data->nxattrs] = 0;
2049 return -(data->nxattrs++);
2053 repodata_get_attrp(Repodata *data, Id handle)
2057 if (handle == SOLVID_META && !data->xattrs)
2059 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2062 return data->xattrs - handle;
2064 if (handle < data->start || handle >= data->end)
2065 repodata_extend(data, handle);
2067 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2068 return data->attrs + (handle - data->start);
2072 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2078 app = repodata_get_attrp(data, handle);
2083 /* Determine equality based on the name only, allows us to change
2084 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2085 for (pp = ap; *pp; pp += 2)
2086 if (data->keys[*pp].name == data->keys[keyid].name)
2090 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2099 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2109 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2113 keyid = repodata_key2id(data, key, 1);
2114 repodata_insert_keyid(data, solvid, keyid, val, 1);
2118 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2122 key.type = REPOKEY_TYPE_ID;
2124 key.storage = KEY_STORAGE_INCORE;
2125 repodata_set(data, solvid, &key, id);
2129 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2133 key.type = REPOKEY_TYPE_NUM;
2135 key.storage = KEY_STORAGE_INCORE;
2136 if (num >= 0x80000000)
2138 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2139 data->attrnum64data[data->attrnum64datalen] = num;
2140 num = 0x80000000 | data->attrnum64datalen++;
2142 repodata_set(data, solvid, &key, (Id)num);
2146 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2150 if (data->localpool)
2151 id = stringpool_str2id(&data->spool, str, 1);
2153 id = pool_str2id(data->repo->pool, str, 1);
2155 key.type = REPOKEY_TYPE_ID;
2157 key.storage = KEY_STORAGE_INCORE;
2158 repodata_set(data, solvid, &key, id);
2162 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2166 key.type = REPOKEY_TYPE_CONSTANT;
2167 key.size = constant;
2168 key.storage = KEY_STORAGE_INCORE;
2169 repodata_set(data, solvid, &key, 0);
2173 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2177 key.type = REPOKEY_TYPE_CONSTANTID;
2179 key.storage = KEY_STORAGE_INCORE;
2180 repodata_set(data, solvid, &key, 0);
2184 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2188 key.type = REPOKEY_TYPE_VOID;
2190 key.storage = KEY_STORAGE_INCORE;
2191 repodata_set(data, solvid, &key, 0);
2195 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2200 l = strlen(str) + 1;
2202 key.type = REPOKEY_TYPE_STR;
2204 key.storage = KEY_STORAGE_INCORE;
2205 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2206 memcpy(data->attrdata + data->attrdatalen, str, l);
2207 repodata_set(data, solvid, &key, data->attrdatalen);
2208 data->attrdatalen += l;
2212 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2220 key.type = REPOKEY_TYPE_BINARY;
2222 key.storage = KEY_STORAGE_INCORE;
2223 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2224 dp = data->attrdata + data->attrdatalen;
2225 if (len >= (1 << 14))
2227 if (len >= (1 << 28))
2228 *dp++ = (len >> 28) | 128;
2229 if (len >= (1 << 21))
2230 *dp++ = (len >> 21) | 128;
2231 *dp++ = (len >> 14) | 128;
2233 if (len >= (1 << 7))
2234 *dp++ = (len >> 7) | 128;
2237 memcpy(dp, buf, len);
2238 repodata_set(data, solvid, &key, data->attrdatalen);
2239 data->attrdatalen = dp + len - data->attrdata;
2242 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2243 * so that the caller can append entrysize new elements plus the termination zero there */
2245 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2248 Id *ida, *pp, **ppp;
2250 /* check if it is the same as last time, this speeds things up a lot */
2251 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2253 /* great! just append the new data */
2254 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2255 data->attriddatalen--; /* overwrite terminating 0 */
2256 data->lastdatalen += entrysize;
2260 ppp = repodata_get_attrp(data, handle);
2264 for (; *pp; pp += 2)
2265 if (data->keys[*pp].name == keyname)
2268 if (!pp || !*pp || data->keys[*pp].type != keytype)
2270 /* not found. allocate new key */
2276 key.storage = KEY_STORAGE_INCORE;
2277 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2278 keyid = repodata_key2id(data, &key, 1);
2279 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2280 data->lasthandle = handle;
2281 data->lastkey = keyid;
2282 data->lastdatalen = data->attriddatalen + entrysize + 1;
2286 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2287 oldsize += entrysize;
2288 if (ida + 1 == data->attriddata + data->attriddatalen)
2290 /* this was the last entry, just append it */
2291 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2292 data->attriddatalen--; /* overwrite terminating 0 */
2296 /* too bad. move to back. */
2297 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2298 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2299 pp[1] = data->attriddatalen;
2300 data->attriddatalen += oldsize;
2302 data->lasthandle = handle;
2303 data->lastkey = *pp;
2304 data->lastdatalen = data->attriddatalen + entrysize + 1;
2308 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2309 const unsigned char *str)
2314 if (!(l = solv_chksum_len(type)))
2319 key.storage = KEY_STORAGE_INCORE;
2320 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2321 memcpy(data->attrdata + data->attrdatalen, str, l);
2322 repodata_set(data, solvid, &key, data->attrdatalen);
2323 data->attrdatalen += l;
2327 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2330 unsigned char buf[64];
2333 if (!(l = solv_chksum_len(type)))
2335 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2337 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2341 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2345 if (!(l = solv_chksum_len(type)))
2347 return pool_bin2hex(data->repo->pool, buf, l);
2350 /* rpm filenames don't contain the epoch, so strip it */
2351 static inline const char *
2352 evrid2vrstr(Pool *pool, Id evrid)
2354 const char *p, *evr = pool_id2str(pool, evrid);
2357 for (p = evr; *p >= '0' && *p <= '9'; p++)
2359 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2363 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2366 if (data->localpool)
2367 id = stringpool_strn2id(&data->spool, str, l, 1);
2369 id = pool_strn2id(data->repo->pool, str, l, 1);
2370 repodata_set_id(data, solvid, keyname, id);
2374 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2377 repodata_set_str(data, solvid, keyname, str);
2380 char *s = solv_strdup(str);
2382 repodata_set_str(data, solvid, keyname, s);
2388 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2390 Pool *pool = data->repo->pool;
2392 const char *str, *fp;
2396 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2399 if ((dir = strrchr(file, '/')) != 0)
2410 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2415 if (l == 1 && dir[0] == '.')
2417 s = pool->solvables + solvid;
2420 str = pool_id2str(pool, s->arch);
2421 if (!strncmp(dir, str, l) && !str[l])
2422 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2424 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2427 str = pool_id2str(pool, s->name);
2429 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2432 str = evrid2vrstr(pool, s->evr);
2434 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2437 str = pool_id2str(pool, s->arch);
2439 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2441 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2446 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2449 /* XXX: medianr is currently not stored */
2451 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2454 const char *evr, *suf, *s;
2458 if ((dir = strrchr(file, '/')) != 0)
2469 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2474 if (l == 1 && dir[0] == '.')
2477 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2478 evr = strchr(file, '-');
2481 for (s = evr - 1; s > file; s--)
2488 suf = strrchr(file, '.');
2491 for (s = suf - 1; s > file; s--)
2497 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2499 /* We accept one more item as suffix. */
2500 for (s = suf - 1; s > file; s--)
2510 if (suf && evr && suf < evr)
2512 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2514 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2516 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2520 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2522 Pool *pool = data->repo->pool;
2523 Solvable *s = pool->solvables + solvid;
2524 const char *p, *sevr, *sarch, *name, *evr;
2526 p = strrchr(sourcepkg, '.');
2527 if (!p || strcmp(p, ".rpm") != 0)
2530 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2534 while (p > sourcepkg && *p != '.')
2536 if (*p != '.' || p == sourcepkg)
2539 while (p > sourcepkg && *p != '-')
2541 if (*p != '-' || p == sourcepkg)
2544 while (p > sourcepkg && *p != '-')
2546 if (*p != '-' || p == sourcepkg)
2549 pool = s->repo->pool;
2551 name = pool_id2str(pool, s->name);
2552 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2553 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2555 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2557 evr = evrid2vrstr(pool, s->evr);
2558 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2559 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2561 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2563 if (!strcmp(sarch, "src.rpm"))
2564 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2565 else if (!strcmp(sarch, "nosrc.rpm"))
2566 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2568 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2572 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2578 key.type = REPOKEY_TYPE_IDARRAY;
2580 key.storage = KEY_STORAGE_INCORE;
2581 repodata_set(data, solvid, &key, data->attriddatalen);
2582 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2583 for (i = 0; i < q->count; i++)
2584 data->attriddata[data->attriddatalen++] = q->elements[i];
2585 data->attriddata[data->attriddatalen++] = 0;
2589 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2593 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2595 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2596 data->attriddata[data->attriddatalen++] = dir;
2597 data->attriddata[data->attriddatalen++] = num;
2598 data->attriddata[data->attriddatalen++] = num2;
2599 data->attriddata[data->attriddatalen++] = 0;
2603 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2609 l = strlen(str) + 1;
2610 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2611 memcpy(data->attrdata + data->attrdatalen, str, l);
2612 stroff = data->attrdatalen;
2613 data->attrdatalen += l;
2616 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2618 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2619 data->attriddata[data->attriddatalen++] = dir;
2620 data->attriddata[data->attriddatalen++] = stroff;
2621 data->attriddata[data->attriddatalen++] = 0;
2625 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2628 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2630 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2631 data->attriddata[data->attriddatalen++] = id;
2632 data->attriddata[data->attriddatalen++] = 0;
2636 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2640 if (data->localpool)
2641 id = stringpool_str2id(&data->spool, str, 1);
2643 id = pool_str2id(data->repo->pool, str, 1);
2644 repodata_add_idarray(data, solvid, keyname, id);
2648 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2650 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2651 data->attriddata[data->attriddatalen++] = ghandle;
2652 data->attriddata[data->attriddatalen++] = 0;
2656 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2658 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2659 data->attriddata[data->attriddatalen++] = ghandle;
2660 data->attriddata[data->attriddatalen++] = 0;
2664 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2667 app = repodata_get_attrp(data, solvid);
2671 for (; *ap; ap += 2)
2672 if (data->keys[*ap].name == keyname)
2678 for (; *ap; ap += 2)
2680 if (data->keys[*ap].name == keyname)
2688 /* XXX: does not work correctly, needs fix in iterators! */
2690 repodata_unset(Repodata *data, Id solvid, Id keyname)
2694 key.type = REPOKEY_TYPE_DELETED;
2696 key.storage = KEY_STORAGE_INCORE;
2697 repodata_set(data, solvid, &key, 0);
2700 /* add all (uninternalized) attrs from src to dest */
2702 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2705 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2707 for (; *keyp; keyp += 2)
2708 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2711 /* add some (uninternalized) attrs from src to dest */
2713 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2716 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2718 for (; *keyp; keyp += 2)
2719 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2720 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2723 /* swap (uninternalized) attrs from src and dest */
2725 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2728 if (!data->attrs || dest == src)
2730 tmpattrs = data->attrs[dest - data->start];
2731 data->attrs[dest - data->start] = data->attrs[src - data->start];
2732 data->attrs[src - data->start] = tmpattrs;
2736 /**********************************************************************/
2738 /* TODO: unify with repo_write and repo_solv! */
2740 #define EXTDATA_BLOCK 1023
2748 data_addid(struct extdata *xd, Id sx)
2750 unsigned int x = (unsigned int)sx;
2753 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2754 dp = xd->buf + xd->len;
2759 *dp++ = (x >> 28) | 128;
2761 *dp++ = (x >> 21) | 128;
2762 *dp++ = (x >> 14) | 128;
2765 *dp++ = (x >> 7) | 128;
2767 xd->len = dp - xd->buf;
2771 data_addid64(struct extdata *xd, unsigned long long x)
2773 if (x >= 0x100000000)
2777 data_addid(xd, (Id)(x >> 35));
2778 xd->buf[xd->len - 1] |= 128;
2780 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2781 xd->buf[xd->len - 5] = (x >> 28) | 128;
2784 data_addid(xd, (Id)x);
2788 data_addideof(struct extdata *xd, Id sx, int eof)
2790 unsigned int x = (unsigned int)sx;
2793 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2794 dp = xd->buf + xd->len;
2799 *dp++ = (x >> 27) | 128;
2801 *dp++ = (x >> 20) | 128;
2802 *dp++ = (x >> 13) | 128;
2805 *dp++ = (x >> 6) | 128;
2806 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2807 xd->len = dp - xd->buf;
2811 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2813 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2814 memcpy(xd->buf + xd->len, blob, len);
2818 /*********************************/
2820 /* internalalize some key into incore/vincore data */
2823 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2824 struct extdata *newvincore,
2826 Repokey *key, Id val)
2830 unsigned int oldvincorelen = 0;
2834 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2837 oldvincorelen = xd->len;
2841 case REPOKEY_TYPE_VOID:
2842 case REPOKEY_TYPE_CONSTANT:
2843 case REPOKEY_TYPE_CONSTANTID:
2845 case REPOKEY_TYPE_STR:
2846 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2848 case REPOKEY_TYPE_MD5:
2849 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2851 case REPOKEY_TYPE_SHA1:
2852 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2854 case REPOKEY_TYPE_SHA256:
2855 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2857 case REPOKEY_TYPE_NUM:
2858 if (val & 0x80000000)
2860 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2864 case REPOKEY_TYPE_ID:
2865 case REPOKEY_TYPE_DIR:
2866 data_addid(xd, val);
2868 case REPOKEY_TYPE_BINARY:
2871 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2872 dp += (unsigned int)len;
2873 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2876 case REPOKEY_TYPE_IDARRAY:
2877 for (ida = data->attriddata + val; *ida; ida++)
2878 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2880 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2881 for (ida = data->attriddata + val; *ida; ida += 3)
2883 data_addid(xd, ida[0]);
2884 data_addid(xd, ida[1]);
2885 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2888 case REPOKEY_TYPE_DIRSTRARRAY:
2889 for (ida = data->attriddata + val; *ida; ida += 2)
2891 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2892 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2895 case REPOKEY_TYPE_FIXARRAY:
2899 for (ida = data->attriddata + val; *ida; ida++)
2903 kp = data->xattrs[-*ida];
2911 schemaid = repodata_schema2id(data, schema, 1);
2912 else if (schemaid != repodata_schema2id(data, schema, 0))
2914 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2920 data_addid(xd, num);
2921 data_addid(xd, schemaid);
2922 for (ida = data->attriddata + val; *ida; ida++)
2924 Id *kp = data->xattrs[-*ida];
2928 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2932 case REPOKEY_TYPE_FLEXARRAY:
2935 for (ida = data->attriddata + val; *ida; ida++)
2937 data_addid(xd, num);
2938 for (ida = data->attriddata + val; *ida; ida++)
2940 Id *kp = data->xattrs[-*ida];
2943 data_addid(xd, 0); /* XXX */
2950 schemaid = repodata_schema2id(data, schema, 1);
2951 data_addid(xd, schemaid);
2952 kp = data->xattrs[-*ida];
2954 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2959 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2962 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2964 /* put offset/len in incore */
2965 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2966 oldvincorelen = xd->len - oldvincorelen;
2967 data_addid(newincore, oldvincorelen);
2972 repodata_internalize(Repodata *data)
2974 Repokey *key, solvkey;
2976 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2977 unsigned char *dp, *ndp;
2978 int newschema, oldcount;
2979 struct extdata newincore;
2980 struct extdata newvincore;
2983 if (!data->attrs && !data->xattrs)
2986 newvincore.buf = data->vincore;
2987 newvincore.len = data->vincorelen;
2989 /* find the solvables key, create if needed */
2990 memset(&solvkey, 0, sizeof(solvkey));
2991 solvkey.name = REPOSITORY_SOLVABLES;
2992 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2994 solvkey.storage = KEY_STORAGE_INCORE;
2995 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2997 schema = solv_malloc2(data->nkeys, sizeof(Id));
2998 seen = solv_malloc2(data->nkeys, sizeof(Id));
3000 /* Merge the data already existing (in data->schemata, ->incoredata and
3001 friends) with the new attributes in data->attrs[]. */
3002 nentry = data->end - data->start;
3003 memset(&newincore, 0, sizeof(newincore));
3004 data_addid(&newincore, 0); /* start data at offset 1 */
3006 data->mainschema = 0;
3007 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3009 /* join entry data */
3010 /* we start with the meta data, entry -1 */
3011 for (entry = -1; entry < nentry; entry++)
3013 memset(seen, 0, data->nkeys * sizeof(Id));
3015 dp = data->incoredata;
3018 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3019 dp = data_read_id(dp, &oldschema);
3022 fprintf(stderr, "oldschema %d\n", oldschema);
3023 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3024 fprintf(stderr, "schemadata %p\n", data->schemadata);
3026 /* seen: -1: old data 0: skipped >0: id + 1 */
3030 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3034 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3042 keyp = data->attrs ? data->attrs[entry] : 0;
3045 /* strip solvables key */
3047 for (sp = keyp = schema; *sp; sp++)
3048 if (*sp != solvkeyid)
3053 seen[solvkeyid] = 0;
3054 keyp = data->xattrs ? data->xattrs[1] : 0;
3057 for (; *keyp; keyp += 2)
3064 seen[*keyp] = keyp[1] + 1;
3066 if (entry < 0 && data->end != data->start)
3073 /* Ideally we'd like to sort the new schema here, to ensure
3074 schema equality independend of the ordering. We can't do that
3075 yet. For once see below (old ids need to come before new ids).
3076 An additional difficulty is that we also need to move
3077 the values with the keys. */
3078 schemaid = repodata_schema2id(data, schema, 1);
3080 schemaid = oldschema;
3083 /* Now create data blob. We walk through the (possibly new) schema
3084 and either copy over old data, or insert the new. */
3085 /* XXX Here we rely on the fact that the (new) schema has the form
3086 o1 o2 o3 o4 ... | n1 n2 n3 ...
3087 (oX being the old keyids (possibly overwritten), and nX being
3088 the new keyids). This rules out sorting the keyids in order
3089 to ensure a small schema count. */
3091 data->incoreoffset[entry] = newincore.len;
3092 data_addid(&newincore, schemaid);
3095 data->mainschema = schemaid;
3096 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3098 keypstart = data->schemadata + data->schemata[schemaid];
3099 for (keyp = keypstart; *keyp; keyp++)
3102 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3103 if (*keyp == solvkeyid)
3105 /* add flexarray entry count */
3106 data_addid(&newincore, data->end - data->start);
3109 key = data->keys + *keyp;
3111 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));
3116 /* Skip the data associated with this old key. */
3117 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3119 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3120 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3122 else if (key->storage == KEY_STORAGE_INCORE)
3123 ndp = data_skip_key(data, dp, key);
3126 if (seen[*keyp] == -1)
3128 /* If this key was an old one _and_ was not overwritten with
3129 a different value copy over the old value (we skipped it
3132 data_addblob(&newincore, dp, ndp - dp);
3135 else if (seen[*keyp])
3137 /* Otherwise we have a new value. Parse it into the internal
3139 repodata_serialize_key(data, &newincore, &newvincore,
3140 schema, key, seen[*keyp] - 1);
3144 if (entry >= 0 && data->attrs && data->attrs[entry])
3145 data->attrs[entry] = solv_free(data->attrs[entry]);
3147 /* free all xattrs */
3148 for (entry = 0; entry < data->nxattrs; entry++)
3149 if (data->xattrs[entry])
3150 solv_free(data->xattrs[entry]);
3151 data->xattrs = solv_free(data->xattrs);
3154 data->lasthandle = 0;
3156 data->lastdatalen = 0;
3159 repodata_free_schemahash(data);
3161 solv_free(data->incoredata);
3162 data->incoredata = newincore.buf;
3163 data->incoredatalen = newincore.len;
3164 data->incoredatafree = 0;
3166 solv_free(data->vincore);
3167 data->vincore = newvincore.buf;
3168 data->vincorelen = newvincore.len;
3170 data->attrs = solv_free(data->attrs);
3171 data->attrdata = solv_free(data->attrdata);
3172 data->attriddata = solv_free(data->attriddata);
3173 data->attrnum64data = solv_free(data->attrnum64data);
3174 data->attrdatalen = 0;
3175 data->attriddatalen = 0;
3176 data->attrnum64datalen = 0;
3180 repodata_disable_paging(Repodata *data)
3182 if (maybe_load_repodata(data, 0))
3184 repopagestore_disable_paging(&data->store);
3190 repodata_load_stub(Repodata *data)
3192 Repo *repo = data->repo;
3193 Pool *pool = repo->pool;
3195 struct _Pool_tmpspace oldtmpspace;
3197 if (!pool->loadcallback)
3199 data->state = REPODATA_ERROR;
3202 data->state = REPODATA_LOADING;
3204 /* save tmp space */
3205 oldtmpspace = pool->tmpspace;
3206 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3208 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3210 /* restore tmp space */
3211 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3212 solv_free(pool->tmpspace.buf[i]);
3213 pool->tmpspace = oldtmpspace;
3215 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3219 repodata_create_stubs(Repodata *data)
3221 Repo *repo = data->repo;
3222 Pool *pool = repo->pool;
3229 int datastart, dataend;
3231 repodataid = data - repo->repodata;
3232 datastart = data->start;
3233 dataend = data->end;
3234 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3235 while (dataiterator_step(&di))
3237 if (di.data - repo->repodata != repodataid)
3241 dataiterator_free(&di);
3244 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3245 for (i = 0; i < cnt; i++)
3247 sdata = repo_add_repodata(repo, 0);
3248 if (dataend > datastart)
3249 repodata_extend_block(sdata, datastart, dataend - datastart);
3250 stubdataids[i] = sdata - repo->repodata;
3251 sdata->state = REPODATA_STUB;
3252 sdata->loadcallback = repodata_load_stub;
3255 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3257 while (dataiterator_step(&di))
3259 if (di.data - repo->repodata != repodataid)
3261 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3263 dataiterator_entersub(&di);
3264 sdata = repo->repodata + stubdataids[i++];
3268 switch (di.key->type)
3270 case REPOKEY_TYPE_ID:
3271 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3273 case REPOKEY_TYPE_CONSTANTID:
3274 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3276 case REPOKEY_TYPE_STR:
3277 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3279 case REPOKEY_TYPE_VOID:
3280 repodata_set_void(sdata, SOLVID_META, di.key->name);
3282 case REPOKEY_TYPE_NUM:
3283 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3285 case REPOKEY_TYPE_MD5:
3286 case REPOKEY_TYPE_SHA1:
3287 case REPOKEY_TYPE_SHA256:
3288 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3290 case REPOKEY_TYPE_IDARRAY:
3291 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3292 if (di.key->name == REPOSITORY_KEYS)
3299 xkeyname = di.kv.id;
3302 xkey.name = xkeyname;
3303 xkey.type = di.kv.id;
3304 xkey.storage = KEY_STORAGE_INCORE;
3306 repodata_key2id(sdata, &xkey, 1);
3313 dataiterator_free(&di);
3314 for (i = 0; i < cnt; i++)
3315 repodata_internalize(repo->repodata + stubdataids[i]);
3316 solv_free(stubdataids);
3320 repodata_memused(Repodata *data)
3322 return data->incoredatalen + data->vincorelen;
3326 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: