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 match = match ? solv_strdup(match) : 0;
1099 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1101 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1102 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1105 solv_free(ma->matchdata);
1106 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1109 if ((flags & SEARCH_FILES) != 0 && match)
1111 /* prepare basename check */
1112 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1114 const char *p = strrchr(match, '/');
1115 ma->matchdata = (void *)(p ? p + 1 : match);
1117 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1120 for (p = match + strlen(match) - 1; p >= match; p--)
1121 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1123 ma->matchdata = (void *)(p + 1);
1130 datamatcher_free(Datamatcher *ma)
1133 ma->match = solv_free((char *)ma->match);
1134 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1136 regfree(ma->matchdata);
1137 solv_free(ma->matchdata);
1143 datamatcher_match(Datamatcher *ma, const char *str)
1146 switch ((ma->flags & SEARCH_STRINGMASK))
1148 case SEARCH_SUBSTRING:
1149 if (ma->flags & SEARCH_NOCASE)
1150 return strcasestr(str, ma->match) != 0;
1152 return strstr(str, ma->match) != 0;
1154 if (ma->flags & SEARCH_NOCASE)
1155 return !strcasecmp(ma->match, str);
1157 return !strcmp(ma->match, str);
1158 case SEARCH_STRINGSTART:
1159 if (ma->flags & SEARCH_NOCASE)
1160 return !strncasecmp(ma->match, str, strlen(ma->match));
1162 return !strncmp(ma->match, str, strlen(ma->match));
1163 case SEARCH_STRINGEND:
1164 l = strlen(str) - strlen(ma->match);
1167 if (ma->flags & SEARCH_NOCASE)
1168 return !strcasecmp(ma->match, str + l);
1170 return !strcmp(ma->match, str + l);
1172 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1174 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1180 /* check if the matcher can match the provides basename */
1183 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1186 const char *match = ma->matchdata;
1189 switch (ma->flags & SEARCH_STRINGMASK)
1193 case SEARCH_STRINGEND:
1194 if (match != ma->match)
1195 break; /* had slash, do exact match on basename */
1198 /* check if the basename ends with match */
1199 l = strlen(basename) - strlen(match);
1205 return 1; /* maybe matches */
1207 if ((ma->flags & SEARCH_NOCASE) != 0)
1208 return !strcasecmp(match, basename);
1210 return !strcmp(match, basename);
1214 repodata_filelistfilter_matches(Repodata *data, const char *str)
1216 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1217 /* for now hardcoded */
1218 if (strstr(str, "bin/"))
1220 if (!strncmp(str, "/etc/", 5))
1222 if (!strcmp(str, "/usr/lib/sendmail"))
1244 di_nextarrayelement,
1250 di_entersolvablekey,
1254 /* see dataiterator.h for documentation */
1256 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1258 memset(di, 0, sizeof(*di));
1260 di->flags = flags & ~SEARCH_THISSOLVID;
1261 if (!pool || (repo && repo->pool != pool))
1269 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1275 di->keyname = keyname;
1276 di->keynames[0] = keyname;
1277 dataiterator_set_search(di, repo, p);
1282 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1287 if (di->dupstr == di->kv.str)
1288 di->dupstr = solv_memdup(di->dupstr, di->dupstrn);
1295 memset(&di->matcher, 0, sizeof(di->matcher));
1296 if (from->matcher.match)
1297 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1302 for (i = 1; i < di->nparents; i++)
1303 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1304 di->kv.parent = &di->parents[di->nparents - 1].kv;
1309 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1311 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1312 datamatcher_free(&di->matcher);
1313 memset(&di->matcher, 0, sizeof(di->matcher));
1317 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1327 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1331 di->flags &= ~SEARCH_THISSOLVID;
1335 if (!di->pool->urepos)
1343 di->repo = di->pool->repos[di->repoid];
1345 di->state = di_enterrepo;
1347 dataiterator_jump_to_solvid(di, p);
1351 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1354 di->keyname = keyname;
1355 di->keynames[0] = keyname;
1359 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1363 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1365 di->state = di_bye; /* sorry */
1368 for (i = di->nkeynames + 1; i > 0; i--)
1369 di->keynames[i] = di->keynames[i - 1];
1370 di->keynames[0] = di->keyname = keyname;
1375 dataiterator_free(Dataiterator *di)
1377 if (di->matcher.match)
1378 datamatcher_free(&di->matcher);
1380 solv_free(di->dupstr);
1383 static unsigned char *
1384 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1387 Repokey *keys = di->data->keys, *key;
1390 for (keyp = di->keyp; *keyp; keyp++)
1391 if (keys[*keyp].name == keyname)
1396 if (key->type == REPOKEY_TYPE_DELETED)
1398 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
1399 return 0; /* get_data will not work, no need to forward */
1400 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1408 is_filelist_extension(Repodata *data)
1411 if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
1413 for (j = 1; j < data->nkeys; j++)
1414 if (data->keys[j].name == SOLVABLE_FILELIST)
1416 if (j == data->nkeys)
1418 if (data->state != REPODATA_AVAILABLE)
1420 for (j = 1; j < data->nkeys; j++)
1421 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1427 dataiterator_filelistcheck(Dataiterator *di)
1430 int needcomplete = 0;
1431 Repodata *data = di->data;
1433 if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
1434 if (!di->matcher.match
1435 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1436 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1437 || !repodata_filelistfilter_matches(data, di->matcher.match))
1439 if (data->state != REPODATA_AVAILABLE)
1440 return needcomplete ? 1 : 0;
1443 /* we don't need the complete filelist, so ignore all stubs */
1444 for (j = 1; j < data->nkeys; j++)
1445 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1451 /* we need the complete filelist. check if we habe a filtered filelist and there's
1452 * a extension with the complete filelist later on */
1453 for (j = 1; j < data->nkeys; j++)
1454 if (data->keys[j].name == SOLVABLE_FILELIST)
1456 if (j == data->nkeys)
1457 return 0; /* does not have filelist */
1458 for (j = 1; j < data->nkeys; j++)
1459 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1461 if (j == data->nkeys)
1462 return 1; /* this is the externsion */
1463 while (data - data->repo->repodata + 1 < data->repo->nrepodata)
1466 if (is_filelist_extension(data))
1474 dataiterator_step(Dataiterator *di)
1478 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1479 unsigned int ddpoff = di->ddp - di->vert_ddp;
1480 di->vert_off += ddpoff;
1481 di->vert_len -= ddpoff;
1482 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1483 di->vert_storestate = di->data->storestate;
1485 di->state = di_nextkey;
1491 case di_enterrepo: di_enterrepo:
1492 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1494 if (!(di->flags & SEARCH_THISSOLVID))
1496 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1497 goto di_nextsolvable;
1501 case di_entersolvable: di_entersolvable:
1504 di->repodataid = 1; /* reset repodata iterator */
1505 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)
1507 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1509 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1511 goto di_entersolvablekey;
1516 case di_enterrepodata: di_enterrepodata:
1519 if (di->repodataid >= di->repo->nrepodata)
1520 goto di_nextsolvable;
1521 di->data = di->repo->repodata + di->repodataid;
1523 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1524 goto di_nextrepodata;
1525 if (!maybe_load_repodata(di->data, di->keyname))
1526 goto di_nextrepodata;
1527 di->dp = solvid2data(di->data, di->solvid, &schema);
1529 goto di_nextrepodata;
1530 if (di->solvid == SOLVID_POS)
1531 di->solvid = di->pool->pos.solvid;
1532 /* reset key iterator */
1533 di->keyp = di->data->schemadata + di->data->schemata[schema];
1536 case di_enterschema: di_enterschema:
1538 di->dp = dataiterator_find_keyname(di, di->keyname);
1539 if (!di->dp || !*di->keyp)
1543 goto di_nextrepodata;
1547 case di_enterkey: di_enterkey:
1549 di->key = di->data->keys + *di->keyp;
1552 /* this is get_data() modified to store vert_ data */
1553 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1556 di->dp = data_read_id(di->dp, &off);
1557 di->dp = data_read_id(di->dp, &len);
1558 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1561 di->vert_storestate = di->data->storestate;
1563 else if (di->key->storage == KEY_STORAGE_INCORE)
1566 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1567 di->dp = data_skip_key(di->data, di->dp, di->key);
1573 if (di->key->type == REPOKEY_TYPE_DELETED)
1575 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1577 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1583 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1585 di->state = di_nextkey;
1587 di->state = di_nextattr;
1590 case di_nextkey: di_nextkey:
1591 if (!di->keyname && *++di->keyp)
1597 case di_nextrepodata: di_nextrepodata:
1598 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1599 goto di_enterrepodata;
1602 case di_nextsolvable: di_nextsolvable:
1603 if (!(di->flags & SEARCH_THISSOLVID))
1606 di->solvid = di->repo->start;
1609 for (; di->solvid < di->repo->end; di->solvid++)
1611 if (di->pool->solvables[di->solvid].repo == di->repo)
1612 goto di_entersolvable;
1617 case di_nextrepo: di_nextrepo:
1622 if (di->repoid < di->pool->nrepos)
1624 di->repo = di->pool->repos[di->repoid];
1630 case di_bye: di_bye:
1634 case di_enterarray: di_enterarray:
1635 if (di->key->name == REPOSITORY_SOLVABLES)
1637 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1642 case di_nextarrayelement: di_nextarrayelement:
1645 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1646 if (di->kv.entry == di->kv.num)
1648 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1650 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1652 di->kv.str = (char *)di->ddp;
1654 di->state = di_nextkey;
1657 if (di->kv.entry == di->kv.num - 1)
1659 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1660 di->ddp = data_read_id(di->ddp, &di->kv.id);
1661 di->kv.str = (char *)di->ddp;
1662 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1664 if ((di->flags & SEARCH_SUB) != 0)
1665 di->state = di_entersub;
1667 di->state = di_nextarrayelement;
1670 case di_entersub: di_entersub:
1671 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1672 goto di_nextarrayelement; /* sorry, full */
1673 di->parents[di->nparents].kv = di->kv;
1674 di->parents[di->nparents].dp = di->dp;
1675 di->parents[di->nparents].keyp = di->keyp;
1676 di->dp = (unsigned char *)di->kv.str;
1677 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1678 memset(&di->kv, 0, sizeof(di->kv));
1679 di->kv.parent = &di->parents[di->nparents].kv;
1681 di->keyname = di->keynames[di->nparents - di->rootlevel];
1682 goto di_enterschema;
1684 case di_leavesub: di_leavesub:
1685 if (di->nparents - 1 < di->rootlevel)
1688 di->dp = di->parents[di->nparents].dp;
1689 di->kv = di->parents[di->nparents].kv;
1690 di->keyp = di->parents[di->nparents].keyp;
1691 di->key = di->data->keys + *di->keyp;
1692 di->ddp = (unsigned char *)di->kv.str;
1693 di->keyname = di->keynames[di->nparents - di->rootlevel];
1694 goto di_nextarrayelement;
1696 /* special solvable attr handling follows */
1698 case di_nextsolvablekey: di_nextsolvablekey:
1699 if (di->keyname || di->key->name == RPM_RPMDBID)
1700 goto di_enterrepodata;
1704 case di_entersolvablekey: di_entersolvablekey:
1705 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1706 if (!di->idp || !*di->idp)
1707 goto di_nextsolvablekey;
1711 di->kv.id = *di->idp;
1712 di->kv.num = *di->idp; /* for rpmdbid */
1713 di->kv.num2 = 0; /* for rpmdbid */
1715 di->state = di_nextsolvablekey;
1721 case di_nextsolvableattr:
1722 di->state = di_nextsolvableattr;
1723 di->kv.id = *di->idp++;
1728 di->state = di_nextsolvablekey;
1734 if (di->matcher.match)
1736 /* simple pre-check so that we don't need to stringify */
1737 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1738 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1740 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1742 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1746 if (!datamatcher_match(&di->matcher, di->kv.str))
1751 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1752 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1754 /* found something! */
1760 dataiterator_entersub(Dataiterator *di)
1762 if (di->state == di_nextarrayelement)
1763 di->state = di_entersub;
1767 dataiterator_setpos(Dataiterator *di)
1769 if (di->kv.eof == 2)
1771 pool_clear_pos(di->pool);
1774 di->pool->pos.solvid = di->solvid;
1775 di->pool->pos.repo = di->repo;
1776 di->pool->pos.repodataid = di->data - di->repo->repodata;
1777 di->pool->pos.schema = di->kv.id;
1778 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1782 dataiterator_setpos_parent(Dataiterator *di)
1784 if (!di->kv.parent || di->kv.parent->eof == 2)
1786 pool_clear_pos(di->pool);
1789 di->pool->pos.solvid = di->solvid;
1790 di->pool->pos.repo = di->repo;
1791 di->pool->pos.repodataid = di->data - di->repo->repodata;
1792 di->pool->pos.schema = di->kv.parent->id;
1793 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1796 /* clones just the position, not the search keys/matcher */
1798 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1800 di->state = from->state;
1801 di->flags &= ~SEARCH_THISSOLVID;
1802 di->flags |= (from->flags & SEARCH_THISSOLVID);
1803 di->repo = from->repo;
1804 di->data = from->data;
1806 di->ddp = from->ddp;
1807 di->idp = from->idp;
1808 di->keyp = from->keyp;
1809 di->key = from->key;
1811 di->repodataid = from->repodataid;
1812 di->solvid = from->solvid;
1813 di->repoid = from->repoid;
1814 di->rootlevel = from->rootlevel;
1815 memcpy(di->parents, from->parents, sizeof(from->parents));
1816 di->nparents = from->nparents;
1820 for (i = 1; i < di->nparents; i++)
1821 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1822 di->kv.parent = &di->parents[di->nparents - 1].kv;
1826 if (from->dupstr && from->dupstr == from->kv.str)
1828 di->dupstrn = from->dupstrn;
1829 di->dupstr = solv_memdup(from->dupstr, from->dupstrn);
1834 dataiterator_seek(Dataiterator *di, int whence)
1836 if ((whence & DI_SEEK_STAY) != 0)
1837 di->rootlevel = di->nparents;
1838 switch (whence & ~DI_SEEK_STAY)
1841 if (di->state != di_nextarrayelement)
1843 if ((whence & DI_SEEK_STAY) != 0)
1844 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1845 di->state = di_entersub;
1847 case DI_SEEK_PARENT:
1854 if (di->rootlevel > di->nparents)
1855 di->rootlevel = di->nparents;
1856 di->dp = di->parents[di->nparents].dp;
1857 di->kv = di->parents[di->nparents].kv;
1858 di->keyp = di->parents[di->nparents].keyp;
1859 di->key = di->data->keys + *di->keyp;
1860 di->ddp = (unsigned char *)di->kv.str;
1861 di->keyname = di->keynames[di->nparents - di->rootlevel];
1862 di->state = di_nextarrayelement;
1864 case DI_SEEK_REWIND:
1870 di->dp = (unsigned char *)di->kv.parent->str;
1871 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1872 di->state = di_enterschema;
1880 dataiterator_skip_attribute(Dataiterator *di)
1882 if (di->state == di_nextsolvableattr)
1883 di->state = di_nextsolvablekey;
1885 di->state = di_nextkey;
1889 dataiterator_skip_solvable(Dataiterator *di)
1894 di->keyname = di->keynames[0];
1895 di->state = di_nextsolvable;
1899 dataiterator_skip_repo(Dataiterator *di)
1904 di->keyname = di->keynames[0];
1905 di->state = di_nextrepo;
1909 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1914 di->keyname = di->keynames[0];
1915 if (solvid == SOLVID_POS)
1917 di->repo = di->pool->pos.repo;
1924 di->data = di->repo->repodata + di->pool->pos.repodataid;
1926 di->solvid = solvid;
1927 di->state = di_enterrepo;
1928 di->flags |= SEARCH_THISSOLVID;
1933 di->repo = di->pool->solvables[solvid].repo;
1936 else if (di->repoid > 0)
1938 if (!di->pool->urepos)
1944 di->repo = di->pool->repos[di->repoid];
1947 di->solvid = solvid;
1949 di->flags |= SEARCH_THISSOLVID;
1950 di->state = di_enterrepo;
1954 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1960 di->repoid = 0; /* 0 means stay at repo */
1963 di->flags &= ~SEARCH_THISSOLVID;
1964 di->state = di_enterrepo;
1968 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1970 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1974 return datamatcher_match(ma, di->kv.str);
1978 dataiterator_strdup(Dataiterator *di)
1982 if (!di->kv.str || di->kv.str == di->dupstr)
1984 switch (di->key->type)
1986 case REPOKEY_TYPE_MD5:
1987 case REPOKEY_TYPE_SHA1:
1988 case REPOKEY_TYPE_SHA256:
1989 case REPOKEY_TYPE_DIRSTRARRAY:
1990 if (di->kv.num) /* was it stringified into tmp space? */
1991 l = strlen(di->kv.str) + 1;
1996 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1998 switch (di->key->type)
2000 case REPOKEY_TYPE_STR:
2001 case REPOKEY_TYPE_DIRSTRARRAY:
2002 l = strlen(di->kv.str) + 1;
2004 case REPOKEY_TYPE_MD5:
2007 case REPOKEY_TYPE_SHA1:
2010 case REPOKEY_TYPE_SHA256:
2013 case REPOKEY_TYPE_BINARY:
2020 if (!di->dupstrn || di->dupstrn < l)
2022 di->dupstrn = l + 16;
2023 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
2026 memcpy(di->dupstr, di->kv.str, l);
2027 di->kv.str = di->dupstr;
2031 /************************************************************************
2032 * data modify functions
2035 /* extend repodata so that it includes solvables p */
2037 repodata_extend(Repodata *data, Id p)
2039 if (data->start == data->end)
2040 data->start = data->end = p;
2043 int old = data->end - data->start;
2044 int new = p - data->end + 1;
2047 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
2048 memset(data->attrs + old, 0, new * sizeof(Id *));
2050 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
2051 memset(data->incoreoffset + old, 0, new * sizeof(Id));
2054 if (p < data->start)
2056 int old = data->end - data->start;
2057 int new = data->start - p;
2060 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
2061 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
2062 memset(data->attrs, 0, new * sizeof(Id *));
2064 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
2065 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
2066 memset(data->incoreoffset, 0, new * sizeof(Id));
2071 /* shrink end of repodata */
2073 repodata_shrink(Repodata *data, int end)
2077 if (data->end <= end)
2079 if (data->start >= end)
2083 for (i = 0; i < data->end - data->start; i++)
2084 solv_free(data->attrs[i]);
2085 data->attrs = solv_free(data->attrs);
2087 data->incoreoffset = solv_free(data->incoreoffset);
2088 data->start = data->end = 0;
2093 for (i = end; i < data->end; i++)
2094 solv_free(data->attrs[i - data->start]);
2095 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2097 if (data->incoreoffset)
2098 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2102 /* extend repodata so that it includes solvables from start to start + num - 1 */
2104 repodata_extend_block(Repodata *data, Id start, Id num)
2108 if (!data->incoreoffset)
2110 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2111 data->start = start;
2112 data->end = start + num;
2115 repodata_extend(data, start);
2117 repodata_extend(data, start + num - 1);
2120 /**********************************************************************/
2123 #define REPODATA_ATTRS_BLOCK 31
2124 #define REPODATA_ATTRDATA_BLOCK 1023
2125 #define REPODATA_ATTRIDDATA_BLOCK 63
2126 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2130 repodata_new_handle(Repodata *data)
2134 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2135 data->nxattrs = 2; /* -1: SOLVID_META */
2137 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2138 data->xattrs[data->nxattrs] = 0;
2139 return -(data->nxattrs++);
2143 repodata_get_attrp(Repodata *data, Id handle)
2147 if (handle == SOLVID_META && !data->xattrs)
2149 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2152 return data->xattrs - handle;
2154 if (handle < data->start || handle >= data->end)
2155 repodata_extend(data, handle);
2157 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2158 return data->attrs + (handle - data->start);
2162 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2168 app = repodata_get_attrp(data, handle);
2173 /* Determine equality based on the name only, allows us to change
2174 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2175 for (pp = ap; *pp; pp += 2)
2176 if (data->keys[*pp].name == data->keys[keyid].name)
2180 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2189 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2199 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2203 keyid = repodata_key2id(data, key, 1);
2204 repodata_insert_keyid(data, solvid, keyid, val, 1);
2208 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2212 key.type = REPOKEY_TYPE_ID;
2214 key.storage = KEY_STORAGE_INCORE;
2215 repodata_set(data, solvid, &key, id);
2219 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2223 key.type = REPOKEY_TYPE_NUM;
2225 key.storage = KEY_STORAGE_INCORE;
2226 if (num >= 0x80000000)
2228 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2229 data->attrnum64data[data->attrnum64datalen] = num;
2230 num = 0x80000000 | data->attrnum64datalen++;
2232 repodata_set(data, solvid, &key, (Id)num);
2236 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2240 if (data->localpool)
2241 id = stringpool_str2id(&data->spool, str, 1);
2243 id = pool_str2id(data->repo->pool, str, 1);
2245 key.type = REPOKEY_TYPE_ID;
2247 key.storage = KEY_STORAGE_INCORE;
2248 repodata_set(data, solvid, &key, id);
2252 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2256 key.type = REPOKEY_TYPE_CONSTANT;
2257 key.size = constant;
2258 key.storage = KEY_STORAGE_INCORE;
2259 repodata_set(data, solvid, &key, 0);
2263 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2267 key.type = REPOKEY_TYPE_CONSTANTID;
2269 key.storage = KEY_STORAGE_INCORE;
2270 repodata_set(data, solvid, &key, 0);
2274 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2278 key.type = REPOKEY_TYPE_VOID;
2280 key.storage = KEY_STORAGE_INCORE;
2281 repodata_set(data, solvid, &key, 0);
2285 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2290 l = strlen(str) + 1;
2292 key.type = REPOKEY_TYPE_STR;
2294 key.storage = KEY_STORAGE_INCORE;
2295 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2296 memcpy(data->attrdata + data->attrdatalen, str, l);
2297 repodata_set(data, solvid, &key, data->attrdatalen);
2298 data->attrdatalen += l;
2302 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2310 key.type = REPOKEY_TYPE_BINARY;
2312 key.storage = KEY_STORAGE_INCORE;
2313 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2314 dp = data->attrdata + data->attrdatalen;
2315 if (len >= (1 << 14))
2317 if (len >= (1 << 28))
2318 *dp++ = (len >> 28) | 128;
2319 if (len >= (1 << 21))
2320 *dp++ = (len >> 21) | 128;
2321 *dp++ = (len >> 14) | 128;
2323 if (len >= (1 << 7))
2324 *dp++ = (len >> 7) | 128;
2327 memcpy(dp, buf, len);
2328 repodata_set(data, solvid, &key, data->attrdatalen);
2329 data->attrdatalen = dp + len - data->attrdata;
2332 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2333 * so that the caller can append entrysize new elements plus the termination zero there */
2335 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2338 Id *ida, *pp, **ppp;
2340 /* check if it is the same as last time, this speeds things up a lot */
2341 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2343 /* great! just append the new data */
2344 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2345 data->attriddatalen--; /* overwrite terminating 0 */
2346 data->lastdatalen += entrysize;
2350 ppp = repodata_get_attrp(data, handle);
2354 for (; *pp; pp += 2)
2355 if (data->keys[*pp].name == keyname)
2358 if (!pp || !*pp || data->keys[*pp].type != keytype)
2360 /* not found. allocate new key */
2366 key.storage = KEY_STORAGE_INCORE;
2367 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2368 keyid = repodata_key2id(data, &key, 1);
2369 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2370 data->lasthandle = handle;
2371 data->lastkey = keyid;
2372 data->lastdatalen = data->attriddatalen + entrysize + 1;
2376 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2377 oldsize += entrysize;
2378 if (ida + 1 == data->attriddata + data->attriddatalen)
2380 /* this was the last entry, just append it */
2381 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2382 data->attriddatalen--; /* overwrite terminating 0 */
2386 /* too bad. move to back. */
2387 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2388 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2389 pp[1] = data->attriddatalen;
2390 data->attriddatalen += oldsize;
2392 data->lasthandle = handle;
2393 data->lastkey = *pp;
2394 data->lastdatalen = data->attriddatalen + entrysize + 1;
2398 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2399 const unsigned char *str)
2404 if (!(l = solv_chksum_len(type)))
2409 key.storage = KEY_STORAGE_INCORE;
2410 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2411 memcpy(data->attrdata + data->attrdatalen, str, l);
2412 repodata_set(data, solvid, &key, data->attrdatalen);
2413 data->attrdatalen += l;
2417 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2420 unsigned char buf[64];
2423 if (!(l = solv_chksum_len(type)))
2425 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2427 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2431 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2435 if (!(l = solv_chksum_len(type)))
2437 return pool_bin2hex(data->repo->pool, buf, l);
2440 /* rpm filenames don't contain the epoch, so strip it */
2441 static inline const char *
2442 evrid2vrstr(Pool *pool, Id evrid)
2444 const char *p, *evr = pool_id2str(pool, evrid);
2447 for (p = evr; *p >= '0' && *p <= '9'; p++)
2449 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2453 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2456 if (data->localpool)
2457 id = stringpool_strn2id(&data->spool, str, l, 1);
2459 id = pool_strn2id(data->repo->pool, str, l, 1);
2460 repodata_set_id(data, solvid, keyname, id);
2464 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2467 repodata_set_str(data, solvid, keyname, str);
2470 char *s = solv_strdup(str);
2472 repodata_set_str(data, solvid, keyname, s);
2478 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2480 Pool *pool = data->repo->pool;
2482 const char *str, *fp;
2486 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2489 if ((dir = strrchr(file, '/')) != 0)
2500 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2505 if (l == 1 && dir[0] == '.')
2507 s = pool->solvables + solvid;
2510 str = pool_id2str(pool, s->arch);
2511 if (!strncmp(dir, str, l) && !str[l])
2512 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2514 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2517 str = pool_id2str(pool, s->name);
2519 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2522 str = evrid2vrstr(pool, s->evr);
2524 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2527 str = pool_id2str(pool, s->arch);
2529 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2531 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2536 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2539 /* XXX: medianr is currently not stored */
2541 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2544 const char *evr, *suf, *s;
2548 if ((dir = strrchr(file, '/')) != 0)
2559 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2564 if (l == 1 && dir[0] == '.')
2567 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2568 evr = strchr(file, '-');
2571 for (s = evr - 1; s > file; s--)
2578 suf = strrchr(file, '.');
2581 for (s = suf - 1; s > file; s--)
2587 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2589 /* We accept one more item as suffix. */
2590 for (s = suf - 1; s > file; s--)
2600 if (suf && evr && suf < evr)
2602 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2604 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2606 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2610 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2612 Pool *pool = data->repo->pool;
2613 Solvable *s = pool->solvables + solvid;
2614 const char *p, *sevr, *sarch, *name, *evr;
2616 p = strrchr(sourcepkg, '.');
2617 if (!p || strcmp(p, ".rpm") != 0)
2620 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2624 while (p > sourcepkg && *p != '.')
2626 if (*p != '.' || p == sourcepkg)
2629 while (p > sourcepkg && *p != '-')
2631 if (*p != '-' || p == sourcepkg)
2634 while (p > sourcepkg && *p != '-')
2636 if (*p != '-' || p == sourcepkg)
2639 pool = s->repo->pool;
2641 name = pool_id2str(pool, s->name);
2642 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2643 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2645 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2647 evr = evrid2vrstr(pool, s->evr);
2648 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2649 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2651 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2653 if (!strcmp(sarch, "src.rpm"))
2654 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2655 else if (!strcmp(sarch, "nosrc.rpm"))
2656 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2658 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2662 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2668 key.type = REPOKEY_TYPE_IDARRAY;
2670 key.storage = KEY_STORAGE_INCORE;
2671 repodata_set(data, solvid, &key, data->attriddatalen);
2672 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2673 for (i = 0; i < q->count; i++)
2674 data->attriddata[data->attriddatalen++] = q->elements[i];
2675 data->attriddata[data->attriddatalen++] = 0;
2679 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2683 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2685 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2686 data->attriddata[data->attriddatalen++] = dir;
2687 data->attriddata[data->attriddatalen++] = num;
2688 data->attriddata[data->attriddatalen++] = num2;
2689 data->attriddata[data->attriddatalen++] = 0;
2693 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2699 l = strlen(str) + 1;
2700 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2701 memcpy(data->attrdata + data->attrdatalen, str, l);
2702 stroff = data->attrdatalen;
2703 data->attrdatalen += l;
2706 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2708 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2709 data->attriddata[data->attriddatalen++] = dir;
2710 data->attriddata[data->attriddatalen++] = stroff;
2711 data->attriddata[data->attriddatalen++] = 0;
2715 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2718 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2720 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2721 data->attriddata[data->attriddatalen++] = id;
2722 data->attriddata[data->attriddatalen++] = 0;
2726 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2730 if (data->localpool)
2731 id = stringpool_str2id(&data->spool, str, 1);
2733 id = pool_str2id(data->repo->pool, str, 1);
2734 repodata_add_idarray(data, solvid, keyname, id);
2738 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2740 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2741 data->attriddata[data->attriddatalen++] = ghandle;
2742 data->attriddata[data->attriddatalen++] = 0;
2746 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2748 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2749 data->attriddata[data->attriddatalen++] = ghandle;
2750 data->attriddata[data->attriddatalen++] = 0;
2754 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2757 app = repodata_get_attrp(data, solvid);
2761 for (; *ap; ap += 2)
2762 if (data->keys[*ap].name == keyname)
2768 for (; *ap; ap += 2)
2770 if (data->keys[*ap].name == keyname)
2778 /* XXX: does not work correctly, needs fix in iterators! */
2780 repodata_unset(Repodata *data, Id solvid, Id keyname)
2784 key.type = REPOKEY_TYPE_DELETED;
2786 key.storage = KEY_STORAGE_INCORE;
2787 repodata_set(data, solvid, &key, 0);
2790 /* add all (uninternalized) attrs from src to dest */
2792 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2795 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2797 for (; *keyp; keyp += 2)
2798 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2801 /* add some (uninternalized) attrs from src to dest */
2803 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2806 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2808 for (; *keyp; keyp += 2)
2809 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2810 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2813 /* swap (uninternalized) attrs from src and dest */
2815 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2818 if (!data->attrs || dest == src)
2820 tmpattrs = data->attrs[dest - data->start];
2821 data->attrs[dest - data->start] = data->attrs[src - data->start];
2822 data->attrs[src - data->start] = tmpattrs;
2826 /**********************************************************************/
2828 /* TODO: unify with repo_write and repo_solv! */
2830 #define EXTDATA_BLOCK 1023
2838 data_addid(struct extdata *xd, Id sx)
2840 unsigned int x = (unsigned int)sx;
2843 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2844 dp = xd->buf + xd->len;
2849 *dp++ = (x >> 28) | 128;
2851 *dp++ = (x >> 21) | 128;
2852 *dp++ = (x >> 14) | 128;
2855 *dp++ = (x >> 7) | 128;
2857 xd->len = dp - xd->buf;
2861 data_addid64(struct extdata *xd, unsigned long long x)
2863 if (x >= 0x100000000)
2867 data_addid(xd, (Id)(x >> 35));
2868 xd->buf[xd->len - 1] |= 128;
2870 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2871 xd->buf[xd->len - 5] = (x >> 28) | 128;
2874 data_addid(xd, (Id)x);
2878 data_addideof(struct extdata *xd, Id sx, int eof)
2880 unsigned int x = (unsigned int)sx;
2883 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2884 dp = xd->buf + xd->len;
2889 *dp++ = (x >> 27) | 128;
2891 *dp++ = (x >> 20) | 128;
2892 *dp++ = (x >> 13) | 128;
2895 *dp++ = (x >> 6) | 128;
2896 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2897 xd->len = dp - xd->buf;
2901 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2903 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2904 memcpy(xd->buf + xd->len, blob, len);
2908 /*********************************/
2910 /* internalalize some key into incore/vincore data */
2913 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2914 struct extdata *newvincore,
2916 Repokey *key, Id val)
2920 unsigned int oldvincorelen = 0;
2924 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2927 oldvincorelen = xd->len;
2931 case REPOKEY_TYPE_VOID:
2932 case REPOKEY_TYPE_CONSTANT:
2933 case REPOKEY_TYPE_CONSTANTID:
2935 case REPOKEY_TYPE_STR:
2936 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2938 case REPOKEY_TYPE_MD5:
2939 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2941 case REPOKEY_TYPE_SHA1:
2942 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2944 case REPOKEY_TYPE_SHA256:
2945 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2947 case REPOKEY_TYPE_NUM:
2948 if (val & 0x80000000)
2950 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2954 case REPOKEY_TYPE_ID:
2955 case REPOKEY_TYPE_DIR:
2956 data_addid(xd, val);
2958 case REPOKEY_TYPE_BINARY:
2961 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2962 dp += (unsigned int)len;
2963 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2966 case REPOKEY_TYPE_IDARRAY:
2967 for (ida = data->attriddata + val; *ida; ida++)
2968 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2970 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2971 for (ida = data->attriddata + val; *ida; ida += 3)
2973 data_addid(xd, ida[0]);
2974 data_addid(xd, ida[1]);
2975 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2978 case REPOKEY_TYPE_DIRSTRARRAY:
2979 for (ida = data->attriddata + val; *ida; ida += 2)
2981 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2982 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2985 case REPOKEY_TYPE_FIXARRAY:
2989 for (ida = data->attriddata + val; *ida; ida++)
2993 kp = data->xattrs[-*ida];
3001 schemaid = repodata_schema2id(data, schema, 1);
3002 else if (schemaid != repodata_schema2id(data, schema, 0))
3004 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
3010 data_addid(xd, num);
3011 data_addid(xd, schemaid);
3012 for (ida = data->attriddata + val; *ida; ida++)
3014 Id *kp = data->xattrs[-*ida];
3018 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3022 case REPOKEY_TYPE_FLEXARRAY:
3025 for (ida = data->attriddata + val; *ida; ida++)
3027 data_addid(xd, num);
3028 for (ida = data->attriddata + val; *ida; ida++)
3030 Id *kp = data->xattrs[-*ida];
3033 data_addid(xd, 0); /* XXX */
3040 schemaid = repodata_schema2id(data, schema, 1);
3041 data_addid(xd, schemaid);
3042 kp = data->xattrs[-*ida];
3044 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3049 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
3052 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3054 /* put offset/len in incore */
3055 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
3056 oldvincorelen = xd->len - oldvincorelen;
3057 data_addid(newincore, oldvincorelen);
3062 repodata_internalize(Repodata *data)
3064 Repokey *key, solvkey;
3066 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
3067 unsigned char *dp, *ndp;
3068 int newschema, oldcount;
3069 struct extdata newincore;
3070 struct extdata newvincore;
3073 if (!data->attrs && !data->xattrs)
3076 newvincore.buf = data->vincore;
3077 newvincore.len = data->vincorelen;
3079 /* find the solvables key, create if needed */
3080 memset(&solvkey, 0, sizeof(solvkey));
3081 solvkey.name = REPOSITORY_SOLVABLES;
3082 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3084 solvkey.storage = KEY_STORAGE_INCORE;
3085 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3087 schema = solv_malloc2(data->nkeys, sizeof(Id));
3088 seen = solv_malloc2(data->nkeys, sizeof(Id));
3090 /* Merge the data already existing (in data->schemata, ->incoredata and
3091 friends) with the new attributes in data->attrs[]. */
3092 nentry = data->end - data->start;
3093 memset(&newincore, 0, sizeof(newincore));
3094 data_addid(&newincore, 0); /* start data at offset 1 */
3096 data->mainschema = 0;
3097 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3099 /* join entry data */
3100 /* we start with the meta data, entry -1 */
3101 for (entry = -1; entry < nentry; entry++)
3103 memset(seen, 0, data->nkeys * sizeof(Id));
3105 dp = data->incoredata;
3108 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3109 dp = data_read_id(dp, &oldschema);
3112 fprintf(stderr, "oldschema %d\n", oldschema);
3113 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3114 fprintf(stderr, "schemadata %p\n", data->schemadata);
3116 /* seen: -1: old data 0: skipped >0: id + 1 */
3120 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3124 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3132 keyp = data->attrs ? data->attrs[entry] : 0;
3135 /* strip solvables key */
3137 for (sp = keyp = schema; *sp; sp++)
3138 if (*sp != solvkeyid)
3143 seen[solvkeyid] = 0;
3144 keyp = data->xattrs ? data->xattrs[1] : 0;
3147 for (; *keyp; keyp += 2)
3154 seen[*keyp] = keyp[1] + 1;
3156 if (entry < 0 && data->end != data->start)
3163 /* Ideally we'd like to sort the new schema here, to ensure
3164 schema equality independend of the ordering. We can't do that
3165 yet. For once see below (old ids need to come before new ids).
3166 An additional difficulty is that we also need to move
3167 the values with the keys. */
3168 schemaid = repodata_schema2id(data, schema, 1);
3170 schemaid = oldschema;
3173 /* Now create data blob. We walk through the (possibly new) schema
3174 and either copy over old data, or insert the new. */
3175 /* XXX Here we rely on the fact that the (new) schema has the form
3176 o1 o2 o3 o4 ... | n1 n2 n3 ...
3177 (oX being the old keyids (possibly overwritten), and nX being
3178 the new keyids). This rules out sorting the keyids in order
3179 to ensure a small schema count. */
3181 data->incoreoffset[entry] = newincore.len;
3182 data_addid(&newincore, schemaid);
3185 data->mainschema = schemaid;
3186 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3188 keypstart = data->schemadata + data->schemata[schemaid];
3189 for (keyp = keypstart; *keyp; keyp++)
3192 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3193 if (*keyp == solvkeyid)
3195 /* add flexarray entry count */
3196 data_addid(&newincore, data->end - data->start);
3199 key = data->keys + *keyp;
3201 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));
3206 /* Skip the data associated with this old key. */
3207 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3209 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3210 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3212 else if (key->storage == KEY_STORAGE_INCORE)
3213 ndp = data_skip_key(data, dp, key);
3216 if (seen[*keyp] == -1)
3218 /* If this key was an old one _and_ was not overwritten with
3219 a different value copy over the old value (we skipped it
3222 data_addblob(&newincore, dp, ndp - dp);
3225 else if (seen[*keyp])
3227 /* Otherwise we have a new value. Parse it into the internal
3229 repodata_serialize_key(data, &newincore, &newvincore,
3230 schema, key, seen[*keyp] - 1);
3234 if (entry >= 0 && data->attrs && data->attrs[entry])
3235 data->attrs[entry] = solv_free(data->attrs[entry]);
3237 /* free all xattrs */
3238 for (entry = 0; entry < data->nxattrs; entry++)
3239 if (data->xattrs[entry])
3240 solv_free(data->xattrs[entry]);
3241 data->xattrs = solv_free(data->xattrs);
3244 data->lasthandle = 0;
3246 data->lastdatalen = 0;
3249 repodata_free_schemahash(data);
3251 solv_free(data->incoredata);
3252 data->incoredata = newincore.buf;
3253 data->incoredatalen = newincore.len;
3254 data->incoredatafree = 0;
3256 solv_free(data->vincore);
3257 data->vincore = newvincore.buf;
3258 data->vincorelen = newvincore.len;
3260 data->attrs = solv_free(data->attrs);
3261 data->attrdata = solv_free(data->attrdata);
3262 data->attriddata = solv_free(data->attriddata);
3263 data->attrnum64data = solv_free(data->attrnum64data);
3264 data->attrdatalen = 0;
3265 data->attriddatalen = 0;
3266 data->attrnum64datalen = 0;
3270 repodata_disable_paging(Repodata *data)
3272 if (maybe_load_repodata(data, 0))
3274 repopagestore_disable_paging(&data->store);
3280 repodata_load_stub(Repodata *data)
3282 Repo *repo = data->repo;
3283 Pool *pool = repo->pool;
3285 struct _Pool_tmpspace oldtmpspace;
3288 if (!pool->loadcallback)
3290 data->state = REPODATA_ERROR;
3293 data->state = REPODATA_LOADING;
3295 /* save tmp space and pos */
3296 oldtmpspace = pool->tmpspace;
3297 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3300 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3302 /* restore tmp space and pos */
3303 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3304 solv_free(pool->tmpspace.buf[i]);
3305 pool->tmpspace = oldtmpspace;
3306 if (r && oldpos.repo == repo && oldpos.repodataid == data->repodataid)
3307 memset(&oldpos, 0, sizeof(oldpos));
3310 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3314 repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
3318 xkey.name = keyname;
3319 xkey.type = keytype;
3320 xkey.storage = KEY_STORAGE_INCORE;
3322 repodata_key2id(data, &xkey, 1);
3326 repodata_add_stub(Repodata **datap)
3328 Repodata *data = *datap;
3329 Repo *repo = data->repo;
3330 Id repodataid = data - repo->repodata;
3331 Repodata *sdata = repo_add_repodata(repo, 0);
3332 data = repo->repodata + repodataid;
3333 if (data->end > data->start)
3334 repodata_extend_block(sdata, data->start, data->end - data->start);
3335 sdata->state = REPODATA_STUB;
3336 sdata->loadcallback = repodata_load_stub;
3342 repodata_create_stubs(Repodata *data)
3344 Repo *repo = data->repo;
3345 Pool *pool = repo->pool;
3352 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3353 while (dataiterator_step(&di))
3354 if (di.data == data)
3356 dataiterator_free(&di);
3359 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3360 for (i = 0; i < cnt; i++)
3362 sdata = repodata_add_stub(&data);
3363 stubdataids[i] = sdata - repo->repodata;
3366 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3368 while (dataiterator_step(&di))
3370 if (di.data != data)
3372 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3374 dataiterator_entersub(&di);
3375 sdata = repo->repodata + stubdataids[i++];
3379 switch (di.key->type)
3381 case REPOKEY_TYPE_ID:
3382 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3384 case REPOKEY_TYPE_CONSTANTID:
3385 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3387 case REPOKEY_TYPE_STR:
3388 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3390 case REPOKEY_TYPE_VOID:
3391 repodata_set_void(sdata, SOLVID_META, di.key->name);
3393 case REPOKEY_TYPE_NUM:
3394 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3396 case REPOKEY_TYPE_MD5:
3397 case REPOKEY_TYPE_SHA1:
3398 case REPOKEY_TYPE_SHA256:
3399 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3401 case REPOKEY_TYPE_IDARRAY:
3402 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3403 if (di.key->name == REPOSITORY_KEYS)
3408 xkeyname = di.kv.id;
3412 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
3421 dataiterator_free(&di);
3422 for (i = 0; i < cnt; i++)
3423 repodata_internalize(repo->repodata + stubdataids[i]);
3424 solv_free(stubdataids);
3429 repodata_memused(Repodata *data)
3431 return data->incoredatalen + data->vincorelen;