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)
101 const NeedId *a = ap;
102 const NeedId *b = bp;
104 r = b->need - a->need;
107 return a->map - b->map;
110 static Stringpool *cmp_spool;
113 needid_cmp_need_s(const void *ap, const void *bp)
115 const NeedId *a = ap;
116 const NeedId *b = bp;
118 r = b->need - a->need;
121 const char *as = cmp_spool->stringspace + cmp_spool->strings[a->map];
122 const char *bs = cmp_spool->stringspace + cmp_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)
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 qsort(sids, i, sizeof (Id), cmp_ids);
308 qsort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids);
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 qsort(sids, i, sizeof (Id), cmp_ids);
483 qsort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids);
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_create(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++)
1514 qsort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s);
1516 /* make first entry '' */
1518 qsort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s);
1520 qsort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need);
1523 for (i = 1; i < reloff; i++)
1525 if (!needid[i].need)
1528 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1532 for (i = 1; i < nstrings; i++)
1533 needid[needid[i].map].need = i;
1535 for (i = 0; i < pool->nrels; i++)
1537 if (!needid[reloff + i].need)
1540 needid[reloff + i].need = 0;
1544 for (i = 0; i < nrels; i++)
1545 needid[needid[reloff + i].map].need = nstrings + i;
1548 /********************************************************************/
1550 /* create dir map */
1555 if (cbdata.dirused && !cbdata.dirused[1])
1556 cbdata.dirused[1] = 1; /* always want / entry */
1557 dirmap = sat_calloc(dirpool->ndirs, sizeof(Id));
1559 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1560 if (!cbdata.dirused)
1561 cbdata.dirused = sat_malloc2(dirpool->ndirs, sizeof(Id));
1562 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1563 for (i = 1; i < ndirmap; i++)
1567 cbdata.dirused[dirmap[i]] = i;
1568 id = dirpool->dirs[dirmap[i]];
1569 if (cbdata.ownspool && dirpooldata && id > 1)
1570 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1571 dirmap[i] = needid[id].need;
1575 /********************************************************************/
1576 cbdata.extdata = sat_calloc(cbdata.nmykeys, sizeof(struct extdata));
1578 xd = cbdata.extdata;
1579 cbdata.current_sub = 0;
1580 /* write main schema */
1582 data_addid(xd, mainschema);
1585 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1586 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1589 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1590 cbdata.maxdata = xd->len - cbdata.lastlen;
1591 cbdata.lastlen = xd->len;
1593 if (repo->nsolvables)
1594 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1595 cbdata.doingsolvables = 1;
1596 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1598 if (s->repo != repo)
1600 data_addid(xd, cbdata.solvschemata[n]);
1601 if (cbdata.keymap[SOLVABLE_NAME])
1602 data_addid(xd, needid[s->name].need);
1603 if (cbdata.keymap[SOLVABLE_ARCH])
1604 data_addid(xd, needid[s->arch].need);
1605 if (cbdata.keymap[SOLVABLE_EVR])
1606 data_addid(xd, needid[s->evr].need);
1607 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1608 data_addid(xd, needid[s->vendor].need);
1609 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1610 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1611 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1612 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1613 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1614 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1615 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1616 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1617 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1618 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1619 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1620 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1621 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1622 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1623 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1624 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1625 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1626 data_addu32(xd, repo->rpmdbid[i - repo->start]);
1627 if (anyrepodataused)
1630 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1632 if (!repodataused[j])
1634 if (i < data->start || i >= data->end)
1636 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1639 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1640 cbdata.maxdata = xd->len - cbdata.lastlen;
1641 cbdata.lastlen = xd->len;
1644 cbdata.doingsolvables = 0;
1646 assert(cbdata.current_sub == cbdata.nsubschemata);
1647 if (cbdata.subschemata)
1649 cbdata.subschemata = sat_free(cbdata.subschemata);
1650 cbdata.nsubschemata = 0;
1654 if (repo->nextra && anyrepodataused)
1655 for (i = -1; i >= -repo->nextra; i--)
1658 dataiterator_init(&di, repo, i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE);
1659 entrysize = xd->len;
1660 data_addid(xd, cbdata.extraschemata[-1 - i]);
1662 while (dataiterator_step(&di))
1663 repo_write_adddata(&cbdata, di.data, di.key, &di.kv);
1664 entrysize = xd->len - entrysize;
1665 if (entrysize > maxentrysize)
1666 maxentrysize = entrysize;
1670 /********************************************************************/
1674 /* write file header */
1675 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1676 write_u32(fp, SOLV_VERSION_8);
1680 write_u32(fp, nstrings);
1681 write_u32(fp, nrels);
1682 write_u32(fp, ndirmap);
1683 write_u32(fp, repo->nsolvables);
1684 write_u32(fp, cbdata.nmykeys);
1685 write_u32(fp, cbdata.nmyschemata);
1687 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1688 write_u32(fp, solv_flags);
1690 /* Build the prefix-encoding of the string pool. We need to know
1691 the size of that before writing it to the file, so we have to
1692 build a separate buffer for that. As it's temporarily possible
1693 that this actually is an expansion we can't easily reuse the
1694 stringspace for this. The max expansion per string is 1 byte,
1695 so it will fit into sizeid+nstrings bytes. */
1696 char *prefix = sat_malloc(sizeid + nstrings);
1699 for (i = 1; i < nstrings; i++)
1701 char *str = spool->stringspace + spool->strings[needid[i].map];
1704 for (same = 0; same < 255; same++)
1705 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1708 len = strlen(str + same) + 1;
1709 memcpy (pp, str + same, len);
1717 write_u32(fp, sizeid);
1718 write_u32(fp, pp - prefix);
1721 if (fwrite(prefix, pp - prefix, 1, fp) != 1)
1723 perror("write error prefix");
1732 for (i = 0; i < nrels; i++)
1734 ran = pool->rels + (needid[reloff + i].map - reloff);
1735 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1736 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1737 write_u8(fp, ran->flags);
1741 * write dirs (skip both root and / entry)
1743 for (i = 2; i < ndirmap; i++)
1746 write_id(fp, dirmap[i]);
1748 write_id(fp, nstrings - dirmap[i]);
1756 *keyarrayp = sat_calloc(2 * cbdata.nmykeys + 1, sizeof(Id));
1757 for (i = 1; i < cbdata.nmykeys; i++)
1759 write_id(fp, needid[cbdata.mykeys[i].name].need);
1760 write_id(fp, needid[cbdata.mykeys[i].type].need);
1761 if (cbdata.mykeys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1763 if (cbdata.mykeys[i].type == type_constantid)
1764 write_id(fp, needid[cbdata.mykeys[i].size].need);
1766 write_id(fp, cbdata.mykeys[i].size);
1769 write_id(fp, cbdata.extdata[i].len);
1770 write_id(fp, cbdata.mykeys[i].storage);
1773 (*keyarrayp)[2 * i - 2] = cbdata.mykeys[i].name;
1774 (*keyarrayp)[2 * i - 1] = cbdata.mykeys[i].type;
1781 write_id(fp, cbdata.myschemadatalen);
1782 if (cbdata.nmyschemata)
1784 for (i = 1; i < cbdata.nmyschemata; i++)
1785 write_idarray(fp, pool, 0, cbdata.myschemadata + cbdata.myschemata[i]);
1800 for (i = 0; i < nsubfiles; i++)
1805 data_addid(&xd, repodataschemata[i]);
1806 if (fileinfo[i].addedfileprovides || fileinfo[i].rpmdbcookie)
1808 if (fileinfo[i].addedfileprovides)
1809 data_addidarray_sort(&xd, pool, needid, fileinfo[i].addedfileprovides, 0);
1810 if (fileinfo[i].rpmdbcookie)
1811 data_addblob(&xd, fileinfo[i].rpmdbcookie, 32);
1815 /* key,type array + location, write idarray */
1816 for (j = 1; j < fileinfo[i].nkeys; j++)
1818 data_addideof(&xd, needid[fileinfo[i].keys[j].name].need, 0);
1819 data_addideof(&xd, needid[fileinfo[i].keys[j].type].need, j == fileinfo[i].nkeys - 1);
1821 if (fileinfo[i].location)
1822 data_addblob(&xd, (unsigned char *)fileinfo[i].location, strlen(fileinfo[i].location) + 1);
1829 write_id(fp, xd.len);
1830 write_blob(fp, xd.buf, xd.len);
1835 /********************************************************************/
1837 write_id(fp, cbdata.maxdata);
1838 write_id(fp, cbdata.extdata[0].len);
1839 if (cbdata.extdata[0].len)
1840 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1841 sat_free(cbdata.extdata[0].buf);
1845 * write Solvable data
1847 if (repo->nsolvables || repo->nextra)
1849 write_id(fp, maxentrysize);
1850 write_id(fp, cbdata.extdata[0].len);
1851 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1853 sat_free(cbdata.extdata[0].buf);
1856 /* write vertical data */
1857 for (i = 1; i < cbdata.nmykeys; i++)
1858 if (cbdata.extdata[i].len)
1860 if (i < cbdata.nmykeys)
1862 unsigned char *dp, vpage[BLOB_PAGESIZE];
1863 int l, ll, lpage = 0;
1865 write_u32(fp, BLOB_PAGESIZE);
1866 for (i = 1; i < cbdata.nmykeys; i++)
1868 if (!cbdata.extdata[i].len)
1870 l = cbdata.extdata[i].len;
1871 dp = cbdata.extdata[i].buf;
1874 ll = BLOB_PAGESIZE - lpage;
1877 memcpy(vpage + lpage, dp, ll);
1881 if (lpage == BLOB_PAGESIZE)
1883 write_compressed_page(fp, vpage, lpage);
1889 write_compressed_page(fp, vpage, lpage);
1893 /* write vertical_offset entries */
1894 write_u32(fp, 0); /* no paging */
1895 for (i = 1; i < cbdata.nmykeys; i++)
1896 if (cbdata.extdata[i].len)
1897 write_blob(fp, cbdata.extdata[i].buf, cbdata.extdata[i].len);
1899 /* Fill fileinfo for our caller. */
1902 fileinfo->checksum = 0;
1903 fileinfo->nchecksum = 0;
1904 fileinfo->checksumtype = 0;
1905 fileinfo->location = 0;
1909 for (i = 1; i < cbdata.nmykeys; i++)
1910 sat_free(cbdata.extdata[i].buf);
1911 sat_free(cbdata.extdata);
1913 if (cbdata.ownspool)
1915 sat_free(cbdata.ownspool->strings);
1916 sat_free(cbdata.ownspool->stringspace);
1917 sat_free(cbdata.ownspool->stringhashtbl);
1919 if (cbdata.owndirpool)
1921 sat_free(cbdata.owndirpool->dirs);
1922 sat_free(cbdata.owndirpool->dirtraverse);
1925 sat_free(cbdata.extraschemata);
1926 sat_free(cbdata.solvschemata);
1927 sat_free(cbdata.myschemadata);
1928 sat_free(cbdata.myschemata);
1929 sat_free(cbdata.schema);
1931 sat_free(cbdata.mykeys);
1932 sat_free(cbdata.keymap);
1933 sat_free(cbdata.keymapstart);
1934 sat_free(cbdata.dirused);
1935 sat_free(repodataused);
1936 sat_free(repodataschemata);