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;)
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 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 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
624 return 0; /* get_data will not work, no need to forward */
625 dp = forward_to_key(data, *kp, keyp, dp);
628 return get_data(data, key, &dp, 0);
632 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
634 Id schema, *keyp, *kp;
635 if (!maybe_load_repodata(data, keyname))
637 if (!solvid2data(data, solvid, &schema))
639 keyp = data->schemadata + data->schemata[schema];
640 for (kp = keyp; *kp; kp++)
641 if (data->keys[*kp].name == keyname)
642 return data->keys[*kp].type;
647 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
653 dp = find_key_data(data, solvid, keyname, &key);
656 if (key->type == REPOKEY_TYPE_CONSTANTID)
658 if (key->type != REPOKEY_TYPE_ID)
660 dp = data_read_id(dp, &id);
665 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
671 dp = find_key_data(data, solvid, keyname, &key);
674 if (key->type == REPOKEY_TYPE_STR)
675 return (const char *)dp;
676 if (key->type == REPOKEY_TYPE_CONSTANTID)
678 else if (key->type == REPOKEY_TYPE_ID)
679 dp = data_read_id(dp, &id);
683 return stringpool_id2str(&data->spool, id);
684 return pool_id2str(data->repo->pool, id);
688 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
692 unsigned int high, low;
695 dp = find_key_data(data, solvid, keyname, &key);
700 case REPOKEY_TYPE_NUM:
701 data_read_num64(dp, &low, &high);
702 *value = (unsigned long long)high << 32 | low;
704 case REPOKEY_TYPE_U32:
705 data_read_u32(dp, &low);
708 case REPOKEY_TYPE_CONSTANT:
717 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
723 if (!maybe_load_repodata(data, keyname))
725 dp = solvid2data(data, solvid, &schema);
728 /* can't use find_key_data as we need to test the type */
729 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
730 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
735 const unsigned char *
736 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
741 dp = find_key_data(data, solvid, keyname, &key);
744 if (!(key->type == REPOKEY_TYPE_MD5 || key->type == REPOKEY_TYPE_SHA1 || key->type == REPOKEY_TYPE_SHA256))
751 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
759 dp = find_key_data(data, solvid, keyname, &key);
762 if (key->type != REPOKEY_TYPE_IDARRAY)
766 dp = data_read_ideof(dp, &id, &eof);
775 repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp)
781 dp = find_key_data(data, solvid, keyname, &key);
782 if (!dp || key->type != REPOKEY_TYPE_BINARY)
787 dp = data_read_id(dp, &len);
793 repodata_globalize_id(Repodata *data, Id id, int create)
795 if (!id || !data || !data->localpool)
797 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
801 repodata_localize_id(Repodata *data, Id id, int create)
803 if (!id || !data || !data->localpool)
805 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
809 repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
811 if (!id || !data || !fromdata)
813 if (!data->localpool || !fromdata->localpool)
815 if (fromdata->localpool)
816 id = repodata_globalize_id(fromdata, id, create);
818 id = repodata_localize_id(data, id, create);
821 /* localpool is set in both data and fromdata */
822 return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create);
826 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
831 ap = data->attrs[solvid - data->start];
836 if (data->keys[*ap].name != keyname)
838 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
840 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
848 /************************************************************************
854 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
858 case REPOKEY_TYPE_ID:
859 case REPOKEY_TYPE_CONSTANTID:
860 case REPOKEY_TYPE_IDARRAY:
861 if (data && data->localpool)
862 kv->str = stringpool_id2str(&data->spool, kv->id);
864 kv->str = pool_id2str(pool, kv->id);
865 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
868 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
870 if (*s == ':' && s > kv->str)
874 case REPOKEY_TYPE_STR:
876 case REPOKEY_TYPE_DIRSTRARRAY:
877 if (!(flags & SEARCH_FILES))
878 return 1; /* match just the basename */
880 return 1; /* already stringified */
881 /* Put the full filename into kv->str. */
882 kv->str = repodata_dir2str(data, kv->id, kv->str);
883 kv->num = 1; /* mark stringification */
885 case REPOKEY_TYPE_MD5:
886 case REPOKEY_TYPE_SHA1:
887 case REPOKEY_TYPE_SHA256:
888 if (!(flags & SEARCH_CHECKSUMS))
889 return 0; /* skip em */
891 return 1; /* already stringified */
892 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
893 kv->num = 1; /* mark stringification */
901 struct subschema_data {
907 /* search a specific repodata */
909 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
913 Id keyid, *kp, *keyp;
914 unsigned char *dp, *ddp;
920 if (!maybe_load_repodata(data, keyname))
922 if (solvid == SOLVID_SUBSCHEMA)
924 struct subschema_data *subd = cbdata;
925 cbdata = subd->cbdata;
927 schema = subd->parent->id;
928 dp = (unsigned char *)subd->parent->str;
929 kv.parent = subd->parent;
934 dp = solvid2data(data, solvid, &schema);
937 s = data->repo->pool->solvables + solvid;
940 keyp = data->schemadata + data->schemata[schema];
943 /* search for a specific key */
944 for (kp = keyp; *kp; kp++)
945 if (data->keys[*kp].name == keyname)
949 dp = forward_to_key(data, *kp, keyp, dp);
955 while ((keyid = *keyp++) != 0)
958 key = data->keys + keyid;
959 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
961 if (key->type == REPOKEY_TYPE_DELETED)
963 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
965 struct subschema_data subd;
969 subd.cbdata = cbdata;
972 ddp = data_read_id(ddp, &nentries);
976 while (ddp && nentries > 0)
980 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
981 ddp = data_read_id(ddp, &schema);
983 kv.str = (char *)ddp;
984 stop = callback(cbdata, s, data, key, &kv);
985 if (stop > SEARCH_NEXT_KEY)
987 if (stop && stop != SEARCH_ENTERSUB)
989 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
990 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
991 ddp = data_skip_schema(data, ddp, schema);
994 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
998 kv.str = (char *)ddp;
999 stop = callback(cbdata, s, data, key, &kv);
1000 if (stop > SEARCH_NEXT_KEY)
1010 ddp = data_fetch(ddp, &kv, key);
1013 stop = callback(cbdata, s, data, key, &kv);
1016 while (!kv.eof && !stop);
1017 if (onekey || stop > SEARCH_NEXT_KEY)
1023 repodata_setpos_kv(Repodata *data, KeyValue *kv)
1025 Pool *pool = data->repo->pool;
1027 pool_clear_pos(pool);
1030 pool->pos.repo = data->repo;
1031 pool->pos.repodataid = data - data->repo->repodata;
1032 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
1033 pool->pos.schema = kv->id;
1037 /************************************************************************
1038 * data iterator functions
1042 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1056 case SOLVABLE_VENDOR:
1059 case SOLVABLE_PROVIDES:
1061 return s->provides ? s->repo->idarraydata + s->provides : 0;
1062 case SOLVABLE_OBSOLETES:
1064 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1065 case SOLVABLE_CONFLICTS:
1067 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1068 case SOLVABLE_REQUIRES:
1070 return s->requires ? s->repo->idarraydata + s->requires : 0;
1071 case SOLVABLE_RECOMMENDS:
1073 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1074 case SOLVABLE_SUPPLEMENTS:
1076 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1077 case SOLVABLE_SUGGESTS:
1079 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1080 case SOLVABLE_ENHANCES:
1082 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1085 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1092 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1094 ma->match = match ? solv_strdup(match) : 0;
1098 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1100 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1101 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1104 solv_free(ma->matchdata);
1105 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1108 if ((flags & SEARCH_FILES) != 0 && match)
1110 /* prepare basename check */
1111 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1113 const char *p = strrchr(match, '/');
1114 ma->matchdata = (void *)(p ? p + 1 : match);
1116 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1119 for (p = match + strlen(match) - 1; p >= match; p--)
1120 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1122 ma->matchdata = (void *)(p + 1);
1129 datamatcher_free(Datamatcher *ma)
1132 ma->match = solv_free((char *)ma->match);
1133 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1135 regfree(ma->matchdata);
1136 solv_free(ma->matchdata);
1142 datamatcher_match(Datamatcher *ma, const char *str)
1145 switch ((ma->flags & SEARCH_STRINGMASK))
1147 case SEARCH_SUBSTRING:
1148 if (ma->flags & SEARCH_NOCASE)
1149 return strcasestr(str, ma->match) != 0;
1151 return strstr(str, ma->match) != 0;
1153 if (ma->flags & SEARCH_NOCASE)
1154 return !strcasecmp(ma->match, str);
1156 return !strcmp(ma->match, str);
1157 case SEARCH_STRINGSTART:
1158 if (ma->flags & SEARCH_NOCASE)
1159 return !strncasecmp(ma->match, str, strlen(ma->match));
1161 return !strncmp(ma->match, str, strlen(ma->match));
1162 case SEARCH_STRINGEND:
1163 l = strlen(str) - strlen(ma->match);
1166 if (ma->flags & SEARCH_NOCASE)
1167 return !strcasecmp(ma->match, str + l);
1169 return !strcmp(ma->match, str + l);
1171 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1173 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1179 /* check if the matcher can match the provides basename */
1182 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1185 const char *match = ma->matchdata;
1188 switch (ma->flags & SEARCH_STRINGMASK)
1192 case SEARCH_STRINGEND:
1193 if (match != ma->match)
1194 break; /* had slash, do exact match on basename */
1197 /* check if the basename ends with match */
1198 l = strlen(basename) - strlen(match);
1204 return 1; /* maybe matches */
1206 if ((ma->flags & SEARCH_NOCASE) != 0)
1207 return !strcasecmp(match, basename);
1209 return !strcmp(match, basename);
1213 repodata_filelistfilter_matches(Repodata *data, const char *str)
1215 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1216 /* for now hardcoded */
1217 if (strstr(str, "bin/"))
1219 if (!strncmp(str, "/etc/", 5))
1221 if (!strcmp(str, "/usr/lib/sendmail"))
1243 di_nextarrayelement,
1249 di_entersolvablekey,
1253 /* see dataiterator.h for documentation */
1255 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1257 memset(di, 0, sizeof(*di));
1259 di->flags = flags & ~SEARCH_THISSOLVID;
1260 if (!pool || (repo && repo->pool != pool))
1268 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1274 di->keyname = keyname;
1275 di->keynames[0] = keyname;
1276 dataiterator_set_search(di, repo, p);
1281 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1286 if (di->dupstr == di->kv.str)
1288 di->dupstr = solv_malloc(di->dupstrn);
1289 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1297 memset(&di->matcher, 0, sizeof(di->matcher));
1298 if (from->matcher.match)
1299 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1304 for (i = 1; i < di->nparents; i++)
1305 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1306 di->kv.parent = &di->parents[di->nparents - 1].kv;
1311 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1313 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1314 datamatcher_free(&di->matcher);
1315 memset(&di->matcher, 0, sizeof(di->matcher));
1319 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1329 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1333 di->flags &= ~SEARCH_THISSOLVID;
1337 if (!di->pool->urepos)
1345 di->repo = di->pool->repos[di->repoid];
1347 di->state = di_enterrepo;
1349 dataiterator_jump_to_solvid(di, p);
1353 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1356 di->keyname = keyname;
1357 di->keynames[0] = keyname;
1361 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1365 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1367 di->state = di_bye; /* sorry */
1370 for (i = di->nkeynames + 1; i > 0; i--)
1371 di->keynames[i] = di->keynames[i - 1];
1372 di->keynames[0] = di->keyname = keyname;
1377 dataiterator_free(Dataiterator *di)
1379 if (di->matcher.match)
1380 datamatcher_free(&di->matcher);
1382 solv_free(di->dupstr);
1385 static unsigned char *
1386 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1389 Repokey *keys = di->data->keys, *key;
1392 for (keyp = di->keyp; *keyp; keyp++)
1393 if (keys[*keyp].name == keyname)
1398 if (key->type == REPOKEY_TYPE_DELETED)
1400 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
1401 return 0; /* get_data will not work, no need to forward */
1402 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1410 is_filelist_extension(Repodata *data)
1413 if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
1415 for (j = 1; j < data->nkeys; j++)
1416 if (data->keys[j].name == SOLVABLE_FILELIST)
1418 if (j == data->nkeys)
1420 if (data->state != REPODATA_AVAILABLE)
1422 for (j = 1; j < data->nkeys; j++)
1423 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1429 dataiterator_filelistcheck(Dataiterator *di)
1432 int needcomplete = 0;
1433 Repodata *data = di->data;
1435 if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
1436 if (!di->matcher.match
1437 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1438 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1439 || !repodata_filelistfilter_matches(data, di->matcher.match))
1441 if (data->state != REPODATA_AVAILABLE)
1442 return needcomplete ? 1 : 0;
1445 /* we don't need the complete filelist, so ignore all stubs */
1446 for (j = 1; j < data->nkeys; j++)
1447 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1453 /* we need the complete filelist. check if we habe a filtered filelist and there's
1454 * a extension with the complete filelist later on */
1455 for (j = 1; j < data->nkeys; j++)
1456 if (data->keys[j].name == SOLVABLE_FILELIST)
1458 if (j == data->nkeys)
1459 return 0; /* does not have filelist */
1460 for (j = 1; j < data->nkeys; j++)
1461 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1463 if (j == data->nkeys)
1464 return 1; /* this is the externsion */
1465 while (data - data->repo->repodata + 1 < data->repo->nrepodata)
1468 if (is_filelist_extension(data))
1476 dataiterator_step(Dataiterator *di)
1480 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1481 unsigned int ddpoff = di->ddp - di->vert_ddp;
1482 di->vert_off += ddpoff;
1483 di->vert_len -= ddpoff;
1484 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1485 di->vert_storestate = di->data->storestate;
1487 di->state = di_nextkey;
1493 case di_enterrepo: di_enterrepo:
1494 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1496 if (!(di->flags & SEARCH_THISSOLVID))
1498 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1499 goto di_nextsolvable;
1503 case di_entersolvable: di_entersolvable:
1506 di->repodataid = 1; /* reset repodata iterator */
1507 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)
1509 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1511 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1513 goto di_entersolvablekey;
1518 case di_enterrepodata: di_enterrepodata:
1521 if (di->repodataid >= di->repo->nrepodata)
1522 goto di_nextsolvable;
1523 di->data = di->repo->repodata + di->repodataid;
1525 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1526 goto di_nextrepodata;
1527 if (!maybe_load_repodata(di->data, di->keyname))
1528 goto di_nextrepodata;
1529 di->dp = solvid2data(di->data, di->solvid, &schema);
1531 goto di_nextrepodata;
1532 if (di->solvid == SOLVID_POS)
1533 di->solvid = di->pool->pos.solvid;
1534 /* reset key iterator */
1535 di->keyp = di->data->schemadata + di->data->schemata[schema];
1538 case di_enterschema: di_enterschema:
1540 di->dp = dataiterator_find_keyname(di, di->keyname);
1541 if (!di->dp || !*di->keyp)
1545 goto di_nextrepodata;
1549 case di_enterkey: di_enterkey:
1551 di->key = di->data->keys + *di->keyp;
1554 /* this is get_data() modified to store vert_ data */
1555 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1558 di->dp = data_read_id(di->dp, &off);
1559 di->dp = data_read_id(di->dp, &len);
1560 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1563 di->vert_storestate = di->data->storestate;
1565 else if (di->key->storage == KEY_STORAGE_INCORE)
1568 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1569 di->dp = data_skip_key(di->data, di->dp, di->key);
1575 if (di->key->type == REPOKEY_TYPE_DELETED)
1577 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1579 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1585 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1587 di->state = di_nextkey;
1589 di->state = di_nextattr;
1592 case di_nextkey: di_nextkey:
1593 if (!di->keyname && *++di->keyp)
1599 case di_nextrepodata: di_nextrepodata:
1600 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1601 goto di_enterrepodata;
1604 case di_nextsolvable: di_nextsolvable:
1605 if (!(di->flags & SEARCH_THISSOLVID))
1608 di->solvid = di->repo->start;
1611 for (; di->solvid < di->repo->end; di->solvid++)
1613 if (di->pool->solvables[di->solvid].repo == di->repo)
1614 goto di_entersolvable;
1619 case di_nextrepo: di_nextrepo:
1624 if (di->repoid < di->pool->nrepos)
1626 di->repo = di->pool->repos[di->repoid];
1632 case di_bye: di_bye:
1636 case di_enterarray: di_enterarray:
1637 if (di->key->name == REPOSITORY_SOLVABLES)
1639 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1644 case di_nextarrayelement: di_nextarrayelement:
1647 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1648 if (di->kv.entry == di->kv.num)
1650 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1652 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1654 di->kv.str = (char *)di->ddp;
1656 di->state = di_nextkey;
1659 if (di->kv.entry == di->kv.num - 1)
1661 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1662 di->ddp = data_read_id(di->ddp, &di->kv.id);
1663 di->kv.str = (char *)di->ddp;
1664 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1666 if ((di->flags & SEARCH_SUB) != 0)
1667 di->state = di_entersub;
1669 di->state = di_nextarrayelement;
1672 case di_entersub: di_entersub:
1673 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1674 goto di_nextarrayelement; /* sorry, full */
1675 di->parents[di->nparents].kv = di->kv;
1676 di->parents[di->nparents].dp = di->dp;
1677 di->parents[di->nparents].keyp = di->keyp;
1678 di->dp = (unsigned char *)di->kv.str;
1679 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1680 memset(&di->kv, 0, sizeof(di->kv));
1681 di->kv.parent = &di->parents[di->nparents].kv;
1683 di->keyname = di->keynames[di->nparents - di->rootlevel];
1684 goto di_enterschema;
1686 case di_leavesub: di_leavesub:
1687 if (di->nparents - 1 < di->rootlevel)
1690 di->dp = di->parents[di->nparents].dp;
1691 di->kv = di->parents[di->nparents].kv;
1692 di->keyp = di->parents[di->nparents].keyp;
1693 di->key = di->data->keys + *di->keyp;
1694 di->ddp = (unsigned char *)di->kv.str;
1695 di->keyname = di->keynames[di->nparents - di->rootlevel];
1696 goto di_nextarrayelement;
1698 /* special solvable attr handling follows */
1700 case di_nextsolvablekey: di_nextsolvablekey:
1701 if (di->keyname || di->key->name == RPM_RPMDBID)
1702 goto di_enterrepodata;
1706 case di_entersolvablekey: di_entersolvablekey:
1707 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1708 if (!di->idp || !*di->idp)
1709 goto di_nextsolvablekey;
1713 di->kv.id = *di->idp;
1714 di->kv.num = *di->idp; /* for rpmdbid */
1715 di->kv.num2 = 0; /* for rpmdbid */
1717 di->state = di_nextsolvablekey;
1723 case di_nextsolvableattr:
1724 di->state = di_nextsolvableattr;
1725 di->kv.id = *di->idp++;
1730 di->state = di_nextsolvablekey;
1736 if (di->matcher.match)
1738 /* simple pre-check so that we don't need to stringify */
1739 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1740 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1742 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1744 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1748 if (!datamatcher_match(&di->matcher, di->kv.str))
1753 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1754 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1756 /* found something! */
1762 dataiterator_entersub(Dataiterator *di)
1764 if (di->state == di_nextarrayelement)
1765 di->state = di_entersub;
1769 dataiterator_setpos(Dataiterator *di)
1771 if (di->kv.eof == 2)
1773 pool_clear_pos(di->pool);
1776 di->pool->pos.solvid = di->solvid;
1777 di->pool->pos.repo = di->repo;
1778 di->pool->pos.repodataid = di->data - di->repo->repodata;
1779 di->pool->pos.schema = di->kv.id;
1780 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1784 dataiterator_setpos_parent(Dataiterator *di)
1786 if (!di->kv.parent || di->kv.parent->eof == 2)
1788 pool_clear_pos(di->pool);
1791 di->pool->pos.solvid = di->solvid;
1792 di->pool->pos.repo = di->repo;
1793 di->pool->pos.repodataid = di->data - di->repo->repodata;
1794 di->pool->pos.schema = di->kv.parent->id;
1795 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1798 /* clones just the position, not the search keys/matcher */
1800 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1802 di->state = from->state;
1803 di->flags &= ~SEARCH_THISSOLVID;
1804 di->flags |= (from->flags & SEARCH_THISSOLVID);
1805 di->repo = from->repo;
1806 di->data = from->data;
1808 di->ddp = from->ddp;
1809 di->idp = from->idp;
1810 di->keyp = from->keyp;
1811 di->key = from->key;
1813 di->repodataid = from->repodataid;
1814 di->solvid = from->solvid;
1815 di->repoid = from->repoid;
1816 di->rootlevel = from->rootlevel;
1817 memcpy(di->parents, from->parents, sizeof(from->parents));
1818 di->nparents = from->nparents;
1822 for (i = 1; i < di->nparents; i++)
1823 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1824 di->kv.parent = &di->parents[di->nparents - 1].kv;
1828 if (from->dupstr && from->dupstr == from->kv.str)
1830 di->dupstrn = from->dupstrn;
1831 di->dupstr = solv_malloc(from->dupstrn);
1832 memcpy(di->dupstr, from->dupstr, di->dupstrn);
1837 dataiterator_seek(Dataiterator *di, int whence)
1839 if ((whence & DI_SEEK_STAY) != 0)
1840 di->rootlevel = di->nparents;
1841 switch (whence & ~DI_SEEK_STAY)
1844 if (di->state != di_nextarrayelement)
1846 if ((whence & DI_SEEK_STAY) != 0)
1847 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1848 di->state = di_entersub;
1850 case DI_SEEK_PARENT:
1857 if (di->rootlevel > di->nparents)
1858 di->rootlevel = di->nparents;
1859 di->dp = di->parents[di->nparents].dp;
1860 di->kv = di->parents[di->nparents].kv;
1861 di->keyp = di->parents[di->nparents].keyp;
1862 di->key = di->data->keys + *di->keyp;
1863 di->ddp = (unsigned char *)di->kv.str;
1864 di->keyname = di->keynames[di->nparents - di->rootlevel];
1865 di->state = di_nextarrayelement;
1867 case DI_SEEK_REWIND:
1873 di->dp = (unsigned char *)di->kv.parent->str;
1874 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1875 di->state = di_enterschema;
1883 dataiterator_skip_attribute(Dataiterator *di)
1885 if (di->state == di_nextsolvableattr)
1886 di->state = di_nextsolvablekey;
1888 di->state = di_nextkey;
1892 dataiterator_skip_solvable(Dataiterator *di)
1897 di->keyname = di->keynames[0];
1898 di->state = di_nextsolvable;
1902 dataiterator_skip_repo(Dataiterator *di)
1907 di->keyname = di->keynames[0];
1908 di->state = di_nextrepo;
1912 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1917 di->keyname = di->keynames[0];
1918 if (solvid == SOLVID_POS)
1920 di->repo = di->pool->pos.repo;
1927 di->data = di->repo->repodata + di->pool->pos.repodataid;
1929 di->solvid = solvid;
1930 di->state = di_enterrepo;
1931 di->flags |= SEARCH_THISSOLVID;
1936 di->repo = di->pool->solvables[solvid].repo;
1939 else if (di->repoid > 0)
1941 if (!di->pool->urepos)
1947 di->repo = di->pool->repos[di->repoid];
1950 di->solvid = solvid;
1952 di->flags |= SEARCH_THISSOLVID;
1953 di->state = di_enterrepo;
1957 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1963 di->repoid = 0; /* 0 means stay at repo */
1966 di->flags &= ~SEARCH_THISSOLVID;
1967 di->state = di_enterrepo;
1971 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1973 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1977 return datamatcher_match(ma, di->kv.str);
1981 dataiterator_strdup(Dataiterator *di)
1985 if (!di->kv.str || di->kv.str == di->dupstr)
1987 switch (di->key->type)
1989 case REPOKEY_TYPE_MD5:
1990 case REPOKEY_TYPE_SHA1:
1991 case REPOKEY_TYPE_SHA256:
1992 case REPOKEY_TYPE_DIRSTRARRAY:
1993 if (di->kv.num) /* was it stringified into tmp space? */
1994 l = strlen(di->kv.str) + 1;
1999 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2001 switch (di->key->type)
2003 case REPOKEY_TYPE_STR:
2004 case REPOKEY_TYPE_DIRSTRARRAY:
2005 l = strlen(di->kv.str) + 1;
2007 case REPOKEY_TYPE_MD5:
2010 case REPOKEY_TYPE_SHA1:
2013 case REPOKEY_TYPE_SHA256:
2016 case REPOKEY_TYPE_BINARY:
2023 if (!di->dupstrn || di->dupstrn < l)
2025 di->dupstrn = l + 16;
2026 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
2029 memcpy(di->dupstr, di->kv.str, l);
2030 di->kv.str = di->dupstr;
2034 /************************************************************************
2035 * data modify functions
2038 /* extend repodata so that it includes solvables p */
2040 repodata_extend(Repodata *data, Id p)
2042 if (data->start == data->end)
2043 data->start = data->end = p;
2046 int old = data->end - data->start;
2047 int new = p - data->end + 1;
2050 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
2051 memset(data->attrs + old, 0, new * sizeof(Id *));
2053 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
2054 memset(data->incoreoffset + old, 0, new * sizeof(Id));
2057 if (p < data->start)
2059 int old = data->end - data->start;
2060 int new = data->start - p;
2063 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
2064 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
2065 memset(data->attrs, 0, new * sizeof(Id *));
2067 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
2068 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
2069 memset(data->incoreoffset, 0, new * sizeof(Id));
2074 /* shrink end of repodata */
2076 repodata_shrink(Repodata *data, int end)
2080 if (data->end <= end)
2082 if (data->start >= end)
2086 for (i = 0; i < data->end - data->start; i++)
2087 solv_free(data->attrs[i]);
2088 data->attrs = solv_free(data->attrs);
2090 data->incoreoffset = solv_free(data->incoreoffset);
2091 data->start = data->end = 0;
2096 for (i = end; i < data->end; i++)
2097 solv_free(data->attrs[i - data->start]);
2098 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2100 if (data->incoreoffset)
2101 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2105 /* extend repodata so that it includes solvables from start to start + num - 1 */
2107 repodata_extend_block(Repodata *data, Id start, Id num)
2111 if (!data->incoreoffset)
2113 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2114 data->start = start;
2115 data->end = start + num;
2118 repodata_extend(data, start);
2120 repodata_extend(data, start + num - 1);
2123 /**********************************************************************/
2126 #define REPODATA_ATTRS_BLOCK 31
2127 #define REPODATA_ATTRDATA_BLOCK 1023
2128 #define REPODATA_ATTRIDDATA_BLOCK 63
2129 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2133 repodata_new_handle(Repodata *data)
2137 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2138 data->nxattrs = 2; /* -1: SOLVID_META */
2140 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2141 data->xattrs[data->nxattrs] = 0;
2142 return -(data->nxattrs++);
2146 repodata_get_attrp(Repodata *data, Id handle)
2150 if (handle == SOLVID_META && !data->xattrs)
2152 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2155 return data->xattrs - handle;
2157 if (handle < data->start || handle >= data->end)
2158 repodata_extend(data, handle);
2160 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2161 return data->attrs + (handle - data->start);
2165 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2171 app = repodata_get_attrp(data, handle);
2176 /* Determine equality based on the name only, allows us to change
2177 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2178 for (pp = ap; *pp; pp += 2)
2179 if (data->keys[*pp].name == data->keys[keyid].name)
2183 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2192 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2202 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2206 keyid = repodata_key2id(data, key, 1);
2207 repodata_insert_keyid(data, solvid, keyid, val, 1);
2211 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2215 key.type = REPOKEY_TYPE_ID;
2217 key.storage = KEY_STORAGE_INCORE;
2218 repodata_set(data, solvid, &key, id);
2222 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2226 key.type = REPOKEY_TYPE_NUM;
2228 key.storage = KEY_STORAGE_INCORE;
2229 if (num >= 0x80000000)
2231 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2232 data->attrnum64data[data->attrnum64datalen] = num;
2233 num = 0x80000000 | data->attrnum64datalen++;
2235 repodata_set(data, solvid, &key, (Id)num);
2239 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2243 if (data->localpool)
2244 id = stringpool_str2id(&data->spool, str, 1);
2246 id = pool_str2id(data->repo->pool, str, 1);
2248 key.type = REPOKEY_TYPE_ID;
2250 key.storage = KEY_STORAGE_INCORE;
2251 repodata_set(data, solvid, &key, id);
2255 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2259 key.type = REPOKEY_TYPE_CONSTANT;
2260 key.size = constant;
2261 key.storage = KEY_STORAGE_INCORE;
2262 repodata_set(data, solvid, &key, 0);
2266 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2270 key.type = REPOKEY_TYPE_CONSTANTID;
2272 key.storage = KEY_STORAGE_INCORE;
2273 repodata_set(data, solvid, &key, 0);
2277 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2281 key.type = REPOKEY_TYPE_VOID;
2283 key.storage = KEY_STORAGE_INCORE;
2284 repodata_set(data, solvid, &key, 0);
2288 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2293 l = strlen(str) + 1;
2295 key.type = REPOKEY_TYPE_STR;
2297 key.storage = KEY_STORAGE_INCORE;
2298 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2299 memcpy(data->attrdata + data->attrdatalen, str, l);
2300 repodata_set(data, solvid, &key, data->attrdatalen);
2301 data->attrdatalen += l;
2305 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2313 key.type = REPOKEY_TYPE_BINARY;
2315 key.storage = KEY_STORAGE_INCORE;
2316 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2317 dp = data->attrdata + data->attrdatalen;
2318 if (len >= (1 << 14))
2320 if (len >= (1 << 28))
2321 *dp++ = (len >> 28) | 128;
2322 if (len >= (1 << 21))
2323 *dp++ = (len >> 21) | 128;
2324 *dp++ = (len >> 14) | 128;
2326 if (len >= (1 << 7))
2327 *dp++ = (len >> 7) | 128;
2330 memcpy(dp, buf, len);
2331 repodata_set(data, solvid, &key, data->attrdatalen);
2332 data->attrdatalen = dp + len - data->attrdata;
2335 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2336 * so that the caller can append entrysize new elements plus the termination zero there */
2338 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2341 Id *ida, *pp, **ppp;
2343 /* check if it is the same as last time, this speeds things up a lot */
2344 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2346 /* great! just append the new data */
2347 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2348 data->attriddatalen--; /* overwrite terminating 0 */
2349 data->lastdatalen += entrysize;
2353 ppp = repodata_get_attrp(data, handle);
2357 for (; *pp; pp += 2)
2358 if (data->keys[*pp].name == keyname)
2361 if (!pp || !*pp || data->keys[*pp].type != keytype)
2363 /* not found. allocate new key */
2369 key.storage = KEY_STORAGE_INCORE;
2370 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2371 keyid = repodata_key2id(data, &key, 1);
2372 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2373 data->lasthandle = handle;
2374 data->lastkey = keyid;
2375 data->lastdatalen = data->attriddatalen + entrysize + 1;
2379 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2380 oldsize += entrysize;
2381 if (ida + 1 == data->attriddata + data->attriddatalen)
2383 /* this was the last entry, just append it */
2384 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2385 data->attriddatalen--; /* overwrite terminating 0 */
2389 /* too bad. move to back. */
2390 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2391 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2392 pp[1] = data->attriddatalen;
2393 data->attriddatalen += oldsize;
2395 data->lasthandle = handle;
2396 data->lastkey = *pp;
2397 data->lastdatalen = data->attriddatalen + entrysize + 1;
2401 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2402 const unsigned char *str)
2407 if (!(l = solv_chksum_len(type)))
2412 key.storage = KEY_STORAGE_INCORE;
2413 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2414 memcpy(data->attrdata + data->attrdatalen, str, l);
2415 repodata_set(data, solvid, &key, data->attrdatalen);
2416 data->attrdatalen += l;
2420 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2423 unsigned char buf[64];
2426 if (!(l = solv_chksum_len(type)))
2428 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2430 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2434 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2438 if (!(l = solv_chksum_len(type)))
2440 return pool_bin2hex(data->repo->pool, buf, l);
2443 /* rpm filenames don't contain the epoch, so strip it */
2444 static inline const char *
2445 evrid2vrstr(Pool *pool, Id evrid)
2447 const char *p, *evr = pool_id2str(pool, evrid);
2450 for (p = evr; *p >= '0' && *p <= '9'; p++)
2452 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2456 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2459 if (data->localpool)
2460 id = stringpool_strn2id(&data->spool, str, l, 1);
2462 id = pool_strn2id(data->repo->pool, str, l, 1);
2463 repodata_set_id(data, solvid, keyname, id);
2467 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2470 repodata_set_str(data, solvid, keyname, str);
2473 char *s = solv_strdup(str);
2475 repodata_set_str(data, solvid, keyname, s);
2481 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2483 Pool *pool = data->repo->pool;
2485 const char *str, *fp;
2489 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2492 if ((dir = strrchr(file, '/')) != 0)
2503 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2508 if (l == 1 && dir[0] == '.')
2510 s = pool->solvables + solvid;
2513 str = pool_id2str(pool, s->arch);
2514 if (!strncmp(dir, str, l) && !str[l])
2515 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2517 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2520 str = pool_id2str(pool, s->name);
2522 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2525 str = evrid2vrstr(pool, s->evr);
2527 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2530 str = pool_id2str(pool, s->arch);
2532 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2534 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2539 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2542 /* XXX: medianr is currently not stored */
2544 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2547 const char *evr, *suf, *s;
2551 if ((dir = strrchr(file, '/')) != 0)
2562 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2567 if (l == 1 && dir[0] == '.')
2570 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2571 evr = strchr(file, '-');
2574 for (s = evr - 1; s > file; s--)
2581 suf = strrchr(file, '.');
2584 for (s = suf - 1; s > file; s--)
2590 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2592 /* We accept one more item as suffix. */
2593 for (s = suf - 1; s > file; s--)
2603 if (suf && evr && suf < evr)
2605 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2607 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2609 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2613 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2615 Pool *pool = data->repo->pool;
2616 Solvable *s = pool->solvables + solvid;
2617 const char *p, *sevr, *sarch, *name, *evr;
2619 p = strrchr(sourcepkg, '.');
2620 if (!p || strcmp(p, ".rpm") != 0)
2623 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2627 while (p > sourcepkg && *p != '.')
2629 if (*p != '.' || p == sourcepkg)
2632 while (p > sourcepkg && *p != '-')
2634 if (*p != '-' || p == sourcepkg)
2637 while (p > sourcepkg && *p != '-')
2639 if (*p != '-' || p == sourcepkg)
2642 pool = s->repo->pool;
2644 name = pool_id2str(pool, s->name);
2645 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2646 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2648 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2650 evr = evrid2vrstr(pool, s->evr);
2651 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2652 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2654 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2656 if (!strcmp(sarch, "src.rpm"))
2657 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2658 else if (!strcmp(sarch, "nosrc.rpm"))
2659 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2661 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2665 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2671 key.type = REPOKEY_TYPE_IDARRAY;
2673 key.storage = KEY_STORAGE_INCORE;
2674 repodata_set(data, solvid, &key, data->attriddatalen);
2675 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2676 for (i = 0; i < q->count; i++)
2677 data->attriddata[data->attriddatalen++] = q->elements[i];
2678 data->attriddata[data->attriddatalen++] = 0;
2682 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2686 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2688 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2689 data->attriddata[data->attriddatalen++] = dir;
2690 data->attriddata[data->attriddatalen++] = num;
2691 data->attriddata[data->attriddatalen++] = num2;
2692 data->attriddata[data->attriddatalen++] = 0;
2696 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2702 l = strlen(str) + 1;
2703 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2704 memcpy(data->attrdata + data->attrdatalen, str, l);
2705 stroff = data->attrdatalen;
2706 data->attrdatalen += l;
2709 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2711 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2712 data->attriddata[data->attriddatalen++] = dir;
2713 data->attriddata[data->attriddatalen++] = stroff;
2714 data->attriddata[data->attriddatalen++] = 0;
2718 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2721 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2723 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2724 data->attriddata[data->attriddatalen++] = id;
2725 data->attriddata[data->attriddatalen++] = 0;
2729 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2733 if (data->localpool)
2734 id = stringpool_str2id(&data->spool, str, 1);
2736 id = pool_str2id(data->repo->pool, str, 1);
2737 repodata_add_idarray(data, solvid, keyname, id);
2741 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2743 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2744 data->attriddata[data->attriddatalen++] = ghandle;
2745 data->attriddata[data->attriddatalen++] = 0;
2749 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2751 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2752 data->attriddata[data->attriddatalen++] = ghandle;
2753 data->attriddata[data->attriddatalen++] = 0;
2757 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2760 app = repodata_get_attrp(data, solvid);
2764 for (; *ap; ap += 2)
2765 if (data->keys[*ap].name == keyname)
2771 for (; *ap; ap += 2)
2773 if (data->keys[*ap].name == keyname)
2781 /* XXX: does not work correctly, needs fix in iterators! */
2783 repodata_unset(Repodata *data, Id solvid, Id keyname)
2787 key.type = REPOKEY_TYPE_DELETED;
2789 key.storage = KEY_STORAGE_INCORE;
2790 repodata_set(data, solvid, &key, 0);
2793 /* add all (uninternalized) attrs from src to dest */
2795 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2798 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2800 for (; *keyp; keyp += 2)
2801 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2804 /* add some (uninternalized) attrs from src to dest */
2806 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2809 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2811 for (; *keyp; keyp += 2)
2812 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2813 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2816 /* swap (uninternalized) attrs from src and dest */
2818 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2821 if (!data->attrs || dest == src)
2823 tmpattrs = data->attrs[dest - data->start];
2824 data->attrs[dest - data->start] = data->attrs[src - data->start];
2825 data->attrs[src - data->start] = tmpattrs;
2829 /**********************************************************************/
2831 /* TODO: unify with repo_write and repo_solv! */
2833 #define EXTDATA_BLOCK 1023
2841 data_addid(struct extdata *xd, Id sx)
2843 unsigned int x = (unsigned int)sx;
2846 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2847 dp = xd->buf + xd->len;
2852 *dp++ = (x >> 28) | 128;
2854 *dp++ = (x >> 21) | 128;
2855 *dp++ = (x >> 14) | 128;
2858 *dp++ = (x >> 7) | 128;
2860 xd->len = dp - xd->buf;
2864 data_addid64(struct extdata *xd, unsigned long long x)
2866 if (x >= 0x100000000)
2870 data_addid(xd, (Id)(x >> 35));
2871 xd->buf[xd->len - 1] |= 128;
2873 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2874 xd->buf[xd->len - 5] = (x >> 28) | 128;
2877 data_addid(xd, (Id)x);
2881 data_addideof(struct extdata *xd, Id sx, int eof)
2883 unsigned int x = (unsigned int)sx;
2886 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2887 dp = xd->buf + xd->len;
2892 *dp++ = (x >> 27) | 128;
2894 *dp++ = (x >> 20) | 128;
2895 *dp++ = (x >> 13) | 128;
2898 *dp++ = (x >> 6) | 128;
2899 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2900 xd->len = dp - xd->buf;
2904 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2906 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2907 memcpy(xd->buf + xd->len, blob, len);
2911 /*********************************/
2913 /* internalalize some key into incore/vincore data */
2916 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2917 struct extdata *newvincore,
2919 Repokey *key, Id val)
2923 unsigned int oldvincorelen = 0;
2927 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2930 oldvincorelen = xd->len;
2934 case REPOKEY_TYPE_VOID:
2935 case REPOKEY_TYPE_CONSTANT:
2936 case REPOKEY_TYPE_CONSTANTID:
2938 case REPOKEY_TYPE_STR:
2939 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2941 case REPOKEY_TYPE_MD5:
2942 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2944 case REPOKEY_TYPE_SHA1:
2945 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2947 case REPOKEY_TYPE_SHA256:
2948 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2950 case REPOKEY_TYPE_NUM:
2951 if (val & 0x80000000)
2953 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2957 case REPOKEY_TYPE_ID:
2958 case REPOKEY_TYPE_DIR:
2959 data_addid(xd, val);
2961 case REPOKEY_TYPE_BINARY:
2964 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2965 dp += (unsigned int)len;
2966 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2969 case REPOKEY_TYPE_IDARRAY:
2970 for (ida = data->attriddata + val; *ida; ida++)
2971 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2973 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2974 for (ida = data->attriddata + val; *ida; ida += 3)
2976 data_addid(xd, ida[0]);
2977 data_addid(xd, ida[1]);
2978 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2981 case REPOKEY_TYPE_DIRSTRARRAY:
2982 for (ida = data->attriddata + val; *ida; ida += 2)
2984 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2985 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2988 case REPOKEY_TYPE_FIXARRAY:
2992 for (ida = data->attriddata + val; *ida; ida++)
2996 kp = data->xattrs[-*ida];
3004 schemaid = repodata_schema2id(data, schema, 1);
3005 else if (schemaid != repodata_schema2id(data, schema, 0))
3007 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
3013 data_addid(xd, num);
3014 data_addid(xd, schemaid);
3015 for (ida = data->attriddata + val; *ida; ida++)
3017 Id *kp = data->xattrs[-*ida];
3021 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3025 case REPOKEY_TYPE_FLEXARRAY:
3028 for (ida = data->attriddata + val; *ida; ida++)
3030 data_addid(xd, num);
3031 for (ida = data->attriddata + val; *ida; ida++)
3033 Id *kp = data->xattrs[-*ida];
3036 data_addid(xd, 0); /* XXX */
3043 schemaid = repodata_schema2id(data, schema, 1);
3044 data_addid(xd, schemaid);
3045 kp = data->xattrs[-*ida];
3047 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3052 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
3055 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3057 /* put offset/len in incore */
3058 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
3059 oldvincorelen = xd->len - oldvincorelen;
3060 data_addid(newincore, oldvincorelen);
3065 repodata_internalize(Repodata *data)
3067 Repokey *key, solvkey;
3069 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
3070 unsigned char *dp, *ndp;
3071 int newschema, oldcount;
3072 struct extdata newincore;
3073 struct extdata newvincore;
3076 if (!data->attrs && !data->xattrs)
3079 newvincore.buf = data->vincore;
3080 newvincore.len = data->vincorelen;
3082 /* find the solvables key, create if needed */
3083 memset(&solvkey, 0, sizeof(solvkey));
3084 solvkey.name = REPOSITORY_SOLVABLES;
3085 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3087 solvkey.storage = KEY_STORAGE_INCORE;
3088 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3090 schema = solv_malloc2(data->nkeys, sizeof(Id));
3091 seen = solv_malloc2(data->nkeys, sizeof(Id));
3093 /* Merge the data already existing (in data->schemata, ->incoredata and
3094 friends) with the new attributes in data->attrs[]. */
3095 nentry = data->end - data->start;
3096 memset(&newincore, 0, sizeof(newincore));
3097 data_addid(&newincore, 0); /* start data at offset 1 */
3099 data->mainschema = 0;
3100 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3102 /* join entry data */
3103 /* we start with the meta data, entry -1 */
3104 for (entry = -1; entry < nentry; entry++)
3106 memset(seen, 0, data->nkeys * sizeof(Id));
3108 dp = data->incoredata;
3111 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3112 dp = data_read_id(dp, &oldschema);
3115 fprintf(stderr, "oldschema %d\n", oldschema);
3116 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3117 fprintf(stderr, "schemadata %p\n", data->schemadata);
3119 /* seen: -1: old data 0: skipped >0: id + 1 */
3123 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3127 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3135 keyp = data->attrs ? data->attrs[entry] : 0;
3138 /* strip solvables key */
3140 for (sp = keyp = schema; *sp; sp++)
3141 if (*sp != solvkeyid)
3146 seen[solvkeyid] = 0;
3147 keyp = data->xattrs ? data->xattrs[1] : 0;
3150 for (; *keyp; keyp += 2)
3157 seen[*keyp] = keyp[1] + 1;
3159 if (entry < 0 && data->end != data->start)
3166 /* Ideally we'd like to sort the new schema here, to ensure
3167 schema equality independend of the ordering. We can't do that
3168 yet. For once see below (old ids need to come before new ids).
3169 An additional difficulty is that we also need to move
3170 the values with the keys. */
3171 schemaid = repodata_schema2id(data, schema, 1);
3173 schemaid = oldschema;
3176 /* Now create data blob. We walk through the (possibly new) schema
3177 and either copy over old data, or insert the new. */
3178 /* XXX Here we rely on the fact that the (new) schema has the form
3179 o1 o2 o3 o4 ... | n1 n2 n3 ...
3180 (oX being the old keyids (possibly overwritten), and nX being
3181 the new keyids). This rules out sorting the keyids in order
3182 to ensure a small schema count. */
3184 data->incoreoffset[entry] = newincore.len;
3185 data_addid(&newincore, schemaid);
3188 data->mainschema = schemaid;
3189 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3191 keypstart = data->schemadata + data->schemata[schemaid];
3192 for (keyp = keypstart; *keyp; keyp++)
3195 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3196 if (*keyp == solvkeyid)
3198 /* add flexarray entry count */
3199 data_addid(&newincore, data->end - data->start);
3202 key = data->keys + *keyp;
3204 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));
3209 /* Skip the data associated with this old key. */
3210 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3212 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3213 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3215 else if (key->storage == KEY_STORAGE_INCORE)
3216 ndp = data_skip_key(data, dp, key);
3219 if (seen[*keyp] == -1)
3221 /* If this key was an old one _and_ was not overwritten with
3222 a different value copy over the old value (we skipped it
3225 data_addblob(&newincore, dp, ndp - dp);
3228 else if (seen[*keyp])
3230 /* Otherwise we have a new value. Parse it into the internal
3232 repodata_serialize_key(data, &newincore, &newvincore,
3233 schema, key, seen[*keyp] - 1);
3237 if (entry >= 0 && data->attrs && data->attrs[entry])
3238 data->attrs[entry] = solv_free(data->attrs[entry]);
3240 /* free all xattrs */
3241 for (entry = 0; entry < data->nxattrs; entry++)
3242 if (data->xattrs[entry])
3243 solv_free(data->xattrs[entry]);
3244 data->xattrs = solv_free(data->xattrs);
3247 data->lasthandle = 0;
3249 data->lastdatalen = 0;
3252 repodata_free_schemahash(data);
3254 solv_free(data->incoredata);
3255 data->incoredata = newincore.buf;
3256 data->incoredatalen = newincore.len;
3257 data->incoredatafree = 0;
3259 solv_free(data->vincore);
3260 data->vincore = newvincore.buf;
3261 data->vincorelen = newvincore.len;
3263 data->attrs = solv_free(data->attrs);
3264 data->attrdata = solv_free(data->attrdata);
3265 data->attriddata = solv_free(data->attriddata);
3266 data->attrnum64data = solv_free(data->attrnum64data);
3267 data->attrdatalen = 0;
3268 data->attriddatalen = 0;
3269 data->attrnum64datalen = 0;
3273 repodata_disable_paging(Repodata *data)
3275 if (maybe_load_repodata(data, 0))
3277 repopagestore_disable_paging(&data->store);
3283 repodata_load_stub(Repodata *data)
3285 Repo *repo = data->repo;
3286 Pool *pool = repo->pool;
3288 struct _Pool_tmpspace oldtmpspace;
3290 if (!pool->loadcallback)
3292 data->state = REPODATA_ERROR;
3295 data->state = REPODATA_LOADING;
3297 /* save tmp space */
3298 oldtmpspace = pool->tmpspace;
3299 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3301 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3303 /* restore tmp space */
3304 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3305 solv_free(pool->tmpspace.buf[i]);
3306 pool->tmpspace = oldtmpspace;
3308 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3312 repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
3316 xkey.name = keyname;
3317 xkey.type = keytype;
3318 xkey.storage = KEY_STORAGE_INCORE;
3320 repodata_key2id(data, &xkey, 1);
3324 repodata_add_stub(Repodata **datap)
3326 Repodata *data = *datap;
3327 Repo *repo = data->repo;
3328 Id repodataid = data - repo->repodata;
3329 Repodata *sdata = repo_add_repodata(repo, 0);
3330 data = repo->repodata + repodataid;
3331 if (data->end > data->start)
3332 repodata_extend_block(sdata, data->start, data->end - data->start);
3333 sdata->state = REPODATA_STUB;
3334 sdata->loadcallback = repodata_load_stub;
3340 repodata_create_stubs(Repodata *data)
3342 Repo *repo = data->repo;
3343 Pool *pool = repo->pool;
3350 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3351 while (dataiterator_step(&di))
3352 if (di.data == data)
3354 dataiterator_free(&di);
3357 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3358 for (i = 0; i < cnt; i++)
3360 sdata = repodata_add_stub(&data);
3361 stubdataids[i] = sdata - repo->repodata;
3364 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3366 while (dataiterator_step(&di))
3368 if (di.data != data)
3370 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3372 dataiterator_entersub(&di);
3373 sdata = repo->repodata + stubdataids[i++];
3377 switch (di.key->type)
3379 case REPOKEY_TYPE_ID:
3380 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3382 case REPOKEY_TYPE_CONSTANTID:
3383 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3385 case REPOKEY_TYPE_STR:
3386 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3388 case REPOKEY_TYPE_VOID:
3389 repodata_set_void(sdata, SOLVID_META, di.key->name);
3391 case REPOKEY_TYPE_NUM:
3392 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3394 case REPOKEY_TYPE_MD5:
3395 case REPOKEY_TYPE_SHA1:
3396 case REPOKEY_TYPE_SHA256:
3397 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3399 case REPOKEY_TYPE_IDARRAY:
3400 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3401 if (di.key->name == REPOSITORY_KEYS)
3406 xkeyname = di.kv.id;
3410 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
3419 dataiterator_free(&di);
3420 for (i = 0; i < cnt; i++)
3421 repodata_internalize(repo->repodata + stubdataids[i]);
3422 solv_free(stubdataids);
3427 repodata_memused(Repodata *data)
3429 return data->incoredatalen + data->vincorelen;