2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
37 #define REPODATA_BLOCK 255
39 static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
42 repodata_initdata(Repodata *data, Repo *repo, int localpool)
44 memset(data, 0, sizeof (*data));
45 data->repodataid = data - repo->repodata;
47 data->localpool = localpool;
49 stringpool_init_empty(&data->spool);
50 /* dirpool_init(&data->dirpool); just zeros out again */
51 data->keys = solv_calloc(1, sizeof(Repokey));
53 data->schemata = solv_calloc(1, sizeof(Id));
54 data->schemadata = solv_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_freedata(Repodata *data)
65 solv_free(data->keys);
67 solv_free(data->schemata);
68 solv_free(data->schemadata);
69 solv_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 solv_free(data->mainschemaoffsets);
75 solv_free(data->incoredata);
76 solv_free(data->incoreoffset);
77 solv_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 solv_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 solv_free(data->attrs[i]);
86 solv_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 solv_free(data->xattrs[i]);
90 solv_free(data->xattrs);
92 solv_free(data->attrdata);
93 solv_free(data->attriddata);
94 solv_free(data->attrnum64data);
96 solv_free(data->dircache);
100 repodata_free(Repodata *data)
102 Repo *repo = data->repo;
103 int i = data - repo->repodata;
106 repodata_freedata(data);
107 if (i < repo->nrepodata - 1)
109 /* whoa! this changes the repodataids! */
110 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
111 for (; i < repo->nrepodata - 1; i++)
112 repo->repodata[i].repodataid = i;
115 if (repo->nrepodata == 1)
117 repo->repodata = solv_free(repo->repodata);
123 repodata_empty(Repodata *data, int localpool)
125 void (*loadcallback)(Repodata *) = data->loadcallback;
126 int state = data->state;
127 repodata_freedata(data);
128 repodata_initdata(data, data->repo, localpool);
130 data->loadcallback = loadcallback;
134 /***************************************************************
135 * key pool management
138 /* this is not so time critical that we need a hash, so we do a simple
141 repodata_key2id(Repodata *data, Repokey *key, int create)
145 for (keyid = 1; keyid < data->nkeys; keyid++)
146 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
148 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
152 if (keyid == data->nkeys)
156 /* allocate new key */
157 data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
158 data->keys[data->nkeys++] = *key;
159 if (data->verticaloffset)
161 data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
162 data->verticaloffset[data->nkeys - 1] = 0;
164 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
170 /***************************************************************
171 * schema pool management
174 #define SCHEMATA_BLOCK 31
175 #define SCHEMATADATA_BLOCK 255
178 repodata_schema2id(Repodata *data, Id *schema, int create)
185 return 0; /* XXX: allow empty schema? */
186 if ((schematahash = data->schematahash) == 0)
188 data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
189 for (i = 1; i < data->nschemata; i++)
191 for (sp = data->schemadata + data->schemata[i], h = 0; *sp; len++)
196 data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
197 data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
200 for (sp = schema, len = 0, h = 0; *sp; len++)
205 cid = schematahash[h];
208 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
210 /* cache conflict, do a slow search */
211 for (cid = 1; cid < data->nschemata; cid++)
212 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
218 data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
219 data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
221 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
222 data->schemata[data->nschemata] = data->schemadatalen;
223 data->schemadatalen += len;
224 schematahash[h] = data->nschemata;
226 fprintf(stderr, "schema2id: new schema\n");
228 return data->nschemata++;
232 repodata_free_schemahash(Repodata *data)
234 data->schematahash = solv_free(data->schematahash);
236 data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
237 data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
241 /***************************************************************
242 * dir pool management
245 #ifndef HAVE_STRCHRNUL
246 static inline const char *strchrnul(const char *str, char x)
248 const char *p = strchr(str, x);
249 return p ? p : str + strlen(str);
253 #define DIRCACHE_SIZE 41 /* < 1k */
257 Id ids[DIRCACHE_SIZE];
258 char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
263 repodata_str2dir(Repodata *data, const char *dir, int create)
274 while (*dir == '/' && dir[1] == '/')
276 if (*dir == '/' && !dir[1])
278 if (data->dirpool.ndirs)
280 return dirpool_add_dir(&data->dirpool, 0, 1, create);
287 struct dircache *dircache = data->dircache;
291 if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
293 parent = dircache->ids[l];
309 dire = strchrnul(dir, '/');
311 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
313 id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
316 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
321 data->dircache = solv_calloc(1, sizeof(struct dircache));
325 if (l < DIRCACHE_SIZE)
327 data->dircache->ids[l] = parent;
328 memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
342 repodata_free_dircache(Repodata *data)
344 data->dircache = solv_free(data->dircache);
348 repodata_dir2str(Repodata *data, Id did, const char *suf)
350 Pool *pool = data->repo->pool;
357 return suf ? suf : "";
361 comp = dirpool_compid(&data->dirpool, parent);
362 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
364 parent = dirpool_parent(&data->dirpool, parent);
369 l += strlen(suf) + 1;
370 p = pool_alloctmpspace(pool, l + 1) + l;
381 comp = dirpool_compid(&data->dirpool, parent);
382 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
385 strncpy(p, comps, l);
386 parent = dirpool_parent(&data->dirpool, parent);
394 /***************************************************************
398 static inline unsigned char *
399 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
401 Id *keyp = data->schemadata + data->schemata[schema];
402 for (; *keyp; keyp++)
403 dp = data_skip_key(data, dp, data->keys + *keyp);
407 static unsigned char *
408 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
410 int nentries, schema;
413 case REPOKEY_TYPE_FIXARRAY:
414 dp = data_read_id(dp, &nentries);
417 dp = data_read_id(dp, &schema);
419 dp = data_skip_schema(data, dp, schema);
421 case REPOKEY_TYPE_FLEXARRAY:
422 dp = data_read_id(dp, &nentries);
425 dp = data_read_id(dp, &schema);
426 dp = data_skip_schema(data, dp, schema);
430 if (key->storage == KEY_STORAGE_INCORE)
431 dp = data_skip(dp, key->type);
432 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
434 dp = data_skip(dp, REPOKEY_TYPE_ID);
435 dp = data_skip(dp, REPOKEY_TYPE_ID);
441 static unsigned char *
442 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
448 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
451 for (i = 0; (k = *keyp++) != 0; i++)
453 return data->incoredata + data->mainschemaoffsets[i];
456 while ((k = *keyp++) != 0)
460 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
462 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
463 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
466 if (data->keys[k].storage != KEY_STORAGE_INCORE)
468 dp = data_skip_key(data, dp, data->keys + k);
473 static unsigned char *
474 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
479 if (off >= data->lastverticaloffset)
481 off -= data->lastverticaloffset;
482 if (off + len > data->vincorelen)
484 return data->vincore + off;
486 if (off + len > key->size)
488 /* we now have the offset, go into vertical */
489 off += data->verticaloffset[key - data->keys];
490 /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
491 dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
493 dp += off % REPOPAGE_BLOBSIZE;
497 static inline unsigned char *
498 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
500 unsigned char *dp = *dpp;
504 if (key->storage == KEY_STORAGE_INCORE)
507 *dpp = data_skip_key(data, dp, key);
510 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
513 dp = data_read_id(dp, &off);
514 dp = data_read_id(dp, &len);
517 return get_vertical_data(data, key, off, len);
523 load_repodata(Repodata *data)
525 if (data->loadcallback)
527 data->loadcallback(data);
528 if (data->state == REPODATA_AVAILABLE)
531 data->state = REPODATA_ERROR;
536 maybe_load_repodata(Repodata *data, Id keyname)
538 if (keyname && !repodata_precheck_keyname(data, keyname))
539 return 0; /* do not bother... */
546 for (i = 1; i < data->nkeys; i++)
547 if (keyname == data->keys[i].name)
549 if (i == data->nkeys)
552 return load_repodata(data);
555 case REPODATA_AVAILABLE:
556 case REPODATA_LOADING:
559 data->state = REPODATA_ERROR;
564 static inline unsigned char *
565 solvid2data(Repodata *data, Id solvid, Id *schemap)
567 unsigned char *dp = data->incoredata;
570 if (solvid == SOLVID_META) /* META */
572 else if (solvid == SOLVID_POS) /* META */
574 Pool *pool = data->repo->pool;
575 if (data->repo != pool->pos.repo)
577 if (data != data->repo->repodata + pool->pos.repodataid)
579 *schemap = pool->pos.schema;
580 return data->incoredata + pool->pos.dp;
584 if (solvid < data->start || solvid >= data->end)
586 dp += data->incoreoffset[solvid - data->start];
588 return data_read_id(dp, schemap);
591 /************************************************************************
595 static inline unsigned char *
596 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
599 Id schema, *keyp, *kp;
602 if (!maybe_load_repodata(data, keyname))
604 dp = solvid2data(data, solvid, &schema);
607 keyp = data->schemadata + data->schemata[schema];
608 for (kp = keyp; *kp; kp++)
609 if (data->keys[*kp].name == keyname)
613 *keypp = key = data->keys + *kp;
614 if (key->type == REPOKEY_TYPE_DELETED)
616 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
617 return dp; /* no need to forward... */
618 dp = forward_to_key(data, *kp, keyp, dp);
621 return get_data(data, key, &dp, 0);
625 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
627 Id schema, *keyp, *kp;
628 if (!maybe_load_repodata(data, keyname))
630 if (!solvid2data(data, solvid, &schema))
632 keyp = data->schemadata + data->schemata[schema];
633 for (kp = keyp; *kp; kp++)
634 if (data->keys[*kp].name == keyname)
635 return data->keys[*kp].type;
640 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
646 dp = find_key_data(data, solvid, keyname, &key);
649 if (key->type == REPOKEY_TYPE_CONSTANTID)
651 if (key->type != REPOKEY_TYPE_ID)
653 dp = data_read_id(dp, &id);
658 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
664 dp = find_key_data(data, solvid, keyname, &key);
667 if (key->type == REPOKEY_TYPE_STR)
668 return (const char *)dp;
669 if (key->type == REPOKEY_TYPE_CONSTANTID)
671 else if (key->type == REPOKEY_TYPE_ID)
672 dp = data_read_id(dp, &id);
676 return stringpool_id2str(&data->spool, id);
677 return pool_id2str(data->repo->pool, id);
681 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
685 unsigned int high, low;
688 dp = find_key_data(data, solvid, keyname, &key);
693 case REPOKEY_TYPE_NUM:
694 data_read_num64(dp, &low, &high);
695 *value = (unsigned long long)high << 32 | low;
697 case REPOKEY_TYPE_U32:
698 data_read_u32(dp, &low);
701 case REPOKEY_TYPE_CONSTANT:
710 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
716 if (!maybe_load_repodata(data, keyname))
718 dp = solvid2data(data, solvid, &schema);
721 /* can't use find_key_data as we need to test the type */
722 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
723 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
728 const unsigned char *
729 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
734 dp = find_key_data(data, solvid, keyname, &key);
737 if (!(key->type == REPOKEY_TYPE_MD5 || key->type == REPOKEY_TYPE_SHA1 || key->type == REPOKEY_TYPE_SHA256))
744 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
752 dp = find_key_data(data, solvid, keyname, &key);
755 if (key->type != REPOKEY_TYPE_IDARRAY && key->type != REPOKEY_TYPE_REL_IDARRAY)
759 dp = data_read_ideof(dp, &id, &eof);
768 repodata_globalize_id(Repodata *data, Id id, int create)
770 if (!id || !data || !data->localpool)
772 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
776 repodata_localize_id(Repodata *data, Id id, int create)
778 if (!id || !data || !data->localpool)
780 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
784 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
789 ap = data->attrs[solvid - data->start];
794 if (data->keys[*ap].name != keyname)
796 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
798 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
806 /************************************************************************
812 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
816 case REPOKEY_TYPE_ID:
817 case REPOKEY_TYPE_CONSTANTID:
818 case REPOKEY_TYPE_IDARRAY:
819 if (data && data->localpool)
820 kv->str = stringpool_id2str(&data->spool, kv->id);
822 kv->str = pool_id2str(pool, kv->id);
823 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
826 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
828 if (*s == ':' && s > kv->str)
832 case REPOKEY_TYPE_STR:
834 case REPOKEY_TYPE_DIRSTRARRAY:
835 if (!(flags & SEARCH_FILES))
836 return 1; /* match just the basename */
837 /* Put the full filename into kv->str. */
838 kv->str = repodata_dir2str(data, kv->id, kv->str);
839 /* And to compensate for that put the "empty" directory into
840 kv->id, so that later calls to repodata_dir2str on this data
841 come up with the same filename again. */
844 case REPOKEY_TYPE_MD5:
845 case REPOKEY_TYPE_SHA1:
846 case REPOKEY_TYPE_SHA256:
847 if (!(flags & SEARCH_CHECKSUMS))
848 return 0; /* skip em */
849 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
857 struct subschema_data {
863 /* search a specific repodata */
865 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
869 Id keyid, *kp, *keyp;
870 unsigned char *dp, *ddp;
876 if (!maybe_load_repodata(data, keyname))
878 if (solvid == SOLVID_SUBSCHEMA)
880 struct subschema_data *subd = cbdata;
881 cbdata = subd->cbdata;
883 schema = subd->parent->id;
884 dp = (unsigned char *)subd->parent->str;
885 kv.parent = subd->parent;
890 dp = solvid2data(data, solvid, &schema);
893 s = data->repo->pool->solvables + solvid;
896 keyp = data->schemadata + data->schemata[schema];
899 /* search for a specific key */
900 for (kp = keyp; *kp; kp++)
901 if (data->keys[*kp].name == keyname)
905 dp = forward_to_key(data, *kp, keyp, dp);
911 while ((keyid = *keyp++) != 0)
914 key = data->keys + keyid;
915 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
917 if (key->type == REPOKEY_TYPE_DELETED)
919 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
921 struct subschema_data subd;
925 subd.cbdata = cbdata;
928 ddp = data_read_id(ddp, &nentries);
932 while (ddp && nentries > 0)
936 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
937 ddp = data_read_id(ddp, &schema);
939 kv.str = (char *)ddp;
940 stop = callback(cbdata, s, data, key, &kv);
941 if (stop > SEARCH_NEXT_KEY)
943 if (stop && stop != SEARCH_ENTERSUB)
945 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
946 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
947 ddp = data_skip_schema(data, ddp, schema);
950 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
954 kv.str = (char *)ddp;
955 stop = callback(cbdata, s, data, key, &kv);
956 if (stop > SEARCH_NEXT_KEY)
966 ddp = data_fetch(ddp, &kv, key);
969 stop = callback(cbdata, s, data, key, &kv);
972 while (!kv.eof && !stop);
973 if (onekey || stop > SEARCH_NEXT_KEY)
979 repodata_setpos_kv(Repodata *data, KeyValue *kv)
981 Pool *pool = data->repo->pool;
983 pool_clear_pos(pool);
986 pool->pos.repo = data->repo;
987 pool->pos.repodataid = data - data->repo->repodata;
988 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
989 pool->pos.schema = kv->id;
993 /************************************************************************
994 * data iterator functions
998 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1012 case SOLVABLE_VENDOR:
1015 case SOLVABLE_PROVIDES:
1017 return s->provides ? s->repo->idarraydata + s->provides : 0;
1018 case SOLVABLE_OBSOLETES:
1020 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1021 case SOLVABLE_CONFLICTS:
1023 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1024 case SOLVABLE_REQUIRES:
1026 return s->requires ? s->repo->idarraydata + s->requires : 0;
1027 case SOLVABLE_RECOMMENDS:
1029 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1030 case SOLVABLE_SUPPLEMENTS:
1032 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1033 case SOLVABLE_SUGGESTS:
1035 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1036 case SOLVABLE_ENHANCES:
1038 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1041 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1048 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1054 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1056 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1057 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1060 solv_free(ma->matchdata);
1061 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1064 if ((flags & SEARCH_FILES) != 0 && match)
1066 /* prepare basename check */
1067 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING)
1069 const char *p = strrchr(match, '/');
1070 ma->matchdata = (void *)(p ? p + 1 : match);
1072 else if ((flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1074 const char *p = strrchr(match, '/');
1075 ma->matchdata = (void *)(p ? p + 1 : 0);
1077 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1080 for (p = match + strlen(match) - 1; p >= match; p--)
1081 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1083 ma->matchdata = (void *)(p + 1);
1090 datamatcher_free(Datamatcher *ma)
1092 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1094 regfree(ma->matchdata);
1095 solv_free(ma->matchdata);
1101 datamatcher_match(Datamatcher *ma, const char *str)
1104 switch ((ma->flags & SEARCH_STRINGMASK))
1106 case SEARCH_SUBSTRING:
1107 if (ma->flags & SEARCH_NOCASE)
1109 if (!strcasestr(str, ma->match))
1114 if (!strstr(str, ma->match))
1119 if (ma->flags & SEARCH_NOCASE)
1121 if (strcasecmp(ma->match, str))
1126 if (strcmp(ma->match, str))
1130 case SEARCH_STRINGSTART:
1131 if (ma->flags & SEARCH_NOCASE)
1133 if (strncasecmp(ma->match, str, strlen(ma->match)))
1138 if (strncmp(ma->match, str, strlen(ma->match)))
1142 case SEARCH_STRINGEND:
1143 l = strlen(str) - strlen(ma->match);
1146 if (ma->flags & SEARCH_NOCASE)
1148 if (strcasecmp(ma->match, str + l))
1153 if (strcmp(ma->match, str + l))
1158 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1162 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
1171 /* check if the matcher can match the provides basename */
1174 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1177 const char *match = ma->match;
1178 switch (ma->flags & SEARCH_STRINGMASK)
1181 match = ma->matchdata;
1183 case SEARCH_STRINGEND:
1186 match = ma->matchdata; /* have slash */
1189 l = strlen(basename) - strlen(match);
1195 match = ma->matchdata;
1198 l = strlen(basename) - strlen(match);
1204 return 1; /* maybe matches */
1208 if ((ma->flags & SEARCH_NOCASE) != 0)
1209 return !strcasecmp(match, basename);
1211 return !strcmp(match, basename);
1215 repodata_filelistfilter_matches(Repodata *data, const char *str)
1217 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1218 /* for now hardcoded */
1219 if (strstr(str, "bin/"))
1221 if (!strncmp(str, "/etc/", 5))
1223 if (!strcmp(str, "/usr/lib/sendmail"))
1245 di_nextarrayelement,
1251 di_entersolvablekey,
1255 /* see dataiterator.h for documentation */
1257 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1259 memset(di, 0, sizeof(*di));
1261 di->flags = flags & ~SEARCH_THISSOLVID;
1262 if (!pool || (repo && repo->pool != pool))
1270 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1276 di->keyname = keyname;
1277 di->keynames[0] = keyname;
1278 dataiterator_set_search(di, repo, p);
1283 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1286 memset(&di->matcher, 0, sizeof(di->matcher));
1287 if (from->matcher.match)
1288 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1293 for (i = 1; i < di->nparents; i++)
1294 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1295 di->kv.parent = &di->parents[di->nparents - 1].kv;
1300 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1302 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1303 datamatcher_free(&di->matcher);
1304 memset(&di->matcher, 0, sizeof(di->matcher));
1308 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1318 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1322 di->flags &= ~SEARCH_THISSOLVID;
1326 if (!di->pool->urepos)
1334 di->repo = di->pool->repos[di->repoid];
1336 di->state = di_enterrepo;
1338 dataiterator_jump_to_solvid(di, p);
1342 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1345 di->keyname = keyname;
1346 di->keynames[0] = keyname;
1350 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1354 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1356 di->state = di_bye; /* sorry */
1359 for (i = di->nkeynames + 1; i > 0; i--)
1360 di->keynames[i] = di->keynames[i - 1];
1361 di->keynames[0] = di->keyname = keyname;
1366 dataiterator_free(Dataiterator *di)
1368 if (di->matcher.match)
1369 datamatcher_free(&di->matcher);
1372 static inline unsigned char *
1373 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1375 Id *keyp = di->keyp;
1376 Repokey *keys = di->data->keys;
1379 for (keyp = di->keyp; *keyp; keyp++)
1380 if (keys[*keyp].name == keyname)
1384 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1392 dataiterator_filelistcheck(Dataiterator *di)
1395 int needcomplete = 0;
1396 Repodata *data = di->data;
1398 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1399 if (!di->matcher.match
1400 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1401 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1402 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1404 if (data->state != REPODATA_AVAILABLE)
1405 return needcomplete ? 1 : 0;
1406 for (j = 1; j < data->nkeys; j++)
1407 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1409 return j == data->nkeys && !needcomplete ? 0 : 1;
1413 dataiterator_step(Dataiterator *di)
1421 case di_enterrepo: di_enterrepo:
1422 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1424 if (!(di->flags & SEARCH_THISSOLVID))
1426 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1427 goto di_nextsolvable;
1431 case di_entersolvable: di_entersolvable:
1434 di->repodataid = 1; /* reset repodata iterator */
1435 if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
1437 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1439 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1441 goto di_entersolvablekey;
1446 case di_enterrepodata: di_enterrepodata:
1449 if (di->repodataid >= di->repo->nrepodata)
1450 goto di_nextsolvable;
1451 di->data = di->repo->repodata + di->repodataid;
1453 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1454 goto di_nextrepodata;
1455 if (!maybe_load_repodata(di->data, di->keyname))
1456 goto di_nextrepodata;
1457 di->dp = solvid2data(di->data, di->solvid, &schema);
1459 goto di_nextrepodata;
1460 if (di->solvid == SOLVID_POS)
1461 di->solvid = di->pool->pos.solvid;
1462 /* reset key iterator */
1463 di->keyp = di->data->schemadata + di->data->schemata[schema];
1466 case di_enterschema: di_enterschema:
1468 di->dp = dataiterator_find_keyname(di, di->keyname);
1469 if (!di->dp || !*di->keyp)
1473 goto di_nextrepodata;
1477 case di_enterkey: di_enterkey:
1479 di->key = di->data->keys + *di->keyp;
1480 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1483 if (di->key->type == REPOKEY_TYPE_DELETED)
1485 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1487 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1493 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1495 di->state = di_nextkey;
1497 di->state = di_nextattr;
1500 case di_nextkey: di_nextkey:
1501 if (!di->keyname && *++di->keyp)
1507 case di_nextrepodata: di_nextrepodata:
1508 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1509 goto di_enterrepodata;
1512 case di_nextsolvable: di_nextsolvable:
1513 if (!(di->flags & SEARCH_THISSOLVID))
1516 di->solvid = di->repo->start;
1519 for (; di->solvid < di->repo->end; di->solvid++)
1521 if (di->pool->solvables[di->solvid].repo == di->repo)
1522 goto di_entersolvable;
1527 case di_nextrepo: di_nextrepo:
1532 if (di->repoid < di->pool->nrepos)
1534 di->repo = di->pool->repos[di->repoid];
1540 case di_bye: di_bye:
1544 case di_enterarray: di_enterarray:
1545 if (di->key->name == REPOSITORY_SOLVABLES)
1547 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1552 case di_nextarrayelement: di_nextarrayelement:
1555 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1556 if (di->kv.entry == di->kv.num)
1558 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1560 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1562 di->kv.str = (char *)di->ddp;
1564 di->state = di_nextkey;
1567 if (di->kv.entry == di->kv.num - 1)
1569 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1570 di->ddp = data_read_id(di->ddp, &di->kv.id);
1571 di->kv.str = (char *)di->ddp;
1572 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1574 if ((di->flags & SEARCH_SUB) != 0)
1575 di->state = di_entersub;
1577 di->state = di_nextarrayelement;
1580 case di_entersub: di_entersub:
1581 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1582 goto di_nextarrayelement; /* sorry, full */
1583 di->parents[di->nparents].kv = di->kv;
1584 di->parents[di->nparents].dp = di->dp;
1585 di->parents[di->nparents].keyp = di->keyp;
1586 di->dp = (unsigned char *)di->kv.str;
1587 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1588 memset(&di->kv, 0, sizeof(di->kv));
1589 di->kv.parent = &di->parents[di->nparents].kv;
1591 di->keyname = di->keynames[di->nparents - di->rootlevel];
1592 goto di_enterschema;
1594 case di_leavesub: di_leavesub:
1595 if (di->nparents - 1 < di->rootlevel)
1598 di->dp = di->parents[di->nparents].dp;
1599 di->kv = di->parents[di->nparents].kv;
1600 di->keyp = di->parents[di->nparents].keyp;
1601 di->key = di->data->keys + *di->keyp;
1602 di->ddp = (unsigned char *)di->kv.str;
1603 di->keyname = di->keynames[di->nparents - di->rootlevel];
1604 goto di_nextarrayelement;
1606 /* special solvable attr handling follows */
1608 case di_nextsolvablekey: di_nextsolvablekey:
1609 if (di->keyname || di->key->name == RPM_RPMDBID)
1610 goto di_enterrepodata;
1614 case di_entersolvablekey: di_entersolvablekey:
1615 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1616 if (!di->idp || !*di->idp)
1617 goto di_nextsolvablekey;
1621 di->kv.id = *di->idp;
1622 di->kv.num = *di->idp; /* for rpmdbid */
1623 di->kv.num2 = 0; /* for rpmdbid */
1625 di->state = di_nextsolvablekey;
1631 case di_nextsolvableattr:
1632 di->state = di_nextsolvableattr;
1633 di->kv.id = *di->idp++;
1638 di->state = di_nextsolvablekey;
1644 if (di->matcher.match)
1646 /* simple pre-check so that we don't need to stringify */
1647 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1648 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1650 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1652 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1656 if (!datamatcher_match(&di->matcher, di->kv.str))
1661 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1662 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1664 /* found something! */
1670 dataiterator_entersub(Dataiterator *di)
1672 if (di->state == di_nextarrayelement)
1673 di->state = di_entersub;
1677 dataiterator_setpos(Dataiterator *di)
1679 if (di->kv.eof == 2)
1681 pool_clear_pos(di->pool);
1684 di->pool->pos.solvid = di->solvid;
1685 di->pool->pos.repo = di->repo;
1686 di->pool->pos.repodataid = di->data - di->repo->repodata;
1687 di->pool->pos.schema = di->kv.id;
1688 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1692 dataiterator_setpos_parent(Dataiterator *di)
1694 if (!di->kv.parent || di->kv.parent->eof == 2)
1696 pool_clear_pos(di->pool);
1699 di->pool->pos.solvid = di->solvid;
1700 di->pool->pos.repo = di->repo;
1701 di->pool->pos.repodataid = di->data - di->repo->repodata;
1702 di->pool->pos.schema = di->kv.parent->id;
1703 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1706 /* clones just the position, not the search keys/matcher */
1708 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1710 di->state = from->state;
1711 di->flags &= ~SEARCH_THISSOLVID;
1712 di->flags |= (from->flags & SEARCH_THISSOLVID);
1713 di->repo = from->repo;
1714 di->data = from->data;
1716 di->ddp = from->ddp;
1717 di->idp = from->idp;
1718 di->keyp = from->keyp;
1719 di->key = from->key;
1721 di->repodataid = from->repodataid;
1722 di->solvid = from->solvid;
1723 di->repoid = from->repoid;
1724 di->rootlevel = from->rootlevel;
1725 memcpy(di->parents, from->parents, sizeof(from->parents));
1726 di->nparents = from->nparents;
1730 for (i = 1; i < di->nparents; i++)
1731 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1732 di->kv.parent = &di->parents[di->nparents - 1].kv;
1737 dataiterator_seek(Dataiterator *di, int whence)
1739 if ((whence & DI_SEEK_STAY) != 0)
1740 di->rootlevel = di->nparents;
1741 switch (whence & ~DI_SEEK_STAY)
1744 if (di->state != di_nextarrayelement)
1746 if ((whence & DI_SEEK_STAY) != 0)
1747 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1748 di->state = di_entersub;
1750 case DI_SEEK_PARENT:
1757 if (di->rootlevel > di->nparents)
1758 di->rootlevel = di->nparents;
1759 di->dp = di->parents[di->nparents].dp;
1760 di->kv = di->parents[di->nparents].kv;
1761 di->keyp = di->parents[di->nparents].keyp;
1762 di->key = di->data->keys + *di->keyp;
1763 di->ddp = (unsigned char *)di->kv.str;
1764 di->keyname = di->keynames[di->nparents - di->rootlevel];
1765 di->state = di_nextarrayelement;
1767 case DI_SEEK_REWIND:
1773 di->dp = (unsigned char *)di->kv.parent->str;
1774 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1775 di->state = di_enterschema;
1783 dataiterator_skip_attribute(Dataiterator *di)
1785 if (di->state == di_nextsolvableattr)
1786 di->state = di_nextsolvablekey;
1788 di->state = di_nextkey;
1792 dataiterator_skip_solvable(Dataiterator *di)
1797 di->keyname = di->keynames[0];
1798 di->state = di_nextsolvable;
1802 dataiterator_skip_repo(Dataiterator *di)
1807 di->keyname = di->keynames[0];
1808 di->state = di_nextrepo;
1812 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1817 di->keyname = di->keynames[0];
1818 if (solvid == SOLVID_POS)
1820 di->repo = di->pool->pos.repo;
1827 di->data = di->repo->repodata + di->pool->pos.repodataid;
1829 di->solvid = solvid;
1830 di->state = di_enterrepo;
1831 di->flags |= SEARCH_THISSOLVID;
1836 di->repo = di->pool->solvables[solvid].repo;
1839 else if (di->repoid > 0)
1841 if (!di->pool->urepos)
1847 di->repo = di->pool->repos[di->repoid];
1850 di->solvid = solvid;
1852 di->flags |= SEARCH_THISSOLVID;
1853 di->state = di_enterrepo;
1857 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1863 di->repoid = 0; /* 0 means stay at repo */
1866 di->flags &= ~SEARCH_THISSOLVID;
1867 di->state = di_enterrepo;
1871 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1873 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1877 return datamatcher_match(ma, di->kv.str);
1880 /************************************************************************
1881 * data modify functions
1884 /* extend repodata so that it includes solvables p */
1886 repodata_extend(Repodata *data, Id p)
1888 if (data->start == data->end)
1889 data->start = data->end = p;
1892 int old = data->end - data->start;
1893 int new = p - data->end + 1;
1896 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1897 memset(data->attrs + old, 0, new * sizeof(Id *));
1899 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1900 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1903 if (p < data->start)
1905 int old = data->end - data->start;
1906 int new = data->start - p;
1909 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1910 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1911 memset(data->attrs, 0, new * sizeof(Id *));
1913 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1914 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1915 memset(data->incoreoffset, 0, new * sizeof(Id));
1920 /* shrink end of repodata */
1922 repodata_shrink(Repodata *data, int end)
1926 if (data->end <= end)
1928 if (data->start >= end)
1932 for (i = 0; i < data->end - data->start; i++)
1933 solv_free(data->attrs[i]);
1934 data->attrs = solv_free(data->attrs);
1936 data->incoreoffset = solv_free(data->incoreoffset);
1937 data->start = data->end = 0;
1942 for (i = end; i < data->end; i++)
1943 solv_free(data->attrs[i - data->start]);
1944 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1946 if (data->incoreoffset)
1947 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1951 /* extend repodata so that it includes solvables from start to start + num - 1 */
1953 repodata_extend_block(Repodata *data, Id start, Id num)
1957 if (!data->incoreoffset)
1959 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1960 data->start = start;
1961 data->end = start + num;
1964 repodata_extend(data, start);
1966 repodata_extend(data, start + num - 1);
1969 /**********************************************************************/
1972 #define REPODATA_ATTRS_BLOCK 31
1973 #define REPODATA_ATTRDATA_BLOCK 1023
1974 #define REPODATA_ATTRIDDATA_BLOCK 63
1975 #define REPODATA_ATTRNUM64DATA_BLOCK 15
1979 repodata_new_handle(Repodata *data)
1983 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1984 data->nxattrs = 2; /* -1: SOLVID_META */
1986 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1987 data->xattrs[data->nxattrs] = 0;
1988 return -(data->nxattrs++);
1992 repodata_get_attrp(Repodata *data, Id handle)
1996 if (handle == SOLVID_META && !data->xattrs)
1998 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2001 return data->xattrs - handle;
2003 if (handle < data->start || handle >= data->end)
2004 repodata_extend(data, handle);
2006 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2007 return data->attrs + (handle - data->start);
2011 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2017 app = repodata_get_attrp(data, handle);
2022 /* Determine equality based on the name only, allows us to change
2023 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2024 for (pp = ap; *pp; pp += 2)
2025 if (data->keys[*pp].name == data->keys[keyid].name)
2029 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2038 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2048 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2052 keyid = repodata_key2id(data, key, 1);
2053 repodata_insert_keyid(data, solvid, keyid, val, 1);
2057 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2061 key.type = REPOKEY_TYPE_ID;
2063 key.storage = KEY_STORAGE_INCORE;
2064 repodata_set(data, solvid, &key, id);
2068 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2072 key.type = REPOKEY_TYPE_NUM;
2074 key.storage = KEY_STORAGE_INCORE;
2075 if (num >= 0x80000000)
2077 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2078 data->attrnum64data[data->attrnum64datalen] = num;
2079 num = 0x80000000 | data->attrnum64datalen++;
2081 repodata_set(data, solvid, &key, (Id)num);
2085 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2089 if (data->localpool)
2090 id = stringpool_str2id(&data->spool, str, 1);
2092 id = pool_str2id(data->repo->pool, str, 1);
2094 key.type = REPOKEY_TYPE_ID;
2096 key.storage = KEY_STORAGE_INCORE;
2097 repodata_set(data, solvid, &key, id);
2101 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2105 key.type = REPOKEY_TYPE_CONSTANT;
2106 key.size = constant;
2107 key.storage = KEY_STORAGE_INCORE;
2108 repodata_set(data, solvid, &key, 0);
2112 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2116 key.type = REPOKEY_TYPE_CONSTANTID;
2118 key.storage = KEY_STORAGE_INCORE;
2119 repodata_set(data, solvid, &key, 0);
2123 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2127 key.type = REPOKEY_TYPE_VOID;
2129 key.storage = KEY_STORAGE_INCORE;
2130 repodata_set(data, solvid, &key, 0);
2134 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2139 l = strlen(str) + 1;
2141 key.type = REPOKEY_TYPE_STR;
2143 key.storage = KEY_STORAGE_INCORE;
2144 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2145 memcpy(data->attrdata + data->attrdatalen, str, l);
2146 repodata_set(data, solvid, &key, data->attrdatalen);
2147 data->attrdatalen += l;
2151 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2159 key.type = REPOKEY_TYPE_BINARY;
2161 key.storage = KEY_STORAGE_INCORE;
2162 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2163 dp = data->attrdata + data->attrdatalen;
2164 if (len >= (1 << 14))
2166 if (len >= (1 << 28))
2167 *dp++ = (len >> 28) | 128;
2168 if (len >= (1 << 21))
2169 *dp++ = (len >> 21) | 128;
2170 *dp++ = (len >> 14) | 128;
2172 if (len >= (1 << 7))
2173 *dp++ = (len >> 7) | 128;
2176 memcpy(dp, buf, len);
2177 repodata_set(data, solvid, &key, data->attrdatalen);
2178 data->attrdatalen = dp + len - data->attrdata;
2181 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2182 * so that the caller can append entrysize new elements plus the termination zero there */
2184 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2187 Id *ida, *pp, **ppp;
2189 /* check if it is the same as last time, this speeds things up a lot */
2190 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2192 /* great! just append the new data */
2193 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2194 data->attriddatalen--; /* overwrite terminating 0 */
2195 data->lastdatalen += entrysize;
2199 ppp = repodata_get_attrp(data, handle);
2203 for (; *pp; pp += 2)
2204 if (data->keys[*pp].name == keyname)
2207 if (!pp || !*pp || data->keys[*pp].type != keytype)
2209 /* not found. allocate new key */
2215 key.storage = KEY_STORAGE_INCORE;
2216 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2217 keyid = repodata_key2id(data, &key, 1);
2218 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2219 data->lasthandle = handle;
2220 data->lastkey = keyid;
2221 data->lastdatalen = data->attriddatalen + entrysize + 1;
2225 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2226 oldsize += entrysize;
2227 if (ida + 1 == data->attriddata + data->attriddatalen)
2229 /* this was the last entry, just append it */
2230 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2231 data->attriddatalen--; /* overwrite terminating 0 */
2235 /* too bad. move to back. */
2236 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2237 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2238 pp[1] = data->attriddatalen;
2239 data->attriddatalen += oldsize;
2241 data->lasthandle = handle;
2242 data->lastkey = *pp;
2243 data->lastdatalen = data->attriddatalen + entrysize + 1;
2247 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2248 const unsigned char *str)
2253 if (!(l = solv_chksum_len(type)))
2258 key.storage = KEY_STORAGE_INCORE;
2259 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2260 memcpy(data->attrdata + data->attrdatalen, str, l);
2261 repodata_set(data, solvid, &key, data->attrdatalen);
2262 data->attrdatalen += l;
2266 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2269 unsigned char buf[64];
2272 if (!(l = solv_chksum_len(type)))
2274 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2276 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2280 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2284 if (!(l = solv_chksum_len(type)))
2286 return pool_bin2hex(data->repo->pool, buf, l);
2289 /* rpm filenames don't contain the epoch, so strip it */
2290 static inline const char *
2291 evrid2vrstr(Pool *pool, Id evrid)
2293 const char *p, *evr = pool_id2str(pool, evrid);
2296 for (p = evr; *p >= '0' && *p <= '9'; p++)
2298 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2302 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2305 if (data->localpool)
2306 id = stringpool_strn2id(&data->spool, str, l, 1);
2308 id = pool_strn2id(data->repo->pool, str, l, 1);
2309 repodata_set_id(data, solvid, keyname, id);
2313 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2316 repodata_set_str(data, solvid, keyname, str);
2319 char *s = solv_strdup(str);
2321 repodata_set_str(data, solvid, keyname, s);
2327 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2329 Pool *pool = data->repo->pool;
2331 const char *str, *fp;
2335 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2338 if ((dir = strrchr(file, '/')) != 0)
2349 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2354 if (l == 1 && dir[0] == '.')
2356 s = pool->solvables + solvid;
2359 str = pool_id2str(pool, s->arch);
2360 if (!strncmp(dir, str, l) && !str[l])
2361 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2363 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2366 str = pool_id2str(pool, s->name);
2368 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2371 str = evrid2vrstr(pool, s->evr);
2373 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2376 str = pool_id2str(pool, s->arch);
2378 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2380 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2385 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2388 /* XXX: medianr is currently not stored */
2390 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2393 const char *evr, *suf, *s;
2397 if ((dir = strrchr(file, '/')) != 0)
2408 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2413 if (l == 1 && dir[0] == '.')
2416 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2417 evr = strchr(file, '-');
2420 for (s = evr - 1; s > file; s--)
2427 suf = strrchr(file, '.');
2430 for (s = suf - 1; s > file; s--)
2436 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2438 /* We accept one more item as suffix. */
2439 for (s = suf - 1; s > file; s--)
2449 if (suf && evr && suf < evr)
2451 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2453 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2455 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2459 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2461 Pool *pool = data->repo->pool;
2462 Solvable *s = pool->solvables + solvid;
2463 const char *p, *sevr, *sarch, *name, *evr;
2465 p = strrchr(sourcepkg, '.');
2466 if (!p || strcmp(p, ".rpm") != 0)
2469 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2473 while (p > sourcepkg && *p != '.')
2475 if (*p != '.' || p == sourcepkg)
2478 while (p > sourcepkg && *p != '-')
2480 if (*p != '-' || p == sourcepkg)
2483 while (p > sourcepkg && *p != '-')
2485 if (*p != '-' || p == sourcepkg)
2488 pool = s->repo->pool;
2490 name = pool_id2str(pool, s->name);
2491 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2492 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2494 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2496 evr = evrid2vrstr(pool, s->evr);
2497 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2498 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2500 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2502 if (!strcmp(sarch, "src.rpm"))
2503 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2504 else if (!strcmp(sarch, "nosrc.rpm"))
2505 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2507 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2511 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2517 key.type = REPOKEY_TYPE_IDARRAY;
2519 key.storage = KEY_STORAGE_INCORE;
2520 repodata_set(data, solvid, &key, data->attriddatalen);
2521 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2522 for (i = 0; i < q->count; i++)
2523 data->attriddata[data->attriddatalen++] = q->elements[i];
2524 data->attriddata[data->attriddatalen++] = 0;
2528 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2532 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2534 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2535 data->attriddata[data->attriddatalen++] = dir;
2536 data->attriddata[data->attriddatalen++] = num;
2537 data->attriddata[data->attriddatalen++] = num2;
2538 data->attriddata[data->attriddatalen++] = 0;
2542 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2548 l = strlen(str) + 1;
2549 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2550 memcpy(data->attrdata + data->attrdatalen, str, l);
2551 stroff = data->attrdatalen;
2552 data->attrdatalen += l;
2555 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2557 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2558 data->attriddata[data->attriddatalen++] = dir;
2559 data->attriddata[data->attriddatalen++] = stroff;
2560 data->attriddata[data->attriddatalen++] = 0;
2564 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2567 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2569 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2570 data->attriddata[data->attriddatalen++] = id;
2571 data->attriddata[data->attriddatalen++] = 0;
2575 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2579 if (data->localpool)
2580 id = stringpool_str2id(&data->spool, str, 1);
2582 id = pool_str2id(data->repo->pool, str, 1);
2583 repodata_add_idarray(data, solvid, keyname, id);
2587 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2589 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2590 data->attriddata[data->attriddatalen++] = ghandle;
2591 data->attriddata[data->attriddatalen++] = 0;
2595 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2597 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2598 data->attriddata[data->attriddatalen++] = ghandle;
2599 data->attriddata[data->attriddatalen++] = 0;
2603 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2606 app = repodata_get_attrp(data, solvid);
2610 for (; *ap; ap += 2)
2611 if (data->keys[*ap].name == keyname)
2617 for (; *ap; ap += 2)
2619 if (data->keys[*ap].name == keyname)
2627 /* XXX: does not work correctly, needs fix in iterators! */
2629 repodata_unset(Repodata *data, Id solvid, Id keyname)
2633 key.type = REPOKEY_TYPE_DELETED;
2635 key.storage = KEY_STORAGE_INCORE;
2636 repodata_set(data, solvid, &key, 0);
2639 /* add all (uninternalized) attrs from src to dest */
2641 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2644 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2646 for (; *keyp; keyp += 2)
2647 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2650 /* add some (uninternalized) attrs from src to dest */
2652 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2655 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2657 for (; *keyp; keyp += 2)
2658 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2659 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2662 /* swap (uninternalized) attrs from src and dest */
2664 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2667 if (!data->attrs || dest == src)
2669 tmpattrs = data->attrs[dest - data->start];
2670 data->attrs[dest - data->start] = data->attrs[src - data->start];
2671 data->attrs[src - data->start] = tmpattrs;
2675 /**********************************************************************/
2677 /* TODO: unify with repo_write and repo_solv! */
2679 #define EXTDATA_BLOCK 1023
2687 data_addid(struct extdata *xd, Id sx)
2689 unsigned int x = (unsigned int)sx;
2692 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2693 dp = xd->buf + xd->len;
2698 *dp++ = (x >> 28) | 128;
2700 *dp++ = (x >> 21) | 128;
2701 *dp++ = (x >> 14) | 128;
2704 *dp++ = (x >> 7) | 128;
2706 xd->len = dp - xd->buf;
2710 data_addid64(struct extdata *xd, unsigned long long x)
2712 if (x >= 0x100000000)
2716 data_addid(xd, (Id)(x >> 35));
2717 xd->buf[xd->len - 1] |= 128;
2719 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2720 xd->buf[xd->len - 5] = (x >> 28) | 128;
2723 data_addid(xd, (Id)x);
2727 data_addideof(struct extdata *xd, Id sx, int eof)
2729 unsigned int x = (unsigned int)sx;
2732 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2733 dp = xd->buf + xd->len;
2738 *dp++ = (x >> 27) | 128;
2740 *dp++ = (x >> 20) | 128;
2741 *dp++ = (x >> 13) | 128;
2744 *dp++ = (x >> 6) | 128;
2745 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2746 xd->len = dp - xd->buf;
2750 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2752 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2753 memcpy(xd->buf + xd->len, blob, len);
2757 /*********************************/
2759 /* internalalize some key into incore/vincore data */
2762 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2763 struct extdata *newvincore,
2765 Repokey *key, Id val)
2769 unsigned int oldvincorelen = 0;
2773 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2776 oldvincorelen = xd->len;
2780 case REPOKEY_TYPE_VOID:
2781 case REPOKEY_TYPE_CONSTANT:
2782 case REPOKEY_TYPE_CONSTANTID:
2784 case REPOKEY_TYPE_STR:
2785 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2787 case REPOKEY_TYPE_MD5:
2788 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2790 case REPOKEY_TYPE_SHA1:
2791 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2793 case REPOKEY_TYPE_SHA256:
2794 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2796 case REPOKEY_TYPE_NUM:
2797 if (val & 0x80000000)
2799 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2803 case REPOKEY_TYPE_ID:
2804 case REPOKEY_TYPE_DIR:
2805 data_addid(xd, val);
2807 case REPOKEY_TYPE_BINARY:
2810 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2811 dp += (unsigned int)len;
2812 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2815 case REPOKEY_TYPE_IDARRAY:
2816 for (ida = data->attriddata + val; *ida; ida++)
2817 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2819 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2820 for (ida = data->attriddata + val; *ida; ida += 3)
2822 data_addid(xd, ida[0]);
2823 data_addid(xd, ida[1]);
2824 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2827 case REPOKEY_TYPE_DIRSTRARRAY:
2828 for (ida = data->attriddata + val; *ida; ida += 2)
2830 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2831 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2834 case REPOKEY_TYPE_FIXARRAY:
2838 for (ida = data->attriddata + val; *ida; ida++)
2842 kp = data->xattrs[-*ida];
2850 schemaid = repodata_schema2id(data, schema, 1);
2851 else if (schemaid != repodata_schema2id(data, schema, 0))
2853 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2859 data_addid(xd, num);
2860 data_addid(xd, schemaid);
2861 for (ida = data->attriddata + val; *ida; ida++)
2863 Id *kp = data->xattrs[-*ida];
2867 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2871 case REPOKEY_TYPE_FLEXARRAY:
2874 for (ida = data->attriddata + val; *ida; ida++)
2876 data_addid(xd, num);
2877 for (ida = data->attriddata + val; *ida; ida++)
2879 Id *kp = data->xattrs[-*ida];
2882 data_addid(xd, 0); /* XXX */
2889 schemaid = repodata_schema2id(data, schema, 1);
2890 data_addid(xd, schemaid);
2891 kp = data->xattrs[-*ida];
2893 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2898 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2901 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2903 /* put offset/len in incore */
2904 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2905 oldvincorelen = xd->len - oldvincorelen;
2906 data_addid(newincore, oldvincorelen);
2911 repodata_internalize(Repodata *data)
2913 Repokey *key, solvkey;
2915 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2916 unsigned char *dp, *ndp;
2917 int newschema, oldcount;
2918 struct extdata newincore;
2919 struct extdata newvincore;
2922 if (!data->attrs && !data->xattrs)
2925 newvincore.buf = data->vincore;
2926 newvincore.len = data->vincorelen;
2928 /* find the solvables key, create if needed */
2929 memset(&solvkey, 0, sizeof(solvkey));
2930 solvkey.name = REPOSITORY_SOLVABLES;
2931 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2933 solvkey.storage = KEY_STORAGE_INCORE;
2934 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2936 schema = solv_malloc2(data->nkeys, sizeof(Id));
2937 seen = solv_malloc2(data->nkeys, sizeof(Id));
2939 /* Merge the data already existing (in data->schemata, ->incoredata and
2940 friends) with the new attributes in data->attrs[]. */
2941 nentry = data->end - data->start;
2942 memset(&newincore, 0, sizeof(newincore));
2943 data_addid(&newincore, 0); /* start data at offset 1 */
2945 data->mainschema = 0;
2946 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
2948 /* join entry data */
2949 /* we start with the meta data, entry -1 */
2950 for (entry = -1; entry < nentry; entry++)
2952 memset(seen, 0, data->nkeys * sizeof(Id));
2954 dp = data->incoredata;
2957 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2958 dp = data_read_id(dp, &oldschema);
2961 fprintf(stderr, "oldschema %d\n", oldschema);
2962 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2963 fprintf(stderr, "schemadata %p\n", data->schemadata);
2965 /* seen: -1: old data 0: skipped >0: id + 1 */
2969 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2973 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
2981 keyp = data->attrs ? data->attrs[entry] : 0;
2984 /* strip solvables key */
2986 for (sp = keyp = schema; *sp; sp++)
2987 if (*sp != solvkeyid)
2992 seen[solvkeyid] = 0;
2993 keyp = data->xattrs ? data->xattrs[1] : 0;
2996 for (; *keyp; keyp += 2)
3003 seen[*keyp] = keyp[1] + 1;
3005 if (entry < 0 && data->end != data->start)
3012 /* Ideally we'd like to sort the new schema here, to ensure
3013 schema equality independend of the ordering. We can't do that
3014 yet. For once see below (old ids need to come before new ids).
3015 An additional difficulty is that we also need to move
3016 the values with the keys. */
3017 schemaid = repodata_schema2id(data, schema, 1);
3019 schemaid = oldschema;
3022 /* Now create data blob. We walk through the (possibly new) schema
3023 and either copy over old data, or insert the new. */
3024 /* XXX Here we rely on the fact that the (new) schema has the form
3025 o1 o2 o3 o4 ... | n1 n2 n3 ...
3026 (oX being the old keyids (possibly overwritten), and nX being
3027 the new keyids). This rules out sorting the keyids in order
3028 to ensure a small schema count. */
3030 data->incoreoffset[entry] = newincore.len;
3031 data_addid(&newincore, schemaid);
3034 data->mainschema = schemaid;
3035 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3037 keypstart = data->schemadata + data->schemata[schemaid];
3038 for (keyp = keypstart; *keyp; keyp++)
3041 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
3042 if (*keyp == solvkeyid)
3044 /* add flexarray entry count */
3045 data_addid(&newincore, data->end - data->start);
3048 key = data->keys + *keyp;
3050 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));
3055 /* Skip the data associated with this old key. */
3056 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3058 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3059 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3061 else if (key->storage == KEY_STORAGE_INCORE)
3062 ndp = data_skip_key(data, dp, key);
3065 if (seen[*keyp] == -1)
3067 /* If this key was an old one _and_ was not overwritten with
3068 a different value copy over the old value (we skipped it
3071 data_addblob(&newincore, dp, ndp - dp);
3074 else if (seen[*keyp])
3076 /* Otherwise we have a new value. Parse it into the internal
3078 repodata_serialize_key(data, &newincore, &newvincore,
3079 schema, key, seen[*keyp] - 1);
3083 if (entry >= 0 && data->attrs && data->attrs[entry])
3084 data->attrs[entry] = solv_free(data->attrs[entry]);
3086 /* free all xattrs */
3087 for (entry = 0; entry < data->nxattrs; entry++)
3088 if (data->xattrs[entry])
3089 solv_free(data->xattrs[entry]);
3090 data->xattrs = solv_free(data->xattrs);
3093 data->lasthandle = 0;
3095 data->lastdatalen = 0;
3098 repodata_free_schemahash(data);
3100 solv_free(data->incoredata);
3101 data->incoredata = newincore.buf;
3102 data->incoredatalen = newincore.len;
3103 data->incoredatafree = 0;
3105 solv_free(data->vincore);
3106 data->vincore = newvincore.buf;
3107 data->vincorelen = newvincore.len;
3109 data->attrs = solv_free(data->attrs);
3110 data->attrdata = solv_free(data->attrdata);
3111 data->attriddata = solv_free(data->attriddata);
3112 data->attrnum64data = solv_free(data->attrnum64data);
3113 data->attrdatalen = 0;
3114 data->attriddatalen = 0;
3115 data->attrnum64datalen = 0;
3119 repodata_disable_paging(Repodata *data)
3121 if (maybe_load_repodata(data, 0))
3122 repopagestore_disable_paging(&data->store);
3126 repodata_load_stub(Repodata *data)
3128 Repo *repo = data->repo;
3129 Pool *pool = repo->pool;
3131 struct _Pool_tmpspace oldtmpspace;
3133 if (!pool->loadcallback)
3135 data->state = REPODATA_ERROR;
3138 data->state = REPODATA_LOADING;
3140 /* save tmp space */
3141 oldtmpspace = pool->tmpspace;
3142 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3144 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3146 /* restore tmp space */
3147 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3148 solv_free(pool->tmpspace.buf[i]);
3149 pool->tmpspace = oldtmpspace;
3151 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3155 repodata_create_stubs(Repodata *data)
3157 Repo *repo = data->repo;
3158 Pool *pool = repo->pool;
3165 int datastart, dataend;
3167 repodataid = data - repo->repodata;
3168 datastart = data->start;
3169 dataend = data->end;
3170 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3171 while (dataiterator_step(&di))
3173 if (di.data - repo->repodata != repodataid)
3177 dataiterator_free(&di);
3180 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3181 for (i = 0; i < cnt; i++)
3183 sdata = repo_add_repodata(repo, 0);
3184 if (dataend > datastart)
3185 repodata_extend_block(sdata, datastart, dataend - datastart);
3186 stubdataids[i] = sdata - repo->repodata;
3187 sdata->state = REPODATA_STUB;
3188 sdata->loadcallback = repodata_load_stub;
3191 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3193 while (dataiterator_step(&di))
3195 if (di.data - repo->repodata != repodataid)
3197 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3199 dataiterator_entersub(&di);
3200 sdata = repo->repodata + stubdataids[i++];
3204 switch (di.key->type)
3206 case REPOKEY_TYPE_ID:
3207 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3209 case REPOKEY_TYPE_CONSTANTID:
3210 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3212 case REPOKEY_TYPE_STR:
3213 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3215 case REPOKEY_TYPE_VOID:
3216 repodata_set_void(sdata, SOLVID_META, di.key->name);
3218 case REPOKEY_TYPE_NUM:
3219 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3221 case REPOKEY_TYPE_MD5:
3222 case REPOKEY_TYPE_SHA1:
3223 case REPOKEY_TYPE_SHA256:
3224 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3226 case REPOKEY_TYPE_IDARRAY:
3227 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3228 if (di.key->name == REPOSITORY_KEYS)
3235 xkeyname = di.kv.id;
3238 xkey.name = xkeyname;
3239 xkey.type = di.kv.id;
3240 xkey.storage = KEY_STORAGE_INCORE;
3242 repodata_key2id(sdata, &xkey, 1);
3249 dataiterator_free(&di);
3250 for (i = 0; i < cnt; i++)
3251 repodata_internalize(repo->repodata + stubdataids[i]);
3252 solv_free(stubdataids);
3256 repodata_memused(Repodata *data)
3258 return data->incoredatalen + data->vincorelen;
3262 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: