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));
212 write_str(FILE *fp, const char *str)
214 if (fputs (str, fp) == EOF || putc (0, fp) == EOF)
216 perror("write error");
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);
361 Stringpool *ownspool;
373 Id *schema; /* schema construction space */
374 Id *sp; /* pointer in above */
375 Id *oldschema, *oldsp;
383 Id schematacache[256];
391 struct extdata *extdata;
400 int doingsolvables; /* working on solvables data */
403 #define NEEDED_BLOCK 1023
404 #define SCHEMATA_BLOCK 31
405 #define SCHEMATADATA_BLOCK 255
406 #define EXTDATA_BLOCK 4095
409 data_addid(struct extdata *xd, Id x)
412 xd->buf = sat_extend(xd->buf, xd->len, 5, 1, EXTDATA_BLOCK);
413 dp = xd->buf + xd->len;
418 *dp++ = (x >> 28) | 128;
420 *dp++ = (x >> 21) | 128;
421 *dp++ = (x >> 14) | 128;
424 *dp++ = (x >> 7) | 128;
426 xd->len = dp - xd->buf;
430 data_addideof(struct extdata *xd, Id x, int eof)
433 x = (x & 63) | ((x & ~63) << 1);
434 data_addid(xd, (eof ? x: x | 64));
438 data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
450 for (len = 0; len < 64 && ids[len]; len++)
454 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
459 for (i = len + 1; ids[i]; i++)
461 sids = sat_malloc2(i, sizeof(Id));
462 memcpy(sids, lids, 64 * sizeof(Id));
463 for (; ids[len]; len++)
467 id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
474 /* That bloody solvable:prereqmarker needs to stay in position :-( */
476 marker = needid[marker].need;
477 for (i = 0; i < len; i++)
478 if (sids[i] == marker)
481 sat_sort(sids, i, sizeof (Id), cmp_ids, 0);
483 sat_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
487 /* The differencing above produces many runs of ones and twos. I tried
488 fairly elaborate schemes to RLE those, but they give only very mediocre
489 improvements in compression, as coding the escapes costs quite some
490 space. Even if they are coded only as bits in IDs. The best improvement
491 was about 2.7% for the whole .solv file. It's probably better to
492 invest some complexity into sharing idarrays, than RLEing. */
493 for (i = 0; i < len - 1; i++)
496 /* Ugly PREREQ handling. A "difference" of 0 is the prereq marker,
497 hence all real differences are offsetted by 1. Otherwise we would
498 have to handle negative differences, which would cost code space for
499 the encoding of the sign. We loose the exact mapping of prereq here,
500 but we know the result, so we can recover from that in the reader. */
508 /* XXX If difference is zero we have multiple equal elements,
509 we might want to skip writing them out. */
511 id = (id & 63) | ((id & ~63) << 1);
512 data_addid(xd, id | 64);
520 id = (id & 63) | ((id & ~63) << 1);
527 data_addblob(struct extdata *xd, unsigned char *blob, int len)
529 xd->buf = sat_extend(xd->buf, xd->len, len, 1, EXTDATA_BLOCK);
530 memcpy(xd->buf + xd->len, blob, len);
535 data_addu32(struct extdata *xd, unsigned int num)
542 data_addblob(xd, d, 4);
546 addschema(struct cbdata *cbdata, Id *schema)
551 for (sp = schema, len = 0, h = 0; *sp; len++)
556 cid = cbdata->schematacache[h];
559 if (!memcmp(cbdata->myschemadata + cbdata->myschemata[cid], schema, len * sizeof(Id)))
562 for (cid = 1; cid < cbdata->nmyschemata; cid++)
563 if (!memcmp(cbdata->myschemadata + cbdata->myschemata[cid], schema, len * sizeof(Id)))
566 /* a new one. make room. */
567 if (!cbdata->nmyschemata)
569 /* allocate schema 0, it is always empty */
570 cbdata->myschemadata = sat_extend(cbdata->myschemadata, cbdata->myschemadatalen, 1, sizeof(Id), SCHEMATADATA_BLOCK);
571 cbdata->myschemata = sat_extend(cbdata->myschemata, cbdata->nmyschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
572 cbdata->myschemata[0] = 0;
573 cbdata->myschemadata[0] = 0;
574 cbdata->nmyschemata = 1;
575 cbdata->myschemadatalen = 1;
578 cbdata->myschemadata = sat_extend(cbdata->myschemadata, cbdata->myschemadatalen, len, sizeof(Id), SCHEMATADATA_BLOCK);
579 cbdata->myschemata = sat_extend(cbdata->myschemata, cbdata->nmyschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
580 memcpy(cbdata->myschemadata + cbdata->myschemadatalen, schema, len * sizeof(Id));
581 cbdata->myschemata[cbdata->nmyschemata] = cbdata->myschemadatalen;
582 cbdata->myschemadatalen += len;
583 cbdata->schematacache[h] = cbdata->nmyschemata;
584 return cbdata->nmyschemata++;
588 putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
590 const char *str = stringpool_id2str(ss, id);
591 id = stringpool_str2id(cbdata->ownspool, str, 1);
592 if (id >= cbdata->needid[0].map)
594 int oldoff = cbdata->needid[0].map;
595 int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
596 int nrels = cbdata->repo->pool->nrels;
597 cbdata->needid = sat_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
599 memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
600 memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
601 cbdata->needid[0].map = newoff;
607 putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
611 parent = dirpool_parent(dp, dir);
613 parent = putinowndirpool(cbdata, data, dp, parent);
614 compid = dp->dirs[dir];
615 if (cbdata->ownspool && compid > 1)
616 compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
617 return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
621 setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
623 if (cbdata->dirused[dir])
625 cbdata->dirused[dir] = 1;
626 while ((dir = dirpool_parent(dp, dir)) != 0)
628 if (cbdata->dirused[dir] == 2)
630 if (cbdata->dirused[dir])
632 cbdata->dirused[dir] = 2;
635 cbdata->dirused[dir] = 2;
637 cbdata->dirused[0] = 2;
641 repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
646 if (key->name == REPOSITORY_SOLVABLES)
647 return SEARCH_NEXT_KEY; /* we do not want this one */
648 if (data != data->repo->repodata + data->repo->nrepodata - 1)
649 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS)
650 return SEARCH_NEXT_KEY;
652 rm = cbdata->keymap[cbdata->keymapstart[data - data->repo->repodata] + (key - data->keys)];
654 return SEARCH_NEXT_KEY; /* we do not want this one */
655 /* record key in schema */
656 if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
657 && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
661 case REPOKEY_TYPE_ID:
662 case REPOKEY_TYPE_IDARRAY:
664 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
665 id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
666 incneedid(repo->pool, id, cbdata->needid);
668 case REPOKEY_TYPE_DIR:
669 case REPOKEY_TYPE_DIRNUMNUMARRAY:
670 case REPOKEY_TYPE_DIRSTRARRAY:
672 if (cbdata->owndirpool)
673 putinowndirpool(cbdata, data, &data->dirpool, id);
675 setdirused(cbdata, &data->dirpool, id);
677 case REPOKEY_TYPE_FIXARRAY:
680 if (cbdata->oldschema)
682 fprintf(stderr, "nested structs not yet implemented\n");
685 cbdata->oldschema = cbdata->schema;
686 cbdata->oldsp = cbdata->sp;
687 cbdata->schema = sat_calloc(cbdata->nmykeys, sizeof(Id));
688 cbdata->sp = cbdata->schema;
690 else if (kv->eof == 1)
692 cbdata->current_sub++;
694 cbdata->subschemata = sat_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
695 cbdata->subschemata[cbdata->nsubschemata++] = addschema(cbdata, cbdata->schema);
697 fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
699 cbdata->sp = cbdata->schema;
703 sat_free(cbdata->schema);
704 cbdata->schema = cbdata->oldschema;
705 cbdata->sp = cbdata->oldsp;
706 cbdata->oldsp = cbdata->oldschema = 0;
709 case REPOKEY_TYPE_FLEXARRAY:
713 *cbdata->sp++ = 0; /* mark start */
717 /* just finished a schema, rewind */
718 Id *sp = cbdata->sp - 1;
722 cbdata->subschemata = sat_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
723 cbdata->subschemata[cbdata->nsubschemata++] = addschema(cbdata, sp);
724 cbdata->sp = kv->eof == 2 ? sp - 1: sp;
734 repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
736 struct cbdata *cbdata = vcbdata;
737 Repo *repo = data->repo;
741 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);
743 return repo_write_collect_needed(cbdata, repo, data, key, kv);
747 repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
755 if (key->name == REPOSITORY_SOLVABLES)
756 return SEARCH_NEXT_KEY;
757 if (data != data->repo->repodata + data->repo->nrepodata - 1)
758 if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS)
759 return SEARCH_NEXT_KEY;
761 rm = cbdata->keymap[cbdata->keymapstart[data - data->repo->repodata] + (key - data->keys)];
763 return SEARCH_NEXT_KEY; /* we do not want this one */
765 if (cbdata->mykeys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
767 xd = cbdata->extdata + rm; /* vertical buffer */
768 if (cbdata->vstart == -1)
769 cbdata->vstart = xd->len;
772 xd = cbdata->extdata + 0; /* incore buffer */
775 case REPOKEY_TYPE_VOID:
776 case REPOKEY_TYPE_CONSTANT:
777 case REPOKEY_TYPE_CONSTANTID:
779 case REPOKEY_TYPE_ID:
781 if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
782 id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
783 id = cbdata->needid[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 id = cbdata->needid[id].need;
791 data_addideof(xd, id, kv->eof);
793 case REPOKEY_TYPE_STR:
794 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
796 case REPOKEY_TYPE_MD5:
797 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_MD5);
799 case REPOKEY_TYPE_SHA1:
800 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA1);
802 case REPOKEY_TYPE_SHA256:
803 data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA256);
805 case REPOKEY_TYPE_U32:
811 data_addblob(xd, v, 4);
813 case REPOKEY_TYPE_NUM:
814 data_addid(xd, kv->num);
816 case REPOKEY_TYPE_DIR:
818 if (cbdata->owndirpool)
819 id = putinowndirpool(cbdata, data, &data->dirpool, id);
820 id = cbdata->dirused[id];
823 case REPOKEY_TYPE_DIRNUMNUMARRAY:
825 if (cbdata->owndirpool)
826 id = putinowndirpool(cbdata, data, &data->dirpool, id);
827 id = cbdata->dirused[id];
829 data_addid(xd, kv->num);
830 data_addideof(xd, kv->num2, kv->eof);
832 case REPOKEY_TYPE_DIRSTRARRAY:
834 if (cbdata->owndirpool)
835 id = putinowndirpool(cbdata, data, &data->dirpool, id);
836 id = cbdata->dirused[id];
837 data_addideof(xd, id, kv->eof);
838 data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
840 case REPOKEY_TYPE_FIXARRAY:
845 data_addid(xd, kv->num);
846 data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
848 fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
852 else if (kv->eof == 1)
854 cbdata->current_sub++;
860 case REPOKEY_TYPE_FLEXARRAY:
862 data_addid(xd, kv->num);
864 data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
865 if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
867 if (xd->len - cbdata->lastlen > cbdata->maxdata)
868 cbdata->maxdata = xd->len - cbdata->lastlen;
869 cbdata->lastlen = xd->len;
873 fprintf(stderr, "unknown type for %d: %d\n", key->name, key->type);
876 if (cbdata->mykeys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
878 /* we can re-use old data in the blob here! */
879 data_addid(cbdata->extdata + 0, cbdata->vstart); /* add offset into incore data */
880 data_addid(cbdata->extdata + 0, xd->len - cbdata->vstart); /* add length into incore data */
887 repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
889 struct cbdata *cbdata = vcbdata;
890 return repo_write_adddata(cbdata, data, key, kv);
894 traverse_dirs(Dirpool *dp, Id *dirmap, Id n, Id dir, Id *used)
900 /* special case for '/', which has to come first */
903 for (sib = dir; sib; sib = dirpool_sibling(dp, sib))
905 if (used && !used[sib])
907 if (sib == 1 && parent == 1)
908 continue; /* already did that one above */
912 for (; parent < lastn; parent++)
914 sib = dirmap[parent];
915 if (used && used[sib] != 2)
917 child = dirpool_child(dp, sib);
920 dirmap[n++] = -parent;
921 n = traverse_dirs(dp, dirmap, n, child, used);
928 write_compressed_page(FILE *fp, unsigned char *page, int len)
931 unsigned char cpage[BLOB_PAGESIZE];
933 clen = repopagestore_compress_page(page, len, cpage, len - 1);
936 write_u32(fp, len * 2);
937 write_blob(fp, page, len);
941 write_u32(fp, clen * 2 + 1);
942 write_blob(fp, cpage, clen);
948 static Id subfilekeys[] = {
949 REPODATA_INFO, REPOKEY_TYPE_VOID,
950 REPODATA_EXTERNAL, REPOKEY_TYPE_VOID,
951 REPODATA_KEYS, REPOKEY_TYPE_IDARRAY,
952 REPODATA_LOCATION, REPOKEY_TYPE_STR,
953 REPODATA_ADDEDFILEPROVIDES, REPOKEY_TYPE_REL_IDARRAY,
954 REPODATA_RPMDBCOOKIE, REPOKEY_TYPE_SHA256,
964 repo_write(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Id **keyarrayp)
966 Pool *pool = repo->pool;
972 unsigned int solv_flags;
981 unsigned char *repodataused;
984 struct cbdata cbdata;
987 int poolusage, dirpoolusage, idused, dirused;
990 Repodata *data, *dirpooldata = 0;
991 Stringpool ownspool, *spool;
992 Dirpool owndirpool, *dirpool;
994 Id *repodataschemata = 0;
999 Id type_constantid = 0;
1001 memset(&cbdata, 0, sizeof(cbdata));
1004 /* go through all repodata and find the keys we need */
1005 /* also unify keys */
1006 /* creates: mykeys - key array, still has global pool ids */
1007 /* keymapstart - maps repo number to keymap offset */
1008 /* keymap - maps repo key to my key, 0 -> not used */
1010 /* start with all KEY_STORAGE_SOLVABLE ids */
1012 n = ID_NUM_INTERNAL;
1013 for (i = 0; i < repo->nrepodata; i++)
1014 n += repo->repodata[i].nkeys;
1015 cbdata.mykeys = sat_calloc(n, sizeof(Repokey));
1016 cbdata.keymap = sat_calloc(n, sizeof(Id));
1017 cbdata.keymapstart = sat_calloc(repo->nrepodata, sizeof(Id));
1018 repodataused = sat_calloc(repo->nrepodata, 1);
1023 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
1025 key = cbdata.mykeys + i;
1027 if (i < SOLVABLE_PROVIDES)
1028 key->type = REPOKEY_TYPE_ID;
1029 else if (i < RPM_RPMDBID)
1030 key->type = REPOKEY_TYPE_REL_IDARRAY;
1032 key->type = REPOKEY_TYPE_U32;
1034 key->storage = KEY_STORAGE_SOLVABLE;
1037 key->storage = keyfilter(repo, key, kfdata);
1038 if (key->storage == KEY_STORAGE_DROPPED)
1040 key->storage = KEY_STORAGE_SOLVABLE;
1043 if (key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
1045 cbdata.keymap[i] = i;
1049 if (repo->nsolvables)
1051 key = cbdata.mykeys + cbdata.nmykeys;
1052 key->name = REPOSITORY_SOLVABLES;
1053 key->type = REPOKEY_TYPE_FLEXARRAY;
1055 key->storage = KEY_STORAGE_INCORE;
1056 cbdata.keymap[key->name] = cbdata.nmykeys++;
1060 /* If we store subfile info, generate the necessary keys. */
1063 for (i = 0; subfilekeys[i]; i += 2)
1065 key = cbdata.mykeys + cbdata.nmykeys;
1066 key->name = subfilekeys[i];
1067 key->type = subfilekeys[i + 1];
1069 key->storage = KEY_STORAGE_SOLVABLE;
1070 cbdata.keymap[key->name] = cbdata.nmykeys++;
1079 n = ID_NUM_INTERNAL;
1080 for (i = 0; i < repo->nrepodata; i++)
1082 data = repo->repodata + i;
1083 cbdata.keymapstart[i] = n;
1084 cbdata.keymap[n++] = 0; /* key 0 */
1087 for (j = 1; j < data->nkeys; j++, n++)
1089 key = data->keys + j;
1090 /* see if we already had this one, should use hash for fast miss */
1091 for (k = 0; k < cbdata.nmykeys; k++)
1093 if (key->name == cbdata.mykeys[k].name && key->type == cbdata.mykeys[k].type)
1095 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != cbdata.mykeys[k].size)
1100 if (k < cbdata.nmykeys)
1101 cbdata.keymap[n] = k;
1104 /* found a new key! */
1105 cbdata.mykeys[cbdata.nmykeys] = *key;
1106 key = cbdata.mykeys + cbdata.nmykeys;
1107 key->storage = KEY_STORAGE_INCORE;
1108 if (key->type != REPOKEY_TYPE_CONSTANT && key->type != REPOKEY_TYPE_CONSTANTID)
1112 key->storage = keyfilter(repo, key, kfdata);
1113 if (key->storage == KEY_STORAGE_DROPPED)
1115 cbdata.keymap[n] = 0;
1119 cbdata.keymap[n] = cbdata.nmykeys++;
1121 /* load repodata if not already loaded */
1122 if (data->state == REPODATA_STUB)
1124 if (data->loadcallback)
1125 data->loadcallback(data);
1127 data->state = REPODATA_ERROR;
1128 if (data->state != REPODATA_ERROR)
1130 /* redo this repodata! */
1132 n = cbdata.keymapstart[i];
1136 if (data->state == REPODATA_ERROR)
1139 cbdata.keymap[n] = 0;
1143 repodataused[i] = 1;
1144 anyrepodataused = 1;
1145 if (key->type != REPOKEY_TYPE_STR
1146 && key->type != REPOKEY_TYPE_U32
1147 && key->type != REPOKEY_TYPE_MD5
1148 && key->type != REPOKEY_TYPE_SHA1)
1150 if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
1152 /* make sure we know that key */
1153 if (data->localpool)
1155 stringpool_str2id(&data->spool, id2str(pool, key->name), 1);
1156 stringpool_str2id(&data->spool, id2str(pool, key->type), 1);
1157 if (key->type == REPOKEY_TYPE_CONSTANTID)
1158 stringpool_str2id(&data->spool, id2str(pool, key->size), 1);
1163 if (data->localpool)
1166 poolusage = 3; /* need local pool */
1170 spool = &data->spool;
1177 else if (poolusage != 1)
1178 poolusage = 3; /* need local pool */
1184 dirpoolusage = 3; /* need local dirpool */
1188 dirpool = &data->dirpool;
1195 /* 0: no pool needed at all */
1196 /* 1: use global pool */
1197 /* 2: use repodata local pool */
1198 /* 3: need own pool */
1204 /* hack: reuse global pool so we don't have to map rel ids */
1205 stringpool_clone(spool, &repo->pool->ss);
1208 stringpool_init_empty(spool);
1209 cbdata.ownspool = spool;
1211 else if (poolusage == 0 || poolusage == 1)
1214 spool = &repo->pool->ss;
1216 if (dirpoolusage == 3)
1218 dirpool = &owndirpool;
1220 dirpool_init(dirpool);
1221 cbdata.owndirpool = dirpool;
1224 cbdata.dirused = sat_calloc(dirpool->ndirs, sizeof(Id));
1227 /********************************************************************/
1229 fprintf(stderr, "poolusage: %d\n", poolusage);
1230 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
1231 fprintf(stderr, "nmykeys: %d\n", cbdata.nmykeys);
1232 for (i = 1; i < cbdata.nmykeys; i++)
1233 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);
1236 /********************************************************************/
1238 /* set needed count of all strings and rels,
1239 * find which keys are used in the solvables
1240 * put all strings in own spool
1243 reloff = spool->nstrings;
1245 reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
1247 needid = calloc(reloff + pool->nrels, sizeof(*needid));
1248 needid[0].map = reloff;
1250 cbdata.needid = needid;
1251 cbdata.schema = sat_calloc(cbdata.nmykeys, sizeof(Id));
1252 cbdata.sp = cbdata.schema;
1253 cbdata.solvschemata = sat_calloc(repo->nsolvables, sizeof(Id));
1255 cbdata.extraschemata = sat_calloc(repo->nextra, sizeof(Id));
1258 /* create main schema */
1259 cbdata.sp = cbdata.schema;
1260 /* collect all other data from all repodatas */
1261 /* XXX: merge arrays of equal keys? */
1262 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1263 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1265 /* add solvables if needed */
1266 if (repo->nsolvables)
1268 *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
1269 cbdata.mykeys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
1272 mainschema = addschema(&cbdata, cbdata.schema);
1275 idarraydata = repo->idarraydata;
1277 cbdata.doingsolvables = 1;
1278 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1280 if (s->repo != repo)
1283 /* set schema info, keep in sync with further down */
1285 if (cbdata.keymap[SOLVABLE_NAME])
1287 *sp++ = SOLVABLE_NAME;
1288 needid[s->name].need++;
1290 if (cbdata.keymap[SOLVABLE_ARCH])
1292 *sp++ = SOLVABLE_ARCH;
1293 needid[s->arch].need++;
1295 if (cbdata.keymap[SOLVABLE_EVR])
1297 *sp++ = SOLVABLE_EVR;
1298 needid[s->evr].need++;
1300 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1302 *sp++ = SOLVABLE_VENDOR;
1303 needid[s->vendor].need++;
1305 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1307 *sp++ = SOLVABLE_PROVIDES;
1308 cbdata.mykeys[SOLVABLE_PROVIDES].size += incneedidarray(pool, idarraydata + s->provides, needid);
1310 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1312 *sp++ = SOLVABLE_OBSOLETES;
1313 cbdata.mykeys[SOLVABLE_OBSOLETES].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
1315 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1317 *sp++ = SOLVABLE_CONFLICTS;
1318 cbdata.mykeys[SOLVABLE_CONFLICTS].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
1320 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1322 *sp++ = SOLVABLE_REQUIRES;
1323 cbdata.mykeys[SOLVABLE_REQUIRES].size += incneedidarray(pool, idarraydata + s->requires, needid);
1325 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1327 *sp++ = SOLVABLE_RECOMMENDS;
1328 cbdata.mykeys[SOLVABLE_RECOMMENDS].size += incneedidarray(pool, idarraydata + s->recommends, needid);
1330 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1332 *sp++ = SOLVABLE_SUGGESTS;
1333 cbdata.mykeys[SOLVABLE_SUGGESTS].size += incneedidarray(pool, idarraydata + s->suggests, needid);
1335 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1337 *sp++ = SOLVABLE_SUPPLEMENTS;
1338 cbdata.mykeys[SOLVABLE_SUPPLEMENTS].size += incneedidarray(pool, idarraydata + s->supplements, needid);
1340 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1342 *sp++ = SOLVABLE_ENHANCES;
1343 cbdata.mykeys[SOLVABLE_ENHANCES].size += incneedidarray(pool, idarraydata + s->enhances, needid);
1345 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1347 *sp++ = RPM_RPMDBID;
1348 cbdata.mykeys[RPM_RPMDBID].size++;
1352 if (anyrepodataused)
1354 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1356 if (!repodataused[j])
1358 if (i < data->start || i >= data->end)
1360 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1361 needid = cbdata.needid;
1365 cbdata.solvschemata[n] = addschema(&cbdata, cbdata.schema);
1368 cbdata.doingsolvables = 0;
1369 assert(n == repo->nsolvables);
1372 if (repo->nextra && anyrepodataused)
1373 for (i = -1; i >= -repo->nextra; i--)
1376 dataiterator_init(&di, repo, i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE);
1377 cbdata.sp = cbdata.schema;
1378 while (dataiterator_step(&di))
1379 repo_write_collect_needed(&cbdata, repo, di.data, di.key, &di.kv);
1381 cbdata.extraschemata[-1 - i] = addschema(&cbdata, cbdata.schema);
1384 /* If we have fileinfos to write, setup schemas and increment needid[]
1385 of the right strings. */
1386 for (i = 0; i < nsubfiles; i++)
1392 if (fileinfo[i].addedfileprovides || fileinfo[i].rpmdbcookie)
1394 /* extra info about this file */
1395 *sp++ = cbdata.keymap[REPODATA_INFO];
1396 if (fileinfo[i].addedfileprovides)
1398 *sp++ = cbdata.keymap[REPODATA_ADDEDFILEPROVIDES];
1399 for (j = 0; fileinfo[i].addedfileprovides[j]; j++)
1401 cbdata.mykeys[cbdata.keymap[REPODATA_ADDEDFILEPROVIDES]].size += j + 1;
1403 if (fileinfo[i].rpmdbcookie)
1404 *sp++ = cbdata.keymap[REPODATA_RPMDBCOOKIE];
1408 *sp++ = cbdata.keymap[REPODATA_EXTERNAL];
1409 *sp++ = cbdata.keymap[REPODATA_KEYS];
1410 if (fileinfo[i].location)
1411 *sp++ = cbdata.keymap[REPODATA_LOCATION];
1414 repodataschemata[i] = addschema(&cbdata, schema);
1415 cbdata.mykeys[cbdata.keymap[REPODATA_KEYS]].size += 2 * fileinfo[i].nkeys + 1;
1416 for (j = 1; j < fileinfo[i].nkeys; j++)
1418 needid[fileinfo[i].keys[j].type].need++;
1419 needid[fileinfo[i].keys[j].name].need++;
1424 /********************************************************************/
1426 /* remove unused keys, convert ids to local ids and increment their needid */
1427 keyused = sat_calloc(cbdata.nmykeys, sizeof(Id));
1428 for (i = 0; i < cbdata.myschemadatalen; i++)
1429 keyused[cbdata.myschemadata[i]] = 1;
1431 for (n = i = 1; i < cbdata.nmykeys; i++)
1437 cbdata.mykeys[n] = cbdata.mykeys[i];
1438 if (cbdata.mykeys[n].type == REPOKEY_TYPE_CONSTANTID)
1440 if (!type_constantid)
1441 type_constantid = poolusage > 1 ? stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].type), 1) : REPOKEY_TYPE_CONSTANTID;
1443 cbdata.mykeys[n].size = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].size), 1);
1444 needid[cbdata.mykeys[n].size].need++;
1448 cbdata.mykeys[n].name = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].name), 1);
1449 cbdata.mykeys[n].type = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].type), 1);
1451 needid[cbdata.mykeys[n].name].need++;
1452 needid[cbdata.mykeys[n].type].need++;
1456 for (i = 0; i < cbdata.myschemadatalen; i++)
1457 cbdata.myschemadata[i] = keyused[cbdata.myschemadata[i]];
1458 for (i = 0; i < cbdata.nkeymap; i++)
1459 cbdata.keymap[i] = keyused[cbdata.keymap[i]];
1460 keyused = sat_free(keyused);
1462 /********************************************************************/
1464 /* increment need id for used dir components */
1465 if (cbdata.dirused && !cbdata.dirused[0])
1467 /* no dirs used at all */
1468 cbdata.dirused = sat_free(cbdata.dirused);
1473 for (i = 1; i < dirpool->ndirs; i++)
1476 fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
1478 id = dirpool->dirs[i];
1481 if (cbdata.dirused && !cbdata.dirused[i])
1483 if (cbdata.ownspool && dirpooldata && id > 1)
1485 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1486 needid = cbdata.needid;
1492 reloff = needid[0].map;
1495 /********************************************************************/
1498 * create mapping table, new keys are sorted by needid[].need
1500 * needid[key].need : old key -> new key
1501 * needid[key].map : new key -> old key
1504 /* zero out id 0 and rel 0 just in case */
1507 needid[reloff].need = 0;
1509 for (i = 1; i < reloff + pool->nrels; i++)
1513 sat_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
1515 /* make first entry '' */
1517 sat_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
1519 sat_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
1522 for (i = 1; i < reloff; i++)
1524 if (!needid[i].need)
1527 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1531 for (i = 1; i < nstrings; i++)
1532 needid[needid[i].map].need = i;
1534 for (i = 0; i < pool->nrels; i++)
1536 if (!needid[reloff + i].need)
1539 needid[reloff + i].need = 0;
1543 for (i = 0; i < nrels; i++)
1544 needid[needid[reloff + i].map].need = nstrings + i;
1547 /********************************************************************/
1549 /* create dir map */
1554 if (cbdata.dirused && !cbdata.dirused[1])
1555 cbdata.dirused[1] = 1; /* always want / entry */
1556 dirmap = sat_calloc(dirpool->ndirs, sizeof(Id));
1558 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1559 if (!cbdata.dirused)
1560 cbdata.dirused = sat_malloc2(dirpool->ndirs, sizeof(Id));
1561 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1562 for (i = 1; i < ndirmap; i++)
1566 cbdata.dirused[dirmap[i]] = i;
1567 id = dirpool->dirs[dirmap[i]];
1568 if (cbdata.ownspool && dirpooldata && id > 1)
1569 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1570 dirmap[i] = needid[id].need;
1574 /********************************************************************/
1575 cbdata.extdata = sat_calloc(cbdata.nmykeys, sizeof(struct extdata));
1577 xd = cbdata.extdata;
1578 cbdata.current_sub = 0;
1579 /* write main schema */
1581 data_addid(xd, mainschema);
1584 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1585 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1588 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1589 cbdata.maxdata = xd->len - cbdata.lastlen;
1590 cbdata.lastlen = xd->len;
1592 if (repo->nsolvables)
1593 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1594 cbdata.doingsolvables = 1;
1595 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1597 if (s->repo != repo)
1599 data_addid(xd, cbdata.solvschemata[n]);
1600 if (cbdata.keymap[SOLVABLE_NAME])
1601 data_addid(xd, needid[s->name].need);
1602 if (cbdata.keymap[SOLVABLE_ARCH])
1603 data_addid(xd, needid[s->arch].need);
1604 if (cbdata.keymap[SOLVABLE_EVR])
1605 data_addid(xd, needid[s->evr].need);
1606 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1607 data_addid(xd, needid[s->vendor].need);
1608 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1609 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1610 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1611 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1612 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1613 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1614 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1615 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1616 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1617 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1618 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1619 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1620 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1621 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1622 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1623 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1624 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1625 data_addu32(xd, repo->rpmdbid[i - repo->start]);
1626 if (anyrepodataused)
1629 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1631 if (!repodataused[j])
1633 if (i < data->start || i >= data->end)
1635 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1638 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1639 cbdata.maxdata = xd->len - cbdata.lastlen;
1640 cbdata.lastlen = xd->len;
1643 cbdata.doingsolvables = 0;
1645 assert(cbdata.current_sub == cbdata.nsubschemata);
1646 if (cbdata.subschemata)
1648 cbdata.subschemata = sat_free(cbdata.subschemata);
1649 cbdata.nsubschemata = 0;
1653 if (repo->nextra && anyrepodataused)
1654 for (i = -1; i >= -repo->nextra; i--)
1657 dataiterator_init(&di, repo, i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE);
1658 entrysize = xd->len;
1659 data_addid(xd, cbdata.extraschemata[-1 - i]);
1661 while (dataiterator_step(&di))
1662 repo_write_adddata(&cbdata, di.data, di.key, &di.kv);
1663 entrysize = xd->len - entrysize;
1664 if (entrysize > maxentrysize)
1665 maxentrysize = entrysize;
1669 /********************************************************************/
1673 /* write file header */
1674 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1675 write_u32(fp, SOLV_VERSION_8);
1679 write_u32(fp, nstrings);
1680 write_u32(fp, nrels);
1681 write_u32(fp, ndirmap);
1682 write_u32(fp, repo->nsolvables);
1683 write_u32(fp, cbdata.nmykeys);
1684 write_u32(fp, cbdata.nmyschemata);
1686 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1687 write_u32(fp, solv_flags);
1689 /* Build the prefix-encoding of the string pool. We need to know
1690 the size of that before writing it to the file, so we have to
1691 build a separate buffer for that. As it's temporarily possible
1692 that this actually is an expansion we can't easily reuse the
1693 stringspace for this. The max expansion per string is 1 byte,
1694 so it will fit into sizeid+nstrings bytes. */
1695 char *prefix = sat_malloc(sizeid + nstrings);
1698 for (i = 1; i < nstrings; i++)
1700 char *str = spool->stringspace + spool->strings[needid[i].map];
1703 for (same = 0; same < 255; same++)
1704 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1707 len = strlen(str + same) + 1;
1708 memcpy (pp, str + same, len);
1716 write_u32(fp, sizeid);
1717 write_u32(fp, pp - prefix);
1720 if (fwrite(prefix, pp - prefix, 1, fp) != 1)
1722 perror("write error prefix");
1731 for (i = 0; i < nrels; i++)
1733 ran = pool->rels + (needid[reloff + i].map - reloff);
1734 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1735 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1736 write_u8(fp, ran->flags);
1740 * write dirs (skip both root and / entry)
1742 for (i = 2; i < ndirmap; i++)
1745 write_id(fp, dirmap[i]);
1747 write_id(fp, nstrings - dirmap[i]);
1755 *keyarrayp = sat_calloc(2 * cbdata.nmykeys + 1, sizeof(Id));
1756 for (i = 1; i < cbdata.nmykeys; i++)
1758 write_id(fp, needid[cbdata.mykeys[i].name].need);
1759 write_id(fp, needid[cbdata.mykeys[i].type].need);
1760 if (cbdata.mykeys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1762 if (cbdata.mykeys[i].type == type_constantid)
1763 write_id(fp, needid[cbdata.mykeys[i].size].need);
1765 write_id(fp, cbdata.mykeys[i].size);
1768 write_id(fp, cbdata.extdata[i].len);
1769 write_id(fp, cbdata.mykeys[i].storage);
1772 (*keyarrayp)[2 * i - 2] = cbdata.mykeys[i].name;
1773 (*keyarrayp)[2 * i - 1] = cbdata.mykeys[i].type;
1780 write_id(fp, cbdata.myschemadatalen);
1781 if (cbdata.nmyschemata)
1783 for (i = 1; i < cbdata.nmyschemata; i++)
1784 write_idarray(fp, pool, 0, cbdata.myschemadata + cbdata.myschemata[i]);
1799 for (i = 0; i < nsubfiles; i++)
1804 data_addid(&xd, repodataschemata[i]);
1805 if (fileinfo[i].addedfileprovides || fileinfo[i].rpmdbcookie)
1807 if (fileinfo[i].addedfileprovides)
1808 data_addidarray_sort(&xd, pool, needid, fileinfo[i].addedfileprovides, 0);
1809 if (fileinfo[i].rpmdbcookie)
1810 data_addblob(&xd, fileinfo[i].rpmdbcookie, 32);
1814 /* key,type array + location, write idarray */
1815 for (j = 1; j < fileinfo[i].nkeys; j++)
1817 data_addideof(&xd, needid[fileinfo[i].keys[j].name].need, 0);
1818 data_addideof(&xd, needid[fileinfo[i].keys[j].type].need, j == fileinfo[i].nkeys - 1);
1820 if (fileinfo[i].location)
1821 data_addblob(&xd, (unsigned char *)fileinfo[i].location, strlen(fileinfo[i].location) + 1);
1828 write_id(fp, xd.len);
1829 write_blob(fp, xd.buf, xd.len);
1834 /********************************************************************/
1836 write_id(fp, cbdata.maxdata);
1837 write_id(fp, cbdata.extdata[0].len);
1838 if (cbdata.extdata[0].len)
1839 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1840 sat_free(cbdata.extdata[0].buf);
1844 * write Solvable data
1846 if (repo->nsolvables || repo->nextra)
1848 write_id(fp, maxentrysize);
1849 write_id(fp, cbdata.extdata[0].len);
1850 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1852 sat_free(cbdata.extdata[0].buf);
1855 /* write vertical data */
1856 for (i = 1; i < cbdata.nmykeys; i++)
1857 if (cbdata.extdata[i].len)
1859 if (i < cbdata.nmykeys)
1861 unsigned char *dp, vpage[BLOB_PAGESIZE];
1862 int l, ll, lpage = 0;
1864 write_u32(fp, BLOB_PAGESIZE);
1865 for (i = 1; i < cbdata.nmykeys; i++)
1867 if (!cbdata.extdata[i].len)
1869 l = cbdata.extdata[i].len;
1870 dp = cbdata.extdata[i].buf;
1873 ll = BLOB_PAGESIZE - lpage;
1876 memcpy(vpage + lpage, dp, ll);
1880 if (lpage == BLOB_PAGESIZE)
1882 write_compressed_page(fp, vpage, lpage);
1888 write_compressed_page(fp, vpage, lpage);
1892 /* write vertical_offset entries */
1893 write_u32(fp, 0); /* no paging */
1894 for (i = 1; i < cbdata.nmykeys; i++)
1895 if (cbdata.extdata[i].len)
1896 write_blob(fp, cbdata.extdata[i].buf, cbdata.extdata[i].len);
1898 /* Fill fileinfo for our caller. */
1901 fileinfo->checksum = 0;
1902 fileinfo->nchecksum = 0;
1903 fileinfo->checksumtype = 0;
1904 fileinfo->location = 0;
1908 for (i = 1; i < cbdata.nmykeys; i++)
1909 sat_free(cbdata.extdata[i].buf);
1910 sat_free(cbdata.extdata);
1912 if (cbdata.ownspool)
1914 sat_free(cbdata.ownspool->strings);
1915 sat_free(cbdata.ownspool->stringspace);
1916 sat_free(cbdata.ownspool->stringhashtbl);
1918 if (cbdata.owndirpool)
1920 sat_free(cbdata.owndirpool->dirs);
1921 sat_free(cbdata.owndirpool->dirtraverse);
1924 sat_free(cbdata.extraschemata);
1925 sat_free(cbdata.solvschemata);
1926 sat_free(cbdata.myschemadata);
1927 sat_free(cbdata.myschemata);
1928 sat_free(cbdata.schema);
1930 sat_free(cbdata.mykeys);
1931 sat_free(cbdata.keymap);
1932 sat_free(cbdata.keymapstart);
1933 sat_free(cbdata.dirused);
1934 sat_free(repodataused);
1935 sat_free(repodataschemata);