2 * Copyright (c) 2007, Novell Inc.
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
11 * Write Repo data out to binary file
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
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 */
135 write_u32(FILE *fp, unsigned int x)
137 if (putc(x >> 24, fp) == EOF ||
138 putc(x >> 16, fp) == EOF ||
139 putc(x >> 8, fp) == EOF ||
142 perror("write error u32");
153 write_u8(FILE *fp, unsigned int x)
155 if (putc(x, fp) == EOF)
157 perror("write error u8");
167 write_blob(FILE *fp, void *data, int len)
169 if (len && fwrite(data, len, 1, fp) != 1)
171 perror("write error blob");
181 write_id(FILE *fp, Id x)
186 putc((x >> 28) | 128, fp);
188 putc((x >> 21) | 128, fp);
189 putc((x >> 14) | 128, fp);
192 putc((x >> 7) | 128, fp);
193 if (putc(x & 127, fp) == EOF)
195 perror("write error id");
201 write_id_eof(FILE *fp, Id x, int eof)
204 x = (x & 63) | ((x & ~63) << 1);
205 write_id(fp, x | (eof ? 0 : 64));
211 write_str(FILE *fp, const char *str)
213 if (fputs(str, fp) == EOF || putc(0, fp) == EOF)
215 perror("write error str");
225 write_idarray(FILE *fp, Pool *pool, NeedId *needid, Id *ids)
239 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
241 id = (id & 63) | ((id & ~63) << 1);
247 write_id(fp, id | 64);
252 cmp_ids(const void *pa, const void *pb, void *dp)
261 write_idarray_sort(FILE *fp, Pool *pool, NeedId *needid, Id *ids, Id marker)
273 for (len = 0; len < 64 && ids[len]; len++)
277 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
282 for (i = len + 1; ids[i]; i++)
284 sids = sat_malloc2(i, sizeof(Id));
285 memcpy(sids, lids, 64 * sizeof(Id));
286 for (; ids[len]; len++)
290 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
297 /* That bloody solvable:prereqmarker needs to stay in position :-( */
299 marker = needid[marker].need;
300 for (i = 0; i < len; i++)
301 if (sids[i] == marker)
304 sat_sort(sids, i, sizeof(Id), cmp_ids, 0);
306 sat_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
310 /* The differencing above produces many runs of ones and twos. I tried
311 fairly elaborate schemes to RLE those, but they give only very mediocre
312 improvements in compression, as coding the escapes costs quite some
313 space. Even if they are coded only as bits in IDs. The best improvement
314 was about 2.7% for the whole .solv file. It's probably better to
315 invest some complexity into sharing idarrays, than RLEing. */
316 for (i = 0; i < len - 1; i++)
319 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
320 hence all real differences are offsetted by 1. Otherwise we would
321 have to handle negative differences, which would cost code space for
322 the encoding of the sign. We loose the exact mapping of prereq here,
323 but we know the result, so we can recover from that in the reader. */
331 /* XXX If difference is zero we have multiple equal elements,
332 we might want to skip writing them out. */
334 id = (id & 63) | ((id & ~63) << 1);
335 write_id(fp, id | 64);
343 id = (id & 63) | ((id & ~63) << 1);
359 Stringpool *ownspool;
371 Id *schema; /* schema construction space */
372 Id *sp; /* pointer in above */
373 Id *oldschema, *oldsp;
381 Id schematacache[256];
389 struct extdata *extdata;
398 int doingsolvables; /* working on solvables data */
401 #define NEEDED_BLOCK 1023
402 #define SCHEMATA_BLOCK 31
403 #define SCHEMATADATA_BLOCK 255
404 #define EXTDATA_BLOCK 4095
407 data_addid(struct extdata *xd, Id x)
410 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
411 dp = xd->buf + xd->len;
416 *dp++ = (x >> 28) | 128;
418 *dp++ = (x >> 21) | 128;
419 *dp++ = (x >> 14) | 128;
422 *dp++ = (x >> 7) | 128;
424 xd->len = dp - xd->buf;
428 data_addideof(struct extdata *xd, Id x, int eof)
431 x = (x & 63) | ((x & ~63) << 1);
432 data_addid(xd, (eof ? x: x | 64));
436 data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
448 for (len = 0; len < 64 && ids[len]; len++)
452 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
457 for (i = len + 1; ids[i]; i++)
459 sids = sat_malloc2(i, sizeof(Id));
460 memcpy(sids, lids, 64 * sizeof(Id));
461 for (; ids[len]; len++)
465 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
472 /* That bloody solvable:prereqmarker needs to stay in position :-( */
474 marker = needid[marker].need;
475 for (i = 0; i < len; i++)
476 if (sids[i] == marker)
479 sat_sort(sids, i, sizeof(Id), cmp_ids, 0);
481 sat_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
485 /* The differencing above produces many runs of ones and twos. I tried
486 fairly elaborate schemes to RLE those, but they give only very mediocre
487 improvements in compression, as coding the escapes costs quite some
488 space. Even if they are coded only as bits in IDs. The best improvement
489 was about 2.7% for the whole .solv file. It's probably better to
490 invest some complexity into sharing idarrays, than RLEing. */
491 for (i = 0; i < len - 1; i++)
494 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
495 hence all real differences are offsetted by 1. Otherwise we would
496 have to handle negative differences, which would cost code space for
497 the encoding of the sign. We loose the exact mapping of prereq here,
498 but we know the result, so we can recover from that in the reader. */
506 /* XXX If difference is zero we have multiple equal elements,
507 we might want to skip writing them out. */
509 id = (id & 63) | ((id & ~63) << 1);
510 data_addid(xd, id | 64);
518 id = (id & 63) | ((id & ~63) << 1);
525 data_addblob(struct extdata *xd, unsigned char *blob, int len)
527 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
528 memcpy(xd->buf + xd->len, blob, len);
533 data_addu32(struct extdata *xd, unsigned int num)
540 data_addblob(xd, d, 4);
544 addschema(struct cbdata *cbdata, Id *schema)
549 for (sp = schema, len = 0, h = 0; *sp; len++)
554 cid = cbdata->schematacache[h];
557 if (!memcmp(cbdata->myschemadata + cbdata->myschemata[cid], schema, len * sizeof(Id)))
560 for (cid = 1; cid < cbdata->nmyschemata; cid++)
561 if (!memcmp(cbdata->myschemadata + cbdata->myschemata[cid], schema, len * sizeof(Id)))
564 /* a new one. make room. */
565 if (!cbdata->nmyschemata)
567 /* allocate schema 0, it is always empty */
568 cbdata->myschemadata = sat_extend(cbdata->myschemadata, cbdata->myschemadatalen, 1, sizeof(Id), SCHEMATADATA_BLOCK);
569 cbdata->myschemata = sat_extend(cbdata->myschemata, cbdata->nmyschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
570 cbdata->myschemata[0] = 0;
571 cbdata->myschemadata[0] = 0;
572 cbdata->nmyschemata = 1;
573 cbdata->myschemadatalen = 1;
576 cbdata->myschemadata = sat_extend(cbdata->myschemadata, cbdata->myschemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
577 cbdata->myschemata = sat_extend(cbdata->myschemata, cbdata->nmyschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
578 memcpy(cbdata->myschemadata + cbdata->myschemadatalen, schema, len * sizeof(Id));
579 cbdata->myschemata[cbdata->nmyschemata] = cbdata->myschemadatalen;
580 cbdata->myschemadatalen += len;
581 cbdata->schematacache[h] = cbdata->nmyschemata;
582 return cbdata->nmyschemata++;
586 putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
588 const char *str = stringpool_id2str(ss, id);
589 id = stringpool_str2id(cbdata->ownspool, str, 1);
590 if (id >= cbdata->needid[0].map)
592 int oldoff = cbdata->needid[0].map;
593 int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
594 int nrels = cbdata->repo->pool->nrels;
595 cbdata->needid = sat_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
597 memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
598 memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
599 cbdata->needid[0].map = newoff;
605 putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
609 parent = dirpool_parent(dp, dir);
611 parent = putinowndirpool(cbdata, data, dp, parent);
612 compid = dp->dirs[dir];
613 if (cbdata->ownspool && compid > 1)
614 compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
615 return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
619 setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
621 if (cbdata->dirused[dir])
623 cbdata->dirused[dir] = 1;
624 while ((dir = dirpool_parent(dp, dir)) != 0)
626 if (cbdata->dirused[dir] == 2)
628 if (cbdata->dirused[dir])
630 cbdata->dirused[dir] = 2;
633 cbdata->dirused[dir] = 2;
635 cbdata->dirused[0] = 2;
639 repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
644 if (key->name == REPOSITORY_SOLVABLES)
645 return SEARCH_NEXT_KEY; /* we do not want this one */
646 if (data != data->repo->repodata + data->repo->nrepodata - 1)
647 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS)
648 return SEARCH_NEXT_KEY;
650 rm = cbdata->keymap[cbdata->keymapstart[data - data->repo->repodata] + (key - data->keys)];
652 return SEARCH_NEXT_KEY; /* we do not want this one */
653 /* record key in schema */
654 if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
655 && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
659 case REPOKEY_TYPE_ID:
660 case REPOKEY_TYPE_IDARRAY:
662 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
663 id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
664 incneedid(repo->pool, id, cbdata->needid);
666 case REPOKEY_TYPE_DIR:
667 case REPOKEY_TYPE_DIRNUMNUMARRAY:
668 case REPOKEY_TYPE_DIRSTRARRAY:
670 if (cbdata->owndirpool)
671 putinowndirpool(cbdata, data, &data->dirpool, id);
673 setdirused(cbdata, &data->dirpool, id);
675 case REPOKEY_TYPE_FIXARRAY:
678 if (cbdata->oldschema)
680 fprintf(stderr, "nested structs not yet implemented\n");
683 cbdata->oldschema = cbdata->schema;
684 cbdata->oldsp = cbdata->sp;
685 cbdata->schema = sat_calloc(cbdata->nmykeys, sizeof(Id));
686 cbdata->sp = cbdata->schema;
688 else if (kv->eof == 1)
690 cbdata->current_sub++;
692 cbdata->subschemata = sat_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
693 cbdata->subschemata[cbdata->nsubschemata++] = addschema(cbdata, cbdata->schema);
695 fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
697 cbdata->sp = cbdata->schema;
701 sat_free(cbdata->schema);
702 cbdata->schema = cbdata->oldschema;
703 cbdata->sp = cbdata->oldsp;
704 cbdata->oldsp = cbdata->oldschema = 0;
707 case REPOKEY_TYPE_FLEXARRAY:
711 *cbdata->sp++ = 0; /* mark start */
715 /* just finished a schema, rewind */
716 Id *sp = cbdata->sp - 1;
720 cbdata->subschemata = sat_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
721 cbdata->subschemata[cbdata->nsubschemata++] = addschema(cbdata, sp);
722 cbdata->sp = kv->eof == 2 ? sp - 1: sp;
732 repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
734 struct cbdata *cbdata = vcbdata;
735 Repo *repo = data->repo;
739 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);
741 return repo_write_collect_needed(cbdata, repo, data, key, kv);
745 repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
754 if (key->name == REPOSITORY_SOLVABLES)
755 return SEARCH_NEXT_KEY;
756 if (data != data->repo->repodata + data->repo->nrepodata - 1)
757 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS)
758 return SEARCH_NEXT_KEY;
760 rm = cbdata->keymap[cbdata->keymapstart[data - data->repo->repodata] + (key - data->keys)];
762 return SEARCH_NEXT_KEY; /* we do not want this one */
764 if (cbdata->mykeys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
766 xd = cbdata->extdata + rm; /* vertical buffer */
767 if (cbdata->vstart == -1)
768 cbdata->vstart = xd->len;
771 xd = cbdata->extdata + 0; /* incore buffer */
774 case REPOKEY_TYPE_VOID:
775 case REPOKEY_TYPE_CONSTANT:
776 case REPOKEY_TYPE_CONSTANTID:
778 case REPOKEY_TYPE_ID:
780 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
781 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
782 needid = cbdata->needid;
783 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
786 case REPOKEY_TYPE_IDARRAY:
788 if (cbdata->ownspool && id > 1)
789 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
790 needid = cbdata->needid;
791 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
792 data_addideof(xd, id, kv->eof);
794 case REPOKEY_TYPE_STR:
795 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
797 case REPOKEY_TYPE_MD5:
798 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
800 case REPOKEY_TYPE_SHA1:
801 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
803 case REPOKEY_TYPE_SHA256:
804 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
806 case REPOKEY_TYPE_U32:
812 data_addblob(xd, v, 4);
814 case REPOKEY_TYPE_NUM:
815 data_addid(xd, kv->num);
817 case REPOKEY_TYPE_DIR:
819 if (cbdata->owndirpool)
820 id = putinowndirpool(cbdata, data, &data->dirpool, id);
821 id = cbdata->dirused[id];
824 case REPOKEY_TYPE_DIRNUMNUMARRAY:
826 if (cbdata->owndirpool)
827 id = putinowndirpool(cbdata, data, &data->dirpool, id);
828 id = cbdata->dirused[id];
830 data_addid(xd, kv->num);
831 data_addideof(xd, kv->num2, kv->eof);
833 case REPOKEY_TYPE_DIRSTRARRAY:
835 if (cbdata->owndirpool)
836 id = putinowndirpool(cbdata, data, &data->dirpool, id);
837 id = cbdata->dirused[id];
838 data_addideof(xd, id, kv->eof);
839 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
841 case REPOKEY_TYPE_FIXARRAY:
846 data_addid(xd, kv->num);
847 data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
849 fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
853 else if (kv->eof == 1)
855 cbdata->current_sub++;
861 case REPOKEY_TYPE_FLEXARRAY:
863 data_addid(xd, kv->num);
865 data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
866 if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
868 if (xd->len - cbdata->lastlen > cbdata->maxdata)
869 cbdata->maxdata = xd->len - cbdata->lastlen;
870 cbdata->lastlen = xd->len;
874 fprintf(stderr, "unknown type for %d: %d\n", key->name, key->type);
877 if (cbdata->mykeys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
879 /* we can re-use old data in the blob here! */
880 data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */
881 data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */
888 repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
890 struct cbdata *cbdata = vcbdata;
891 return repo_write_adddata(cbdata, data, key, kv);
895 traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
901 /* special case for '/', which has to come first */
904 for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
906 if (used && !used[sib])
908 if (sib == 1 && parent == 1)
909 continue; /* already did that one above */
913 for (; parent < lastn; parent++)
915 sib = dirmap[parent];
916 if (used && used[sib] != 2)
918 child = dirpool_child(dp, sib);
921 dirmap[n++] = -parent;
922 n = traverse_dirs(dp, dirmap, n, child, used);
929 write_compressed_page(FILE *fp, unsigned char *page, int len)
932 unsigned char cpage[BLOB_PAGESIZE];
934 clen = repopagestore_compress_page(page, len, cpage, len - 1);
937 write_u32(fp, len * 2);
938 write_blob(fp, page, len);
942 write_u32(fp, clen * 2 + 1);
943 write_blob(fp, cpage, clen);
949 static Id subfilekeys[] = {
950 REPODATA_INFO, REPOKEY_TYPE_VOID,
951 REPODATA_EXTERNAL, REPOKEY_TYPE_VOID,
952 REPODATA_KEYS, REPOKEY_TYPE_IDARRAY,
953 REPODATA_LOCATION, REPOKEY_TYPE_STR,
954 REPODATA_ADDEDFILEPROVIDES, REPOKEY_TYPE_REL_IDARRAY,
955 REPODATA_RPMDBCOOKIE, REPOKEY_TYPE_SHA256,
960 static Id verticals[] = {
962 SOLVABLE_DESCRIPTION,
971 static char *languagetags[] = {
973 "solvable:description:",
974 "solvable:messageins:",
975 "solvable:messagedel:",
981 repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
986 for (i = 0; verticals[i]; i++)
987 if (key->name == verticals[i])
988 return KEY_STORAGE_VERTICAL_OFFSET;
989 keyname = id2str(repo->pool, key->name);
990 for (i = 0; languagetags[i] != 0; i++)
991 if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
992 return KEY_STORAGE_VERTICAL_OFFSET;
993 return KEY_STORAGE_INCORE;
1001 repo_write(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Id **keyarrayp)
1003 Pool *pool = repo->pool;
1007 int nstrings, nrels;
1008 unsigned int sizeid;
1009 unsigned int solv_flags;
1018 unsigned char *repodataused;
1019 int anyrepodataused;
1021 struct cbdata cbdata;
1024 int poolusage, dirpoolusage, idused, dirused;
1027 Repodata *data, *dirpooldata = 0;
1028 Stringpool ownspool, *spool;
1029 Dirpool owndirpool, *dirpool;
1031 Id *repodataschemata = 0;
1036 Id type_constantid = 0;
1038 memset(&cbdata, 0, sizeof(cbdata));
1041 /* go through all repodata and find the keys we need */
1042 /* also unify keys */
1043 /* creates: mykeys - key array, still has global pool ids */
1044 /* keymapstart - maps repo number to keymap offset */
1045 /* keymap - maps repo key to my key, 0 -> not used */
1047 /* start with all KEY_STORAGE_SOLVABLE ids */
1049 n = ID_NUM_INTERNAL;
1050 for (i = 0; i < repo->nrepodata; i++)
1051 n += repo->repodata[i].nkeys;
1052 cbdata.mykeys = sat_calloc(n, sizeof(Repokey));
1053 cbdata.keymap = sat_calloc(n, sizeof(Id));
1054 cbdata.keymapstart = sat_calloc(repo->nrepodata, sizeof(Id));
1055 repodataused = sat_calloc(repo->nrepodata, 1);
1060 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
1062 key = cbdata.mykeys + i;
1064 if (i < SOLVABLE_PROVIDES)
1065 key->type = REPOKEY_TYPE_ID;
1066 else if (i < RPM_RPMDBID)
1067 key->type = REPOKEY_TYPE_REL_IDARRAY;
1069 key->type = REPOKEY_TYPE_U32;
1071 key->storage = KEY_STORAGE_SOLVABLE;
1074 key->storage = keyfilter(repo, key, kfdata);
1075 if (key->storage == KEY_STORAGE_DROPPED)
1077 key->storage = KEY_STORAGE_SOLVABLE;
1080 if (key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
1082 cbdata.keymap[i] = i;
1086 if (repo->nsolvables)
1088 key = cbdata.mykeys + cbdata.nmykeys;
1089 key->name = REPOSITORY_SOLVABLES;
1090 key->type = REPOKEY_TYPE_FLEXARRAY;
1092 key->storage = KEY_STORAGE_INCORE;
1093 cbdata.keymap[key->name] = cbdata.nmykeys++;
1097 /* If we store subfile info, generate the necessary keys. */
1100 for (i = 0; subfilekeys[i]; i += 2)
1102 key = cbdata.mykeys + cbdata.nmykeys;
1103 key->name = subfilekeys[i];
1104 key->type = subfilekeys[i + 1];
1106 key->storage = KEY_STORAGE_SOLVABLE;
1107 cbdata.keymap[key->name] = cbdata.nmykeys++;
1116 n = ID_NUM_INTERNAL;
1117 for (i = 0; i < repo->nrepodata; i++)
1119 data = repo->repodata + i;
1120 cbdata.keymapstart[i] = n;
1121 cbdata.keymap[n++] = 0; /* key 0 */
1127 /* check if we want this repodata */
1128 memset(&zerokey, 0, sizeof(zerokey));
1132 if (keyfilter(repo, &zerokey, kfdata) == -1)
1135 for (j = 1; j < data->nkeys; j++, n++)
1137 key = data->keys + j;
1138 if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
1140 cbdata.keymap[n] = cbdata.keymap[key->name];
1143 /* see if we already had this one, should use hash for fast miss */
1144 for (k = 0; k < cbdata.nmykeys; k++)
1146 if (key->name == cbdata.mykeys[k].name && key->type == cbdata.mykeys[k].type)
1148 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != cbdata.mykeys[k].size)
1153 if (k < cbdata.nmykeys)
1154 cbdata.keymap[n] = k;
1157 /* found a new key! */
1158 cbdata.mykeys[cbdata.nmykeys] = *key;
1159 key = cbdata.mykeys + cbdata.nmykeys;
1160 key->storage = KEY_STORAGE_INCORE;
1161 if (key->type != REPOKEY_TYPE_CONSTANT && key->type != REPOKEY_TYPE_CONSTANTID)
1165 key->storage = keyfilter(repo, key, kfdata);
1166 if (key->storage == KEY_STORAGE_DROPPED)
1168 cbdata.keymap[n] = 0;
1172 cbdata.keymap[n] = cbdata.nmykeys++;
1174 /* load repodata if not already loaded */
1175 if (data->state == REPODATA_STUB)
1177 if (data->loadcallback)
1178 data->loadcallback(data);
1180 data->state = REPODATA_ERROR;
1181 if (data->state != REPODATA_ERROR)
1183 /* redo this repodata! */
1185 n = cbdata.keymapstart[i];
1189 if (data->state == REPODATA_ERROR)
1192 cbdata.keymap[n] = 0;
1196 repodataused[i] = 1;
1197 anyrepodataused = 1;
1198 if (key->type != REPOKEY_TYPE_STR
1199 && key->type != REPOKEY_TYPE_U32
1200 && key->type != REPOKEY_TYPE_MD5
1201 && key->type != REPOKEY_TYPE_SHA1)
1203 if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
1205 /* make sure we know that key */
1206 if (data->localpool)
1208 stringpool_str2id(&data->spool, id2str(pool, key->name), 1);
1209 stringpool_str2id(&data->spool, id2str(pool, key->type), 1);
1210 if (key->type == REPOKEY_TYPE_CONSTANTID)
1211 stringpool_str2id(&data->spool, id2str(pool, key->size), 1);
1216 if (data->localpool)
1219 poolusage = 3; /* need local pool */
1223 spool = &data->spool;
1230 else if (poolusage != 1)
1231 poolusage = 3; /* need local pool */
1237 dirpoolusage = 3; /* need local dirpool */
1241 dirpool = &data->dirpool;
1248 /* 0: no pool needed at all */
1249 /* 1: use global pool */
1250 /* 2: use repodata local pool */
1251 /* 3: need own pool */
1257 /* hack: reuse global pool so we don't have to map rel ids */
1258 stringpool_clone(spool, &repo->pool->ss);
1261 stringpool_init_empty(spool);
1262 cbdata.ownspool = spool;
1264 else if (poolusage == 0 || poolusage == 1)
1267 spool = &repo->pool->ss;
1269 if (dirpoolusage == 3)
1271 dirpool = &owndirpool;
1273 dirpool_init(dirpool);
1274 cbdata.owndirpool = dirpool;
1277 cbdata.dirused = sat_calloc(dirpool->ndirs, sizeof(Id));
1280 /********************************************************************/
1282 fprintf(stderr, "poolusage: %d\n", poolusage);
1283 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
1284 fprintf(stderr, "nmykeys: %d\n", cbdata.nmykeys);
1285 for (i = 1; i < cbdata.nmykeys; i++)
1286 fprintf(stderr, " %2d: %s[%d] %d %d %d\n", i, id2str(pool, cbdata.mykeys[i].name), cbdata.mykeys[i].name, cbdata.mykeys[i].type, cbdata.mykeys[i].size, cbdata.mykeys[i].storage);
1289 /********************************************************************/
1291 /* set needed count of all strings and rels,
1292 * find which keys are used in the solvables
1293 * put all strings in own spool
1296 reloff = spool->nstrings;
1298 reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
1300 needid = calloc(reloff + pool->nrels, sizeof(*needid));
1301 needid[0].map = reloff;
1303 cbdata.needid = needid;
1304 cbdata.schema = sat_calloc(cbdata.nmykeys, sizeof(Id));
1305 cbdata.sp = cbdata.schema;
1306 cbdata.solvschemata = sat_calloc(repo->nsolvables, sizeof(Id));
1308 cbdata.extraschemata = sat_calloc(repo->nextra, sizeof(Id));
1311 /* create main schema */
1312 cbdata.sp = cbdata.schema;
1313 /* collect all other data from all repodatas */
1314 /* XXX: merge arrays of equal keys? */
1315 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1317 if (!repodataused[j])
1319 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1322 /* add solvables if needed */
1323 if (repo->nsolvables)
1325 *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
1326 cbdata.mykeys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
1329 mainschema = addschema(&cbdata, cbdata.schema);
1332 idarraydata = repo->idarraydata;
1334 cbdata.doingsolvables = 1;
1335 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1337 if (s->repo != repo)
1340 /* set schema info, keep in sync with further down */
1342 if (cbdata.keymap[SOLVABLE_NAME])
1344 *sp++ = SOLVABLE_NAME;
1345 needid[s->name].need++;
1347 if (cbdata.keymap[SOLVABLE_ARCH])
1349 *sp++ = SOLVABLE_ARCH;
1350 needid[s->arch].need++;
1352 if (cbdata.keymap[SOLVABLE_EVR])
1354 *sp++ = SOLVABLE_EVR;
1355 needid[s->evr].need++;
1357 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1359 *sp++ = SOLVABLE_VENDOR;
1360 needid[s->vendor].need++;
1362 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1364 *sp++ = SOLVABLE_PROVIDES;
1365 cbdata.mykeys[SOLVABLE_PROVIDES].size += incneedidarray(pool, idarraydata + s->provides, needid);
1367 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1369 *sp++ = SOLVABLE_OBSOLETES;
1370 cbdata.mykeys[SOLVABLE_OBSOLETES].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
1372 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1374 *sp++ = SOLVABLE_CONFLICTS;
1375 cbdata.mykeys[SOLVABLE_CONFLICTS].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
1377 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1379 *sp++ = SOLVABLE_REQUIRES;
1380 cbdata.mykeys[SOLVABLE_REQUIRES].size += incneedidarray(pool, idarraydata + s->requires, needid);
1382 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1384 *sp++ = SOLVABLE_RECOMMENDS;
1385 cbdata.mykeys[SOLVABLE_RECOMMENDS].size += incneedidarray(pool, idarraydata + s->recommends, needid);
1387 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1389 *sp++ = SOLVABLE_SUGGESTS;
1390 cbdata.mykeys[SOLVABLE_SUGGESTS].size += incneedidarray(pool, idarraydata + s->suggests, needid);
1392 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1394 *sp++ = SOLVABLE_SUPPLEMENTS;
1395 cbdata.mykeys[SOLVABLE_SUPPLEMENTS].size += incneedidarray(pool, idarraydata + s->supplements, needid);
1397 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1399 *sp++ = SOLVABLE_ENHANCES;
1400 cbdata.mykeys[SOLVABLE_ENHANCES].size += incneedidarray(pool, idarraydata + s->enhances, needid);
1402 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1404 *sp++ = RPM_RPMDBID;
1405 cbdata.mykeys[RPM_RPMDBID].size++;
1409 if (anyrepodataused)
1411 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1413 if (!repodataused[j])
1415 if (i < data->start || i >= data->end)
1417 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1418 needid = cbdata.needid;
1422 cbdata.solvschemata[n] = addschema(&cbdata, cbdata.schema);
1425 cbdata.doingsolvables = 0;
1426 assert(n == repo->nsolvables);
1429 if (repo->nextra && anyrepodataused)
1430 for (i = -1; i >= -repo->nextra; i--)
1433 dataiterator_init(&di, repo, i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE);
1434 cbdata.sp = cbdata.schema;
1435 while (dataiterator_step(&di))
1436 repo_write_collect_needed(&cbdata, repo, di.data, di.key, &di.kv);
1438 cbdata.extraschemata[-1 - i] = addschema(&cbdata, cbdata.schema);
1441 /* If we have fileinfos to write, setup schemas and increment needid[]
1442 of the right strings. */
1443 for (i = 0; i < nsubfiles; i++)
1449 if (fileinfo[i].addedfileprovides || fileinfo[i].rpmdbcookie)
1451 /* extra info about this file */
1452 *sp++ = cbdata.keymap[REPODATA_INFO];
1453 if (fileinfo[i].addedfileprovides)
1455 *sp++ = cbdata.keymap[REPODATA_ADDEDFILEPROVIDES];
1456 for (j = 0; fileinfo[i].addedfileprovides[j]; j++)
1458 cbdata.mykeys[cbdata.keymap[REPODATA_ADDEDFILEPROVIDES]].size += j + 1;
1460 if (fileinfo[i].rpmdbcookie)
1461 *sp++ = cbdata.keymap[REPODATA_RPMDBCOOKIE];
1465 *sp++ = cbdata.keymap[REPODATA_EXTERNAL];
1466 *sp++ = cbdata.keymap[REPODATA_KEYS];
1467 if (fileinfo[i].location)
1468 *sp++ = cbdata.keymap[REPODATA_LOCATION];
1471 repodataschemata[i] = addschema(&cbdata, schema);
1472 cbdata.mykeys[cbdata.keymap[REPODATA_KEYS]].size += 2 * fileinfo[i].nkeys + 1;
1473 for (j = 1; j < fileinfo[i].nkeys; j++)
1475 needid[fileinfo[i].keys[j].type].need++;
1476 needid[fileinfo[i].keys[j].name].need++;
1481 /********************************************************************/
1483 /* remove unused keys, convert ids to local ids and increment their needid */
1484 keyused = sat_calloc(cbdata.nmykeys, sizeof(Id));
1485 for (i = 0; i < cbdata.myschemadatalen; i++)
1486 keyused[cbdata.myschemadata[i]] = 1;
1488 for (n = i = 1; i < cbdata.nmykeys; i++)
1494 cbdata.mykeys[n] = cbdata.mykeys[i];
1495 if (cbdata.mykeys[n].type == REPOKEY_TYPE_CONSTANTID)
1497 if (!type_constantid)
1498 type_constantid = poolusage > 1 ? stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].type), 1) : REPOKEY_TYPE_CONSTANTID;
1500 cbdata.mykeys[n].size = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].size), 1);
1501 needid[cbdata.mykeys[n].size].need++;
1505 cbdata.mykeys[n].name = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].name), 1);
1506 cbdata.mykeys[n].type = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].type), 1);
1508 needid[cbdata.mykeys[n].name].need++;
1509 needid[cbdata.mykeys[n].type].need++;
1513 for (i = 0; i < cbdata.myschemadatalen; i++)
1514 cbdata.myschemadata[i] = keyused[cbdata.myschemadata[i]];
1515 for (i = 0; i < cbdata.nkeymap; i++)
1516 cbdata.keymap[i] = keyused[cbdata.keymap[i]];
1517 keyused = sat_free(keyused);
1519 /********************************************************************/
1521 /* increment need id for used dir components */
1522 if (cbdata.dirused && !cbdata.dirused[0])
1524 /* no dirs used at all */
1525 cbdata.dirused = sat_free(cbdata.dirused);
1530 for (i = 1; i < dirpool->ndirs; i++)
1533 fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
1535 id = dirpool->dirs[i];
1538 if (cbdata.dirused && !cbdata.dirused[i])
1540 if (cbdata.ownspool && dirpooldata && id > 1)
1542 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1543 needid = cbdata.needid;
1549 reloff = needid[0].map;
1552 /********************************************************************/
1555 * create mapping table, new keys are sorted by needid[].need
1557 * needid[key].need : old key -> new key
1558 * needid[key].map : new key -> old key
1561 /* zero out id 0 and rel 0 just in case */
1564 needid[reloff].need = 0;
1566 for (i = 1; i < reloff + pool->nrels; i++)
1570 sat_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
1572 /* make first entry '' */
1574 sat_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
1576 sat_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
1579 for (i = 1; i < reloff; i++)
1581 if (!needid[i].need)
1584 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1588 for (i = 1; i < nstrings; i++)
1589 needid[needid[i].map].need = i;
1591 for (i = 0; i < pool->nrels; i++)
1593 if (!needid[reloff + i].need)
1596 needid[reloff + i].need = 0;
1600 for (i = 0; i < nrels; i++)
1601 needid[needid[reloff + i].map].need = nstrings + i;
1604 /********************************************************************/
1606 /* create dir map */
1611 if (cbdata.dirused && !cbdata.dirused[1])
1612 cbdata.dirused[1] = 1; /* always want / entry */
1613 dirmap = sat_calloc(dirpool->ndirs, sizeof(Id));
1615 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1616 if (!cbdata.dirused)
1617 cbdata.dirused = sat_malloc2(dirpool->ndirs, sizeof(Id));
1618 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1619 for (i = 1; i < ndirmap; i++)
1623 cbdata.dirused[dirmap[i]] = i;
1624 id = dirpool->dirs[dirmap[i]];
1625 if (cbdata.ownspool && dirpooldata && id > 1)
1626 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1627 dirmap[i] = needid[id].need;
1631 /********************************************************************/
1632 cbdata.extdata = sat_calloc(cbdata.nmykeys, sizeof(struct extdata));
1634 xd = cbdata.extdata;
1635 cbdata.current_sub = 0;
1636 /* write main schema */
1638 data_addid(xd, mainschema);
1641 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1643 if (!repodataused[j])
1645 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1649 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1650 cbdata.maxdata = xd->len - cbdata.lastlen;
1651 cbdata.lastlen = xd->len;
1653 if (repo->nsolvables)
1654 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1655 cbdata.doingsolvables = 1;
1656 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1658 if (s->repo != repo)
1660 data_addid(xd, cbdata.solvschemata[n]);
1661 if (cbdata.keymap[SOLVABLE_NAME])
1662 data_addid(xd, needid[s->name].need);
1663 if (cbdata.keymap[SOLVABLE_ARCH])
1664 data_addid(xd, needid[s->arch].need);
1665 if (cbdata.keymap[SOLVABLE_EVR])
1666 data_addid(xd, needid[s->evr].need);
1667 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1668 data_addid(xd, needid[s->vendor].need);
1669 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1670 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1671 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1672 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1673 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1674 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1675 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1676 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1677 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1678 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1679 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1680 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1681 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1682 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1683 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1684 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1685 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1686 data_addu32(xd, repo->rpmdbid[i - repo->start]);
1687 if (anyrepodataused)
1690 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1692 if (!repodataused[j])
1694 if (i < data->start || i >= data->end)
1696 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1699 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1700 cbdata.maxdata = xd->len - cbdata.lastlen;
1701 cbdata.lastlen = xd->len;
1704 cbdata.doingsolvables = 0;
1706 assert(cbdata.current_sub == cbdata.nsubschemata);
1707 if (cbdata.subschemata)
1709 cbdata.subschemata = sat_free(cbdata.subschemata);
1710 cbdata.nsubschemata = 0;
1714 if (repo->nextra && anyrepodataused)
1715 for (i = -1; i >= -repo->nextra; i--)
1718 dataiterator_init(&di, repo, i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE);
1719 entrysize = xd->len;
1720 data_addid(xd, cbdata.extraschemata[-1 - i]);
1722 while (dataiterator_step(&di))
1723 repo_write_adddata(&cbdata, di.data, di.key, &di.kv);
1724 entrysize = xd->len - entrysize;
1725 if (entrysize > maxentrysize)
1726 maxentrysize = entrysize;
1730 /********************************************************************/
1734 /* write file header */
1735 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1736 write_u32(fp, SOLV_VERSION_8);
1740 write_u32(fp, nstrings);
1741 write_u32(fp, nrels);
1742 write_u32(fp, ndirmap);
1743 write_u32(fp, repo->nsolvables);
1744 write_u32(fp, cbdata.nmykeys);
1745 write_u32(fp, cbdata.nmyschemata);
1747 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1748 write_u32(fp, solv_flags);
1751 * calculate prefix encoding of the strings
1753 unsigned char *prefixcomp = sat_malloc(nstrings);
1754 unsigned int compsum = 0;
1758 for (i = 1; i < nstrings; i++)
1760 char *str = spool->stringspace + spool->strings[needid[i].map];
1762 for (same = 0; same < 255; same++)
1763 if (!old_str[same] || old_str[same] != str[same])
1765 prefixcomp[i] = same;
1773 write_u32(fp, sizeid);
1774 /* we save compsum bytes but need 1 extra byte for every string */
1775 write_u32(fp, sizeid + (nstrings ? nstrings - 1 : 0) - compsum);
1776 if (sizeid + (nstrings ? nstrings - 1 : 0) != compsum)
1778 for (i = 1; i < nstrings; i++)
1780 char *str = spool->stringspace + spool->strings[needid[i].map];
1781 write_u8(fp, prefixcomp[i]);
1782 write_str(fp, str + prefixcomp[i]);
1785 sat_free(prefixcomp);
1788 /* Build the prefix-encoding of the string pool. We need to know
1789 the size of that before writing it to the file, so we have to
1790 build a separate buffer for that. As it's temporarily possible
1791 that this actually is an expansion we can't easily reuse the
1792 stringspace for this. The max expansion per string is 1 byte,
1793 so it will fit into sizeid+nstrings bytes. */
1794 char *prefix = sat_malloc(sizeid + nstrings);
1797 for (i = 1; i < nstrings; i++)
1799 char *str = spool->stringspace + spool->strings[needid[i].map];
1802 for (same = 0; same < 255; same++)
1803 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1806 len = strlen(str + same) + 1;
1807 memcpy(pp, str + same, len);
1815 write_u32(fp, sizeid);
1816 write_u32(fp, pp - prefix);
1819 if (fwrite(prefix, pp - prefix, 1, fp) != 1)
1821 perror("write error prefix");
1831 for (i = 0; i < nrels; i++)
1833 ran = pool->rels + (needid[reloff + i].map - reloff);
1834 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1835 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1836 write_u8(fp, ran->flags);
1840 * write dirs (skip both root and / entry)
1842 for (i = 2; i < ndirmap; i++)
1845 write_id(fp, dirmap[i]);
1847 write_id(fp, nstrings - dirmap[i]);
1855 *keyarrayp = sat_calloc(2 * cbdata.nmykeys + 1, sizeof(Id));
1856 for (i = 1; i < cbdata.nmykeys; i++)
1858 write_id(fp, needid[cbdata.mykeys[i].name].need);
1859 write_id(fp, needid[cbdata.mykeys[i].type].need);
1860 if (cbdata.mykeys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1862 if (cbdata.mykeys[i].type == type_constantid)
1863 write_id(fp, needid[cbdata.mykeys[i].size].need);
1865 write_id(fp, cbdata.mykeys[i].size);
1868 write_id(fp, cbdata.extdata[i].len);
1869 write_id(fp, cbdata.mykeys[i].storage);
1872 (*keyarrayp)[2 * i - 2] = cbdata.mykeys[i].name;
1873 (*keyarrayp)[2 * i - 1] = cbdata.mykeys[i].type;
1880 write_id(fp, cbdata.myschemadatalen);
1881 if (cbdata.nmyschemata)
1883 for (i = 1; i < cbdata.nmyschemata; i++)
1884 write_idarray(fp, pool, 0, cbdata.myschemadata + cbdata.myschemata[i]);
1899 for (i = 0; i < nsubfiles; i++)
1904 data_addid(&xd, repodataschemata[i]);
1905 if (fileinfo[i].addedfileprovides || fileinfo[i].rpmdbcookie)
1907 if (fileinfo[i].addedfileprovides)
1908 data_addidarray_sort(&xd, pool, needid, fileinfo[i].addedfileprovides, 0);
1909 if (fileinfo[i].rpmdbcookie)
1910 data_addblob(&xd, fileinfo[i].rpmdbcookie, 32);
1914 /* key,type array + location, write idarray */
1915 for (j = 1; j < fileinfo[i].nkeys; j++)
1917 data_addideof(&xd, needid[fileinfo[i].keys[j].name].need, 0);
1918 data_addideof(&xd, needid[fileinfo[i].keys[j].type].need, j == fileinfo[i].nkeys - 1);
1920 if (fileinfo[i].location)
1921 data_addblob(&xd, (unsigned char *)fileinfo[i].location, strlen(fileinfo[i].location) + 1);
1928 write_id(fp, xd.len);
1929 write_blob(fp, xd.buf, xd.len);
1934 /********************************************************************/
1936 write_id(fp, cbdata.maxdata);
1937 write_id(fp, cbdata.extdata[0].len);
1938 if (cbdata.extdata[0].len)
1939 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1940 sat_free(cbdata.extdata[0].buf);
1944 * write Solvable data
1946 if (repo->nsolvables || repo->nextra)
1948 write_id(fp, maxentrysize);
1949 write_id(fp, cbdata.extdata[0].len);
1950 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1952 sat_free(cbdata.extdata[0].buf);
1955 /* write vertical data */
1956 for (i = 1; i < cbdata.nmykeys; i++)
1957 if (cbdata.extdata[i].len)
1959 if (i < cbdata.nmykeys)
1961 unsigned char *dp, vpage[BLOB_PAGESIZE];
1962 int l, ll, lpage = 0;
1964 write_u32(fp, BLOB_PAGESIZE);
1965 for (i = 1; i < cbdata.nmykeys; i++)
1967 if (!cbdata.extdata[i].len)
1969 l = cbdata.extdata[i].len;
1970 dp = cbdata.extdata[i].buf;
1973 ll = BLOB_PAGESIZE - lpage;
1976 memcpy(vpage + lpage, dp, ll);
1980 if (lpage == BLOB_PAGESIZE)
1982 write_compressed_page(fp, vpage, lpage);
1988 write_compressed_page(fp, vpage, lpage);
1992 /* write vertical_offset entries */
1993 write_u32(fp, 0); /* no paging */
1994 for (i = 1; i < cbdata.nmykeys; i++)
1995 if (cbdata.extdata[i].len)
1996 write_blob(fp, cbdata.extdata[i].buf, cbdata.extdata[i].len);
1998 /* Fill fileinfo for our caller. */
2001 fileinfo->checksum = 0;
2002 fileinfo->nchecksum = 0;
2003 fileinfo->checksumtype = 0;
2004 fileinfo->location = 0;
2008 for (i = 1; i < cbdata.nmykeys; i++)
2009 sat_free(cbdata.extdata[i].buf);
2010 sat_free(cbdata.extdata);
2012 if (cbdata.ownspool)
2014 sat_free(cbdata.ownspool->strings);
2015 sat_free(cbdata.ownspool->stringspace);
2016 sat_free(cbdata.ownspool->stringhashtbl);
2018 if (cbdata.owndirpool)
2020 sat_free(cbdata.owndirpool->dirs);
2021 sat_free(cbdata.owndirpool->dirtraverse);
2024 sat_free(cbdata.extraschemata);
2025 sat_free(cbdata.solvschemata);
2026 sat_free(cbdata.myschemadata);
2027 sat_free(cbdata.myschemata);
2028 sat_free(cbdata.schema);
2030 sat_free(cbdata.mykeys);
2031 sat_free(cbdata.keymap);
2032 sat_free(cbdata.keymapstart);
2033 sat_free(cbdata.dirused);
2034 sat_free(repodataused);
2035 sat_free(repodataschemata);
2038 struct repodata_write_data {
2039 int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
2045 repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata)
2047 struct repodata_write_data *wd = kfdata;
2049 /* XXX: special repodata selection hack */
2050 if (key->name == 1 && key->size != wd->repodataid)
2052 if (key->storage == KEY_STORAGE_SOLVABLE)
2053 return KEY_STORAGE_DROPPED; /* not part of this repodata */
2055 return (*wd->keyfilter)(repo, key, wd->kfdata);
2056 return key->storage;
2060 repodata_write(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata)
2062 struct repodata_write_data wd;
2064 wd.keyfilter = keyfilter;
2066 wd.repodataid = data - data->repo->repodata;
2067 repo_write(data->repo, fp, repodata_write_keyfilter, &wd, 0);