2 * Copyright (c) 2007-2011, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Write Repo data out to a file in solv format
13 * See doc/README.format for a description
14 * of the binary file format
18 #include <sys/types.h>
28 #include "repo_write.h"
31 /*------------------------------------------------------------------*/
32 /* Id map optimizations */
34 typedef struct needid {
40 #define RELOFF(id) (needid[0].map + GETRELID(id))
44 * idarray: array of Ids, ID_NULL terminated
45 * needid: array of Id->NeedId
47 * return size of array (including trailing zero)
52 incneedid(Pool *pool, Id id, NeedId *needid)
56 Reldep *rd = GETRELDEP(pool, id);
57 needid[RELOFF(id)].need++;
58 if (ISRELDEP(rd->evr))
59 incneedid(pool, rd->evr, needid);
61 needid[rd->evr].need++;
68 incneedidarray(Pool *pool, Id *idarray, NeedId *needid)
75 while ((id = *idarray++) != 0)
80 Reldep *rd = GETRELDEP(pool, id);
81 needid[RELOFF(id)].need++;
82 if (ISRELDEP(rd->evr))
83 incneedid(pool, rd->evr, needid);
85 needid[rd->evr].need++;
99 needid_cmp_need(const void *ap, const void *bp, void *dp)
101 const NeedId *a = ap;
102 const NeedId *b = bp;
104 r = b->need - a->need;
107 return a->map - b->map;
111 needid_cmp_need_s(const void *ap, const void *bp, void *dp)
113 const NeedId *a = ap;
114 const NeedId *b = bp;
115 Stringpool *spool = dp;
118 r = b->need - a->need;
121 const char *as = spool->stringspace + spool->strings[a->map];
122 const char *bs = spool->stringspace + spool->strings[b->map];
123 return strcmp(as, bs);
127 /*------------------------------------------------------------------*/
128 /* output helper routines, used for writing the header */
129 /* (the data itself is accumulated in memory and written with
137 write_u32(FILE *fp, unsigned int x)
139 if (putc(x >> 24, fp) == EOF ||
140 putc(x >> 16, fp) == EOF ||
141 putc(x >> 8, fp) == EOF ||
144 perror("write error u32");
155 write_u8(FILE *fp, unsigned int x)
157 if (putc(x, fp) == EOF)
159 perror("write error u8");
169 write_blob(FILE *fp, void *data, int len)
171 if (len && fwrite(data, len, 1, fp) != 1)
173 perror("write error blob");
183 write_id(FILE *fp, Id x)
188 putc((x >> 28) | 128, fp);
190 putc((x >> 21) | 128, fp);
191 putc((x >> 14) | 128, fp);
194 putc((x >> 7) | 128, fp);
195 if (putc(x & 127, fp) == EOF)
197 perror("write error id");
203 write_id_eof(FILE *fp, Id x, int eof)
206 x = (x & 63) | ((x & ~63) << 1);
207 write_id(fp, x | (eof ? 0 : 64));
213 write_str(FILE *fp, const char *str)
215 if (fputs(str, fp) == EOF || putc(0, fp) == EOF)
217 perror("write error str");
227 write_idarray(FILE *fp, Pool *pool, NeedId *needid, Id *ids)
241 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
243 id = (id & 63) | ((id & ~63) << 1);
249 write_id(fp, id | 64);
254 cmp_ids(const void *pa, const void *pb, void *dp)
263 write_idarray_sort(FILE *fp, Pool *pool, NeedId *needid, Id *ids, Id marker)
275 for (len = 0; len < 64 && ids[len]; len++)
279 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
284 for (i = len + 1; ids[i]; i++)
286 sids = sat_malloc2(i, sizeof(Id));
287 memcpy(sids, lids, 64 * sizeof(Id));
288 for (; ids[len]; len++)
292 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
299 /* That bloody solvable:prereqmarker needs to stay in position :-( */
301 marker = needid[marker].need;
302 for (i = 0; i < len; i++)
303 if (sids[i] == marker)
306 sat_sort(sids, i, sizeof(Id), cmp_ids, 0);
308 sat_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
312 /* The differencing above produces many runs of ones and twos. I tried
313 fairly elaborate schemes to RLE those, but they give only very mediocre
314 improvements in compression, as coding the escapes costs quite some
315 space. Even if they are coded only as bits in IDs. The best improvement
316 was about 2.7% for the whole .solv file. It's probably better to
317 invest some complexity into sharing idarrays, than RLEing. */
318 for (i = 0; i < len - 1; i++)
321 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
322 hence all real differences are offsetted by 1. Otherwise we would
323 have to handle negative differences, which would cost code space for
324 the encoding of the sign. We loose the exact mapping of prereq here,
325 but we know the result, so we can recover from that in the reader. */
333 /* XXX If difference is zero we have multiple equal elements,
334 we might want to skip writing them out. */
336 id = (id & 63) | ((id & ~63) << 1);
337 write_id(fp, id | 64);
345 id = (id & 63) | ((id & ~63) << 1);
362 Stringpool *ownspool;
371 Id *schema; /* schema construction space */
372 Id *sp; /* pointer in above */
373 Id *oldschema, *oldsp;
380 struct extdata *extdata;
389 int doingsolvables; /* working on solvables data */
392 #define NEEDED_BLOCK 1023
393 #define SCHEMATA_BLOCK 31
394 #define SCHEMATADATA_BLOCK 255
395 #define EXTDATA_BLOCK 4095
398 data_addid(struct extdata *xd, Id x)
401 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
402 dp = xd->buf + xd->len;
407 *dp++ = (x >> 28) | 128;
409 *dp++ = (x >> 21) | 128;
410 *dp++ = (x >> 14) | 128;
413 *dp++ = (x >> 7) | 128;
415 xd->len = dp - xd->buf;
419 data_addideof(struct extdata *xd, Id x, int eof)
422 x = (x & 63) | ((x & ~63) << 1);
423 data_addid(xd, (eof ? x: x | 64));
427 data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
439 for (len = 0; len < 64 && ids[len]; len++)
443 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
448 for (i = len + 1; ids[i]; i++)
450 sids = sat_malloc2(i, sizeof(Id));
451 memcpy(sids, lids, 64 * sizeof(Id));
452 for (; ids[len]; len++)
456 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
463 /* That bloody solvable:prereqmarker needs to stay in position :-( */
465 marker = needid[marker].need;
466 for (i = 0; i < len; i++)
467 if (sids[i] == marker)
470 sat_sort(sids, i, sizeof(Id), cmp_ids, 0);
472 sat_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
476 /* The differencing above produces many runs of ones and twos. I tried
477 fairly elaborate schemes to RLE those, but they give only very mediocre
478 improvements in compression, as coding the escapes costs quite some
479 space. Even if they are coded only as bits in IDs. The best improvement
480 was about 2.7% for the whole .solv file. It's probably better to
481 invest some complexity into sharing idarrays, than RLEing. */
482 for (i = 0; i < len - 1; i++)
485 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
486 hence all real differences are offsetted by 1. Otherwise we would
487 have to handle negative differences, which would cost code space for
488 the encoding of the sign. We loose the exact mapping of prereq here,
489 but we know the result, so we can recover from that in the reader. */
497 /* XXX If difference is zero we have multiple equal elements,
498 we might want to skip writing them out. */
500 id = (id & 63) | ((id & ~63) << 1);
501 data_addid(xd, id | 64);
509 id = (id & 63) | ((id & ~63) << 1);
516 data_addblob(struct extdata *xd, unsigned char *blob, int len)
518 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
519 memcpy(xd->buf + xd->len, blob, len);
524 data_addu32(struct extdata *xd, unsigned int num)
531 data_addblob(xd, d, 4);
535 putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
537 const char *str = stringpool_id2str(ss, id);
538 id = stringpool_str2id(cbdata->ownspool, str, 1);
539 if (id >= cbdata->needid[0].map)
541 int oldoff = cbdata->needid[0].map;
542 int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
543 int nrels = cbdata->repo->pool->nrels;
544 cbdata->needid = sat_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
546 memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
547 memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
548 cbdata->needid[0].map = newoff;
554 putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
558 parent = dirpool_parent(dp, dir);
560 parent = putinowndirpool(cbdata, data, dp, parent);
561 compid = dp->dirs[dir];
562 if (cbdata->ownspool && compid > 1)
563 compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
564 return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
568 * collect usage information about the dirs
569 * 1: dir used, no child of dir used
570 * 2: dir used as parent of another used dir
573 setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
575 if (cbdata->dirused[dir])
577 cbdata->dirused[dir] = 1;
578 while ((dir = dirpool_parent(dp, dir)) != 0)
580 if (cbdata->dirused[dir] == 2)
582 if (cbdata->dirused[dir])
584 cbdata->dirused[dir] = 2;
587 cbdata->dirused[dir] = 2;
589 cbdata->dirused[0] = 2;
594 * collect key/id/dirid usage information, create needed schemas
597 repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
602 if (key->name == REPOSITORY_SOLVABLES)
603 return SEARCH_NEXT_KEY; /* we do not want this one */
604 if (data != data->repo->repodata + data->repo->nrepodata - 1)
605 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
606 return SEARCH_NEXT_KEY;
608 rm = cbdata->keymap[cbdata->keymapstart[data - data->repo->repodata] + (key - data->keys)];
610 return SEARCH_NEXT_KEY; /* we do not want this one */
612 /* record key in schema */
613 if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
614 && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
619 case REPOKEY_TYPE_ID:
620 case REPOKEY_TYPE_IDARRAY:
622 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
623 id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
624 incneedid(repo->pool, id, cbdata->needid);
626 case REPOKEY_TYPE_DIR:
627 case REPOKEY_TYPE_DIRNUMNUMARRAY:
628 case REPOKEY_TYPE_DIRSTRARRAY:
630 if (cbdata->owndirpool)
631 putinowndirpool(cbdata, data, &data->dirpool, id);
633 setdirused(cbdata, &data->dirpool, id);
635 case REPOKEY_TYPE_FIXARRAY:
638 if (cbdata->oldschema)
640 fprintf(stderr, "nested structs not yet implemented\n");
643 cbdata->oldschema = cbdata->schema;
644 cbdata->oldsp = cbdata->sp;
645 cbdata->schema = sat_calloc(cbdata->target->nkeys, sizeof(Id));
646 cbdata->sp = cbdata->schema;
648 else if (kv->eof == 1)
650 cbdata->current_sub++;
652 cbdata->subschemata = sat_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
653 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1);
655 fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
657 cbdata->sp = cbdata->schema;
661 sat_free(cbdata->schema);
662 cbdata->schema = cbdata->oldschema;
663 cbdata->sp = cbdata->oldsp;
664 cbdata->oldsp = cbdata->oldschema = 0;
667 case REPOKEY_TYPE_FLEXARRAY:
671 *cbdata->sp++ = 0; /* mark start */
675 /* just finished a schema, rewind */
676 Id *sp = cbdata->sp - 1;
680 cbdata->subschemata = sat_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
681 cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
682 cbdata->sp = kv->eof == 2 ? sp - 1: sp;
692 repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
694 struct cbdata *cbdata = vcbdata;
695 Repo *repo = data->repo;
699 fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? s - repo->pool->solvables : 0, s ? id2str(repo->pool, s->name) : "", key->name, id2str(repo->pool, key->name), key->type);
701 return repo_write_collect_needed(cbdata, repo, data, key, kv);
707 * encode all of the data into the correct buffers
711 repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
720 if (key->name == REPOSITORY_SOLVABLES)
721 return SEARCH_NEXT_KEY;
722 if (data != data->repo->repodata + data->repo->nrepodata - 1)
723 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
724 return SEARCH_NEXT_KEY;
726 rm = cbdata->keymap[cbdata->keymapstart[data - data->repo->repodata] + (key - data->keys)];
728 return SEARCH_NEXT_KEY; /* we do not want this one */
730 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
732 xd = cbdata->extdata + rm; /* vertical buffer */
733 if (cbdata->vstart == -1)
734 cbdata->vstart = xd->len;
737 xd = cbdata->extdata + 0; /* incore buffer */
740 case REPOKEY_TYPE_VOID:
741 case REPOKEY_TYPE_CONSTANT:
742 case REPOKEY_TYPE_CONSTANTID:
744 case REPOKEY_TYPE_ID:
746 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
747 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
748 needid = cbdata->needid;
749 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
752 case REPOKEY_TYPE_IDARRAY:
754 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
755 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
756 needid = cbdata->needid;
757 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
758 data_addideof(xd, id, kv->eof);
760 case REPOKEY_TYPE_STR:
761 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
763 case REPOKEY_TYPE_MD5:
764 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
766 case REPOKEY_TYPE_SHA1:
767 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
769 case REPOKEY_TYPE_SHA256:
770 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
772 case REPOKEY_TYPE_U32:
778 data_addblob(xd, v, 4);
780 case REPOKEY_TYPE_NUM:
781 data_addid(xd, kv->num);
783 case REPOKEY_TYPE_DIR:
785 if (cbdata->owndirpool)
786 id = putinowndirpool(cbdata, data, &data->dirpool, id);
787 id = cbdata->dirused[id];
790 case REPOKEY_TYPE_BINARY:
791 data_addid(xd, kv->num);
793 data_addblob(xd, (unsigned char *)kv->str, kv->num);
795 case REPOKEY_TYPE_DIRNUMNUMARRAY:
797 if (cbdata->owndirpool)
798 id = putinowndirpool(cbdata, data, &data->dirpool, id);
799 id = cbdata->dirused[id];
801 data_addid(xd, kv->num);
802 data_addideof(xd, kv->num2, kv->eof);
804 case REPOKEY_TYPE_DIRSTRARRAY:
806 if (cbdata->owndirpool)
807 id = putinowndirpool(cbdata, data, &data->dirpool, id);
808 id = cbdata->dirused[id];
809 data_addideof(xd, id, kv->eof);
810 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
812 case REPOKEY_TYPE_FIXARRAY:
817 data_addid(xd, kv->num);
818 data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
820 fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
824 else if (kv->eof == 1)
826 cbdata->current_sub++;
829 case REPOKEY_TYPE_FLEXARRAY:
831 data_addid(xd, kv->num);
833 data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
834 if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
836 if (xd->len - cbdata->lastlen > cbdata->maxdata)
837 cbdata->maxdata = xd->len - cbdata->lastlen;
838 cbdata->lastlen = xd->len;
842 fprintf(stderr, "unknown type for %d: %d\n", key->name, key->type);
845 if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
847 /* we can re-use old data in the blob here! */
848 data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */
849 data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */
856 repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
858 struct cbdata *cbdata = vcbdata;
859 return repo_write_adddata(cbdata, data, key, kv);
862 /* traverse through directory with first child "dir" */
864 traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
870 /* special case for '/', which has to come first */
873 for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
875 if (used && !used[sib])
877 if (sib == 1 && parent == 1)
878 continue; /* already did that one above */
882 /* now go through all the siblings we just added and
883 * do recursive calls on them */
885 for (; parent < lastn; parent++)
887 sib = dirmap[parent];
888 if (used && used[sib] != 2) /* 2: used as parent */
890 child = dirpool_child(dp, sib);
893 dirmap[n++] = -parent; /* start new block */
894 n = traverse_dirs(dp, dirmap, n, child, used);
901 write_compressed_page(FILE *fp, unsigned char *page, int len)
904 unsigned char cpage[BLOB_PAGESIZE];
906 clen = repopagestore_compress_page(page, len, cpage, len - 1);
909 write_u32(fp, len * 2);
910 write_blob(fp, page, len);
914 write_u32(fp, clen * 2 + 1);
915 write_blob(fp, cpage, clen);
919 static Id verticals[] = {
921 SOLVABLE_DESCRIPTION,
930 static char *languagetags[] = {
932 "solvable:description:",
933 "solvable:messageins:",
934 "solvable:messagedel:",
940 repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
945 for (i = 0; verticals[i]; i++)
946 if (key->name == verticals[i])
947 return KEY_STORAGE_VERTICAL_OFFSET;
948 keyname = id2str(repo->pool, key->name);
949 for (i = 0; languagetags[i] != 0; i++)
950 if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
951 return KEY_STORAGE_VERTICAL_OFFSET;
952 return KEY_STORAGE_INCORE;
960 * the code works the following way:
962 * 1) find which keys should be written
963 * 2) collect usage information for keys/ids/dirids, create schema
965 * 3) use usage information to create mapping tables, so that often
966 * used ids get a lower number
967 * 4) encode data into buffers using the mapping tables
968 * 5) write everything to disk
971 repo_write(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Id **keyarrayp)
973 Pool *pool = repo->pool;
979 unsigned int solv_flags;
988 unsigned char *repodataused;
989 int anyrepodataused = 0;
990 int anysolvableused = 0;
992 struct cbdata cbdata;
995 int poolusage, dirpoolusage, idused, dirused;
998 Repodata *data, *dirpooldata;
1009 Id type_constantid = 0;
1012 memset(&cbdata, 0, sizeof(cbdata));
1014 cbdata.target = ⌖
1016 repodata_initdata(&target, repo, 1);
1018 /* go through all repodata and find the keys we need */
1019 /* also unify keys */
1020 /* keymapstart - maps repo number to keymap offset */
1021 /* keymap - maps repo key to my key, 0 -> not used */
1023 /* start with all KEY_STORAGE_SOLVABLE ids */
1025 n = ID_NUM_INTERNAL;
1026 for (i = 0; i < repo->nrepodata; i++)
1027 n += repo->repodata[i].nkeys;
1028 cbdata.keymap = sat_calloc(n, sizeof(Id));
1029 cbdata.keymapstart = sat_calloc(repo->nrepodata, sizeof(Id));
1030 repodataused = sat_calloc(repo->nrepodata, 1);
1035 /* add keys for STORAGE_SOLVABLE */
1036 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
1040 if (i < SOLVABLE_PROVIDES)
1041 keyd.type = REPOKEY_TYPE_ID;
1042 else if (i < RPM_RPMDBID)
1043 keyd.type = REPOKEY_TYPE_REL_IDARRAY;
1045 keyd.type = REPOKEY_TYPE_U32;
1047 keyd.storage = KEY_STORAGE_SOLVABLE;
1050 keyd.storage = keyfilter(repo, &keyd, kfdata);
1051 if (keyd.storage == KEY_STORAGE_DROPPED)
1053 keyd.storage = KEY_STORAGE_SOLVABLE;
1057 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1060 if (repo->nsolvables)
1063 keyd.name = REPOSITORY_SOLVABLES;
1064 keyd.type = REPOKEY_TYPE_FLEXARRAY;
1066 keyd.storage = KEY_STORAGE_INCORE;
1067 cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
1075 n = ID_NUM_INTERNAL;
1076 for (i = 0; i < repo->nrepodata; i++)
1078 data = repo->repodata + i;
1079 cbdata.keymapstart[i] = n;
1080 cbdata.keymap[n++] = 0; /* key 0 */
1086 /* check if we want this repodata */
1087 memset(&keyd, 0, sizeof(keyd));
1091 if (keyfilter(repo, &keyd, kfdata) == -1)
1094 for (j = 1; j < data->nkeys; j++, n++)
1096 key = data->keys + j;
1097 if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
1099 cbdata.keymap[n] = cbdata.keymap[key->name];
1102 if (key->type == REPOKEY_TYPE_DELETED)
1104 cbdata.keymap[n] = 0;
1107 id = repodata_key2id(&target, key, 0);
1110 Repokey keyd = *key;
1111 keyd.storage = KEY_STORAGE_INCORE;
1112 if (keyd.type != REPOKEY_TYPE_CONSTANT && keyd.type != REPOKEY_TYPE_CONSTANTID)
1116 keyd.storage = keyfilter(repo, &keyd, kfdata);
1117 if (keyd.storage == KEY_STORAGE_DROPPED)
1119 cbdata.keymap[n] = 0;
1123 id = repodata_key2id(&target, &keyd, 1);
1125 cbdata.keymap[n] = id;
1126 /* load repodata if not already loaded */
1127 if (data->state == REPODATA_STUB)
1129 if (data->loadcallback)
1130 data->loadcallback(data);
1132 data->state = REPODATA_ERROR;
1133 if (data->state != REPODATA_ERROR)
1135 /* redo this repodata! */
1137 n = cbdata.keymapstart[i];
1141 if (data->state == REPODATA_ERROR)
1144 cbdata.keymap[n] = 0;
1148 repodataused[i] = 1;
1149 anyrepodataused = 1;
1150 if (key->type == REPOKEY_TYPE_CONSTANTID || key->type == REPOKEY_TYPE_ID ||
1151 key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
1153 else if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
1155 idused = 1; /* dirs also use ids */
1161 if (data->localpool)
1164 poolusage = 3; /* need own pool */
1168 spool = &data->spool;
1175 else if (poolusage != 1)
1176 poolusage = 3; /* need own pool */
1182 dirpoolusage = 3; /* need own dirpool */
1186 dirpool = &data->dirpool;
1193 /* 0: no pool needed at all */
1194 /* 1: use global pool */
1195 /* 2: use repodata local pool */
1196 /* 3: need own pool */
1199 spool = &target.spool;
1200 /* hack: reuse global pool data so we don't have to map pool ids */
1203 stringpool_free(spool);
1204 stringpool_clone(spool, &pool->ss);
1206 cbdata.ownspool = spool;
1208 else if (poolusage == 0 || poolusage == 1)
1214 if (dirpoolusage == 3)
1216 dirpool = &target.dirpool;
1218 cbdata.owndirpool = dirpool;
1221 cbdata.dirused = sat_calloc(dirpool->ndirs, sizeof(Id));
1224 /********************************************************************/
1226 fprintf(stderr, "poolusage: %d\n", poolusage);
1227 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
1228 fprintf(stderr, "nkeys: %d\n", target.nkeys);
1229 for (i = 1; i < target.nkeys; i++)
1230 fprintf(stderr, " %2d: %s[%d] %d %d %d\n", i, id2str(pool, target.keys[i].name), target.keys[i].name, target.keys[i].type, target.keys[i].size, target.keys[i].storage);
1235 /* put all the keys we need in our string pool */
1236 for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
1238 stringpool_str2id(spool, id2str(pool, key->name), 1);
1239 stringpool_str2id(spool, id2str(pool, key->type), 1);
1240 if (key->type == REPOKEY_TYPE_CONSTANTID)
1241 stringpool_str2id(spool, id2str(pool, key->size), 1);
1246 /********************************************************************/
1248 /* set needed count of all strings and rels,
1249 * find which keys are used in the solvables
1250 * put all strings in own spool
1253 reloff = spool->nstrings;
1255 reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
1257 needid = calloc(reloff + pool->nrels, sizeof(*needid));
1258 needid[0].map = reloff;
1260 cbdata.needid = needid;
1261 cbdata.schema = sat_calloc(target.nkeys, sizeof(Id));
1262 cbdata.sp = cbdata.schema;
1263 cbdata.solvschemata = sat_calloc(repo->nsolvables, sizeof(Id));
1265 /* create main schema */
1266 cbdata.sp = cbdata.schema;
1267 /* collect all other data from all repodatas */
1268 /* XXX: merge arrays of equal keys? */
1269 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1271 if (!repodataused[j])
1273 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1276 /* add solvables if needed (may revert later) */
1277 if (repo->nsolvables)
1279 *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
1280 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
1283 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1285 idarraydata = repo->idarraydata;
1287 anysolvableused = 0;
1288 cbdata.doingsolvables = 1;
1289 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1291 if (s->repo != repo)
1294 /* set schema info, keep in sync with further down */
1296 if (cbdata.keymap[SOLVABLE_NAME])
1298 *sp++ = cbdata.keymap[SOLVABLE_NAME];
1299 needid[s->name].need++;
1301 if (cbdata.keymap[SOLVABLE_ARCH])
1303 *sp++ = cbdata.keymap[SOLVABLE_ARCH];
1304 needid[s->arch].need++;
1306 if (cbdata.keymap[SOLVABLE_EVR])
1308 *sp++ = cbdata.keymap[SOLVABLE_EVR];
1309 needid[s->evr].need++;
1311 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1313 *sp++ = cbdata.keymap[SOLVABLE_VENDOR];
1314 needid[s->vendor].need++;
1316 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1318 *sp++ = cbdata.keymap[SOLVABLE_PROVIDES];
1319 target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid);
1321 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1323 *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES];
1324 target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
1326 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1328 *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS];
1329 target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
1331 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1333 *sp++ = cbdata.keymap[SOLVABLE_REQUIRES];
1334 target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid);
1336 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1338 *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS];
1339 target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid);
1341 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1343 *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS];
1344 target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid);
1346 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1348 *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS];
1349 target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid);
1351 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1353 *sp++ = cbdata.keymap[SOLVABLE_ENHANCES];
1354 target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid);
1356 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1358 *sp++ = cbdata.keymap[RPM_RPMDBID];
1359 target.keys[cbdata.keymap[RPM_RPMDBID]].size++;
1363 if (anyrepodataused)
1365 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1367 if (!repodataused[j])
1369 if (i < data->start || i >= data->end)
1371 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1372 needid = cbdata.needid;
1376 cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1377 if (cbdata.solvschemata[n])
1378 anysolvableused = 1;
1381 cbdata.doingsolvables = 0;
1382 assert(n == repo->nsolvables);
1384 if (repo->nsolvables && !anysolvableused)
1386 /* strip off solvable from the main schema */
1387 target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0;
1389 for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++)
1391 *sp = target.schemadata[target.schemata[mainschema] + i];
1392 if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES])
1395 assert(target.schemadatalen == target.schemata[mainschema] + i + 1);
1397 target.schemadatalen = target.schemata[mainschema];
1399 repodata_free_schemahash(&target);
1400 mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
1403 /********************************************************************/
1405 /* remove unused keys */
1406 keyused = sat_calloc(target.nkeys, sizeof(Id));
1407 for (i = 1; i < target.schemadatalen; i++)
1408 keyused[target.schemadata[i]] = 1;
1410 for (n = i = 1; i < target.nkeys; i++)
1416 target.keys[n] = target.keys[i];
1420 /* update schema data to the new key ids */
1421 for (i = 1; i < target.schemadatalen; i++)
1422 target.schemadata[i] = keyused[target.schemadata[i]];
1423 /* update keymap to the new key ids */
1424 for (i = 0; i < cbdata.nkeymap; i++)
1425 cbdata.keymap[i] = keyused[cbdata.keymap[i]];
1426 keyused = sat_free(keyused);
1428 /* copy keys if requested */
1431 *keyarrayp = sat_calloc(2 * target.nkeys + 1, sizeof(Id));
1432 for (i = 1; i < target.nkeys; i++)
1434 (*keyarrayp)[2 * i - 2] = target.keys[i].name;
1435 (*keyarrayp)[2 * i - 1] = target.keys[i].type;
1439 /* convert ids to local ids and increment their needid */
1440 for (i = 1; i < target.nkeys; i++)
1442 if (target.keys[i].type == REPOKEY_TYPE_CONSTANTID)
1444 if (!type_constantid)
1445 type_constantid = poolusage > 1 ? stringpool_str2id(spool, id2str(pool, target.keys[i].type), 1) : REPOKEY_TYPE_CONSTANTID;
1447 target.keys[i].size = stringpool_str2id(spool, id2str(pool, target.keys[i].size), 1);
1448 needid[target.keys[i].size].need++;
1452 target.keys[i].name = stringpool_str2id(spool, id2str(pool, target.keys[i].name), 1);
1453 target.keys[i].type = stringpool_str2id(spool, id2str(pool, target.keys[i].type), 1);
1455 needid[target.keys[i].name].need++;
1456 needid[target.keys[i].type].need++;
1459 /********************************************************************/
1461 if (dirpool && cbdata.dirused && !cbdata.dirused[0])
1463 /* no dirs used at all */
1464 cbdata.dirused = sat_free(cbdata.dirused);
1468 /* increment need id for used dir components */
1471 /* if we have own dirpool, all entries in it are used.
1472 also, all comp ids are already mapped by putinowndirpool(),
1473 so we can simply increment needid.
1474 (owndirpool != 0, dirused == 0, dirpooldata == 0) */
1475 /* else we re-use a dirpool of repodata "dirpooldata".
1476 dirused tells us which of the ids are used.
1477 we need to map comp ids if we generate a new pool.
1478 (owndirpool == 0, dirused != 0, dirpooldata != 0) */
1479 for (i = 1; i < dirpool->ndirs; i++)
1482 fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
1484 if (cbdata.dirused && !cbdata.dirused[i])
1486 id = dirpool->dirs[i];
1489 if (dirpooldata && cbdata.ownspool && id > 1)
1491 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1492 needid = cbdata.needid;
1499 /********************************************************************/
1502 * create mapping table, new keys are sorted by needid[].need
1504 * needid[key].need : old key -> new key
1505 * needid[key].map : new key -> old key
1508 /* zero out id 0 and rel 0 just in case */
1509 reloff = needid[0].map;
1511 needid[reloff].need = 0;
1513 for (i = 1; i < reloff + pool->nrels; i++)
1517 sat_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
1519 /* make first entry '' */
1521 sat_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
1523 sat_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
1524 /* now needid is in new order, needid[newid].map -> oldid */
1526 /* calculate string space size, also zero out needid[].need */
1528 for (i = 1; i < reloff; i++)
1530 if (!needid[i].need)
1531 break; /* as we have sorted, every entry after this also has need == 0 */
1533 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1535 nstrings = i; /* our new string id end */
1537 /* make needid[oldid].need point to newid */
1538 for (i = 1; i < nstrings; i++)
1539 needid[needid[i].map].need = i;
1541 /* same as above for relations */
1542 for (i = 0; i < pool->nrels; i++)
1544 if (!needid[reloff + i].need)
1546 needid[reloff + i].need = 0;
1548 nrels = i; /* our new rel id end */
1550 for (i = 0; i < nrels; i++)
1551 needid[needid[reloff + i].map].need = nstrings + i;
1553 /* now we have: needid[oldid].need -> newid
1554 needid[newid].map -> oldid
1555 both for strings and relations */
1558 /********************************************************************/
1564 /* create our new target directory structure by traversing through all
1565 * used dirs. This will concatenate blocks with the same parent
1566 * directory into single blocks.
1567 * Instead of components, traverse_dirs stores the old dirids,
1568 * we will change this in the second step below */
1569 /* (dirpooldata and dirused are 0 if we have our own dirpool) */
1570 if (cbdata.dirused && !cbdata.dirused[1])
1571 cbdata.dirused[1] = 1; /* always want / entry */
1572 dirmap = sat_calloc(dirpool->ndirs, sizeof(Id));
1574 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1576 /* (re)create dirused, so that it maps from "old dirid" to "new dirid" */
1577 /* change dirmap so that it maps from "new dirid" to "new compid" */
1578 if (!cbdata.dirused)
1579 cbdata.dirused = sat_malloc2(dirpool->ndirs, sizeof(Id));
1580 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1581 for (i = 1; i < ndirmap; i++)
1585 cbdata.dirused[dirmap[i]] = i;
1586 id = dirpool->dirs[dirmap[i]];
1587 if (dirpooldata && cbdata.ownspool && id > 1)
1588 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1589 dirmap[i] = needid[id].need;
1591 /* now the new target directory structure is complete (dirmap), and we have
1592 * dirused[olddirid] -> newdirid */
1595 /********************************************************************/
1598 * we use extdata[0] for incore data and extdata[keyid] for vertical data
1601 cbdata.extdata = sat_calloc(target.nkeys, sizeof(struct extdata));
1603 xd = cbdata.extdata;
1604 cbdata.current_sub = 0;
1605 /* add main schema */
1607 data_addid(xd, mainschema);
1610 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1612 if (!repodataused[j])
1614 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1618 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1619 cbdata.maxdata = xd->len - cbdata.lastlen;
1620 cbdata.lastlen = xd->len;
1622 if (anysolvableused)
1624 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1625 cbdata.doingsolvables = 1;
1626 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1628 if (s->repo != repo)
1630 data_addid(xd, cbdata.solvschemata[n]);
1631 if (cbdata.keymap[SOLVABLE_NAME])
1632 data_addid(xd, needid[s->name].need);
1633 if (cbdata.keymap[SOLVABLE_ARCH])
1634 data_addid(xd, needid[s->arch].need);
1635 if (cbdata.keymap[SOLVABLE_EVR])
1636 data_addid(xd, needid[s->evr].need);
1637 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1638 data_addid(xd, needid[s->vendor].need);
1639 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1640 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1641 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1642 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1643 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1644 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1645 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1646 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1647 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1648 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1649 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1650 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1651 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1652 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1653 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1654 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1655 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1656 data_addu32(xd, repo->rpmdbid[i - repo->start]);
1657 if (anyrepodataused)
1660 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1662 if (!repodataused[j])
1664 if (i < data->start || i >= data->end)
1666 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1669 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1670 cbdata.maxdata = xd->len - cbdata.lastlen;
1671 cbdata.lastlen = xd->len;
1674 cbdata.doingsolvables = 0;
1677 assert(cbdata.current_sub == cbdata.nsubschemata);
1678 if (cbdata.subschemata)
1680 cbdata.subschemata = sat_free(cbdata.subschemata);
1681 cbdata.nsubschemata = 0;
1684 /********************************************************************/
1688 /* write file header */
1689 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1690 write_u32(fp, SOLV_VERSION_8);
1694 write_u32(fp, nstrings);
1695 write_u32(fp, nrels);
1696 write_u32(fp, ndirmap);
1697 write_u32(fp, anysolvableused ? repo->nsolvables : 0);
1698 write_u32(fp, target.nkeys);
1699 write_u32(fp, target.nschemata);
1701 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1702 write_u32(fp, solv_flags);
1705 * calculate prefix encoding of the strings
1707 unsigned char *prefixcomp = sat_malloc(nstrings);
1708 unsigned int compsum = 0;
1712 for (i = 1; i < nstrings; i++)
1714 char *str = spool->stringspace + spool->strings[needid[i].map];
1716 for (same = 0; same < 255; same++)
1717 if (!old_str[same] || old_str[same] != str[same])
1719 prefixcomp[i] = same;
1727 write_u32(fp, sizeid);
1728 /* we save compsum bytes but need 1 extra byte for every string */
1729 write_u32(fp, sizeid + (nstrings ? nstrings - 1 : 0) - compsum);
1730 if (sizeid + (nstrings ? nstrings - 1 : 0) != compsum)
1732 for (i = 1; i < nstrings; i++)
1734 char *str = spool->stringspace + spool->strings[needid[i].map];
1735 write_u8(fp, prefixcomp[i]);
1736 write_str(fp, str + prefixcomp[i]);
1739 sat_free(prefixcomp);
1742 /* Build the prefix-encoding of the string pool. We need to know
1743 the size of that before writing it to the file, so we have to
1744 build a separate buffer for that. As it's temporarily possible
1745 that this actually is an expansion we can't easily reuse the
1746 stringspace for this. The max expansion per string is 1 byte,
1747 so it will fit into sizeid+nstrings bytes. */
1748 char *prefix = sat_malloc(sizeid + nstrings);
1751 for (i = 1; i < nstrings; i++)
1753 char *str = spool->stringspace + spool->strings[needid[i].map];
1756 for (same = 0; same < 255; same++)
1757 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1760 len = strlen(str + same) + 1;
1761 memcpy(pp, str + same, len);
1769 write_u32(fp, sizeid);
1770 write_u32(fp, pp - prefix);
1773 if (fwrite(prefix, pp - prefix, 1, fp) != 1)
1775 perror("write error prefix");
1785 for (i = 0; i < nrels; i++)
1787 ran = pool->rels + (needid[reloff + i].map - reloff);
1788 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1789 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1790 write_u8(fp, ran->flags);
1794 * write dirs (skip both root and / entry)
1796 for (i = 2; i < ndirmap; i++)
1799 write_id(fp, dirmap[i]);
1801 write_id(fp, nstrings - dirmap[i]);
1808 for (i = 1; i < target.nkeys; i++)
1810 write_id(fp, needid[target.keys[i].name].need);
1811 write_id(fp, needid[target.keys[i].type].need);
1812 if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1814 if (target.keys[i].type == type_constantid)
1815 write_id(fp, needid[target.keys[i].size].need);
1817 write_id(fp, target.keys[i].size);
1820 write_id(fp, cbdata.extdata[i].len);
1821 write_id(fp, target.keys[i].storage);
1827 write_id(fp, target.schemadatalen); /* XXX -1? */
1828 for (i = 1; i < target.nschemata; i++)
1829 write_idarray(fp, pool, 0, repodata_id2schema(&target, i));
1831 /********************************************************************/
1833 write_id(fp, cbdata.maxdata);
1834 write_id(fp, cbdata.extdata[0].len);
1835 if (cbdata.extdata[0].len)
1836 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1837 sat_free(cbdata.extdata[0].buf);
1839 /* do we have vertical data? */
1840 for (i = 1; i < target.nkeys; i++)
1841 if (cbdata.extdata[i].len)
1843 if (i < target.nkeys)
1845 /* yes, write it in pages */
1846 unsigned char *dp, vpage[BLOB_PAGESIZE];
1847 int l, ll, lpage = 0;
1849 write_u32(fp, BLOB_PAGESIZE);
1850 for (i = 1; i < target.nkeys; i++)
1852 if (!cbdata.extdata[i].len)
1854 l = cbdata.extdata[i].len;
1855 dp = cbdata.extdata[i].buf;
1858 ll = BLOB_PAGESIZE - lpage;
1861 memcpy(vpage + lpage, dp, ll);
1865 if (lpage == BLOB_PAGESIZE)
1867 write_compressed_page(fp, vpage, lpage);
1873 write_compressed_page(fp, vpage, lpage);
1876 for (i = 1; i < target.nkeys; i++)
1877 sat_free(cbdata.extdata[i].buf);
1878 sat_free(cbdata.extdata);
1880 repodata_freedata(&target);
1883 sat_free(cbdata.solvschemata);
1884 sat_free(cbdata.schema);
1886 sat_free(cbdata.keymap);
1887 sat_free(cbdata.keymapstart);
1888 sat_free(cbdata.dirused);
1889 sat_free(repodataused);
1892 struct repodata_write_data {
1893 int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
1899 repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata)
1901 struct repodata_write_data *wd = kfdata;
1903 /* XXX: special repodata selection hack */
1904 if (key->name == 1 && key->size != wd->repodataid)
1906 if (key->storage == KEY_STORAGE_SOLVABLE)
1907 return KEY_STORAGE_DROPPED; /* not part of this repodata */
1909 return (*wd->keyfilter)(repo, key, wd->kfdata);
1910 return key->storage;
1914 repodata_write(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata)
1916 struct repodata_write_data wd;
1918 wd.keyfilter = keyfilter;
1920 wd.repodataid = data - data->repo->repodata;
1921 repo_write(data->repo, fp, repodata_write_keyfilter, &wd, 0);