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 || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1069 const char *p = strrchr(match, '/');
1070 ma->matchdata = (void *)(p ? p + 1 : match);
1072 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1075 for (p = match + strlen(match) - 1; p >= match; p--)
1076 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1078 ma->matchdata = (void *)(p + 1);
1085 datamatcher_free(Datamatcher *ma)
1087 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1089 regfree(ma->matchdata);
1090 solv_free(ma->matchdata);
1096 datamatcher_match(Datamatcher *ma, const char *str)
1099 switch ((ma->flags & SEARCH_STRINGMASK))
1101 case SEARCH_SUBSTRING:
1102 if (ma->flags & SEARCH_NOCASE)
1103 return strcasestr(str, ma->match) != 0;
1105 return strstr(str, ma->match) != 0;
1107 if (ma->flags & SEARCH_NOCASE)
1108 return !strcasecmp(ma->match, str);
1110 return !strcmp(ma->match, str);
1111 case SEARCH_STRINGSTART:
1112 if (ma->flags & SEARCH_NOCASE)
1113 return !strncasecmp(ma->match, str, strlen(ma->match));
1115 return !strncmp(ma->match, str, strlen(ma->match));
1116 case SEARCH_STRINGEND:
1117 l = strlen(str) - strlen(ma->match);
1120 if (ma->flags & SEARCH_NOCASE)
1121 return !strcasecmp(ma->match, str + l);
1123 return !strcmp(ma->match, str + l);
1125 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1127 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1133 /* check if the matcher can match the provides basename */
1136 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1139 const char *match = ma->matchdata;
1142 switch (ma->flags & SEARCH_STRINGMASK)
1146 case SEARCH_STRINGEND:
1147 if (match != ma->match)
1148 break; /* had slash, do exact match on basename */
1151 /* check if the basename ends with match */
1152 l = strlen(basename) - strlen(match);
1158 return 1; /* maybe matches */
1160 if ((ma->flags & SEARCH_NOCASE) != 0)
1161 return !strcasecmp(match, basename);
1163 return !strcmp(match, basename);
1167 repodata_filelistfilter_matches(Repodata *data, const char *str)
1169 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1170 /* for now hardcoded */
1171 if (strstr(str, "bin/"))
1173 if (!strncmp(str, "/etc/", 5))
1175 if (!strcmp(str, "/usr/lib/sendmail"))
1197 di_nextarrayelement,
1203 di_entersolvablekey,
1207 /* see dataiterator.h for documentation */
1209 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1211 memset(di, 0, sizeof(*di));
1213 di->flags = flags & ~SEARCH_THISSOLVID;
1214 if (!pool || (repo && repo->pool != pool))
1222 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1228 di->keyname = keyname;
1229 di->keynames[0] = keyname;
1230 dataiterator_set_search(di, repo, p);
1235 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1238 memset(&di->matcher, 0, sizeof(di->matcher));
1239 if (from->matcher.match)
1240 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1245 for (i = 1; i < di->nparents; i++)
1246 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1247 di->kv.parent = &di->parents[di->nparents - 1].kv;
1252 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1254 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1255 datamatcher_free(&di->matcher);
1256 memset(&di->matcher, 0, sizeof(di->matcher));
1260 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1270 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1274 di->flags &= ~SEARCH_THISSOLVID;
1278 if (!di->pool->urepos)
1286 di->repo = di->pool->repos[di->repoid];
1288 di->state = di_enterrepo;
1290 dataiterator_jump_to_solvid(di, p);
1294 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1297 di->keyname = keyname;
1298 di->keynames[0] = keyname;
1302 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1306 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1308 di->state = di_bye; /* sorry */
1311 for (i = di->nkeynames + 1; i > 0; i--)
1312 di->keynames[i] = di->keynames[i - 1];
1313 di->keynames[0] = di->keyname = keyname;
1318 dataiterator_free(Dataiterator *di)
1320 if (di->matcher.match)
1321 datamatcher_free(&di->matcher);
1324 static inline unsigned char *
1325 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1327 Id *keyp = di->keyp;
1328 Repokey *keys = di->data->keys;
1331 for (keyp = di->keyp; *keyp; keyp++)
1332 if (keys[*keyp].name == keyname)
1336 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1344 dataiterator_filelistcheck(Dataiterator *di)
1347 int needcomplete = 0;
1348 Repodata *data = di->data;
1350 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1351 if (!di->matcher.match
1352 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1353 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1354 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1356 if (data->state != REPODATA_AVAILABLE)
1357 return needcomplete ? 1 : 0;
1358 for (j = 1; j < data->nkeys; j++)
1359 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1361 return j == data->nkeys && !needcomplete ? 0 : 1;
1365 dataiterator_step(Dataiterator *di)
1373 case di_enterrepo: di_enterrepo:
1374 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1376 if (!(di->flags & SEARCH_THISSOLVID))
1378 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1379 goto di_nextsolvable;
1383 case di_entersolvable: di_entersolvable:
1386 di->repodataid = 1; /* reset repodata iterator */
1387 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)
1389 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1391 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1393 goto di_entersolvablekey;
1398 case di_enterrepodata: di_enterrepodata:
1401 if (di->repodataid >= di->repo->nrepodata)
1402 goto di_nextsolvable;
1403 di->data = di->repo->repodata + di->repodataid;
1405 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1406 goto di_nextrepodata;
1407 if (!maybe_load_repodata(di->data, di->keyname))
1408 goto di_nextrepodata;
1409 di->dp = solvid2data(di->data, di->solvid, &schema);
1411 goto di_nextrepodata;
1412 if (di->solvid == SOLVID_POS)
1413 di->solvid = di->pool->pos.solvid;
1414 /* reset key iterator */
1415 di->keyp = di->data->schemadata + di->data->schemata[schema];
1418 case di_enterschema: di_enterschema:
1420 di->dp = dataiterator_find_keyname(di, di->keyname);
1421 if (!di->dp || !*di->keyp)
1425 goto di_nextrepodata;
1429 case di_enterkey: di_enterkey:
1431 di->key = di->data->keys + *di->keyp;
1432 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1435 if (di->key->type == REPOKEY_TYPE_DELETED)
1437 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1439 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1445 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1447 di->state = di_nextkey;
1449 di->state = di_nextattr;
1452 case di_nextkey: di_nextkey:
1453 if (!di->keyname && *++di->keyp)
1459 case di_nextrepodata: di_nextrepodata:
1460 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1461 goto di_enterrepodata;
1464 case di_nextsolvable: di_nextsolvable:
1465 if (!(di->flags & SEARCH_THISSOLVID))
1468 di->solvid = di->repo->start;
1471 for (; di->solvid < di->repo->end; di->solvid++)
1473 if (di->pool->solvables[di->solvid].repo == di->repo)
1474 goto di_entersolvable;
1479 case di_nextrepo: di_nextrepo:
1484 if (di->repoid < di->pool->nrepos)
1486 di->repo = di->pool->repos[di->repoid];
1492 case di_bye: di_bye:
1496 case di_enterarray: di_enterarray:
1497 if (di->key->name == REPOSITORY_SOLVABLES)
1499 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1504 case di_nextarrayelement: di_nextarrayelement:
1507 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1508 if (di->kv.entry == di->kv.num)
1510 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1512 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1514 di->kv.str = (char *)di->ddp;
1516 di->state = di_nextkey;
1519 if (di->kv.entry == di->kv.num - 1)
1521 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1522 di->ddp = data_read_id(di->ddp, &di->kv.id);
1523 di->kv.str = (char *)di->ddp;
1524 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1526 if ((di->flags & SEARCH_SUB) != 0)
1527 di->state = di_entersub;
1529 di->state = di_nextarrayelement;
1532 case di_entersub: di_entersub:
1533 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1534 goto di_nextarrayelement; /* sorry, full */
1535 di->parents[di->nparents].kv = di->kv;
1536 di->parents[di->nparents].dp = di->dp;
1537 di->parents[di->nparents].keyp = di->keyp;
1538 di->dp = (unsigned char *)di->kv.str;
1539 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1540 memset(&di->kv, 0, sizeof(di->kv));
1541 di->kv.parent = &di->parents[di->nparents].kv;
1543 di->keyname = di->keynames[di->nparents - di->rootlevel];
1544 goto di_enterschema;
1546 case di_leavesub: di_leavesub:
1547 if (di->nparents - 1 < di->rootlevel)
1550 di->dp = di->parents[di->nparents].dp;
1551 di->kv = di->parents[di->nparents].kv;
1552 di->keyp = di->parents[di->nparents].keyp;
1553 di->key = di->data->keys + *di->keyp;
1554 di->ddp = (unsigned char *)di->kv.str;
1555 di->keyname = di->keynames[di->nparents - di->rootlevel];
1556 goto di_nextarrayelement;
1558 /* special solvable attr handling follows */
1560 case di_nextsolvablekey: di_nextsolvablekey:
1561 if (di->keyname || di->key->name == RPM_RPMDBID)
1562 goto di_enterrepodata;
1566 case di_entersolvablekey: di_entersolvablekey:
1567 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1568 if (!di->idp || !*di->idp)
1569 goto di_nextsolvablekey;
1573 di->kv.id = *di->idp;
1574 di->kv.num = *di->idp; /* for rpmdbid */
1575 di->kv.num2 = 0; /* for rpmdbid */
1577 di->state = di_nextsolvablekey;
1583 case di_nextsolvableattr:
1584 di->state = di_nextsolvableattr;
1585 di->kv.id = *di->idp++;
1590 di->state = di_nextsolvablekey;
1596 if (di->matcher.match)
1598 /* simple pre-check so that we don't need to stringify */
1599 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1600 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1602 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1604 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1608 if (!datamatcher_match(&di->matcher, di->kv.str))
1613 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1614 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1616 /* found something! */
1622 dataiterator_entersub(Dataiterator *di)
1624 if (di->state == di_nextarrayelement)
1625 di->state = di_entersub;
1629 dataiterator_setpos(Dataiterator *di)
1631 if (di->kv.eof == 2)
1633 pool_clear_pos(di->pool);
1636 di->pool->pos.solvid = di->solvid;
1637 di->pool->pos.repo = di->repo;
1638 di->pool->pos.repodataid = di->data - di->repo->repodata;
1639 di->pool->pos.schema = di->kv.id;
1640 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1644 dataiterator_setpos_parent(Dataiterator *di)
1646 if (!di->kv.parent || di->kv.parent->eof == 2)
1648 pool_clear_pos(di->pool);
1651 di->pool->pos.solvid = di->solvid;
1652 di->pool->pos.repo = di->repo;
1653 di->pool->pos.repodataid = di->data - di->repo->repodata;
1654 di->pool->pos.schema = di->kv.parent->id;
1655 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1658 /* clones just the position, not the search keys/matcher */
1660 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1662 di->state = from->state;
1663 di->flags &= ~SEARCH_THISSOLVID;
1664 di->flags |= (from->flags & SEARCH_THISSOLVID);
1665 di->repo = from->repo;
1666 di->data = from->data;
1668 di->ddp = from->ddp;
1669 di->idp = from->idp;
1670 di->keyp = from->keyp;
1671 di->key = from->key;
1673 di->repodataid = from->repodataid;
1674 di->solvid = from->solvid;
1675 di->repoid = from->repoid;
1676 di->rootlevel = from->rootlevel;
1677 memcpy(di->parents, from->parents, sizeof(from->parents));
1678 di->nparents = from->nparents;
1682 for (i = 1; i < di->nparents; i++)
1683 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1684 di->kv.parent = &di->parents[di->nparents - 1].kv;
1689 dataiterator_seek(Dataiterator *di, int whence)
1691 if ((whence & DI_SEEK_STAY) != 0)
1692 di->rootlevel = di->nparents;
1693 switch (whence & ~DI_SEEK_STAY)
1696 if (di->state != di_nextarrayelement)
1698 if ((whence & DI_SEEK_STAY) != 0)
1699 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1700 di->state = di_entersub;
1702 case DI_SEEK_PARENT:
1709 if (di->rootlevel > di->nparents)
1710 di->rootlevel = di->nparents;
1711 di->dp = di->parents[di->nparents].dp;
1712 di->kv = di->parents[di->nparents].kv;
1713 di->keyp = di->parents[di->nparents].keyp;
1714 di->key = di->data->keys + *di->keyp;
1715 di->ddp = (unsigned char *)di->kv.str;
1716 di->keyname = di->keynames[di->nparents - di->rootlevel];
1717 di->state = di_nextarrayelement;
1719 case DI_SEEK_REWIND:
1725 di->dp = (unsigned char *)di->kv.parent->str;
1726 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1727 di->state = di_enterschema;
1735 dataiterator_skip_attribute(Dataiterator *di)
1737 if (di->state == di_nextsolvableattr)
1738 di->state = di_nextsolvablekey;
1740 di->state = di_nextkey;
1744 dataiterator_skip_solvable(Dataiterator *di)
1749 di->keyname = di->keynames[0];
1750 di->state = di_nextsolvable;
1754 dataiterator_skip_repo(Dataiterator *di)
1759 di->keyname = di->keynames[0];
1760 di->state = di_nextrepo;
1764 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1769 di->keyname = di->keynames[0];
1770 if (solvid == SOLVID_POS)
1772 di->repo = di->pool->pos.repo;
1779 di->data = di->repo->repodata + di->pool->pos.repodataid;
1781 di->solvid = solvid;
1782 di->state = di_enterrepo;
1783 di->flags |= SEARCH_THISSOLVID;
1788 di->repo = di->pool->solvables[solvid].repo;
1791 else if (di->repoid > 0)
1793 if (!di->pool->urepos)
1799 di->repo = di->pool->repos[di->repoid];
1802 di->solvid = solvid;
1804 di->flags |= SEARCH_THISSOLVID;
1805 di->state = di_enterrepo;
1809 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1815 di->repoid = 0; /* 0 means stay at repo */
1818 di->flags &= ~SEARCH_THISSOLVID;
1819 di->state = di_enterrepo;
1823 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1825 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1829 return datamatcher_match(ma, di->kv.str);
1832 /************************************************************************
1833 * data modify functions
1836 /* extend repodata so that it includes solvables p */
1838 repodata_extend(Repodata *data, Id p)
1840 if (data->start == data->end)
1841 data->start = data->end = p;
1844 int old = data->end - data->start;
1845 int new = p - data->end + 1;
1848 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1849 memset(data->attrs + old, 0, new * sizeof(Id *));
1851 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1852 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1855 if (p < data->start)
1857 int old = data->end - data->start;
1858 int new = data->start - p;
1861 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1862 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1863 memset(data->attrs, 0, new * sizeof(Id *));
1865 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1866 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1867 memset(data->incoreoffset, 0, new * sizeof(Id));
1872 /* shrink end of repodata */
1874 repodata_shrink(Repodata *data, int end)
1878 if (data->end <= end)
1880 if (data->start >= end)
1884 for (i = 0; i < data->end - data->start; i++)
1885 solv_free(data->attrs[i]);
1886 data->attrs = solv_free(data->attrs);
1888 data->incoreoffset = solv_free(data->incoreoffset);
1889 data->start = data->end = 0;
1894 for (i = end; i < data->end; i++)
1895 solv_free(data->attrs[i - data->start]);
1896 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1898 if (data->incoreoffset)
1899 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1903 /* extend repodata so that it includes solvables from start to start + num - 1 */
1905 repodata_extend_block(Repodata *data, Id start, Id num)
1909 if (!data->incoreoffset)
1911 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1912 data->start = start;
1913 data->end = start + num;
1916 repodata_extend(data, start);
1918 repodata_extend(data, start + num - 1);
1921 /**********************************************************************/
1924 #define REPODATA_ATTRS_BLOCK 31
1925 #define REPODATA_ATTRDATA_BLOCK 1023
1926 #define REPODATA_ATTRIDDATA_BLOCK 63
1927 #define REPODATA_ATTRNUM64DATA_BLOCK 15
1931 repodata_new_handle(Repodata *data)
1935 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1936 data->nxattrs = 2; /* -1: SOLVID_META */
1938 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1939 data->xattrs[data->nxattrs] = 0;
1940 return -(data->nxattrs++);
1944 repodata_get_attrp(Repodata *data, Id handle)
1948 if (handle == SOLVID_META && !data->xattrs)
1950 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1953 return data->xattrs - handle;
1955 if (handle < data->start || handle >= data->end)
1956 repodata_extend(data, handle);
1958 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1959 return data->attrs + (handle - data->start);
1963 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1969 app = repodata_get_attrp(data, handle);
1974 /* Determine equality based on the name only, allows us to change
1975 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1976 for (pp = ap; *pp; pp += 2)
1977 if (data->keys[*pp].name == data->keys[keyid].name)
1981 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
1990 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2000 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2004 keyid = repodata_key2id(data, key, 1);
2005 repodata_insert_keyid(data, solvid, keyid, val, 1);
2009 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2013 key.type = REPOKEY_TYPE_ID;
2015 key.storage = KEY_STORAGE_INCORE;
2016 repodata_set(data, solvid, &key, id);
2020 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2024 key.type = REPOKEY_TYPE_NUM;
2026 key.storage = KEY_STORAGE_INCORE;
2027 if (num >= 0x80000000)
2029 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2030 data->attrnum64data[data->attrnum64datalen] = num;
2031 num = 0x80000000 | data->attrnum64datalen++;
2033 repodata_set(data, solvid, &key, (Id)num);
2037 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2041 if (data->localpool)
2042 id = stringpool_str2id(&data->spool, str, 1);
2044 id = pool_str2id(data->repo->pool, str, 1);
2046 key.type = REPOKEY_TYPE_ID;
2048 key.storage = KEY_STORAGE_INCORE;
2049 repodata_set(data, solvid, &key, id);
2053 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2057 key.type = REPOKEY_TYPE_CONSTANT;
2058 key.size = constant;
2059 key.storage = KEY_STORAGE_INCORE;
2060 repodata_set(data, solvid, &key, 0);
2064 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2068 key.type = REPOKEY_TYPE_CONSTANTID;
2070 key.storage = KEY_STORAGE_INCORE;
2071 repodata_set(data, solvid, &key, 0);
2075 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2079 key.type = REPOKEY_TYPE_VOID;
2081 key.storage = KEY_STORAGE_INCORE;
2082 repodata_set(data, solvid, &key, 0);
2086 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2091 l = strlen(str) + 1;
2093 key.type = REPOKEY_TYPE_STR;
2095 key.storage = KEY_STORAGE_INCORE;
2096 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2097 memcpy(data->attrdata + data->attrdatalen, str, l);
2098 repodata_set(data, solvid, &key, data->attrdatalen);
2099 data->attrdatalen += l;
2103 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2111 key.type = REPOKEY_TYPE_BINARY;
2113 key.storage = KEY_STORAGE_INCORE;
2114 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2115 dp = data->attrdata + data->attrdatalen;
2116 if (len >= (1 << 14))
2118 if (len >= (1 << 28))
2119 *dp++ = (len >> 28) | 128;
2120 if (len >= (1 << 21))
2121 *dp++ = (len >> 21) | 128;
2122 *dp++ = (len >> 14) | 128;
2124 if (len >= (1 << 7))
2125 *dp++ = (len >> 7) | 128;
2128 memcpy(dp, buf, len);
2129 repodata_set(data, solvid, &key, data->attrdatalen);
2130 data->attrdatalen = dp + len - data->attrdata;
2133 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2134 * so that the caller can append entrysize new elements plus the termination zero there */
2136 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2139 Id *ida, *pp, **ppp;
2141 /* check if it is the same as last time, this speeds things up a lot */
2142 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2144 /* great! just append the new data */
2145 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2146 data->attriddatalen--; /* overwrite terminating 0 */
2147 data->lastdatalen += entrysize;
2151 ppp = repodata_get_attrp(data, handle);
2155 for (; *pp; pp += 2)
2156 if (data->keys[*pp].name == keyname)
2159 if (!pp || !*pp || data->keys[*pp].type != keytype)
2161 /* not found. allocate new key */
2167 key.storage = KEY_STORAGE_INCORE;
2168 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2169 keyid = repodata_key2id(data, &key, 1);
2170 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2171 data->lasthandle = handle;
2172 data->lastkey = keyid;
2173 data->lastdatalen = data->attriddatalen + entrysize + 1;
2177 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2178 oldsize += entrysize;
2179 if (ida + 1 == data->attriddata + data->attriddatalen)
2181 /* this was the last entry, just append it */
2182 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2183 data->attriddatalen--; /* overwrite terminating 0 */
2187 /* too bad. move to back. */
2188 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2189 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2190 pp[1] = data->attriddatalen;
2191 data->attriddatalen += oldsize;
2193 data->lasthandle = handle;
2194 data->lastkey = *pp;
2195 data->lastdatalen = data->attriddatalen + entrysize + 1;
2199 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2200 const unsigned char *str)
2205 if (!(l = solv_chksum_len(type)))
2210 key.storage = KEY_STORAGE_INCORE;
2211 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2212 memcpy(data->attrdata + data->attrdatalen, str, l);
2213 repodata_set(data, solvid, &key, data->attrdatalen);
2214 data->attrdatalen += l;
2218 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2221 unsigned char buf[64];
2224 if (!(l = solv_chksum_len(type)))
2226 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2228 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2232 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2236 if (!(l = solv_chksum_len(type)))
2238 return pool_bin2hex(data->repo->pool, buf, l);
2241 /* rpm filenames don't contain the epoch, so strip it */
2242 static inline const char *
2243 evrid2vrstr(Pool *pool, Id evrid)
2245 const char *p, *evr = pool_id2str(pool, evrid);
2248 for (p = evr; *p >= '0' && *p <= '9'; p++)
2250 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2254 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2257 if (data->localpool)
2258 id = stringpool_strn2id(&data->spool, str, l, 1);
2260 id = pool_strn2id(data->repo->pool, str, l, 1);
2261 repodata_set_id(data, solvid, keyname, id);
2265 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2268 repodata_set_str(data, solvid, keyname, str);
2271 char *s = solv_strdup(str);
2273 repodata_set_str(data, solvid, keyname, s);
2279 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2281 Pool *pool = data->repo->pool;
2283 const char *str, *fp;
2287 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2290 if ((dir = strrchr(file, '/')) != 0)
2301 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2306 if (l == 1 && dir[0] == '.')
2308 s = pool->solvables + solvid;
2311 str = pool_id2str(pool, s->arch);
2312 if (!strncmp(dir, str, l) && !str[l])
2313 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2315 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2318 str = pool_id2str(pool, s->name);
2320 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2323 str = evrid2vrstr(pool, s->evr);
2325 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2328 str = pool_id2str(pool, s->arch);
2330 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2332 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2337 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2340 /* XXX: medianr is currently not stored */
2342 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2345 const char *evr, *suf, *s;
2349 if ((dir = strrchr(file, '/')) != 0)
2360 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2365 if (l == 1 && dir[0] == '.')
2368 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2369 evr = strchr(file, '-');
2372 for (s = evr - 1; s > file; s--)
2379 suf = strrchr(file, '.');
2382 for (s = suf - 1; s > file; s--)
2388 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2390 /* We accept one more item as suffix. */
2391 for (s = suf - 1; s > file; s--)
2401 if (suf && evr && suf < evr)
2403 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2405 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2407 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2411 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2413 Pool *pool = data->repo->pool;
2414 Solvable *s = pool->solvables + solvid;
2415 const char *p, *sevr, *sarch, *name, *evr;
2417 p = strrchr(sourcepkg, '.');
2418 if (!p || strcmp(p, ".rpm") != 0)
2421 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2425 while (p > sourcepkg && *p != '.')
2427 if (*p != '.' || p == sourcepkg)
2430 while (p > sourcepkg && *p != '-')
2432 if (*p != '-' || p == sourcepkg)
2435 while (p > sourcepkg && *p != '-')
2437 if (*p != '-' || p == sourcepkg)
2440 pool = s->repo->pool;
2442 name = pool_id2str(pool, s->name);
2443 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2444 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2446 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2448 evr = evrid2vrstr(pool, s->evr);
2449 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2450 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2452 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2454 if (!strcmp(sarch, "src.rpm"))
2455 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2456 else if (!strcmp(sarch, "nosrc.rpm"))
2457 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2459 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2463 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2469 key.type = REPOKEY_TYPE_IDARRAY;
2471 key.storage = KEY_STORAGE_INCORE;
2472 repodata_set(data, solvid, &key, data->attriddatalen);
2473 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2474 for (i = 0; i < q->count; i++)
2475 data->attriddata[data->attriddatalen++] = q->elements[i];
2476 data->attriddata[data->attriddatalen++] = 0;
2480 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2484 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2486 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2487 data->attriddata[data->attriddatalen++] = dir;
2488 data->attriddata[data->attriddatalen++] = num;
2489 data->attriddata[data->attriddatalen++] = num2;
2490 data->attriddata[data->attriddatalen++] = 0;
2494 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2500 l = strlen(str) + 1;
2501 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2502 memcpy(data->attrdata + data->attrdatalen, str, l);
2503 stroff = data->attrdatalen;
2504 data->attrdatalen += l;
2507 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2509 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2510 data->attriddata[data->attriddatalen++] = dir;
2511 data->attriddata[data->attriddatalen++] = stroff;
2512 data->attriddata[data->attriddatalen++] = 0;
2516 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2519 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2521 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2522 data->attriddata[data->attriddatalen++] = id;
2523 data->attriddata[data->attriddatalen++] = 0;
2527 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2531 if (data->localpool)
2532 id = stringpool_str2id(&data->spool, str, 1);
2534 id = pool_str2id(data->repo->pool, str, 1);
2535 repodata_add_idarray(data, solvid, keyname, id);
2539 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2541 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2542 data->attriddata[data->attriddatalen++] = ghandle;
2543 data->attriddata[data->attriddatalen++] = 0;
2547 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2549 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2550 data->attriddata[data->attriddatalen++] = ghandle;
2551 data->attriddata[data->attriddatalen++] = 0;
2555 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2558 app = repodata_get_attrp(data, solvid);
2562 for (; *ap; ap += 2)
2563 if (data->keys[*ap].name == keyname)
2569 for (; *ap; ap += 2)
2571 if (data->keys[*ap].name == keyname)
2579 /* XXX: does not work correctly, needs fix in iterators! */
2581 repodata_unset(Repodata *data, Id solvid, Id keyname)
2585 key.type = REPOKEY_TYPE_DELETED;
2587 key.storage = KEY_STORAGE_INCORE;
2588 repodata_set(data, solvid, &key, 0);
2591 /* add all (uninternalized) attrs from src to dest */
2593 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2596 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2598 for (; *keyp; keyp += 2)
2599 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2602 /* add some (uninternalized) attrs from src to dest */
2604 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2607 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2609 for (; *keyp; keyp += 2)
2610 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2611 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2614 /* swap (uninternalized) attrs from src and dest */
2616 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2619 if (!data->attrs || dest == src)
2621 tmpattrs = data->attrs[dest - data->start];
2622 data->attrs[dest - data->start] = data->attrs[src - data->start];
2623 data->attrs[src - data->start] = tmpattrs;
2627 /**********************************************************************/
2629 /* TODO: unify with repo_write and repo_solv! */
2631 #define EXTDATA_BLOCK 1023
2639 data_addid(struct extdata *xd, Id sx)
2641 unsigned int x = (unsigned int)sx;
2644 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2645 dp = xd->buf + xd->len;
2650 *dp++ = (x >> 28) | 128;
2652 *dp++ = (x >> 21) | 128;
2653 *dp++ = (x >> 14) | 128;
2656 *dp++ = (x >> 7) | 128;
2658 xd->len = dp - xd->buf;
2662 data_addid64(struct extdata *xd, unsigned long long x)
2664 if (x >= 0x100000000)
2668 data_addid(xd, (Id)(x >> 35));
2669 xd->buf[xd->len - 1] |= 128;
2671 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2672 xd->buf[xd->len - 5] = (x >> 28) | 128;
2675 data_addid(xd, (Id)x);
2679 data_addideof(struct extdata *xd, Id sx, int eof)
2681 unsigned int x = (unsigned int)sx;
2684 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2685 dp = xd->buf + xd->len;
2690 *dp++ = (x >> 27) | 128;
2692 *dp++ = (x >> 20) | 128;
2693 *dp++ = (x >> 13) | 128;
2696 *dp++ = (x >> 6) | 128;
2697 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2698 xd->len = dp - xd->buf;
2702 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2704 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2705 memcpy(xd->buf + xd->len, blob, len);
2709 /*********************************/
2711 /* internalalize some key into incore/vincore data */
2714 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2715 struct extdata *newvincore,
2717 Repokey *key, Id val)
2721 unsigned int oldvincorelen = 0;
2725 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2728 oldvincorelen = xd->len;
2732 case REPOKEY_TYPE_VOID:
2733 case REPOKEY_TYPE_CONSTANT:
2734 case REPOKEY_TYPE_CONSTANTID:
2736 case REPOKEY_TYPE_STR:
2737 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2739 case REPOKEY_TYPE_MD5:
2740 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2742 case REPOKEY_TYPE_SHA1:
2743 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2745 case REPOKEY_TYPE_SHA256:
2746 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2748 case REPOKEY_TYPE_NUM:
2749 if (val & 0x80000000)
2751 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2755 case REPOKEY_TYPE_ID:
2756 case REPOKEY_TYPE_DIR:
2757 data_addid(xd, val);
2759 case REPOKEY_TYPE_BINARY:
2762 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2763 dp += (unsigned int)len;
2764 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2767 case REPOKEY_TYPE_IDARRAY:
2768 for (ida = data->attriddata + val; *ida; ida++)
2769 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2771 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2772 for (ida = data->attriddata + val; *ida; ida += 3)
2774 data_addid(xd, ida[0]);
2775 data_addid(xd, ida[1]);
2776 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2779 case REPOKEY_TYPE_DIRSTRARRAY:
2780 for (ida = data->attriddata + val; *ida; ida += 2)
2782 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2783 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2786 case REPOKEY_TYPE_FIXARRAY:
2790 for (ida = data->attriddata + val; *ida; ida++)
2794 kp = data->xattrs[-*ida];
2802 schemaid = repodata_schema2id(data, schema, 1);
2803 else if (schemaid != repodata_schema2id(data, schema, 0))
2805 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2811 data_addid(xd, num);
2812 data_addid(xd, schemaid);
2813 for (ida = data->attriddata + val; *ida; ida++)
2815 Id *kp = data->xattrs[-*ida];
2819 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2823 case REPOKEY_TYPE_FLEXARRAY:
2826 for (ida = data->attriddata + val; *ida; ida++)
2828 data_addid(xd, num);
2829 for (ida = data->attriddata + val; *ida; ida++)
2831 Id *kp = data->xattrs[-*ida];
2834 data_addid(xd, 0); /* XXX */
2841 schemaid = repodata_schema2id(data, schema, 1);
2842 data_addid(xd, schemaid);
2843 kp = data->xattrs[-*ida];
2845 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2850 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2853 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2855 /* put offset/len in incore */
2856 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2857 oldvincorelen = xd->len - oldvincorelen;
2858 data_addid(newincore, oldvincorelen);
2863 repodata_internalize(Repodata *data)
2865 Repokey *key, solvkey;
2867 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2868 unsigned char *dp, *ndp;
2869 int newschema, oldcount;
2870 struct extdata newincore;
2871 struct extdata newvincore;
2874 if (!data->attrs && !data->xattrs)
2877 newvincore.buf = data->vincore;
2878 newvincore.len = data->vincorelen;
2880 /* find the solvables key, create if needed */
2881 memset(&solvkey, 0, sizeof(solvkey));
2882 solvkey.name = REPOSITORY_SOLVABLES;
2883 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2885 solvkey.storage = KEY_STORAGE_INCORE;
2886 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2888 schema = solv_malloc2(data->nkeys, sizeof(Id));
2889 seen = solv_malloc2(data->nkeys, sizeof(Id));
2891 /* Merge the data already existing (in data->schemata, ->incoredata and
2892 friends) with the new attributes in data->attrs[]. */
2893 nentry = data->end - data->start;
2894 memset(&newincore, 0, sizeof(newincore));
2895 data_addid(&newincore, 0); /* start data at offset 1 */
2897 data->mainschema = 0;
2898 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
2900 /* join entry data */
2901 /* we start with the meta data, entry -1 */
2902 for (entry = -1; entry < nentry; entry++)
2904 memset(seen, 0, data->nkeys * sizeof(Id));
2906 dp = data->incoredata;
2909 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2910 dp = data_read_id(dp, &oldschema);
2913 fprintf(stderr, "oldschema %d\n", oldschema);
2914 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2915 fprintf(stderr, "schemadata %p\n", data->schemadata);
2917 /* seen: -1: old data 0: skipped >0: id + 1 */
2921 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2925 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
2933 keyp = data->attrs ? data->attrs[entry] : 0;
2936 /* strip solvables key */
2938 for (sp = keyp = schema; *sp; sp++)
2939 if (*sp != solvkeyid)
2944 seen[solvkeyid] = 0;
2945 keyp = data->xattrs ? data->xattrs[1] : 0;
2948 for (; *keyp; keyp += 2)
2955 seen[*keyp] = keyp[1] + 1;
2957 if (entry < 0 && data->end != data->start)
2964 /* Ideally we'd like to sort the new schema here, to ensure
2965 schema equality independend of the ordering. We can't do that
2966 yet. For once see below (old ids need to come before new ids).
2967 An additional difficulty is that we also need to move
2968 the values with the keys. */
2969 schemaid = repodata_schema2id(data, schema, 1);
2971 schemaid = oldschema;
2974 /* Now create data blob. We walk through the (possibly new) schema
2975 and either copy over old data, or insert the new. */
2976 /* XXX Here we rely on the fact that the (new) schema has the form
2977 o1 o2 o3 o4 ... | n1 n2 n3 ...
2978 (oX being the old keyids (possibly overwritten), and nX being
2979 the new keyids). This rules out sorting the keyids in order
2980 to ensure a small schema count. */
2982 data->incoreoffset[entry] = newincore.len;
2983 data_addid(&newincore, schemaid);
2986 data->mainschema = schemaid;
2987 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
2989 keypstart = data->schemadata + data->schemata[schemaid];
2990 for (keyp = keypstart; *keyp; keyp++)
2993 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2994 if (*keyp == solvkeyid)
2996 /* add flexarray entry count */
2997 data_addid(&newincore, data->end - data->start);
3000 key = data->keys + *keyp;
3002 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));
3007 /* Skip the data associated with this old key. */
3008 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3010 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3011 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3013 else if (key->storage == KEY_STORAGE_INCORE)
3014 ndp = data_skip_key(data, dp, key);
3017 if (seen[*keyp] == -1)
3019 /* If this key was an old one _and_ was not overwritten with
3020 a different value copy over the old value (we skipped it
3023 data_addblob(&newincore, dp, ndp - dp);
3026 else if (seen[*keyp])
3028 /* Otherwise we have a new value. Parse it into the internal
3030 repodata_serialize_key(data, &newincore, &newvincore,
3031 schema, key, seen[*keyp] - 1);
3035 if (entry >= 0 && data->attrs && data->attrs[entry])
3036 data->attrs[entry] = solv_free(data->attrs[entry]);
3038 /* free all xattrs */
3039 for (entry = 0; entry < data->nxattrs; entry++)
3040 if (data->xattrs[entry])
3041 solv_free(data->xattrs[entry]);
3042 data->xattrs = solv_free(data->xattrs);
3045 data->lasthandle = 0;
3047 data->lastdatalen = 0;
3050 repodata_free_schemahash(data);
3052 solv_free(data->incoredata);
3053 data->incoredata = newincore.buf;
3054 data->incoredatalen = newincore.len;
3055 data->incoredatafree = 0;
3057 solv_free(data->vincore);
3058 data->vincore = newvincore.buf;
3059 data->vincorelen = newvincore.len;
3061 data->attrs = solv_free(data->attrs);
3062 data->attrdata = solv_free(data->attrdata);
3063 data->attriddata = solv_free(data->attriddata);
3064 data->attrnum64data = solv_free(data->attrnum64data);
3065 data->attrdatalen = 0;
3066 data->attriddatalen = 0;
3067 data->attrnum64datalen = 0;
3071 repodata_disable_paging(Repodata *data)
3073 if (maybe_load_repodata(data, 0))
3074 repopagestore_disable_paging(&data->store);
3078 repodata_load_stub(Repodata *data)
3080 Repo *repo = data->repo;
3081 Pool *pool = repo->pool;
3083 struct _Pool_tmpspace oldtmpspace;
3085 if (!pool->loadcallback)
3087 data->state = REPODATA_ERROR;
3090 data->state = REPODATA_LOADING;
3092 /* save tmp space */
3093 oldtmpspace = pool->tmpspace;
3094 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3096 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3098 /* restore tmp space */
3099 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3100 solv_free(pool->tmpspace.buf[i]);
3101 pool->tmpspace = oldtmpspace;
3103 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3107 repodata_create_stubs(Repodata *data)
3109 Repo *repo = data->repo;
3110 Pool *pool = repo->pool;
3117 int datastart, dataend;
3119 repodataid = data - repo->repodata;
3120 datastart = data->start;
3121 dataend = data->end;
3122 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3123 while (dataiterator_step(&di))
3125 if (di.data - repo->repodata != repodataid)
3129 dataiterator_free(&di);
3132 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3133 for (i = 0; i < cnt; i++)
3135 sdata = repo_add_repodata(repo, 0);
3136 if (dataend > datastart)
3137 repodata_extend_block(sdata, datastart, dataend - datastart);
3138 stubdataids[i] = sdata - repo->repodata;
3139 sdata->state = REPODATA_STUB;
3140 sdata->loadcallback = repodata_load_stub;
3143 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3145 while (dataiterator_step(&di))
3147 if (di.data - repo->repodata != repodataid)
3149 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3151 dataiterator_entersub(&di);
3152 sdata = repo->repodata + stubdataids[i++];
3156 switch (di.key->type)
3158 case REPOKEY_TYPE_ID:
3159 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3161 case REPOKEY_TYPE_CONSTANTID:
3162 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3164 case REPOKEY_TYPE_STR:
3165 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3167 case REPOKEY_TYPE_VOID:
3168 repodata_set_void(sdata, SOLVID_META, di.key->name);
3170 case REPOKEY_TYPE_NUM:
3171 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3173 case REPOKEY_TYPE_MD5:
3174 case REPOKEY_TYPE_SHA1:
3175 case REPOKEY_TYPE_SHA256:
3176 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3178 case REPOKEY_TYPE_IDARRAY:
3179 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3180 if (di.key->name == REPOSITORY_KEYS)
3187 xkeyname = di.kv.id;
3190 xkey.name = xkeyname;
3191 xkey.type = di.kv.id;
3192 xkey.storage = KEY_STORAGE_INCORE;
3194 repodata_key2id(sdata, &xkey, 1);
3201 dataiterator_free(&di);
3202 for (i = 0; i < cnt; i++)
3203 repodata_internalize(repo->repodata + stubdataids[i]);
3204 solv_free(stubdataids);
3208 repodata_memused(Repodata *data)
3210 return data->incoredatalen + data->vincorelen;
3214 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: