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;
1068 datamatcher_free(Datamatcher *ma)
1070 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1072 regfree(ma->matchdata);
1073 ma->matchdata = solv_free(ma->matchdata);
1078 datamatcher_match(Datamatcher *ma, const char *str)
1081 switch ((ma->flags & SEARCH_STRINGMASK))
1083 case SEARCH_SUBSTRING:
1084 if (ma->flags & SEARCH_NOCASE)
1086 if (!strcasestr(str, ma->match))
1091 if (!strstr(str, ma->match))
1096 if (ma->flags & SEARCH_NOCASE)
1098 if (strcasecmp(ma->match, str))
1103 if (strcmp(ma->match, str))
1107 case SEARCH_STRINGSTART:
1108 if (ma->flags & SEARCH_NOCASE)
1110 if (strncasecmp(ma->match, str, strlen(ma->match)))
1115 if (strncmp(ma->match, str, strlen(ma->match)))
1119 case SEARCH_STRINGEND:
1120 l = strlen(str) - strlen(ma->match);
1123 if (ma->flags & SEARCH_NOCASE)
1125 if (strcasecmp(ma->match, str + l))
1130 if (strcmp(ma->match, str + l))
1135 if (fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0))
1139 if (regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0))
1149 repodata_filelistfilter_matches(Repodata *data, const char *str)
1151 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1152 /* for now hardcoded */
1153 if (strstr(str, "bin/"))
1155 if (!strncmp(str, "/etc/", 5))
1157 if (!strcmp(str, "/usr/lib/sendmail"))
1179 di_nextarrayelement,
1185 di_entersolvablekey,
1189 /* see dataiterator.h for documentation */
1191 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1193 memset(di, 0, sizeof(*di));
1195 di->flags = flags & ~SEARCH_THISSOLVID;
1196 if (!pool || (repo && repo->pool != pool))
1204 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1210 di->keyname = keyname;
1211 di->keynames[0] = keyname;
1212 dataiterator_set_search(di, repo, p);
1217 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1220 memset(&di->matcher, 0, sizeof(di->matcher));
1221 if (from->matcher.match)
1222 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1227 for (i = 1; i < di->nparents; i++)
1228 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1229 di->kv.parent = &di->parents[di->nparents - 1].kv;
1234 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1236 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1237 datamatcher_free(&di->matcher);
1238 memset(&di->matcher, 0, sizeof(di->matcher));
1242 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1252 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1256 di->flags &= ~SEARCH_THISSOLVID;
1260 if (!di->pool->urepos)
1268 di->repo = di->pool->repos[di->repoid];
1270 di->state = di_enterrepo;
1272 dataiterator_jump_to_solvid(di, p);
1276 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1279 di->keyname = keyname;
1280 di->keynames[0] = keyname;
1284 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1288 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1290 di->state = di_bye; /* sorry */
1293 for (i = di->nkeynames + 1; i > 0; i--)
1294 di->keynames[i] = di->keynames[i - 1];
1295 di->keynames[0] = di->keyname = keyname;
1300 dataiterator_free(Dataiterator *di)
1302 if (di->matcher.match)
1303 datamatcher_free(&di->matcher);
1306 static inline unsigned char *
1307 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1309 Id *keyp = di->keyp;
1310 Repokey *keys = di->data->keys;
1313 for (keyp = di->keyp; *keyp; keyp++)
1314 if (keys[*keyp].name == keyname)
1318 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1326 dataiterator_filelistcheck(Dataiterator *di)
1329 int needcomplete = 0;
1330 Repodata *data = di->data;
1332 if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
1333 if (!di->matcher.match
1334 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1335 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1336 || !repodata_filelistfilter_matches(di->data, di->matcher.match))
1338 if (data->state != REPODATA_AVAILABLE)
1339 return needcomplete ? 1 : 0;
1340 for (j = 1; j < data->nkeys; j++)
1341 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1343 return j == data->nkeys && !needcomplete ? 0 : 1;
1347 dataiterator_step(Dataiterator *di)
1355 case di_enterrepo: di_enterrepo:
1356 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1358 if (!(di->flags & SEARCH_THISSOLVID))
1360 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1361 goto di_nextsolvable;
1365 case di_entersolvable: di_entersolvable:
1368 di->repodataid = 1; /* reset repodata iterator */
1369 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)
1371 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1373 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1375 goto di_entersolvablekey;
1380 case di_enterrepodata: di_enterrepodata:
1383 if (di->repodataid >= di->repo->nrepodata)
1384 goto di_nextsolvable;
1385 di->data = di->repo->repodata + di->repodataid;
1387 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1388 goto di_nextrepodata;
1389 if (!maybe_load_repodata(di->data, di->keyname))
1390 goto di_nextrepodata;
1391 di->dp = solvid2data(di->data, di->solvid, &schema);
1393 goto di_nextrepodata;
1394 if (di->solvid == SOLVID_POS)
1395 di->solvid = di->pool->pos.solvid;
1396 /* reset key iterator */
1397 di->keyp = di->data->schemadata + di->data->schemata[schema];
1400 case di_enterschema: di_enterschema:
1402 di->dp = dataiterator_find_keyname(di, di->keyname);
1403 if (!di->dp || !*di->keyp)
1407 goto di_nextrepodata;
1411 case di_enterkey: di_enterkey:
1413 di->key = di->data->keys + *di->keyp;
1414 di->ddp = get_data(di->data, di->key, &di->dp, di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0) ? 1 : 0);
1417 if (di->key->type == REPOKEY_TYPE_DELETED)
1419 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1421 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1427 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1429 di->state = di_nextkey;
1431 di->state = di_nextattr;
1434 case di_nextkey: di_nextkey:
1435 if (!di->keyname && *++di->keyp)
1441 case di_nextrepodata: di_nextrepodata:
1442 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1443 goto di_enterrepodata;
1446 case di_nextsolvable: di_nextsolvable:
1447 if (!(di->flags & SEARCH_THISSOLVID))
1450 di->solvid = di->repo->start;
1453 for (; di->solvid < di->repo->end; di->solvid++)
1455 if (di->pool->solvables[di->solvid].repo == di->repo)
1456 goto di_entersolvable;
1461 case di_nextrepo: di_nextrepo:
1466 if (di->repoid < di->pool->nrepos)
1468 di->repo = di->pool->repos[di->repoid];
1474 case di_bye: di_bye:
1478 case di_enterarray: di_enterarray:
1479 if (di->key->name == REPOSITORY_SOLVABLES)
1481 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1486 case di_nextarrayelement: di_nextarrayelement:
1489 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1490 if (di->kv.entry == di->kv.num)
1492 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1494 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1496 di->kv.str = (char *)di->ddp;
1498 di->state = di_nextkey;
1501 if (di->kv.entry == di->kv.num - 1)
1503 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1504 di->ddp = data_read_id(di->ddp, &di->kv.id);
1505 di->kv.str = (char *)di->ddp;
1506 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1508 if ((di->flags & SEARCH_SUB) != 0)
1509 di->state = di_entersub;
1511 di->state = di_nextarrayelement;
1514 case di_entersub: di_entersub:
1515 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1516 goto di_nextarrayelement; /* sorry, full */
1517 di->parents[di->nparents].kv = di->kv;
1518 di->parents[di->nparents].dp = di->dp;
1519 di->parents[di->nparents].keyp = di->keyp;
1520 di->dp = (unsigned char *)di->kv.str;
1521 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1522 memset(&di->kv, 0, sizeof(di->kv));
1523 di->kv.parent = &di->parents[di->nparents].kv;
1525 di->keyname = di->keynames[di->nparents - di->rootlevel];
1526 goto di_enterschema;
1528 case di_leavesub: di_leavesub:
1529 if (di->nparents - 1 < di->rootlevel)
1532 di->dp = di->parents[di->nparents].dp;
1533 di->kv = di->parents[di->nparents].kv;
1534 di->keyp = di->parents[di->nparents].keyp;
1535 di->key = di->data->keys + *di->keyp;
1536 di->ddp = (unsigned char *)di->kv.str;
1537 di->keyname = di->keynames[di->nparents - di->rootlevel];
1538 goto di_nextarrayelement;
1540 /* special solvable attr handling follows */
1542 case di_nextsolvablekey: di_nextsolvablekey:
1543 if (di->keyname || di->key->name == RPM_RPMDBID)
1544 goto di_enterrepodata;
1548 case di_entersolvablekey: di_entersolvablekey:
1549 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1550 if (!di->idp || !*di->idp)
1551 goto di_nextsolvablekey;
1555 di->kv.id = *di->idp;
1556 di->kv.num = *di->idp; /* for rpmdbid */
1557 di->kv.num2 = 0; /* for rpmdbid */
1559 di->state = di_nextsolvablekey;
1565 case di_nextsolvableattr:
1566 di->state = di_nextsolvableattr;
1567 di->kv.id = *di->idp++;
1572 di->state = di_nextsolvablekey;
1578 if (di->matcher.match)
1580 /* simple pre-check so that we don't need to stringify */
1581 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && di->matcher.match && (di->matcher.flags & (SEARCH_FILES|SEARCH_NOCASE|SEARCH_STRINGMASK)) == (SEARCH_FILES|SEARCH_STRING))
1583 int l = strlen(di->matcher.match) - strlen(di->kv.str);
1584 if (l < 0 || strcmp(di->matcher.match + l, di->kv.str))
1587 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1589 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1593 if (!datamatcher_match(&di->matcher, di->kv.str))
1598 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1599 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1601 /* found something! */
1607 dataiterator_entersub(Dataiterator *di)
1609 if (di->state == di_nextarrayelement)
1610 di->state = di_entersub;
1614 dataiterator_setpos(Dataiterator *di)
1616 if (di->kv.eof == 2)
1618 pool_clear_pos(di->pool);
1621 di->pool->pos.solvid = di->solvid;
1622 di->pool->pos.repo = di->repo;
1623 di->pool->pos.repodataid = di->data - di->repo->repodata;
1624 di->pool->pos.schema = di->kv.id;
1625 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1629 dataiterator_setpos_parent(Dataiterator *di)
1631 if (!di->kv.parent || di->kv.parent->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.parent->id;
1640 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1643 /* clones just the position, not the search keys/matcher */
1645 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1647 di->state = from->state;
1648 di->flags &= ~SEARCH_THISSOLVID;
1649 di->flags |= (from->flags & SEARCH_THISSOLVID);
1650 di->repo = from->repo;
1651 di->data = from->data;
1653 di->ddp = from->ddp;
1654 di->idp = from->idp;
1655 di->keyp = from->keyp;
1656 di->key = from->key;
1658 di->repodataid = from->repodataid;
1659 di->solvid = from->solvid;
1660 di->repoid = from->repoid;
1661 di->rootlevel = from->rootlevel;
1662 memcpy(di->parents, from->parents, sizeof(from->parents));
1663 di->nparents = from->nparents;
1667 for (i = 1; i < di->nparents; i++)
1668 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1669 di->kv.parent = &di->parents[di->nparents - 1].kv;
1674 dataiterator_seek(Dataiterator *di, int whence)
1676 if ((whence & DI_SEEK_STAY) != 0)
1677 di->rootlevel = di->nparents;
1678 switch (whence & ~DI_SEEK_STAY)
1681 if (di->state != di_nextarrayelement)
1683 if ((whence & DI_SEEK_STAY) != 0)
1684 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1685 di->state = di_entersub;
1687 case DI_SEEK_PARENT:
1694 if (di->rootlevel > di->nparents)
1695 di->rootlevel = di->nparents;
1696 di->dp = di->parents[di->nparents].dp;
1697 di->kv = di->parents[di->nparents].kv;
1698 di->keyp = di->parents[di->nparents].keyp;
1699 di->key = di->data->keys + *di->keyp;
1700 di->ddp = (unsigned char *)di->kv.str;
1701 di->keyname = di->keynames[di->nparents - di->rootlevel];
1702 di->state = di_nextarrayelement;
1704 case DI_SEEK_REWIND:
1710 di->dp = (unsigned char *)di->kv.parent->str;
1711 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1712 di->state = di_enterschema;
1720 dataiterator_skip_attribute(Dataiterator *di)
1722 if (di->state == di_nextsolvableattr)
1723 di->state = di_nextsolvablekey;
1725 di->state = di_nextkey;
1729 dataiterator_skip_solvable(Dataiterator *di)
1734 di->keyname = di->keynames[0];
1735 di->state = di_nextsolvable;
1739 dataiterator_skip_repo(Dataiterator *di)
1744 di->keyname = di->keynames[0];
1745 di->state = di_nextrepo;
1749 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1754 di->keyname = di->keynames[0];
1755 if (solvid == SOLVID_POS)
1757 di->repo = di->pool->pos.repo;
1764 di->data = di->repo->repodata + di->pool->pos.repodataid;
1766 di->solvid = solvid;
1767 di->state = di_enterrepo;
1768 di->flags |= SEARCH_THISSOLVID;
1773 di->repo = di->pool->solvables[solvid].repo;
1776 else if (di->repoid > 0)
1778 if (!di->pool->urepos)
1784 di->repo = di->pool->repos[di->repoid];
1787 di->solvid = solvid;
1789 di->flags |= SEARCH_THISSOLVID;
1790 di->state = di_enterrepo;
1794 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1800 di->repoid = 0; /* 0 means stay at repo */
1803 di->flags &= ~SEARCH_THISSOLVID;
1804 di->state = di_enterrepo;
1808 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1810 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1814 return datamatcher_match(ma, di->kv.str);
1817 /************************************************************************
1818 * data modify functions
1821 /* extend repodata so that it includes solvables p */
1823 repodata_extend(Repodata *data, Id p)
1825 if (data->start == data->end)
1826 data->start = data->end = p;
1829 int old = data->end - data->start;
1830 int new = p - data->end + 1;
1833 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
1834 memset(data->attrs + old, 0, new * sizeof(Id *));
1836 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
1837 memset(data->incoreoffset + old, 0, new * sizeof(Id));
1840 if (p < data->start)
1842 int old = data->end - data->start;
1843 int new = data->start - p;
1846 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
1847 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
1848 memset(data->attrs, 0, new * sizeof(Id *));
1850 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
1851 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
1852 memset(data->incoreoffset, 0, new * sizeof(Id));
1857 /* shrink end of repodata */
1859 repodata_shrink(Repodata *data, int end)
1863 if (data->end <= end)
1865 if (data->start >= end)
1869 for (i = 0; i < data->end - data->start; i++)
1870 solv_free(data->attrs[i]);
1871 data->attrs = solv_free(data->attrs);
1873 data->incoreoffset = solv_free(data->incoreoffset);
1874 data->start = data->end = 0;
1879 for (i = end; i < data->end; i++)
1880 solv_free(data->attrs[i - data->start]);
1881 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
1883 if (data->incoreoffset)
1884 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
1888 /* extend repodata so that it includes solvables from start to start + num - 1 */
1890 repodata_extend_block(Repodata *data, Id start, Id num)
1894 if (!data->incoreoffset)
1896 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
1897 data->start = start;
1898 data->end = start + num;
1901 repodata_extend(data, start);
1903 repodata_extend(data, start + num - 1);
1906 /**********************************************************************/
1909 #define REPODATA_ATTRS_BLOCK 31
1910 #define REPODATA_ATTRDATA_BLOCK 1023
1911 #define REPODATA_ATTRIDDATA_BLOCK 63
1912 #define REPODATA_ATTRNUM64DATA_BLOCK 15
1916 repodata_new_handle(Repodata *data)
1920 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1921 data->nxattrs = 2; /* -1: SOLVID_META */
1923 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
1924 data->xattrs[data->nxattrs] = 0;
1925 return -(data->nxattrs++);
1929 repodata_get_attrp(Repodata *data, Id handle)
1933 if (handle == SOLVID_META && !data->xattrs)
1935 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
1938 return data->xattrs - handle;
1940 if (handle < data->start || handle >= data->end)
1941 repodata_extend(data, handle);
1943 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
1944 return data->attrs + (handle - data->start);
1948 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
1954 app = repodata_get_attrp(data, handle);
1959 /* Determine equality based on the name only, allows us to change
1960 type (when overwrite is set), and makes TYPE_CONSTANT work. */
1961 for (pp = ap; *pp; pp += 2)
1962 if (data->keys[*pp].name == data->keys[keyid].name)
1966 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
1975 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
1985 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
1989 keyid = repodata_key2id(data, key, 1);
1990 repodata_insert_keyid(data, solvid, keyid, val, 1);
1994 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
1998 key.type = REPOKEY_TYPE_ID;
2000 key.storage = KEY_STORAGE_INCORE;
2001 repodata_set(data, solvid, &key, id);
2005 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2009 key.type = REPOKEY_TYPE_NUM;
2011 key.storage = KEY_STORAGE_INCORE;
2012 if (num >= 0x80000000)
2014 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2015 data->attrnum64data[data->attrnum64datalen] = num;
2016 num = 0x80000000 | data->attrnum64datalen++;
2018 repodata_set(data, solvid, &key, (Id)num);
2022 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2026 if (data->localpool)
2027 id = stringpool_str2id(&data->spool, str, 1);
2029 id = pool_str2id(data->repo->pool, str, 1);
2031 key.type = REPOKEY_TYPE_ID;
2033 key.storage = KEY_STORAGE_INCORE;
2034 repodata_set(data, solvid, &key, id);
2038 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2042 key.type = REPOKEY_TYPE_CONSTANT;
2043 key.size = constant;
2044 key.storage = KEY_STORAGE_INCORE;
2045 repodata_set(data, solvid, &key, 0);
2049 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2053 key.type = REPOKEY_TYPE_CONSTANTID;
2055 key.storage = KEY_STORAGE_INCORE;
2056 repodata_set(data, solvid, &key, 0);
2060 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2064 key.type = REPOKEY_TYPE_VOID;
2066 key.storage = KEY_STORAGE_INCORE;
2067 repodata_set(data, solvid, &key, 0);
2071 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2076 l = strlen(str) + 1;
2078 key.type = REPOKEY_TYPE_STR;
2080 key.storage = KEY_STORAGE_INCORE;
2081 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2082 memcpy(data->attrdata + data->attrdatalen, str, l);
2083 repodata_set(data, solvid, &key, data->attrdatalen);
2084 data->attrdatalen += l;
2088 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2096 key.type = REPOKEY_TYPE_BINARY;
2098 key.storage = KEY_STORAGE_INCORE;
2099 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2100 dp = data->attrdata + data->attrdatalen;
2101 if (len >= (1 << 14))
2103 if (len >= (1 << 28))
2104 *dp++ = (len >> 28) | 128;
2105 if (len >= (1 << 21))
2106 *dp++ = (len >> 21) | 128;
2107 *dp++ = (len >> 14) | 128;
2109 if (len >= (1 << 7))
2110 *dp++ = (len >> 7) | 128;
2113 memcpy(dp, buf, len);
2114 repodata_set(data, solvid, &key, data->attrdatalen);
2115 data->attrdatalen = dp + len - data->attrdata;
2118 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2119 * so that the caller can append entrysize new elements plus the termination zero there */
2121 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2124 Id *ida, *pp, **ppp;
2126 /* check if it is the same as last time, this speeds things up a lot */
2127 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2129 /* great! just append the new data */
2130 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2131 data->attriddatalen--; /* overwrite terminating 0 */
2132 data->lastdatalen += entrysize;
2136 ppp = repodata_get_attrp(data, handle);
2140 for (; *pp; pp += 2)
2141 if (data->keys[*pp].name == keyname)
2144 if (!pp || !*pp || data->keys[*pp].type != keytype)
2146 /* not found. allocate new key */
2152 key.storage = KEY_STORAGE_INCORE;
2153 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2154 keyid = repodata_key2id(data, &key, 1);
2155 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2156 data->lasthandle = handle;
2157 data->lastkey = keyid;
2158 data->lastdatalen = data->attriddatalen + entrysize + 1;
2162 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2163 oldsize += entrysize;
2164 if (ida + 1 == data->attriddata + data->attriddatalen)
2166 /* this was the last entry, just append it */
2167 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2168 data->attriddatalen--; /* overwrite terminating 0 */
2172 /* too bad. move to back. */
2173 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2174 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2175 pp[1] = data->attriddatalen;
2176 data->attriddatalen += oldsize;
2178 data->lasthandle = handle;
2179 data->lastkey = *pp;
2180 data->lastdatalen = data->attriddatalen + entrysize + 1;
2184 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2185 const unsigned char *str)
2190 if (!(l = solv_chksum_len(type)))
2195 key.storage = KEY_STORAGE_INCORE;
2196 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2197 memcpy(data->attrdata + data->attrdatalen, str, l);
2198 repodata_set(data, solvid, &key, data->attrdatalen);
2199 data->attrdatalen += l;
2203 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2206 unsigned char buf[64];
2209 if (!(l = solv_chksum_len(type)))
2211 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2213 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2217 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2221 if (!(l = solv_chksum_len(type)))
2223 return pool_bin2hex(data->repo->pool, buf, l);
2226 /* rpm filenames don't contain the epoch, so strip it */
2227 static inline const char *
2228 evrid2vrstr(Pool *pool, Id evrid)
2230 const char *p, *evr = pool_id2str(pool, evrid);
2233 for (p = evr; *p >= '0' && *p <= '9'; p++)
2235 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2239 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2242 if (data->localpool)
2243 id = stringpool_strn2id(&data->spool, str, l, 1);
2245 id = pool_strn2id(data->repo->pool, str, l, 1);
2246 repodata_set_id(data, solvid, keyname, id);
2250 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2253 repodata_set_str(data, solvid, keyname, str);
2256 char *s = solv_strdup(str);
2258 repodata_set_str(data, solvid, keyname, s);
2264 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2266 Pool *pool = data->repo->pool;
2268 const char *str, *fp;
2272 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2275 if ((dir = strrchr(file, '/')) != 0)
2286 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2291 if (l == 1 && dir[0] == '.')
2293 s = pool->solvables + solvid;
2296 str = pool_id2str(pool, s->arch);
2297 if (!strncmp(dir, str, l) && !str[l])
2298 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2300 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2303 str = pool_id2str(pool, s->name);
2305 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2308 str = evrid2vrstr(pool, s->evr);
2310 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2313 str = pool_id2str(pool, s->arch);
2315 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2317 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2322 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2325 /* XXX: medianr is currently not stored */
2327 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2330 const char *evr, *suf, *s;
2334 if ((dir = strrchr(file, '/')) != 0)
2345 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2350 if (l == 1 && dir[0] == '.')
2353 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2354 evr = strchr(file, '-');
2357 for (s = evr - 1; s > file; s--)
2364 suf = strrchr(file, '.');
2367 for (s = suf - 1; s > file; s--)
2373 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2375 /* We accept one more item as suffix. */
2376 for (s = suf - 1; s > file; s--)
2386 if (suf && evr && suf < evr)
2388 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2390 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2392 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2396 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2398 Pool *pool = data->repo->pool;
2399 Solvable *s = pool->solvables + solvid;
2400 const char *p, *sevr, *sarch, *name, *evr;
2402 p = strrchr(sourcepkg, '.');
2403 if (!p || strcmp(p, ".rpm") != 0)
2406 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2410 while (p > sourcepkg && *p != '.')
2412 if (*p != '.' || p == sourcepkg)
2415 while (p > sourcepkg && *p != '-')
2417 if (*p != '-' || p == sourcepkg)
2420 while (p > sourcepkg && *p != '-')
2422 if (*p != '-' || p == sourcepkg)
2425 pool = s->repo->pool;
2427 name = pool_id2str(pool, s->name);
2428 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2429 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2431 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2433 evr = evrid2vrstr(pool, s->evr);
2434 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2435 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2437 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2439 if (!strcmp(sarch, "src.rpm"))
2440 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2441 else if (!strcmp(sarch, "nosrc.rpm"))
2442 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2444 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2448 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2454 key.type = REPOKEY_TYPE_IDARRAY;
2456 key.storage = KEY_STORAGE_INCORE;
2457 repodata_set(data, solvid, &key, data->attriddatalen);
2458 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2459 for (i = 0; i < q->count; i++)
2460 data->attriddata[data->attriddatalen++] = q->elements[i];
2461 data->attriddata[data->attriddatalen++] = 0;
2465 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2469 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2471 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2472 data->attriddata[data->attriddatalen++] = dir;
2473 data->attriddata[data->attriddatalen++] = num;
2474 data->attriddata[data->attriddatalen++] = num2;
2475 data->attriddata[data->attriddatalen++] = 0;
2479 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2485 l = strlen(str) + 1;
2486 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2487 memcpy(data->attrdata + data->attrdatalen, str, l);
2488 stroff = data->attrdatalen;
2489 data->attrdatalen += l;
2492 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2494 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2495 data->attriddata[data->attriddatalen++] = dir;
2496 data->attriddata[data->attriddatalen++] = stroff;
2497 data->attriddata[data->attriddatalen++] = 0;
2501 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2504 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2506 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2507 data->attriddata[data->attriddatalen++] = id;
2508 data->attriddata[data->attriddatalen++] = 0;
2512 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2516 if (data->localpool)
2517 id = stringpool_str2id(&data->spool, str, 1);
2519 id = pool_str2id(data->repo->pool, str, 1);
2520 repodata_add_idarray(data, solvid, keyname, id);
2524 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2526 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2527 data->attriddata[data->attriddatalen++] = ghandle;
2528 data->attriddata[data->attriddatalen++] = 0;
2532 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2534 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2535 data->attriddata[data->attriddatalen++] = ghandle;
2536 data->attriddata[data->attriddatalen++] = 0;
2540 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2543 app = repodata_get_attrp(data, solvid);
2547 for (; *ap; ap += 2)
2548 if (data->keys[*ap].name == keyname)
2554 for (; *ap; ap += 2)
2556 if (data->keys[*ap].name == keyname)
2564 /* XXX: does not work correctly, needs fix in iterators! */
2566 repodata_unset(Repodata *data, Id solvid, Id keyname)
2570 key.type = REPOKEY_TYPE_DELETED;
2572 key.storage = KEY_STORAGE_INCORE;
2573 repodata_set(data, solvid, &key, 0);
2576 /* add all (uninternalized) attrs from src to dest */
2578 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2581 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2583 for (; *keyp; keyp += 2)
2584 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2587 /* add some (uninternalized) attrs from src to dest */
2589 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2592 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2594 for (; *keyp; keyp += 2)
2595 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2596 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2599 /* swap (uninternalized) attrs from src and dest */
2601 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2604 if (!data->attrs || dest == src)
2606 tmpattrs = data->attrs[dest - data->start];
2607 data->attrs[dest - data->start] = data->attrs[src - data->start];
2608 data->attrs[src - data->start] = tmpattrs;
2612 /**********************************************************************/
2614 /* TODO: unify with repo_write and repo_solv! */
2616 #define EXTDATA_BLOCK 1023
2624 data_addid(struct extdata *xd, Id sx)
2626 unsigned int x = (unsigned int)sx;
2629 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2630 dp = xd->buf + xd->len;
2635 *dp++ = (x >> 28) | 128;
2637 *dp++ = (x >> 21) | 128;
2638 *dp++ = (x >> 14) | 128;
2641 *dp++ = (x >> 7) | 128;
2643 xd->len = dp - xd->buf;
2647 data_addid64(struct extdata *xd, unsigned long long x)
2649 if (x >= 0x100000000)
2653 data_addid(xd, (Id)(x >> 35));
2654 xd->buf[xd->len - 1] |= 128;
2656 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2657 xd->buf[xd->len - 5] = (x >> 28) | 128;
2660 data_addid(xd, (Id)x);
2664 data_addideof(struct extdata *xd, Id sx, int eof)
2666 unsigned int x = (unsigned int)sx;
2669 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2670 dp = xd->buf + xd->len;
2675 *dp++ = (x >> 27) | 128;
2677 *dp++ = (x >> 20) | 128;
2678 *dp++ = (x >> 13) | 128;
2681 *dp++ = (x >> 6) | 128;
2682 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2683 xd->len = dp - xd->buf;
2687 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2689 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2690 memcpy(xd->buf + xd->len, blob, len);
2694 /*********************************/
2696 /* internalalize some key into incore/vincore data */
2699 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2700 struct extdata *newvincore,
2702 Repokey *key, Id val)
2706 unsigned int oldvincorelen = 0;
2710 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2713 oldvincorelen = xd->len;
2717 case REPOKEY_TYPE_VOID:
2718 case REPOKEY_TYPE_CONSTANT:
2719 case REPOKEY_TYPE_CONSTANTID:
2721 case REPOKEY_TYPE_STR:
2722 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2724 case REPOKEY_TYPE_MD5:
2725 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2727 case REPOKEY_TYPE_SHA1:
2728 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2730 case REPOKEY_TYPE_SHA256:
2731 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2733 case REPOKEY_TYPE_NUM:
2734 if (val & 0x80000000)
2736 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2740 case REPOKEY_TYPE_ID:
2741 case REPOKEY_TYPE_DIR:
2742 data_addid(xd, val);
2744 case REPOKEY_TYPE_BINARY:
2747 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2748 dp += (unsigned int)len;
2749 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
2752 case REPOKEY_TYPE_IDARRAY:
2753 for (ida = data->attriddata + val; *ida; ida++)
2754 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
2756 case REPOKEY_TYPE_DIRNUMNUMARRAY:
2757 for (ida = data->attriddata + val; *ida; ida += 3)
2759 data_addid(xd, ida[0]);
2760 data_addid(xd, ida[1]);
2761 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
2764 case REPOKEY_TYPE_DIRSTRARRAY:
2765 for (ida = data->attriddata + val; *ida; ida += 2)
2767 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
2768 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
2771 case REPOKEY_TYPE_FIXARRAY:
2775 for (ida = data->attriddata + val; *ida; ida++)
2779 kp = data->xattrs[-*ida];
2787 schemaid = repodata_schema2id(data, schema, 1);
2788 else if (schemaid != repodata_schema2id(data, schema, 0))
2790 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
2796 data_addid(xd, num);
2797 data_addid(xd, schemaid);
2798 for (ida = data->attriddata + val; *ida; ida++)
2800 Id *kp = data->xattrs[-*ida];
2804 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2808 case REPOKEY_TYPE_FLEXARRAY:
2811 for (ida = data->attriddata + val; *ida; ida++)
2813 data_addid(xd, num);
2814 for (ida = data->attriddata + val; *ida; ida++)
2816 Id *kp = data->xattrs[-*ida];
2819 data_addid(xd, 0); /* XXX */
2826 schemaid = repodata_schema2id(data, schema, 1);
2827 data_addid(xd, schemaid);
2828 kp = data->xattrs[-*ida];
2830 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
2835 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
2838 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2840 /* put offset/len in incore */
2841 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
2842 oldvincorelen = xd->len - oldvincorelen;
2843 data_addid(newincore, oldvincorelen);
2848 repodata_internalize(Repodata *data)
2850 Repokey *key, solvkey;
2852 Id schemaid, *schema, *sp, oldschema, *keyp, *keypstart, *seen;
2853 unsigned char *dp, *ndp;
2854 int newschema, oldcount;
2855 struct extdata newincore;
2856 struct extdata newvincore;
2859 if (!data->attrs && !data->xattrs)
2862 newvincore.buf = data->vincore;
2863 newvincore.len = data->vincorelen;
2865 /* find the solvables key, create if needed */
2866 memset(&solvkey, 0, sizeof(solvkey));
2867 solvkey.name = REPOSITORY_SOLVABLES;
2868 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
2870 solvkey.storage = KEY_STORAGE_INCORE;
2871 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
2873 schema = solv_malloc2(data->nkeys, sizeof(Id));
2874 seen = solv_malloc2(data->nkeys, sizeof(Id));
2876 /* Merge the data already existing (in data->schemata, ->incoredata and
2877 friends) with the new attributes in data->attrs[]. */
2878 nentry = data->end - data->start;
2879 memset(&newincore, 0, sizeof(newincore));
2880 data_addid(&newincore, 0); /* start data at offset 1 */
2882 data->mainschema = 0;
2883 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
2885 /* join entry data */
2886 /* we start with the meta data, entry -1 */
2887 for (entry = -1; entry < nentry; entry++)
2889 memset(seen, 0, data->nkeys * sizeof(Id));
2891 dp = data->incoredata;
2894 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
2895 dp = data_read_id(dp, &oldschema);
2898 fprintf(stderr, "oldschema %d\n", oldschema);
2899 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
2900 fprintf(stderr, "schemadata %p\n", data->schemadata);
2902 /* seen: -1: old data 0: skipped >0: id + 1 */
2906 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
2910 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
2918 keyp = data->attrs ? data->attrs[entry] : 0;
2921 /* strip solvables key */
2923 for (sp = keyp = schema; *sp; sp++)
2924 if (*sp != solvkeyid)
2929 seen[solvkeyid] = 0;
2930 keyp = data->xattrs ? data->xattrs[1] : 0;
2933 for (; *keyp; keyp += 2)
2940 seen[*keyp] = keyp[1] + 1;
2942 if (entry < 0 && data->end != data->start)
2949 /* Ideally we'd like to sort the new schema here, to ensure
2950 schema equality independend of the ordering. We can't do that
2951 yet. For once see below (old ids need to come before new ids).
2952 An additional difficulty is that we also need to move
2953 the values with the keys. */
2954 schemaid = repodata_schema2id(data, schema, 1);
2956 schemaid = oldschema;
2959 /* Now create data blob. We walk through the (possibly new) schema
2960 and either copy over old data, or insert the new. */
2961 /* XXX Here we rely on the fact that the (new) schema has the form
2962 o1 o2 o3 o4 ... | n1 n2 n3 ...
2963 (oX being the old keyids (possibly overwritten), and nX being
2964 the new keyids). This rules out sorting the keyids in order
2965 to ensure a small schema count. */
2967 data->incoreoffset[entry] = newincore.len;
2968 data_addid(&newincore, schemaid);
2971 data->mainschema = schemaid;
2972 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
2974 keypstart = data->schemadata + data->schemata[schemaid];
2975 for (keyp = keypstart; *keyp; keyp++)
2978 data->mainschemaoffsets[keyp - keypstart] = newincore.len;
2979 if (*keyp == solvkeyid)
2981 /* add flexarray entry count */
2982 data_addid(&newincore, data->end - data->start);
2985 key = data->keys + *keyp;
2987 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));
2992 /* Skip the data associated with this old key. */
2993 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2995 ndp = data_skip(dp, REPOKEY_TYPE_ID);
2996 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
2998 else if (key->storage == KEY_STORAGE_INCORE)
2999 ndp = data_skip_key(data, dp, key);
3002 if (seen[*keyp] == -1)
3004 /* If this key was an old one _and_ was not overwritten with
3005 a different value copy over the old value (we skipped it
3008 data_addblob(&newincore, dp, ndp - dp);
3011 else if (seen[*keyp])
3013 /* Otherwise we have a new value. Parse it into the internal
3015 repodata_serialize_key(data, &newincore, &newvincore,
3016 schema, key, seen[*keyp] - 1);
3020 if (entry >= 0 && data->attrs && data->attrs[entry])
3021 data->attrs[entry] = solv_free(data->attrs[entry]);
3023 /* free all xattrs */
3024 for (entry = 0; entry < data->nxattrs; entry++)
3025 if (data->xattrs[entry])
3026 solv_free(data->xattrs[entry]);
3027 data->xattrs = solv_free(data->xattrs);
3030 data->lasthandle = 0;
3032 data->lastdatalen = 0;
3035 repodata_free_schemahash(data);
3037 solv_free(data->incoredata);
3038 data->incoredata = newincore.buf;
3039 data->incoredatalen = newincore.len;
3040 data->incoredatafree = 0;
3042 solv_free(data->vincore);
3043 data->vincore = newvincore.buf;
3044 data->vincorelen = newvincore.len;
3046 data->attrs = solv_free(data->attrs);
3047 data->attrdata = solv_free(data->attrdata);
3048 data->attriddata = solv_free(data->attriddata);
3049 data->attrnum64data = solv_free(data->attrnum64data);
3050 data->attrdatalen = 0;
3051 data->attriddatalen = 0;
3052 data->attrnum64datalen = 0;
3056 repodata_disable_paging(Repodata *data)
3058 if (maybe_load_repodata(data, 0))
3059 repopagestore_disable_paging(&data->store);
3063 repodata_load_stub(Repodata *data)
3065 Repo *repo = data->repo;
3066 Pool *pool = repo->pool;
3068 struct _Pool_tmpspace oldtmpspace;
3070 if (!pool->loadcallback)
3072 data->state = REPODATA_ERROR;
3075 data->state = REPODATA_LOADING;
3077 /* save tmp space */
3078 oldtmpspace = pool->tmpspace;
3079 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3081 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3083 /* restore tmp space */
3084 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3085 solv_free(pool->tmpspace.buf[i]);
3086 pool->tmpspace = oldtmpspace;
3088 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3092 repodata_create_stubs(Repodata *data)
3094 Repo *repo = data->repo;
3095 Pool *pool = repo->pool;
3102 int datastart, dataend;
3104 repodataid = data - repo->repodata;
3105 datastart = data->start;
3106 dataend = data->end;
3107 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3108 while (dataiterator_step(&di))
3110 if (di.data - repo->repodata != repodataid)
3114 dataiterator_free(&di);
3117 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3118 for (i = 0; i < cnt; i++)
3120 sdata = repo_add_repodata(repo, 0);
3121 if (dataend > datastart)
3122 repodata_extend_block(sdata, datastart, dataend - datastart);
3123 stubdataids[i] = sdata - repo->repodata;
3124 sdata->state = REPODATA_STUB;
3125 sdata->loadcallback = repodata_load_stub;
3128 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3130 while (dataiterator_step(&di))
3132 if (di.data - repo->repodata != repodataid)
3134 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3136 dataiterator_entersub(&di);
3137 sdata = repo->repodata + stubdataids[i++];
3141 switch (di.key->type)
3143 case REPOKEY_TYPE_ID:
3144 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3146 case REPOKEY_TYPE_CONSTANTID:
3147 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3149 case REPOKEY_TYPE_STR:
3150 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3152 case REPOKEY_TYPE_VOID:
3153 repodata_set_void(sdata, SOLVID_META, di.key->name);
3155 case REPOKEY_TYPE_NUM:
3156 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3158 case REPOKEY_TYPE_MD5:
3159 case REPOKEY_TYPE_SHA1:
3160 case REPOKEY_TYPE_SHA256:
3161 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3163 case REPOKEY_TYPE_IDARRAY:
3164 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3165 if (di.key->name == REPOSITORY_KEYS)
3172 xkeyname = di.kv.id;
3175 xkey.name = xkeyname;
3176 xkey.type = di.kv.id;
3177 xkey.storage = KEY_STORAGE_INCORE;
3179 repodata_key2id(sdata, &xkey, 1);
3186 dataiterator_free(&di);
3187 for (i = 0; i < cnt; i++)
3188 repodata_internalize(repo->repodata + stubdataids[i]);
3189 solv_free(stubdataids);
3193 repodata_memused(Repodata *data)
3195 return data->incoredatalen + data->vincorelen;
3199 vim:cinoptions={.5s,g0,p5,t0,(0,^-0.5s,n-0.5s:tw=78:cindent:sw=4: