2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Manage data coming from one repository
13 * a repository can contain multiple repodata entries, consisting of
14 * different sets of keys and different sets of solvables
29 #include "poolid_private.h"
37 #define REPODATA_BLOCK 255
39 static unsigned char *data_skip_key(Repodata *data, unsigned char *dp, Repokey *key);
42 repodata_initdata(Repodata *data, Repo *repo, int localpool)
44 memset(data, 0, sizeof (*data));
45 data->repodataid = data - repo->repodata;
47 data->localpool = localpool;
49 stringpool_init_empty(&data->spool);
50 /* dirpool_init(&data->dirpool); just zeros out again */
51 data->keys = solv_calloc(1, sizeof(Repokey));
53 data->schemata = solv_calloc(1, sizeof(Id));
54 data->schemadata = solv_calloc(1, sizeof(Id));
56 data->schemadatalen = 1;
57 repopagestore_init(&data->store);
61 repodata_freedata(Repodata *data)
65 solv_free(data->keys);
67 solv_free(data->schemata);
68 solv_free(data->schemadata);
69 solv_free(data->schematahash);
71 stringpool_free(&data->spool);
72 dirpool_free(&data->dirpool);
74 solv_free(data->mainschemaoffsets);
75 solv_free(data->incoredata);
76 solv_free(data->incoreoffset);
77 solv_free(data->verticaloffset);
79 repopagestore_free(&data->store);
81 solv_free(data->vincore);
84 for (i = 0; i < data->end - data->start; i++)
85 solv_free(data->attrs[i]);
86 solv_free(data->attrs);
88 for (i = 0; i < data->nxattrs; i++)
89 solv_free(data->xattrs[i]);
90 solv_free(data->xattrs);
92 solv_free(data->attrdata);
93 solv_free(data->attriddata);
94 solv_free(data->attrnum64data);
96 solv_free(data->dircache);
100 repodata_free(Repodata *data)
102 Repo *repo = data->repo;
103 int i = data - repo->repodata;
106 repodata_freedata(data);
107 if (i < repo->nrepodata - 1)
109 /* whoa! this changes the repodataids! */
110 memmove(repo->repodata + i, repo->repodata + i + 1, (repo->nrepodata - 1 - i) * sizeof(Repodata));
111 for (; i < repo->nrepodata - 1; i++)
112 repo->repodata[i].repodataid = i;
115 if (repo->nrepodata == 1)
117 repo->repodata = solv_free(repo->repodata);
123 repodata_empty(Repodata *data, int localpool)
125 void (*loadcallback)(Repodata *) = data->loadcallback;
126 int state = data->state;
127 repodata_freedata(data);
128 repodata_initdata(data, data->repo, localpool);
130 data->loadcallback = loadcallback;
134 /***************************************************************
135 * key pool management
138 /* this is not so time critical that we need a hash, so we do a simple
141 repodata_key2id(Repodata *data, Repokey *key, int create)
145 for (keyid = 1; keyid < data->nkeys; keyid++)
146 if (data->keys[keyid].name == key->name && data->keys[keyid].type == key->type)
148 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != data->keys[keyid].size)
152 if (keyid == data->nkeys)
156 /* allocate new key */
157 data->keys = solv_realloc2(data->keys, data->nkeys + 1, sizeof(Repokey));
158 data->keys[data->nkeys++] = *key;
159 if (data->verticaloffset)
161 data->verticaloffset = solv_realloc2(data->verticaloffset, data->nkeys, sizeof(Id));
162 data->verticaloffset[data->nkeys - 1] = 0;
164 data->keybits[(key->name >> 3) & (sizeof(data->keybits) - 1)] |= 1 << (key->name & 7);
170 /***************************************************************
171 * schema pool management
174 #define SCHEMATA_BLOCK 31
175 #define SCHEMATADATA_BLOCK 255
178 repodata_schema2id(Repodata *data, Id *schema, int create)
185 return 0; /* XXX: allow empty schema? */
186 if ((schematahash = data->schematahash) == 0)
188 data->schematahash = schematahash = solv_calloc(256, sizeof(Id));
189 for (i = 1; i < data->nschemata; i++)
191 for (sp = data->schemadata + data->schemata[i], h = 0; *sp;)
196 data->schemadata = solv_extend_resize(data->schemadata, data->schemadatalen, sizeof(Id), SCHEMATADATA_BLOCK);
197 data->schemata = solv_extend_resize(data->schemata, data->nschemata, sizeof(Id), SCHEMATA_BLOCK);
200 for (sp = schema, len = 0, h = 0; *sp; len++)
205 cid = schematahash[h];
208 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
210 /* cache conflict, do a slow search */
211 for (cid = 1; cid < data->nschemata; cid++)
212 if (!memcmp(data->schemadata + data->schemata[cid], schema, len * sizeof(Id)))
218 data->schemadata = solv_extend(data->schemadata, data->schemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
219 data->schemata = solv_extend(data->schemata, data->nschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
221 memcpy(data->schemadata + data->schemadatalen, schema, len * sizeof(Id));
222 data->schemata[data->nschemata] = data->schemadatalen;
223 data->schemadatalen += len;
224 schematahash[h] = data->nschemata;
226 fprintf(stderr, "schema2id: new schema\n");
228 return data->nschemata++;
232 repodata_free_schemahash(Repodata *data)
234 data->schematahash = solv_free(data->schematahash);
236 data->schemata = solv_realloc2(data->schemata, data->nschemata, sizeof(Id));
237 data->schemadata = solv_realloc2(data->schemadata, data->schemadatalen, sizeof(Id));
241 /***************************************************************
242 * dir pool management
245 #ifndef HAVE_STRCHRNUL
246 static inline const char *strchrnul(const char *str, char x)
248 const char *p = strchr(str, x);
249 return p ? p : str + strlen(str);
253 #define DIRCACHE_SIZE 41 /* < 1k */
257 Id ids[DIRCACHE_SIZE];
258 char str[(DIRCACHE_SIZE * (DIRCACHE_SIZE - 1)) / 2];
263 repodata_str2dir(Repodata *data, const char *dir, int create)
274 while (*dir == '/' && dir[1] == '/')
276 if (*dir == '/' && !dir[1])
278 if (data->dirpool.ndirs)
280 return dirpool_add_dir(&data->dirpool, 0, 1, create);
287 struct dircache *dircache = data->dircache;
291 if (l < DIRCACHE_SIZE && dircache->ids[l] && !memcmp(dircache->str + l * (l - 1) / 2, dir, l))
293 parent = dircache->ids[l];
309 dire = strchrnul(dir, '/');
311 id = stringpool_strn2id(&data->spool, dir, dire - dir, create);
313 id = pool_strn2id(data->repo->pool, dir, dire - dir, create);
316 parent = dirpool_add_dir(&data->dirpool, parent, id, create);
321 data->dircache = solv_calloc(1, sizeof(struct dircache));
325 if (l < DIRCACHE_SIZE)
327 data->dircache->ids[l] = parent;
328 memcpy(data->dircache->str + l * (l - 1) / 2, dirs, l);
342 repodata_free_dircache(Repodata *data)
344 data->dircache = solv_free(data->dircache);
348 repodata_dir2str(Repodata *data, Id did, const char *suf)
350 Pool *pool = data->repo->pool;
357 return suf ? suf : "";
361 comp = dirpool_compid(&data->dirpool, parent);
362 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
364 parent = dirpool_parent(&data->dirpool, parent);
369 l += strlen(suf) + 1;
370 p = pool_alloctmpspace(pool, l + 1) + l;
381 comp = dirpool_compid(&data->dirpool, parent);
382 comps = stringpool_id2str(data->localpool ? &data->spool : &pool->ss, comp);
385 strncpy(p, comps, l);
386 parent = dirpool_parent(&data->dirpool, parent);
394 /***************************************************************
398 static inline unsigned char *
399 data_skip_schema(Repodata *data, unsigned char *dp, Id schema)
401 Id *keyp = data->schemadata + data->schemata[schema];
402 for (; *keyp; keyp++)
403 dp = data_skip_key(data, dp, data->keys + *keyp);
407 static unsigned char *
408 data_skip_key(Repodata *data, unsigned char *dp, Repokey *key)
410 int nentries, schema;
413 case REPOKEY_TYPE_FIXARRAY:
414 dp = data_read_id(dp, &nentries);
417 dp = data_read_id(dp, &schema);
419 dp = data_skip_schema(data, dp, schema);
421 case REPOKEY_TYPE_FLEXARRAY:
422 dp = data_read_id(dp, &nentries);
425 dp = data_read_id(dp, &schema);
426 dp = data_skip_schema(data, dp, schema);
430 if (key->storage == KEY_STORAGE_INCORE)
431 dp = data_skip(dp, key->type);
432 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
434 dp = data_skip(dp, REPOKEY_TYPE_ID);
435 dp = data_skip(dp, REPOKEY_TYPE_ID);
441 static unsigned char *
442 forward_to_key(Repodata *data, Id keyid, Id *keyp, unsigned char *dp)
448 if (data->mainschemaoffsets && dp == data->incoredata + data->mainschemaoffsets[0] && keyp == data->schemadata + data->schemata[data->mainschema])
451 for (i = 0; (k = *keyp++) != 0; i++)
453 return data->incoredata + data->mainschemaoffsets[i];
456 while ((k = *keyp++) != 0)
460 if (data->keys[k].storage == KEY_STORAGE_VERTICAL_OFFSET)
462 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip offset */
463 dp = data_skip(dp, REPOKEY_TYPE_ID); /* skip length */
466 if (data->keys[k].storage != KEY_STORAGE_INCORE)
468 dp = data_skip_key(data, dp, data->keys + k);
473 static unsigned char *
474 get_vertical_data(Repodata *data, Repokey *key, Id off, Id len)
479 if (off >= data->lastverticaloffset)
481 off -= data->lastverticaloffset;
482 if (off + len > data->vincorelen)
484 return data->vincore + off;
486 if (off + len > key->size)
488 /* we now have the offset, go into vertical */
489 off += data->verticaloffset[key - data->keys];
490 /* fprintf(stderr, "key %d page %d\n", key->name, off / REPOPAGE_BLOBSIZE); */
491 dp = repopagestore_load_page_range(&data->store, off / REPOPAGE_BLOBSIZE, (off + len - 1) / REPOPAGE_BLOBSIZE);
494 dp += off % REPOPAGE_BLOBSIZE;
498 static inline unsigned char *
499 get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
501 unsigned char *dp = *dpp;
505 if (key->storage == KEY_STORAGE_INCORE)
508 *dpp = data_skip_key(data, dp, key);
511 else if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
514 dp = data_read_id(dp, &off);
515 dp = data_read_id(dp, &len);
518 return get_vertical_data(data, key, off, len);
524 load_repodata(Repodata *data)
526 if (data->loadcallback)
528 data->loadcallback(data);
529 if (data->state == REPODATA_AVAILABLE)
532 data->state = REPODATA_ERROR;
537 maybe_load_repodata(Repodata *data, Id keyname)
539 if (keyname && !repodata_precheck_keyname(data, keyname))
540 return 0; /* do not bother... */
547 for (i = 1; i < data->nkeys; i++)
548 if (keyname == data->keys[i].name)
550 if (i == data->nkeys)
553 return load_repodata(data);
556 case REPODATA_AVAILABLE:
557 case REPODATA_LOADING:
560 data->state = REPODATA_ERROR;
565 static inline unsigned char *
566 solvid2data(Repodata *data, Id solvid, Id *schemap)
568 unsigned char *dp = data->incoredata;
571 if (solvid == SOLVID_META)
572 dp += 1; /* offset of "meta" solvable */
573 else if (solvid == SOLVID_POS)
575 Pool *pool = data->repo->pool;
576 if (data->repo != pool->pos.repo)
578 if (data != data->repo->repodata + pool->pos.repodataid)
581 if (pool->pos.dp != 1)
583 *schemap = pool->pos.schema;
589 if (solvid < data->start || solvid >= data->end)
591 dp += data->incoreoffset[solvid - data->start];
593 return data_read_id(dp, schemap);
596 /************************************************************************
600 static unsigned char *
601 find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
604 Id schema, *keyp, *kp;
607 if (!maybe_load_repodata(data, keyname))
609 dp = solvid2data(data, solvid, &schema);
612 keyp = data->schemadata + data->schemata[schema];
613 for (kp = keyp; *kp; kp++)
614 if (data->keys[*kp].name == keyname)
618 *keypp = key = data->keys + *kp;
619 if (key->type == REPOKEY_TYPE_DELETED)
621 if (key->type == REPOKEY_TYPE_VOID || key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID)
622 return dp; /* no need to forward... */
623 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
624 return 0; /* get_data will not work, no need to forward */
625 dp = forward_to_key(data, *kp, keyp, dp);
628 return get_data(data, key, &dp, 0);
632 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
634 Id schema, *keyp, *kp;
635 if (!maybe_load_repodata(data, keyname))
637 if (!solvid2data(data, solvid, &schema))
639 keyp = data->schemadata + data->schemata[schema];
640 for (kp = keyp; *kp; kp++)
641 if (data->keys[*kp].name == keyname)
642 return data->keys[*kp].type;
647 repodata_lookup_id(Repodata *data, Id solvid, Id keyname)
653 dp = find_key_data(data, solvid, keyname, &key);
656 if (key->type == REPOKEY_TYPE_CONSTANTID)
658 if (key->type != REPOKEY_TYPE_ID)
660 dp = data_read_id(dp, &id);
665 repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
671 dp = find_key_data(data, solvid, keyname, &key);
674 if (key->type == REPOKEY_TYPE_STR)
675 return (const char *)dp;
676 if (key->type == REPOKEY_TYPE_CONSTANTID)
678 else if (key->type == REPOKEY_TYPE_ID)
679 dp = data_read_id(dp, &id);
683 return stringpool_id2str(&data->spool, id);
684 return pool_id2str(data->repo->pool, id);
688 repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
692 unsigned int high, low;
695 dp = find_key_data(data, solvid, keyname, &key);
700 case REPOKEY_TYPE_NUM:
701 data_read_num64(dp, &low, &high);
702 *value = (unsigned long long)high << 32 | low;
704 case REPOKEY_TYPE_U32:
705 data_read_u32(dp, &low);
708 case REPOKEY_TYPE_CONSTANT:
717 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
723 if (!maybe_load_repodata(data, keyname))
725 dp = solvid2data(data, solvid, &schema);
728 /* can't use find_key_data as we need to test the type */
729 for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
730 if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
735 const unsigned char *
736 repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep)
741 dp = find_key_data(data, solvid, keyname, &key);
746 case REPOKEY_TYPE_MD5:
747 case REPOKEY_TYPE_SHA1:
748 case REPOKEY_TYPE_SHA224:
749 case REPOKEY_TYPE_SHA256:
750 case REPOKEY_TYPE_SHA384:
751 case REPOKEY_TYPE_SHA512:
761 repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
769 dp = find_key_data(data, solvid, keyname, &key);
772 if (key->type != REPOKEY_TYPE_IDARRAY)
776 dp = data_read_ideof(dp, &id, &eof);
785 repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp)
791 dp = find_key_data(data, solvid, keyname, &key);
792 if (!dp || key->type != REPOKEY_TYPE_BINARY)
797 dp = data_read_id(dp, &len);
803 repodata_globalize_id(Repodata *data, Id id, int create)
805 if (!id || !data || !data->localpool)
807 return pool_str2id(data->repo->pool, stringpool_id2str(&data->spool, id), create);
811 repodata_localize_id(Repodata *data, Id id, int create)
813 if (!id || !data || !data->localpool)
815 return stringpool_str2id(&data->spool, pool_id2str(data->repo->pool, id), create);
819 repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
821 if (!id || !data || !fromdata)
823 if (!data->localpool || !fromdata->localpool)
825 if (fromdata->localpool)
826 id = repodata_globalize_id(fromdata, id, create);
828 id = repodata_localize_id(data, id, create);
831 /* localpool is set in both data and fromdata */
832 return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create);
836 repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
841 ap = data->attrs[solvid - data->start];
846 if (data->keys[*ap].name != keyname)
848 if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
850 if (data->keys[*ap].type == REPOKEY_TYPE_ID)
858 /************************************************************************
864 repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int flags)
868 case REPOKEY_TYPE_ID:
869 case REPOKEY_TYPE_CONSTANTID:
870 case REPOKEY_TYPE_IDARRAY:
871 if (data && data->localpool)
872 kv->str = stringpool_id2str(&data->spool, kv->id);
874 kv->str = pool_id2str(pool, kv->id);
875 if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
878 for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
880 if (*s == ':' && s > kv->str)
884 case REPOKEY_TYPE_STR:
886 case REPOKEY_TYPE_DIRSTRARRAY:
887 if (!(flags & SEARCH_FILES))
888 return 1; /* match just the basename */
890 return 1; /* already stringified */
891 /* Put the full filename into kv->str. */
892 kv->str = repodata_dir2str(data, kv->id, kv->str);
893 kv->num = 1; /* mark stringification */
895 case REPOKEY_TYPE_MD5:
896 case REPOKEY_TYPE_SHA1:
897 case REPOKEY_TYPE_SHA224:
898 case REPOKEY_TYPE_SHA256:
899 case REPOKEY_TYPE_SHA384:
900 case REPOKEY_TYPE_SHA512:
901 if (!(flags & SEARCH_CHECKSUMS))
902 return 0; /* skip em */
904 return 1; /* already stringified */
905 kv->str = repodata_chk2str(data, key->type, (const unsigned char *)kv->str);
906 kv->num = 1; /* mark stringification */
914 struct subschema_data {
920 /* search a specific repodata */
922 repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
926 Id keyid, *kp, *keyp;
927 unsigned char *dp, *ddp;
933 if (!maybe_load_repodata(data, keyname))
935 if (solvid == SOLVID_SUBSCHEMA)
937 struct subschema_data *subd = cbdata;
938 cbdata = subd->cbdata;
940 schema = subd->parent->id;
941 dp = (unsigned char *)subd->parent->str;
942 kv.parent = subd->parent;
947 dp = solvid2data(data, solvid, &schema);
950 s = data->repo->pool->solvables + solvid;
953 keyp = data->schemadata + data->schemata[schema];
956 /* search for a specific key */
957 for (kp = keyp; *kp; kp++)
958 if (data->keys[*kp].name == keyname)
962 dp = forward_to_key(data, *kp, keyp, dp);
968 while ((keyid = *keyp++) != 0)
971 key = data->keys + keyid;
972 ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
974 if (key->type == REPOKEY_TYPE_DELETED)
976 if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
978 struct subschema_data subd;
982 subd.cbdata = cbdata;
985 ddp = data_read_id(ddp, &nentries);
989 while (ddp && nentries > 0)
993 if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
994 ddp = data_read_id(ddp, &schema);
996 kv.str = (char *)ddp;
997 stop = callback(cbdata, s, data, key, &kv);
998 if (stop > SEARCH_NEXT_KEY)
1000 if (stop && stop != SEARCH_ENTERSUB)
1002 if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
1003 repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
1004 ddp = data_skip_schema(data, ddp, schema);
1007 if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
1011 kv.str = (char *)ddp;
1012 stop = callback(cbdata, s, data, key, &kv);
1013 if (stop > SEARCH_NEXT_KEY)
1023 ddp = data_fetch(ddp, &kv, key);
1026 stop = callback(cbdata, s, data, key, &kv);
1029 while (!kv.eof && !stop);
1030 if (onekey || stop > SEARCH_NEXT_KEY)
1036 repodata_setpos_kv(Repodata *data, KeyValue *kv)
1038 Pool *pool = data->repo->pool;
1040 pool_clear_pos(pool);
1043 pool->pos.repo = data->repo;
1044 pool->pos.repodataid = data - data->repo->repodata;
1045 pool->pos.dp = (unsigned char *)kv->str - data->incoredata;
1046 pool->pos.schema = kv->id;
1050 /************************************************************************
1051 * data iterator functions
1055 solvabledata_fetch(Solvable *s, KeyValue *kv, Id keyname)
1069 case SOLVABLE_VENDOR:
1072 case SOLVABLE_PROVIDES:
1074 return s->provides ? s->repo->idarraydata + s->provides : 0;
1075 case SOLVABLE_OBSOLETES:
1077 return s->obsoletes ? s->repo->idarraydata + s->obsoletes : 0;
1078 case SOLVABLE_CONFLICTS:
1080 return s->conflicts ? s->repo->idarraydata + s->conflicts : 0;
1081 case SOLVABLE_REQUIRES:
1083 return s->requires ? s->repo->idarraydata + s->requires : 0;
1084 case SOLVABLE_RECOMMENDS:
1086 return s->recommends ? s->repo->idarraydata + s->recommends : 0;
1087 case SOLVABLE_SUPPLEMENTS:
1089 return s->supplements ? s->repo->idarraydata + s->supplements : 0;
1090 case SOLVABLE_SUGGESTS:
1092 return s->suggests ? s->repo->idarraydata + s->suggests : 0;
1093 case SOLVABLE_ENHANCES:
1095 return s->enhances ? s->repo->idarraydata + s->enhances : 0;
1098 return s->repo->rpmdbid ? s->repo->rpmdbid + (s - s->repo->pool->solvables - s->repo->start) : 0;
1105 datamatcher_init(Datamatcher *ma, const char *match, int flags)
1107 match = match ? solv_strdup(match) : 0;
1112 if ((flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
1114 ma->matchdata = solv_calloc(1, sizeof(regex_t));
1115 ma->error = regcomp((regex_t *)ma->matchdata, match, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | ((flags & SEARCH_NOCASE) ? REG_ICASE : 0));
1118 solv_free(ma->matchdata);
1119 ma->flags = (flags & ~SEARCH_STRINGMASK) | SEARCH_ERROR;
1122 if ((flags & SEARCH_FILES) != 0 && match)
1124 /* prepare basename check */
1125 if ((flags & SEARCH_STRINGMASK) == SEARCH_STRING || (flags & SEARCH_STRINGMASK) == SEARCH_STRINGEND)
1127 const char *p = strrchr(match, '/');
1128 ma->matchdata = (void *)(p ? p + 1 : match);
1130 else if ((flags & SEARCH_STRINGMASK) == SEARCH_GLOB)
1133 for (p = match + strlen(match) - 1; p >= match; p--)
1134 if (*p == '[' || *p == ']' || *p == '*' || *p == '?' || *p == '/')
1136 ma->matchdata = (void *)(p + 1);
1143 datamatcher_free(Datamatcher *ma)
1146 ma->match = solv_free((char *)ma->match);
1147 if ((ma->flags & SEARCH_STRINGMASK) == SEARCH_REGEX && ma->matchdata)
1149 regfree(ma->matchdata);
1150 solv_free(ma->matchdata);
1156 datamatcher_match(Datamatcher *ma, const char *str)
1159 switch ((ma->flags & SEARCH_STRINGMASK))
1161 case SEARCH_SUBSTRING:
1162 if (ma->flags & SEARCH_NOCASE)
1163 return strcasestr(str, ma->match) != 0;
1165 return strstr(str, ma->match) != 0;
1167 if (ma->flags & SEARCH_NOCASE)
1168 return !strcasecmp(ma->match, str);
1170 return !strcmp(ma->match, str);
1171 case SEARCH_STRINGSTART:
1172 if (ma->flags & SEARCH_NOCASE)
1173 return !strncasecmp(ma->match, str, strlen(ma->match));
1175 return !strncmp(ma->match, str, strlen(ma->match));
1176 case SEARCH_STRINGEND:
1177 l = strlen(str) - strlen(ma->match);
1180 if (ma->flags & SEARCH_NOCASE)
1181 return !strcasecmp(ma->match, str + l);
1183 return !strcmp(ma->match, str + l);
1185 return !fnmatch(ma->match, str, (ma->flags & SEARCH_NOCASE) ? FNM_CASEFOLD : 0);
1187 return !regexec((const regex_t *)ma->matchdata, str, 0, NULL, 0);
1193 /* check if the matcher can match the provides basename */
1196 datamatcher_checkbasename(Datamatcher *ma, const char *basename)
1199 const char *match = ma->matchdata;
1202 switch (ma->flags & SEARCH_STRINGMASK)
1206 case SEARCH_STRINGEND:
1207 if (match != ma->match)
1208 break; /* had slash, do exact match on basename */
1211 /* check if the basename ends with match */
1212 l = strlen(basename) - strlen(match);
1218 return 1; /* maybe matches */
1220 if ((ma->flags & SEARCH_NOCASE) != 0)
1221 return !strcasecmp(match, basename);
1223 return !strcmp(match, basename);
1227 repodata_filelistfilter_matches(Repodata *data, const char *str)
1229 /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
1230 /* for now hardcoded */
1231 if (strstr(str, "bin/"))
1233 if (!strncmp(str, "/etc/", 5))
1235 if (!strcmp(str, "/usr/lib/sendmail"))
1257 di_nextarrayelement,
1263 di_entersolvablekey,
1267 /* see dataiterator.h for documentation */
1269 dataiterator_init(Dataiterator *di, Pool *pool, Repo *repo, Id p, Id keyname, const char *match, int flags)
1271 memset(di, 0, sizeof(*di));
1273 di->flags = flags & ~SEARCH_THISSOLVID;
1274 if (!pool || (repo && repo->pool != pool))
1282 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1288 di->keyname = keyname;
1289 di->keynames[0] = keyname;
1290 dataiterator_set_search(di, repo, p);
1295 dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
1300 if (di->dupstr == di->kv.str)
1301 di->dupstr = solv_memdup(di->dupstr, di->dupstrn);
1308 memset(&di->matcher, 0, sizeof(di->matcher));
1309 if (from->matcher.match)
1310 datamatcher_init(&di->matcher, from->matcher.match, from->matcher.flags);
1315 for (i = 1; i < di->nparents; i++)
1316 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1317 di->kv.parent = &di->parents[di->nparents - 1].kv;
1322 dataiterator_set_match(Dataiterator *di, const char *match, int flags)
1324 di->flags = (flags & ~SEARCH_THISSOLVID) | (di->flags & SEARCH_THISSOLVID);
1325 datamatcher_free(&di->matcher);
1326 memset(&di->matcher, 0, sizeof(di->matcher));
1330 if ((error = datamatcher_init(&di->matcher, match, flags)) != 0)
1340 dataiterator_set_search(Dataiterator *di, Repo *repo, Id p)
1344 di->flags &= ~SEARCH_THISSOLVID;
1348 if (!di->pool->urepos)
1356 di->repo = di->pool->repos[di->repoid];
1358 di->state = di_enterrepo;
1360 dataiterator_jump_to_solvid(di, p);
1364 dataiterator_set_keyname(Dataiterator *di, Id keyname)
1367 di->keyname = keyname;
1368 di->keynames[0] = keyname;
1372 dataiterator_prepend_keyname(Dataiterator *di, Id keyname)
1376 if (di->nkeynames >= sizeof(di->keynames)/sizeof(*di->keynames) - 2)
1378 di->state = di_bye; /* sorry */
1381 for (i = di->nkeynames + 1; i > 0; i--)
1382 di->keynames[i] = di->keynames[i - 1];
1383 di->keynames[0] = di->keyname = keyname;
1388 dataiterator_free(Dataiterator *di)
1390 if (di->matcher.match)
1391 datamatcher_free(&di->matcher);
1393 solv_free(di->dupstr);
1396 static unsigned char *
1397 dataiterator_find_keyname(Dataiterator *di, Id keyname)
1400 Repokey *keys = di->data->keys, *key;
1403 for (keyp = di->keyp; *keyp; keyp++)
1404 if (keys[*keyp].name == keyname)
1409 if (key->type == REPOKEY_TYPE_DELETED)
1411 if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET)
1412 return 0; /* get_data will not work, no need to forward */
1413 dp = forward_to_key(di->data, *keyp, di->keyp, di->dp);
1421 is_filelist_extension(Repodata *data)
1424 if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
1426 for (j = 1; j < data->nkeys; j++)
1427 if (data->keys[j].name == SOLVABLE_FILELIST)
1429 if (j == data->nkeys)
1431 if (data->state != REPODATA_AVAILABLE)
1433 for (j = 1; j < data->nkeys; j++)
1434 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1440 dataiterator_filelistcheck(Dataiterator *di)
1443 int needcomplete = 0;
1444 Repodata *data = di->data;
1446 if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
1447 if (!di->matcher.match
1448 || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
1449 && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
1450 || !repodata_filelistfilter_matches(data, di->matcher.match))
1452 if (data->state != REPODATA_AVAILABLE)
1453 return needcomplete ? 1 : 0;
1456 /* we don't need the complete filelist, so ignore all stubs */
1457 for (j = 1; j < data->nkeys; j++)
1458 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1464 /* we need the complete filelist. check if we habe a filtered filelist and there's
1465 * a extension with the complete filelist later on */
1466 for (j = 1; j < data->nkeys; j++)
1467 if (data->keys[j].name == SOLVABLE_FILELIST)
1469 if (j == data->nkeys)
1470 return 0; /* does not have filelist */
1471 for (j = 1; j < data->nkeys; j++)
1472 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
1474 if (j == data->nkeys)
1475 return 1; /* this is the externsion */
1476 while (data - data->repo->repodata + 1 < data->repo->nrepodata)
1479 if (is_filelist_extension(data))
1487 dataiterator_step(Dataiterator *di)
1491 if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
1492 unsigned int ddpoff = di->ddp - di->vert_ddp;
1493 di->vert_off += ddpoff;
1494 di->vert_len -= ddpoff;
1495 di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
1496 di->vert_storestate = di->data->storestate;
1498 di->state = di_nextkey;
1504 case di_enterrepo: di_enterrepo:
1505 if (!di->repo || (di->repo->disabled && !(di->flags & SEARCH_DISABLED_REPOS)))
1507 if (!(di->flags & SEARCH_THISSOLVID))
1509 di->solvid = di->repo->start - 1; /* reset solvid iterator */
1510 goto di_nextsolvable;
1514 case di_entersolvable: di_entersolvable:
1517 di->repodataid = 1; /* reset repodata iterator */
1518 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)
1520 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
1522 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
1524 goto di_entersolvablekey;
1529 case di_enterrepodata: di_enterrepodata:
1532 if (di->repodataid >= di->repo->nrepodata)
1533 goto di_nextsolvable;
1534 di->data = di->repo->repodata + di->repodataid;
1536 if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
1537 goto di_nextrepodata;
1538 if (!maybe_load_repodata(di->data, di->keyname))
1539 goto di_nextrepodata;
1540 di->dp = solvid2data(di->data, di->solvid, &schema);
1542 goto di_nextrepodata;
1543 if (di->solvid == SOLVID_POS)
1544 di->solvid = di->pool->pos.solvid;
1545 /* reset key iterator */
1546 di->keyp = di->data->schemadata + di->data->schemata[schema];
1549 case di_enterschema: di_enterschema:
1551 di->dp = dataiterator_find_keyname(di, di->keyname);
1552 if (!di->dp || !*di->keyp)
1556 goto di_nextrepodata;
1560 case di_enterkey: di_enterkey:
1562 di->key = di->data->keys + *di->keyp;
1565 /* this is get_data() modified to store vert_ data */
1566 if (di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
1569 di->dp = data_read_id(di->dp, &off);
1570 di->dp = data_read_id(di->dp, &len);
1571 di->vert_ddp = di->ddp = get_vertical_data(di->data, di->key, off, len);
1574 di->vert_storestate = di->data->storestate;
1576 else if (di->key->storage == KEY_STORAGE_INCORE)
1579 if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
1580 di->dp = data_skip_key(di->data, di->dp, di->key);
1586 if (di->key->type == REPOKEY_TYPE_DELETED)
1588 if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
1590 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1596 di->ddp = data_fetch(di->ddp, &di->kv, di->key);
1598 di->state = di_nextkey;
1600 di->state = di_nextattr;
1603 case di_nextkey: di_nextkey:
1604 if (!di->keyname && *++di->keyp)
1610 case di_nextrepodata: di_nextrepodata:
1611 if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
1612 goto di_enterrepodata;
1615 case di_nextsolvable: di_nextsolvable:
1616 if (!(di->flags & SEARCH_THISSOLVID))
1619 di->solvid = di->repo->start;
1622 for (; di->solvid < di->repo->end; di->solvid++)
1624 if (di->pool->solvables[di->solvid].repo == di->repo)
1625 goto di_entersolvable;
1630 case di_nextrepo: di_nextrepo:
1635 if (di->repoid < di->pool->nrepos)
1637 di->repo = di->pool->repos[di->repoid];
1643 case di_bye: di_bye:
1647 case di_enterarray: di_enterarray:
1648 if (di->key->name == REPOSITORY_SOLVABLES)
1650 di->ddp = data_read_id(di->ddp, (Id *)&di->kv.num);
1655 case di_nextarrayelement: di_nextarrayelement:
1658 di->ddp = data_skip_schema(di->data, di->ddp, di->kv.id);
1659 if (di->kv.entry == di->kv.num)
1661 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1663 if (!(di->flags & SEARCH_ARRAYSENTINEL))
1665 di->kv.str = (char *)di->ddp;
1667 di->state = di_nextkey;
1670 if (di->kv.entry == di->kv.num - 1)
1672 if (di->key->type == REPOKEY_TYPE_FLEXARRAY || !di->kv.entry)
1673 di->ddp = data_read_id(di->ddp, &di->kv.id);
1674 di->kv.str = (char *)di->ddp;
1675 if (di->nkeynames && di->nparents - di->rootlevel < di->nkeynames)
1677 if ((di->flags & SEARCH_SUB) != 0)
1678 di->state = di_entersub;
1680 di->state = di_nextarrayelement;
1683 case di_entersub: di_entersub:
1684 if (di->nparents == sizeof(di->parents)/sizeof(*di->parents) - 1)
1685 goto di_nextarrayelement; /* sorry, full */
1686 di->parents[di->nparents].kv = di->kv;
1687 di->parents[di->nparents].dp = di->dp;
1688 di->parents[di->nparents].keyp = di->keyp;
1689 di->dp = (unsigned char *)di->kv.str;
1690 di->keyp = di->data->schemadata + di->data->schemata[di->kv.id];
1691 memset(&di->kv, 0, sizeof(di->kv));
1692 di->kv.parent = &di->parents[di->nparents].kv;
1694 di->keyname = di->keynames[di->nparents - di->rootlevel];
1695 goto di_enterschema;
1697 case di_leavesub: di_leavesub:
1698 if (di->nparents - 1 < di->rootlevel)
1701 di->dp = di->parents[di->nparents].dp;
1702 di->kv = di->parents[di->nparents].kv;
1703 di->keyp = di->parents[di->nparents].keyp;
1704 di->key = di->data->keys + *di->keyp;
1705 di->ddp = (unsigned char *)di->kv.str;
1706 di->keyname = di->keynames[di->nparents - di->rootlevel];
1707 goto di_nextarrayelement;
1709 /* special solvable attr handling follows */
1711 case di_nextsolvablekey: di_nextsolvablekey:
1712 if (di->keyname || di->key->name == RPM_RPMDBID)
1713 goto di_enterrepodata;
1717 case di_entersolvablekey: di_entersolvablekey:
1718 di->idp = solvabledata_fetch(di->pool->solvables + di->solvid, &di->kv, di->key->name);
1719 if (!di->idp || !*di->idp)
1720 goto di_nextsolvablekey;
1724 di->kv.id = *di->idp;
1725 di->kv.num = *di->idp; /* for rpmdbid */
1726 di->kv.num2 = 0; /* for rpmdbid */
1728 di->state = di_nextsolvablekey;
1734 case di_nextsolvableattr:
1735 di->state = di_nextsolvableattr;
1736 di->kv.id = *di->idp++;
1741 di->state = di_nextsolvablekey;
1747 if (di->matcher.match)
1749 /* simple pre-check so that we don't need to stringify */
1750 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
1751 if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
1753 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1755 if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
1759 if (!datamatcher_match(&di->matcher, di->kv.str))
1764 if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
1765 repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
1767 /* found something! */
1773 dataiterator_entersub(Dataiterator *di)
1775 if (di->state == di_nextarrayelement)
1776 di->state = di_entersub;
1780 dataiterator_setpos(Dataiterator *di)
1782 if (di->kv.eof == 2)
1784 pool_clear_pos(di->pool);
1787 di->pool->pos.solvid = di->solvid;
1788 di->pool->pos.repo = di->repo;
1789 di->pool->pos.repodataid = di->data - di->repo->repodata;
1790 di->pool->pos.schema = di->kv.id;
1791 di->pool->pos.dp = (unsigned char *)di->kv.str - di->data->incoredata;
1795 dataiterator_setpos_parent(Dataiterator *di)
1797 if (!di->kv.parent || di->kv.parent->eof == 2)
1799 pool_clear_pos(di->pool);
1802 di->pool->pos.solvid = di->solvid;
1803 di->pool->pos.repo = di->repo;
1804 di->pool->pos.repodataid = di->data - di->repo->repodata;
1805 di->pool->pos.schema = di->kv.parent->id;
1806 di->pool->pos.dp = (unsigned char *)di->kv.parent->str - di->data->incoredata;
1809 /* clones just the position, not the search keys/matcher */
1811 dataiterator_clonepos(Dataiterator *di, Dataiterator *from)
1813 di->state = from->state;
1814 di->flags &= ~SEARCH_THISSOLVID;
1815 di->flags |= (from->flags & SEARCH_THISSOLVID);
1816 di->repo = from->repo;
1817 di->data = from->data;
1819 di->ddp = from->ddp;
1820 di->idp = from->idp;
1821 di->keyp = from->keyp;
1822 di->key = from->key;
1824 di->repodataid = from->repodataid;
1825 di->solvid = from->solvid;
1826 di->repoid = from->repoid;
1827 di->rootlevel = from->rootlevel;
1828 memcpy(di->parents, from->parents, sizeof(from->parents));
1829 di->nparents = from->nparents;
1833 for (i = 1; i < di->nparents; i++)
1834 di->parents[i].kv.parent = &di->parents[i - 1].kv;
1835 di->kv.parent = &di->parents[di->nparents - 1].kv;
1839 if (from->dupstr && from->dupstr == from->kv.str)
1841 di->dupstrn = from->dupstrn;
1842 di->dupstr = solv_memdup(from->dupstr, from->dupstrn);
1847 dataiterator_seek(Dataiterator *di, int whence)
1849 if ((whence & DI_SEEK_STAY) != 0)
1850 di->rootlevel = di->nparents;
1851 switch (whence & ~DI_SEEK_STAY)
1854 if (di->state != di_nextarrayelement)
1856 if ((whence & DI_SEEK_STAY) != 0)
1857 di->rootlevel = di->nparents + 1; /* XXX: dangerous! */
1858 di->state = di_entersub;
1860 case DI_SEEK_PARENT:
1867 if (di->rootlevel > di->nparents)
1868 di->rootlevel = di->nparents;
1869 di->dp = di->parents[di->nparents].dp;
1870 di->kv = di->parents[di->nparents].kv;
1871 di->keyp = di->parents[di->nparents].keyp;
1872 di->key = di->data->keys + *di->keyp;
1873 di->ddp = (unsigned char *)di->kv.str;
1874 di->keyname = di->keynames[di->nparents - di->rootlevel];
1875 di->state = di_nextarrayelement;
1877 case DI_SEEK_REWIND:
1883 di->dp = (unsigned char *)di->kv.parent->str;
1884 di->keyp = di->data->schemadata + di->data->schemata[di->kv.parent->id];
1885 di->state = di_enterschema;
1893 dataiterator_skip_attribute(Dataiterator *di)
1895 if (di->state == di_nextsolvableattr)
1896 di->state = di_nextsolvablekey;
1898 di->state = di_nextkey;
1902 dataiterator_skip_solvable(Dataiterator *di)
1907 di->keyname = di->keynames[0];
1908 di->state = di_nextsolvable;
1912 dataiterator_skip_repo(Dataiterator *di)
1917 di->keyname = di->keynames[0];
1918 di->state = di_nextrepo;
1922 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
1927 di->keyname = di->keynames[0];
1928 if (solvid == SOLVID_POS)
1930 di->repo = di->pool->pos.repo;
1937 di->data = di->repo->repodata + di->pool->pos.repodataid;
1939 di->solvid = solvid;
1940 di->state = di_enterrepo;
1941 di->flags |= SEARCH_THISSOLVID;
1946 di->repo = di->pool->solvables[solvid].repo;
1949 else if (di->repoid > 0)
1951 if (!di->pool->urepos)
1957 di->repo = di->pool->repos[di->repoid];
1960 di->solvid = solvid;
1962 di->flags |= SEARCH_THISSOLVID;
1963 di->state = di_enterrepo;
1967 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
1973 di->repoid = 0; /* 0 means stay at repo */
1976 di->flags &= ~SEARCH_THISSOLVID;
1977 di->state = di_enterrepo;
1981 dataiterator_match(Dataiterator *di, Datamatcher *ma)
1983 if (!repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags))
1987 return datamatcher_match(ma, di->kv.str);
1991 dataiterator_strdup(Dataiterator *di)
1995 if (!di->kv.str || di->kv.str == di->dupstr)
1997 switch (di->key->type)
1999 case REPOKEY_TYPE_MD5:
2000 case REPOKEY_TYPE_SHA1:
2001 case REPOKEY_TYPE_SHA224:
2002 case REPOKEY_TYPE_SHA256:
2003 case REPOKEY_TYPE_SHA384:
2004 case REPOKEY_TYPE_SHA512:
2005 case REPOKEY_TYPE_DIRSTRARRAY:
2006 if (di->kv.num) /* was it stringified into tmp space? */
2007 l = strlen(di->kv.str) + 1;
2012 if (l < 0 && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2014 switch (di->key->type)
2016 case REPOKEY_TYPE_STR:
2017 case REPOKEY_TYPE_DIRSTRARRAY:
2018 l = strlen(di->kv.str) + 1;
2020 case REPOKEY_TYPE_MD5:
2023 case REPOKEY_TYPE_SHA1:
2026 case REPOKEY_TYPE_SHA224:
2029 case REPOKEY_TYPE_SHA256:
2032 case REPOKEY_TYPE_SHA384:
2035 case REPOKEY_TYPE_SHA512:
2038 case REPOKEY_TYPE_BINARY:
2045 if (!di->dupstrn || di->dupstrn < l)
2047 di->dupstrn = l + 16;
2048 di->dupstr = solv_realloc(di->dupstr, di->dupstrn);
2051 memcpy(di->dupstr, di->kv.str, l);
2052 di->kv.str = di->dupstr;
2056 /************************************************************************
2057 * data modify functions
2060 /* extend repodata so that it includes solvables p */
2062 repodata_extend(Repodata *data, Id p)
2064 if (data->start == data->end)
2065 data->start = data->end = p;
2068 int old = data->end - data->start;
2069 int new = p - data->end + 1;
2072 data->attrs = solv_extend(data->attrs, old, new, sizeof(Id *), REPODATA_BLOCK);
2073 memset(data->attrs + old, 0, new * sizeof(Id *));
2075 data->incoreoffset = solv_extend(data->incoreoffset, old, new, sizeof(Id), REPODATA_BLOCK);
2076 memset(data->incoreoffset + old, 0, new * sizeof(Id));
2079 if (p < data->start)
2081 int old = data->end - data->start;
2082 int new = data->start - p;
2085 data->attrs = solv_extend_resize(data->attrs, old + new, sizeof(Id *), REPODATA_BLOCK);
2086 memmove(data->attrs + new, data->attrs, old * sizeof(Id *));
2087 memset(data->attrs, 0, new * sizeof(Id *));
2089 data->incoreoffset = solv_extend_resize(data->incoreoffset, old + new, sizeof(Id), REPODATA_BLOCK);
2090 memmove(data->incoreoffset + new, data->incoreoffset, old * sizeof(Id));
2091 memset(data->incoreoffset, 0, new * sizeof(Id));
2096 /* shrink end of repodata */
2098 repodata_shrink(Repodata *data, int end)
2102 if (data->end <= end)
2104 if (data->start >= end)
2108 for (i = 0; i < data->end - data->start; i++)
2109 solv_free(data->attrs[i]);
2110 data->attrs = solv_free(data->attrs);
2112 data->incoreoffset = solv_free(data->incoreoffset);
2113 data->start = data->end = 0;
2118 for (i = end; i < data->end; i++)
2119 solv_free(data->attrs[i - data->start]);
2120 data->attrs = solv_extend_resize(data->attrs, end - data->start, sizeof(Id *), REPODATA_BLOCK);
2122 if (data->incoreoffset)
2123 data->incoreoffset = solv_extend_resize(data->incoreoffset, end - data->start, sizeof(Id), REPODATA_BLOCK);
2127 /* extend repodata so that it includes solvables from start to start + num - 1 */
2129 repodata_extend_block(Repodata *data, Id start, Id num)
2133 if (!data->incoreoffset)
2135 data->incoreoffset = solv_calloc_block(num, sizeof(Id), REPODATA_BLOCK);
2136 data->start = start;
2137 data->end = start + num;
2140 repodata_extend(data, start);
2142 repodata_extend(data, start + num - 1);
2145 /**********************************************************************/
2148 #define REPODATA_ATTRS_BLOCK 31
2149 #define REPODATA_ATTRDATA_BLOCK 1023
2150 #define REPODATA_ATTRIDDATA_BLOCK 63
2151 #define REPODATA_ATTRNUM64DATA_BLOCK 15
2155 repodata_new_handle(Repodata *data)
2159 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2160 data->nxattrs = 2; /* -1: SOLVID_META */
2162 data->xattrs = solv_extend(data->xattrs, data->nxattrs, 1, sizeof(Id *), REPODATA_BLOCK);
2163 data->xattrs[data->nxattrs] = 0;
2164 return -(data->nxattrs++);
2168 repodata_get_attrp(Repodata *data, Id handle)
2172 if (handle == SOLVID_META && !data->xattrs)
2174 data->xattrs = solv_calloc_block(1, sizeof(Id *), REPODATA_BLOCK);
2177 return data->xattrs - handle;
2179 if (handle < data->start || handle >= data->end)
2180 repodata_extend(data, handle);
2182 data->attrs = solv_calloc_block(data->end - data->start, sizeof(Id *), REPODATA_BLOCK);
2183 return data->attrs + (handle - data->start);
2187 repodata_insert_keyid(Repodata *data, Id handle, Id keyid, Id val, int overwrite)
2193 app = repodata_get_attrp(data, handle);
2198 /* Determine equality based on the name only, allows us to change
2199 type (when overwrite is set), and makes TYPE_CONSTANT work. */
2200 for (pp = ap; *pp; pp += 2)
2201 if (data->keys[*pp].name == data->keys[keyid].name)
2205 if (overwrite || data->keys[*pp].type == REPOKEY_TYPE_DELETED)
2214 ap = solv_extend(ap, i, 3, sizeof(Id), REPODATA_ATTRS_BLOCK);
2224 repodata_set(Repodata *data, Id solvid, Repokey *key, Id val)
2228 keyid = repodata_key2id(data, key, 1);
2229 repodata_insert_keyid(data, solvid, keyid, val, 1);
2233 repodata_set_id(Repodata *data, Id solvid, Id keyname, Id id)
2237 key.type = REPOKEY_TYPE_ID;
2239 key.storage = KEY_STORAGE_INCORE;
2240 repodata_set(data, solvid, &key, id);
2244 repodata_set_num(Repodata *data, Id solvid, Id keyname, unsigned long long num)
2248 key.type = REPOKEY_TYPE_NUM;
2250 key.storage = KEY_STORAGE_INCORE;
2251 if (num >= 0x80000000)
2253 data->attrnum64data = solv_extend(data->attrnum64data, data->attrnum64datalen, 1, sizeof(unsigned long long), REPODATA_ATTRNUM64DATA_BLOCK);
2254 data->attrnum64data[data->attrnum64datalen] = num;
2255 num = 0x80000000 | data->attrnum64datalen++;
2257 repodata_set(data, solvid, &key, (Id)num);
2261 repodata_set_poolstr(Repodata *data, Id solvid, Id keyname, const char *str)
2265 if (data->localpool)
2266 id = stringpool_str2id(&data->spool, str, 1);
2268 id = pool_str2id(data->repo->pool, str, 1);
2270 key.type = REPOKEY_TYPE_ID;
2272 key.storage = KEY_STORAGE_INCORE;
2273 repodata_set(data, solvid, &key, id);
2277 repodata_set_constant(Repodata *data, Id solvid, Id keyname, unsigned int constant)
2281 key.type = REPOKEY_TYPE_CONSTANT;
2282 key.size = constant;
2283 key.storage = KEY_STORAGE_INCORE;
2284 repodata_set(data, solvid, &key, 0);
2288 repodata_set_constantid(Repodata *data, Id solvid, Id keyname, Id id)
2292 key.type = REPOKEY_TYPE_CONSTANTID;
2294 key.storage = KEY_STORAGE_INCORE;
2295 repodata_set(data, solvid, &key, 0);
2299 repodata_set_void(Repodata *data, Id solvid, Id keyname)
2303 key.type = REPOKEY_TYPE_VOID;
2305 key.storage = KEY_STORAGE_INCORE;
2306 repodata_set(data, solvid, &key, 0);
2310 repodata_set_str(Repodata *data, Id solvid, Id keyname, const char *str)
2315 l = strlen(str) + 1;
2317 key.type = REPOKEY_TYPE_STR;
2319 key.storage = KEY_STORAGE_INCORE;
2320 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2321 memcpy(data->attrdata + data->attrdatalen, str, l);
2322 repodata_set(data, solvid, &key, data->attrdatalen);
2323 data->attrdatalen += l;
2327 repodata_set_binary(Repodata *data, Id solvid, Id keyname, void *buf, int len)
2335 key.type = REPOKEY_TYPE_BINARY;
2337 key.storage = KEY_STORAGE_INCORE;
2338 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, len + 5, 1, REPODATA_ATTRDATA_BLOCK);
2339 dp = data->attrdata + data->attrdatalen;
2340 if (len >= (1 << 14))
2342 if (len >= (1 << 28))
2343 *dp++ = (len >> 28) | 128;
2344 if (len >= (1 << 21))
2345 *dp++ = (len >> 21) | 128;
2346 *dp++ = (len >> 14) | 128;
2348 if (len >= (1 << 7))
2349 *dp++ = (len >> 7) | 128;
2352 memcpy(dp, buf, len);
2353 repodata_set(data, solvid, &key, data->attrdatalen);
2354 data->attrdatalen = dp + len - data->attrdata;
2357 /* add an array element consisting of entrysize Ids to the repodata. modifies attriddata
2358 * so that the caller can append entrysize new elements plus the termination zero there */
2360 repodata_add_array(Repodata *data, Id handle, Id keyname, Id keytype, int entrysize)
2363 Id *ida, *pp, **ppp;
2365 /* check if it is the same as last time, this speeds things up a lot */
2366 if (handle == data->lasthandle && data->keys[data->lastkey].name == keyname && data->keys[data->lastkey].type == keytype && data->attriddatalen == data->lastdatalen)
2368 /* great! just append the new data */
2369 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2370 data->attriddatalen--; /* overwrite terminating 0 */
2371 data->lastdatalen += entrysize;
2375 ppp = repodata_get_attrp(data, handle);
2379 for (; *pp; pp += 2)
2380 if (data->keys[*pp].name == keyname)
2383 if (!pp || !*pp || data->keys[*pp].type != keytype)
2385 /* not found. allocate new key */
2391 key.storage = KEY_STORAGE_INCORE;
2392 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2393 keyid = repodata_key2id(data, &key, 1);
2394 repodata_insert_keyid(data, handle, keyid, data->attriddatalen, 1);
2395 data->lasthandle = handle;
2396 data->lastkey = keyid;
2397 data->lastdatalen = data->attriddatalen + entrysize + 1;
2401 for (ida = data->attriddata + pp[1]; *ida; ida += entrysize)
2402 oldsize += entrysize;
2403 if (ida + 1 == data->attriddata + data->attriddatalen)
2405 /* this was the last entry, just append it */
2406 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, entrysize, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2407 data->attriddatalen--; /* overwrite terminating 0 */
2411 /* too bad. move to back. */
2412 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, oldsize + entrysize + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2413 memcpy(data->attriddata + data->attriddatalen, data->attriddata + pp[1], oldsize * sizeof(Id));
2414 pp[1] = data->attriddatalen;
2415 data->attriddatalen += oldsize;
2417 data->lasthandle = handle;
2418 data->lastkey = *pp;
2419 data->lastdatalen = data->attriddatalen + entrysize + 1;
2423 repodata_set_bin_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2424 const unsigned char *str)
2429 if (!(l = solv_chksum_len(type)))
2434 key.storage = KEY_STORAGE_INCORE;
2435 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2436 memcpy(data->attrdata + data->attrdatalen, str, l);
2437 repodata_set(data, solvid, &key, data->attrdatalen);
2438 data->attrdatalen += l;
2442 repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
2445 unsigned char buf[64];
2448 if (!(l = solv_chksum_len(type)))
2450 if (l > sizeof(buf) || solv_hex2bin(&str, buf, l) != l)
2452 repodata_set_bin_checksum(data, solvid, keyname, type, buf);
2456 repodata_chk2str(Repodata *data, Id type, const unsigned char *buf)
2460 if (!(l = solv_chksum_len(type)))
2462 return pool_bin2hex(data->repo->pool, buf, l);
2465 /* rpm filenames don't contain the epoch, so strip it */
2466 static inline const char *
2467 evrid2vrstr(Pool *pool, Id evrid)
2469 const char *p, *evr = pool_id2str(pool, evrid);
2472 for (p = evr; *p >= '0' && *p <= '9'; p++)
2474 return p != evr && *p == ':' && p[1] ? p + 1 : evr;
2478 repodata_set_poolstrn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2481 if (data->localpool)
2482 id = stringpool_strn2id(&data->spool, str, l, 1);
2484 id = pool_strn2id(data->repo->pool, str, l, 1);
2485 repodata_set_id(data, solvid, keyname, id);
2489 repodata_set_strn(Repodata *data, Id solvid, Id keyname, const char *str, int l)
2492 repodata_set_str(data, solvid, keyname, str);
2495 char *s = solv_strdup(str);
2497 repodata_set_str(data, solvid, keyname, s);
2503 repodata_set_location(Repodata *data, Id solvid, int medianr, const char *dir, const char *file)
2505 Pool *pool = data->repo->pool;
2507 const char *str, *fp;
2511 repodata_set_constant(data, solvid, SOLVABLE_MEDIANR, medianr);
2514 if ((dir = strrchr(file, '/')) != 0)
2525 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2530 if (l == 1 && dir[0] == '.')
2532 s = pool->solvables + solvid;
2535 str = pool_id2str(pool, s->arch);
2536 if (!strncmp(dir, str, l) && !str[l])
2537 repodata_set_void(data, solvid, SOLVABLE_MEDIADIR);
2539 repodata_set_strn(data, solvid, SOLVABLE_MEDIADIR, dir, l);
2542 str = pool_id2str(pool, s->name);
2544 if ((!l || !strncmp(fp, str, l)) && fp[l] == '-')
2547 str = evrid2vrstr(pool, s->evr);
2549 if ((!l || !strncmp(fp, str, l)) && fp[l] == '.')
2552 str = pool_id2str(pool, s->arch);
2554 if ((!l || !strncmp(fp, str, l)) && !strcmp(fp + l, ".rpm"))
2556 repodata_set_void(data, solvid, SOLVABLE_MEDIAFILE);
2561 repodata_set_str(data, solvid, SOLVABLE_MEDIAFILE, file);
2564 /* XXX: medianr is currently not stored */
2566 repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file)
2569 const char *evr, *suf, *s;
2573 if ((dir = strrchr(file, '/')) != 0)
2584 if (l >= 2 && dir[0] == '.' && dir[1] == '/' && (l == 2 || dir[2] != '/'))
2589 if (l == 1 && dir[0] == '.')
2592 repodata_set_poolstrn(data, handle, DELTA_LOCATION_DIR, dir, l);
2593 evr = strchr(file, '-');
2596 for (s = evr - 1; s > file; s--)
2603 suf = strrchr(file, '.');
2606 for (s = suf - 1; s > file; s--)
2612 if (!strcmp(suf, ".delta.rpm") || !strcmp(suf, ".patch.rpm"))
2614 /* We accept one more item as suffix. */
2615 for (s = suf - 1; s > file; s--)
2625 if (suf && evr && suf < evr)
2627 repodata_set_poolstrn(data, handle, DELTA_LOCATION_NAME, file, evr ? evr - file : strlen(file));
2629 repodata_set_poolstrn(data, handle, DELTA_LOCATION_EVR, evr + 1, suf ? suf - evr - 1: strlen(evr + 1));
2631 repodata_set_poolstr(data, handle, DELTA_LOCATION_SUFFIX, suf + 1);
2635 repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg)
2637 Pool *pool = data->repo->pool;
2638 Solvable *s = pool->solvables + solvid;
2639 const char *p, *sevr, *sarch, *name, *evr;
2641 p = strrchr(sourcepkg, '.');
2642 if (!p || strcmp(p, ".rpm") != 0)
2645 repodata_set_str(data, solvid, SOLVABLE_SOURCENAME, sourcepkg);
2649 while (p > sourcepkg && *p != '.')
2651 if (*p != '.' || p == sourcepkg)
2654 while (p > sourcepkg && *p != '-')
2656 if (*p != '-' || p == sourcepkg)
2659 while (p > sourcepkg && *p != '-')
2661 if (*p != '-' || p == sourcepkg)
2664 pool = s->repo->pool;
2666 name = pool_id2str(pool, s->name);
2667 if (name && !strncmp(sourcepkg, name, sevr - sourcepkg - 1) && name[sevr - sourcepkg - 1] == 0)
2668 repodata_set_void(data, solvid, SOLVABLE_SOURCENAME);
2670 repodata_set_id(data, solvid, SOLVABLE_SOURCENAME, pool_strn2id(pool, sourcepkg, sevr - sourcepkg - 1, 1));
2672 evr = evrid2vrstr(pool, s->evr);
2673 if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0)
2674 repodata_set_void(data, solvid, SOLVABLE_SOURCEEVR);
2676 repodata_set_id(data, solvid, SOLVABLE_SOURCEEVR, pool_strn2id(pool, sevr, sarch - sevr - 1, 1));
2678 if (!strcmp(sarch, "src.rpm"))
2679 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_SRC);
2680 else if (!strcmp(sarch, "nosrc.rpm"))
2681 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, ARCH_NOSRC);
2683 repodata_set_constantid(data, solvid, SOLVABLE_SOURCEARCH, pool_strn2id(pool, sarch, strlen(sarch) - 4, 1));
2687 repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
2693 key.type = REPOKEY_TYPE_IDARRAY;
2695 key.storage = KEY_STORAGE_INCORE;
2696 repodata_set(data, solvid, &key, data->attriddatalen);
2697 data->attriddata = solv_extend(data->attriddata, data->attriddatalen, q->count + 1, sizeof(Id), REPODATA_ATTRIDDATA_BLOCK);
2698 for (i = 0; i < q->count; i++)
2699 data->attriddata[data->attriddatalen++] = q->elements[i];
2700 data->attriddata[data->attriddatalen++] = 0;
2704 repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2)
2708 fprintf(stderr, "repodata_add_dirnumnum %d %d %d %d (%d)\n", solvid, dir, num, num2, data->attriddatalen);
2710 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRNUMNUMARRAY, 3);
2711 data->attriddata[data->attriddatalen++] = dir;
2712 data->attriddata[data->attriddatalen++] = num;
2713 data->attriddata[data->attriddatalen++] = num2;
2714 data->attriddata[data->attriddatalen++] = 0;
2718 repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str)
2724 l = strlen(str) + 1;
2725 data->attrdata = solv_extend(data->attrdata, data->attrdatalen, l, 1, REPODATA_ATTRDATA_BLOCK);
2726 memcpy(data->attrdata + data->attrdatalen, str, l);
2727 stroff = data->attrdatalen;
2728 data->attrdatalen += l;
2731 fprintf(stderr, "repodata_add_dirstr %d %d %s (%d)\n", solvid, dir, str, data->attriddatalen);
2733 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_DIRSTRARRAY, 2);
2734 data->attriddata[data->attriddatalen++] = dir;
2735 data->attriddata[data->attriddatalen++] = stroff;
2736 data->attriddata[data->attriddatalen++] = 0;
2740 repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id)
2743 fprintf(stderr, "repodata_add_idarray %d %d (%d)\n", solvid, id, data->attriddatalen);
2745 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_IDARRAY, 1);
2746 data->attriddata[data->attriddatalen++] = id;
2747 data->attriddata[data->attriddatalen++] = 0;
2751 repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
2755 if (data->localpool)
2756 id = stringpool_str2id(&data->spool, str, 1);
2758 id = pool_str2id(data->repo->pool, str, 1);
2759 repodata_add_idarray(data, solvid, keyname, id);
2763 repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2765 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
2766 data->attriddata[data->attriddatalen++] = ghandle;
2767 data->attriddata[data->attriddatalen++] = 0;
2771 repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
2773 repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
2774 data->attriddata[data->attriddatalen++] = ghandle;
2775 data->attriddata[data->attriddatalen++] = 0;
2779 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
2782 app = repodata_get_attrp(data, solvid);
2786 for (; *ap; ap += 2)
2787 if (data->keys[*ap].name == keyname)
2793 for (; *ap; ap += 2)
2795 if (data->keys[*ap].name == keyname)
2803 /* XXX: does not work correctly, needs fix in iterators! */
2805 repodata_unset(Repodata *data, Id solvid, Id keyname)
2809 key.type = REPOKEY_TYPE_DELETED;
2811 key.storage = KEY_STORAGE_INCORE;
2812 repodata_set(data, solvid, &key, 0);
2815 /* add all (uninternalized) attrs from src to dest */
2817 repodata_merge_attrs(Repodata *data, Id dest, Id src)
2820 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2822 for (; *keyp; keyp += 2)
2823 repodata_insert_keyid(data, dest, keyp[0], keyp[1], 0);
2826 /* add some (uninternalized) attrs from src to dest */
2828 repodata_merge_some_attrs(Repodata *data, Id dest, Id src, Map *keyidmap, int overwrite)
2831 if (dest == src || !data->attrs || !(keyp = data->attrs[src - data->start]))
2833 for (; *keyp; keyp += 2)
2834 if (!keyidmap || MAPTST(keyidmap, keyp[0]))
2835 repodata_insert_keyid(data, dest, keyp[0], keyp[1], overwrite);
2838 /* swap (uninternalized) attrs from src and dest */
2840 repodata_swap_attrs(Repodata *data, Id dest, Id src)
2843 if (!data->attrs || dest == src)
2845 tmpattrs = data->attrs[dest - data->start];
2846 data->attrs[dest - data->start] = data->attrs[src - data->start];
2847 data->attrs[src - data->start] = tmpattrs;
2851 /**********************************************************************/
2853 /* TODO: unify with repo_write and repo_solv! */
2855 #define EXTDATA_BLOCK 1023
2863 data_addid(struct extdata *xd, Id sx)
2865 unsigned int x = (unsigned int)sx;
2868 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2869 dp = xd->buf + xd->len;
2874 *dp++ = (x >> 28) | 128;
2876 *dp++ = (x >> 21) | 128;
2877 *dp++ = (x >> 14) | 128;
2880 *dp++ = (x >> 7) | 128;
2882 xd->len = dp - xd->buf;
2886 data_addid64(struct extdata *xd, unsigned long long x)
2888 if (x >= 0x100000000)
2892 data_addid(xd, (Id)(x >> 35));
2893 xd->buf[xd->len - 1] |= 128;
2895 data_addid(xd, (Id)((unsigned int)x | 0x80000000));
2896 xd->buf[xd->len - 5] = (x >> 28) | 128;
2899 data_addid(xd, (Id)x);
2903 data_addideof(struct extdata *xd, Id sx, int eof)
2905 unsigned int x = (unsigned int)sx;
2908 xd->buf = solv_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
2909 dp = xd->buf + xd->len;
2914 *dp++ = (x >> 27) | 128;
2916 *dp++ = (x >> 20) | 128;
2917 *dp++ = (x >> 13) | 128;
2920 *dp++ = (x >> 6) | 128;
2921 *dp++ = eof ? (x & 63) : (x & 63) | 64;
2922 xd->len = dp - xd->buf;
2926 data_addblob(struct extdata *xd, unsigned char *blob, int len)
2928 xd->buf = solv_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
2929 memcpy(xd->buf + xd->len, blob, len);
2933 /*********************************/
2935 /* internalalize some key into incore/vincore data */
2938 repodata_serialize_key(Repodata *data, struct extdata *newincore,
2939 struct extdata *newvincore,
2941 Repokey *key, Id val)
2945 unsigned int oldvincorelen = 0;
2949 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
2952 oldvincorelen = xd->len;
2956 case REPOKEY_TYPE_VOID:
2957 case REPOKEY_TYPE_CONSTANT:
2958 case REPOKEY_TYPE_CONSTANTID:
2960 case REPOKEY_TYPE_STR:
2961 data_addblob(xd, data->attrdata + val, strlen((char *)(data->attrdata + val)) + 1);
2963 case REPOKEY_TYPE_MD5:
2964 data_addblob(xd, data->attrdata + val, SIZEOF_MD5);
2966 case REPOKEY_TYPE_SHA1:
2967 data_addblob(xd, data->attrdata + val, SIZEOF_SHA1);
2969 case REPOKEY_TYPE_SHA224:
2970 data_addblob(xd, data->attrdata + val, SIZEOF_SHA224);
2972 case REPOKEY_TYPE_SHA256:
2973 data_addblob(xd, data->attrdata + val, SIZEOF_SHA256);
2975 case REPOKEY_TYPE_SHA384:
2976 data_addblob(xd, data->attrdata + val, SIZEOF_SHA384);
2978 case REPOKEY_TYPE_SHA512:
2979 data_addblob(xd, data->attrdata + val, SIZEOF_SHA512);
2981 case REPOKEY_TYPE_NUM:
2982 if (val & 0x80000000)
2984 data_addid64(xd, data->attrnum64data[val ^ 0x80000000]);
2988 case REPOKEY_TYPE_ID:
2989 case REPOKEY_TYPE_DIR:
2990 data_addid(xd, val);
2992 case REPOKEY_TYPE_BINARY:
2995 unsigned char *dp = data_read_id(data->attrdata + val, &len);
2996 dp += (unsigned int)len;
2997 data_addblob(xd, data->attrdata + val, dp - (data->attrdata + val));
3000 case REPOKEY_TYPE_IDARRAY:
3001 for (ida = data->attriddata + val; *ida; ida++)
3002 data_addideof(xd, ida[0], ida[1] ? 0 : 1);
3004 case REPOKEY_TYPE_DIRNUMNUMARRAY:
3005 for (ida = data->attriddata + val; *ida; ida += 3)
3007 data_addid(xd, ida[0]);
3008 data_addid(xd, ida[1]);
3009 data_addideof(xd, ida[2], ida[3] ? 0 : 1);
3012 case REPOKEY_TYPE_DIRSTRARRAY:
3013 for (ida = data->attriddata + val; *ida; ida += 2)
3015 data_addideof(xd, ida[0], ida[2] ? 0 : 1);
3016 data_addblob(xd, data->attrdata + ida[1], strlen((char *)(data->attrdata + ida[1])) + 1);
3019 case REPOKEY_TYPE_FIXARRAY:
3023 for (ida = data->attriddata + val; *ida; ida++)
3027 kp = data->xattrs[-*ida];
3035 schemaid = repodata_schema2id(data, schema, 1);
3036 else if (schemaid != repodata_schema2id(data, schema, 0))
3038 pool_debug(data->repo->pool, SOLV_FATAL, "fixarray substructs with different schemas\n");
3044 data_addid(xd, num);
3045 data_addid(xd, schemaid);
3046 for (ida = data->attriddata + val; *ida; ida++)
3048 Id *kp = data->xattrs[-*ida];
3052 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3056 case REPOKEY_TYPE_FLEXARRAY:
3059 for (ida = data->attriddata + val; *ida; ida++)
3061 data_addid(xd, num);
3062 for (ida = data->attriddata + val; *ida; ida++)
3064 Id *kp = data->xattrs[-*ida];
3067 data_addid(xd, 0); /* XXX */
3074 schemaid = repodata_schema2id(data, schema, 1);
3075 data_addid(xd, schemaid);
3076 kp = data->xattrs[-*ida];
3078 repodata_serialize_key(data, newincore, newvincore, schema, data->keys + *kp, kp[1]);
3083 pool_debug(data->repo->pool, SOLV_FATAL, "don't know how to handle type %d\n", key->type);
3086 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3088 /* put offset/len in incore */
3089 data_addid(newincore, data->lastverticaloffset + oldvincorelen);
3090 oldvincorelen = xd->len - oldvincorelen;
3091 data_addid(newincore, oldvincorelen);
3096 repodata_internalize(Repodata *data)
3098 Repokey *key, solvkey;
3100 Id schemaid, keyid, *schema, *sp, oldschema, *keyp, *seen;
3102 unsigned char *dp, *ndp;
3103 int newschema, oldcount;
3104 struct extdata newincore;
3105 struct extdata newvincore;
3108 if (!data->attrs && !data->xattrs)
3111 newvincore.buf = data->vincore;
3112 newvincore.len = data->vincorelen;
3114 /* find the solvables key, create if needed */
3115 memset(&solvkey, 0, sizeof(solvkey));
3116 solvkey.name = REPOSITORY_SOLVABLES;
3117 solvkey.type = REPOKEY_TYPE_FLEXARRAY;
3119 solvkey.storage = KEY_STORAGE_INCORE;
3120 solvkeyid = repodata_key2id(data, &solvkey, data->end != data->start ? 1 : 0);
3122 schema = solv_malloc2(data->nkeys, sizeof(Id));
3123 seen = solv_malloc2(data->nkeys, sizeof(Id));
3125 /* Merge the data already existing (in data->schemata, ->incoredata and
3126 friends) with the new attributes in data->attrs[]. */
3127 nentry = data->end - data->start;
3128 memset(&newincore, 0, sizeof(newincore));
3129 data_addid(&newincore, 0); /* start data at offset 1 */
3131 data->mainschema = 0;
3132 data->mainschemaoffsets = solv_free(data->mainschemaoffsets);
3134 /* join entry data */
3135 /* we start with the meta data, entry -1 */
3136 for (entry = -1; entry < nentry; entry++)
3138 memset(seen, 0, data->nkeys * sizeof(Id));
3140 dp = data->incoredata;
3143 dp += entry >= 0 ? data->incoreoffset[entry] : 1;
3144 dp = data_read_id(dp, &oldschema);
3147 fprintf(stderr, "oldschema %d\n", oldschema);
3148 fprintf(stderr, "schemata %d\n", data->schemata[oldschema]);
3149 fprintf(stderr, "schemadata %p\n", data->schemadata);
3151 /* seen: -1: old data 0: skipped >0: id + 1 */
3155 for (keyp = data->schemadata + data->schemata[oldschema]; *keyp; keyp++)
3159 pool_debug(data->repo->pool, SOLV_FATAL, "Inconsistent old data (key occured twice).\n");
3167 keyp = data->attrs ? data->attrs[entry] : 0;
3170 /* strip solvables key */
3172 for (sp = keyp = schema; *sp; sp++)
3173 if (*sp != solvkeyid)
3178 seen[solvkeyid] = 0;
3179 keyp = data->xattrs ? data->xattrs[1] : 0;
3182 for (; *keyp; keyp += 2)
3189 seen[*keyp] = keyp[1] + 1;
3191 if (entry < 0 && data->end != data->start)
3198 /* Ideally we'd like to sort the new schema here, to ensure
3199 schema equality independend of the ordering. We can't do that
3200 yet. For once see below (old ids need to come before new ids).
3201 An additional difficulty is that we also need to move
3202 the values with the keys. */
3203 schemaid = repodata_schema2id(data, schema, 1);
3205 schemaid = oldschema;
3208 /* Now create data blob. We walk through the (possibly new) schema
3209 and either copy over old data, or insert the new. */
3210 /* XXX Here we rely on the fact that the (new) schema has the form
3211 o1 o2 o3 o4 ... | n1 n2 n3 ...
3212 (oX being the old keyids (possibly overwritten), and nX being
3213 the new keyids). This rules out sorting the keyids in order
3214 to ensure a small schema count. */
3216 data->incoreoffset[entry] = newincore.len;
3217 data_addid(&newincore, schemaid);
3220 data->mainschema = schemaid;
3221 data->mainschemaoffsets = solv_calloc(sp - schema, sizeof(Id));
3223 /* we don't use a pointer to the schemadata here as repodata_serialize_key
3224 * may call repodata_schema2id() which might realloc our schemadata */
3225 for (schemaidx = data->schemata[schemaid]; (keyid = data->schemadata[schemaidx]) != 0; schemaidx++)
3228 data->mainschemaoffsets[schemaidx - data->schemata[schemaid]] = newincore.len;
3229 if (keyid == solvkeyid)
3231 /* add flexarray entry count */
3232 data_addid(&newincore, data->end - data->start);
3235 key = data->keys + keyid;
3237 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));
3242 /* Skip the data associated with this old key. */
3243 if (key->storage == KEY_STORAGE_VERTICAL_OFFSET)
3245 ndp = data_skip(dp, REPOKEY_TYPE_ID);
3246 ndp = data_skip(ndp, REPOKEY_TYPE_ID);
3248 else if (key->storage == KEY_STORAGE_INCORE)
3249 ndp = data_skip_key(data, dp, key);
3252 if (seen[keyid] == -1)
3254 /* If this key was an old one _and_ was not overwritten with
3255 a different value copy over the old value (we skipped it
3258 data_addblob(&newincore, dp, ndp - dp);
3261 else if (seen[keyid])
3263 /* Otherwise we have a new value. Parse it into the internal form. */
3264 repodata_serialize_key(data, &newincore, &newvincore, schema, key, seen[keyid] - 1);
3268 if (entry >= 0 && data->attrs && data->attrs[entry])
3269 data->attrs[entry] = solv_free(data->attrs[entry]);
3271 /* free all xattrs */
3272 for (entry = 0; entry < data->nxattrs; entry++)
3273 if (data->xattrs[entry])
3274 solv_free(data->xattrs[entry]);
3275 data->xattrs = solv_free(data->xattrs);
3278 data->lasthandle = 0;
3280 data->lastdatalen = 0;
3283 repodata_free_schemahash(data);
3285 solv_free(data->incoredata);
3286 data->incoredata = newincore.buf;
3287 data->incoredatalen = newincore.len;
3288 data->incoredatafree = 0;
3290 solv_free(data->vincore);
3291 data->vincore = newvincore.buf;
3292 data->vincorelen = newvincore.len;
3294 data->attrs = solv_free(data->attrs);
3295 data->attrdata = solv_free(data->attrdata);
3296 data->attriddata = solv_free(data->attriddata);
3297 data->attrnum64data = solv_free(data->attrnum64data);
3298 data->attrdatalen = 0;
3299 data->attriddatalen = 0;
3300 data->attrnum64datalen = 0;
3304 repodata_disable_paging(Repodata *data)
3306 if (maybe_load_repodata(data, 0))
3308 repopagestore_disable_paging(&data->store);
3314 repodata_load_stub(Repodata *data)
3316 Repo *repo = data->repo;
3317 Pool *pool = repo->pool;
3319 struct _Pool_tmpspace oldtmpspace;
3322 if (!pool->loadcallback)
3324 data->state = REPODATA_ERROR;
3327 data->state = REPODATA_LOADING;
3329 /* save tmp space and pos */
3330 oldtmpspace = pool->tmpspace;
3331 memset(&pool->tmpspace, 0, sizeof(pool->tmpspace));
3334 r = pool->loadcallback(pool, data, pool->loadcallbackdata);
3336 /* restore tmp space and pos */
3337 for (i = 0; i < POOL_TMPSPACEBUF; i++)
3338 solv_free(pool->tmpspace.buf[i]);
3339 pool->tmpspace = oldtmpspace;
3340 if (r && oldpos.repo == repo && oldpos.repodataid == data->repodataid)
3341 memset(&oldpos, 0, sizeof(oldpos));
3344 data->state = r ? REPODATA_AVAILABLE : REPODATA_ERROR;
3348 repodata_add_stubkey(Repodata *data, Id keyname, Id keytype)
3352 xkey.name = keyname;
3353 xkey.type = keytype;
3354 xkey.storage = KEY_STORAGE_INCORE;
3356 repodata_key2id(data, &xkey, 1);
3360 repodata_add_stub(Repodata **datap)
3362 Repodata *data = *datap;
3363 Repo *repo = data->repo;
3364 Id repodataid = data - repo->repodata;
3365 Repodata *sdata = repo_add_repodata(repo, 0);
3366 data = repo->repodata + repodataid;
3367 if (data->end > data->start)
3368 repodata_extend_block(sdata, data->start, data->end - data->start);
3369 sdata->state = REPODATA_STUB;
3370 sdata->loadcallback = repodata_load_stub;
3376 repodata_create_stubs(Repodata *data)
3378 Repo *repo = data->repo;
3379 Pool *pool = repo->pool;
3386 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3387 while (dataiterator_step(&di))
3388 if (di.data == data)
3390 dataiterator_free(&di);
3393 stubdataids = solv_calloc(cnt, sizeof(*stubdataids));
3394 for (i = 0; i < cnt; i++)
3396 sdata = repodata_add_stub(&data);
3397 stubdataids[i] = sdata - repo->repodata;
3400 dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_EXTERNAL, 0, 0);
3402 while (dataiterator_step(&di))
3404 if (di.data != data)
3406 if (di.key->name == REPOSITORY_EXTERNAL && !di.nparents)
3408 dataiterator_entersub(&di);
3409 sdata = repo->repodata + stubdataids[i++];
3413 switch (di.key->type)
3415 case REPOKEY_TYPE_ID:
3416 repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
3418 case REPOKEY_TYPE_CONSTANTID:
3419 repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
3421 case REPOKEY_TYPE_STR:
3422 repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
3424 case REPOKEY_TYPE_VOID:
3425 repodata_set_void(sdata, SOLVID_META, di.key->name);
3427 case REPOKEY_TYPE_NUM:
3428 repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
3430 case REPOKEY_TYPE_MD5:
3431 case REPOKEY_TYPE_SHA1:
3432 case REPOKEY_TYPE_SHA224:
3433 case REPOKEY_TYPE_SHA256:
3434 case REPOKEY_TYPE_SHA384:
3435 case REPOKEY_TYPE_SHA512:
3436 repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
3438 case REPOKEY_TYPE_IDARRAY:
3439 repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
3440 if (di.key->name == REPOSITORY_KEYS)
3445 xkeyname = di.kv.id;
3449 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
3458 dataiterator_free(&di);
3459 for (i = 0; i < cnt; i++)
3460 repodata_internalize(repo->repodata + stubdataids[i]);
3461 solv_free(stubdataids);
3466 repodata_memused(Repodata *data)
3468 return data->incoredatalen + data->vincorelen;