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,
959 static Id verticals[] = {
961 SOLVABLE_DESCRIPTION,
970 static char *languagetags[] = {
972 "solvable:description:",
973 "solvable:messageins:",
974 "solvable:messagedel:",
980 repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
985 for (i = 0; verticals[i]; i++)
986 if (key->name == verticals[i])
987 return KEY_STORAGE_VERTICAL_OFFSET;
988 keyname = id2str(repo->pool, key->name);
989 for (i = 0; languagetags[i] != 0; i++)
990 if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
991 return KEY_STORAGE_VERTICAL_OFFSET;
992 return KEY_STORAGE_INCORE;
1000 repo_write(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Id **keyarrayp)
1002 Pool *pool = repo->pool;
1006 int nstrings, nrels;
1007 unsigned int sizeid;
1008 unsigned int solv_flags;
1017 unsigned char *repodataused;
1018 int anyrepodataused;
1020 struct cbdata cbdata;
1023 int poolusage, dirpoolusage, idused, dirused;
1026 Repodata *data, *dirpooldata = 0;
1027 Stringpool ownspool, *spool;
1028 Dirpool owndirpool, *dirpool;
1030 Id *repodataschemata = 0;
1035 Id type_constantid = 0;
1037 memset(&cbdata, 0, sizeof(cbdata));
1040 /* go through all repodata and find the keys we need */
1041 /* also unify keys */
1042 /* creates: mykeys - key array, still has global pool ids */
1043 /* keymapstart - maps repo number to keymap offset */
1044 /* keymap - maps repo key to my key, 0 -> not used */
1046 /* start with all KEY_STORAGE_SOLVABLE ids */
1048 n = ID_NUM_INTERNAL;
1049 for (i = 0; i < repo->nrepodata; i++)
1050 n += repo->repodata[i].nkeys;
1051 cbdata.mykeys = sat_calloc(n, sizeof(Repokey));
1052 cbdata.keymap = sat_calloc(n, sizeof(Id));
1053 cbdata.keymapstart = sat_calloc(repo->nrepodata, sizeof(Id));
1054 repodataused = sat_calloc(repo->nrepodata, 1);
1059 for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
1061 key = cbdata.mykeys + i;
1063 if (i < SOLVABLE_PROVIDES)
1064 key->type = REPOKEY_TYPE_ID;
1065 else if (i < RPM_RPMDBID)
1066 key->type = REPOKEY_TYPE_REL_IDARRAY;
1068 key->type = REPOKEY_TYPE_U32;
1070 key->storage = KEY_STORAGE_SOLVABLE;
1073 key->storage = keyfilter(repo, key, kfdata);
1074 if (key->storage == KEY_STORAGE_DROPPED)
1076 key->storage = KEY_STORAGE_SOLVABLE;
1079 if (key->type == REPOKEY_TYPE_IDARRAY || key->type == REPOKEY_TYPE_REL_IDARRAY)
1081 cbdata.keymap[i] = i;
1085 if (repo->nsolvables)
1087 key = cbdata.mykeys + cbdata.nmykeys;
1088 key->name = REPOSITORY_SOLVABLES;
1089 key->type = REPOKEY_TYPE_FLEXARRAY;
1091 key->storage = KEY_STORAGE_INCORE;
1092 cbdata.keymap[key->name] = cbdata.nmykeys++;
1096 /* If we store subfile info, generate the necessary keys. */
1099 for (i = 0; subfilekeys[i]; i += 2)
1101 key = cbdata.mykeys + cbdata.nmykeys;
1102 key->name = subfilekeys[i];
1103 key->type = subfilekeys[i + 1];
1105 key->storage = KEY_STORAGE_SOLVABLE;
1106 cbdata.keymap[key->name] = cbdata.nmykeys++;
1115 n = ID_NUM_INTERNAL;
1116 for (i = 0; i < repo->nrepodata; i++)
1118 data = repo->repodata + i;
1119 cbdata.keymapstart[i] = n;
1120 cbdata.keymap[n++] = 0; /* key 0 */
1126 /* check if we want this repodata */
1127 memset(&zerokey, 0, sizeof(zerokey));
1131 if (keyfilter(repo, &zerokey, kfdata) == -1)
1134 for (j = 1; j < data->nkeys; j++, n++)
1136 key = data->keys + j;
1137 if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
1139 cbdata.keymap[n] = cbdata.keymap[key->name];
1142 /* see if we already had this one, should use hash for fast miss */
1143 for (k = 0; k < cbdata.nmykeys; k++)
1145 if (key->name == cbdata.mykeys[k].name && key->type == cbdata.mykeys[k].type)
1147 if ((key->type == REPOKEY_TYPE_CONSTANT || key->type == REPOKEY_TYPE_CONSTANTID) && key->size != cbdata.mykeys[k].size)
1152 if (k < cbdata.nmykeys)
1153 cbdata.keymap[n] = k;
1156 /* found a new key! */
1157 cbdata.mykeys[cbdata.nmykeys] = *key;
1158 key = cbdata.mykeys + cbdata.nmykeys;
1159 key->storage = KEY_STORAGE_INCORE;
1160 if (key->type != REPOKEY_TYPE_CONSTANT && key->type != REPOKEY_TYPE_CONSTANTID)
1164 key->storage = keyfilter(repo, key, kfdata);
1165 if (key->storage == KEY_STORAGE_DROPPED)
1167 cbdata.keymap[n] = 0;
1171 cbdata.keymap[n] = cbdata.nmykeys++;
1173 /* load repodata if not already loaded */
1174 if (data->state == REPODATA_STUB)
1176 if (data->loadcallback)
1177 data->loadcallback(data);
1179 data->state = REPODATA_ERROR;
1180 if (data->state != REPODATA_ERROR)
1182 /* redo this repodata! */
1184 n = cbdata.keymapstart[i];
1188 if (data->state == REPODATA_ERROR)
1191 cbdata.keymap[n] = 0;
1195 repodataused[i] = 1;
1196 anyrepodataused = 1;
1197 if (key->type != REPOKEY_TYPE_STR
1198 && key->type != REPOKEY_TYPE_U32
1199 && key->type != REPOKEY_TYPE_MD5
1200 && key->type != REPOKEY_TYPE_SHA1)
1202 if (key->type == REPOKEY_TYPE_DIR || key->type == REPOKEY_TYPE_DIRNUMNUMARRAY || key->type == REPOKEY_TYPE_DIRSTRARRAY)
1204 /* make sure we know that key */
1205 if (data->localpool)
1207 stringpool_str2id(&data->spool, id2str(pool, key->name), 1);
1208 stringpool_str2id(&data->spool, id2str(pool, key->type), 1);
1209 if (key->type == REPOKEY_TYPE_CONSTANTID)
1210 stringpool_str2id(&data->spool, id2str(pool, key->size), 1);
1215 if (data->localpool)
1218 poolusage = 3; /* need local pool */
1222 spool = &data->spool;
1229 else if (poolusage != 1)
1230 poolusage = 3; /* need local pool */
1236 dirpoolusage = 3; /* need local dirpool */
1240 dirpool = &data->dirpool;
1247 /* 0: no pool needed at all */
1248 /* 1: use global pool */
1249 /* 2: use repodata local pool */
1250 /* 3: need own pool */
1256 /* hack: reuse global pool so we don't have to map rel ids */
1257 stringpool_clone(spool, &repo->pool->ss);
1260 stringpool_init_empty(spool);
1261 cbdata.ownspool = spool;
1263 else if (poolusage == 0 || poolusage == 1)
1266 spool = &repo->pool->ss;
1268 if (dirpoolusage == 3)
1270 dirpool = &owndirpool;
1272 dirpool_init(dirpool);
1273 cbdata.owndirpool = dirpool;
1276 cbdata.dirused = sat_calloc(dirpool->ndirs, sizeof(Id));
1279 /********************************************************************/
1281 fprintf(stderr, "poolusage: %d\n", poolusage);
1282 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
1283 fprintf(stderr, "nmykeys: %d\n", cbdata.nmykeys);
1284 for (i = 1; i < cbdata.nmykeys; i++)
1285 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);
1288 /********************************************************************/
1290 /* set needed count of all strings and rels,
1291 * find which keys are used in the solvables
1292 * put all strings in own spool
1295 reloff = spool->nstrings;
1297 reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
1299 needid = calloc(reloff + pool->nrels, sizeof(*needid));
1300 needid[0].map = reloff;
1302 cbdata.needid = needid;
1303 cbdata.schema = sat_calloc(cbdata.nmykeys, sizeof(Id));
1304 cbdata.sp = cbdata.schema;
1305 cbdata.solvschemata = sat_calloc(repo->nsolvables, sizeof(Id));
1307 cbdata.extraschemata = sat_calloc(repo->nextra, sizeof(Id));
1310 /* create main schema */
1311 cbdata.sp = cbdata.schema;
1312 /* collect all other data from all repodatas */
1313 /* XXX: merge arrays of equal keys? */
1314 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1316 if (!repodataused[j])
1318 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1321 /* add solvables if needed */
1322 if (repo->nsolvables)
1324 *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
1325 cbdata.mykeys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
1328 mainschema = addschema(&cbdata, cbdata.schema);
1331 idarraydata = repo->idarraydata;
1333 cbdata.doingsolvables = 1;
1334 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1336 if (s->repo != repo)
1339 /* set schema info, keep in sync with further down */
1341 if (cbdata.keymap[SOLVABLE_NAME])
1343 *sp++ = SOLVABLE_NAME;
1344 needid[s->name].need++;
1346 if (cbdata.keymap[SOLVABLE_ARCH])
1348 *sp++ = SOLVABLE_ARCH;
1349 needid[s->arch].need++;
1351 if (cbdata.keymap[SOLVABLE_EVR])
1353 *sp++ = SOLVABLE_EVR;
1354 needid[s->evr].need++;
1356 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1358 *sp++ = SOLVABLE_VENDOR;
1359 needid[s->vendor].need++;
1361 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1363 *sp++ = SOLVABLE_PROVIDES;
1364 cbdata.mykeys[SOLVABLE_PROVIDES].size += incneedidarray(pool, idarraydata + s->provides, needid);
1366 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1368 *sp++ = SOLVABLE_OBSOLETES;
1369 cbdata.mykeys[SOLVABLE_OBSOLETES].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
1371 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1373 *sp++ = SOLVABLE_CONFLICTS;
1374 cbdata.mykeys[SOLVABLE_CONFLICTS].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
1376 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1378 *sp++ = SOLVABLE_REQUIRES;
1379 cbdata.mykeys[SOLVABLE_REQUIRES].size += incneedidarray(pool, idarraydata + s->requires, needid);
1381 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1383 *sp++ = SOLVABLE_RECOMMENDS;
1384 cbdata.mykeys[SOLVABLE_RECOMMENDS].size += incneedidarray(pool, idarraydata + s->recommends, needid);
1386 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1388 *sp++ = SOLVABLE_SUGGESTS;
1389 cbdata.mykeys[SOLVABLE_SUGGESTS].size += incneedidarray(pool, idarraydata + s->suggests, needid);
1391 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1393 *sp++ = SOLVABLE_SUPPLEMENTS;
1394 cbdata.mykeys[SOLVABLE_SUPPLEMENTS].size += incneedidarray(pool, idarraydata + s->supplements, needid);
1396 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1398 *sp++ = SOLVABLE_ENHANCES;
1399 cbdata.mykeys[SOLVABLE_ENHANCES].size += incneedidarray(pool, idarraydata + s->enhances, needid);
1401 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1403 *sp++ = RPM_RPMDBID;
1404 cbdata.mykeys[RPM_RPMDBID].size++;
1408 if (anyrepodataused)
1410 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1412 if (!repodataused[j])
1414 if (i < data->start || i >= data->end)
1416 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
1417 needid = cbdata.needid;
1421 cbdata.solvschemata[n] = addschema(&cbdata, cbdata.schema);
1424 cbdata.doingsolvables = 0;
1425 assert(n == repo->nsolvables);
1428 if (repo->nextra && anyrepodataused)
1429 for (i = -1; i >= -repo->nextra; i--)
1432 dataiterator_init(&di, repo, i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE);
1433 cbdata.sp = cbdata.schema;
1434 while (dataiterator_step(&di))
1435 repo_write_collect_needed(&cbdata, repo, di.data, di.key, &di.kv);
1437 cbdata.extraschemata[-1 - i] = addschema(&cbdata, cbdata.schema);
1440 /* If we have fileinfos to write, setup schemas and increment needid[]
1441 of the right strings. */
1442 for (i = 0; i < nsubfiles; i++)
1448 if (fileinfo[i].addedfileprovides || fileinfo[i].rpmdbcookie)
1450 /* extra info about this file */
1451 *sp++ = cbdata.keymap[REPODATA_INFO];
1452 if (fileinfo[i].addedfileprovides)
1454 *sp++ = cbdata.keymap[REPODATA_ADDEDFILEPROVIDES];
1455 for (j = 0; fileinfo[i].addedfileprovides[j]; j++)
1457 cbdata.mykeys[cbdata.keymap[REPODATA_ADDEDFILEPROVIDES]].size += j + 1;
1459 if (fileinfo[i].rpmdbcookie)
1460 *sp++ = cbdata.keymap[REPODATA_RPMDBCOOKIE];
1464 *sp++ = cbdata.keymap[REPODATA_EXTERNAL];
1465 *sp++ = cbdata.keymap[REPODATA_KEYS];
1466 if (fileinfo[i].location)
1467 *sp++ = cbdata.keymap[REPODATA_LOCATION];
1470 repodataschemata[i] = addschema(&cbdata, schema);
1471 cbdata.mykeys[cbdata.keymap[REPODATA_KEYS]].size += 2 * fileinfo[i].nkeys + 1;
1472 for (j = 1; j < fileinfo[i].nkeys; j++)
1474 needid[fileinfo[i].keys[j].type].need++;
1475 needid[fileinfo[i].keys[j].name].need++;
1480 /********************************************************************/
1482 /* remove unused keys, convert ids to local ids and increment their needid */
1483 keyused = sat_calloc(cbdata.nmykeys, sizeof(Id));
1484 for (i = 0; i < cbdata.myschemadatalen; i++)
1485 keyused[cbdata.myschemadata[i]] = 1;
1487 for (n = i = 1; i < cbdata.nmykeys; i++)
1493 cbdata.mykeys[n] = cbdata.mykeys[i];
1494 if (cbdata.mykeys[n].type == REPOKEY_TYPE_CONSTANTID)
1496 if (!type_constantid)
1497 type_constantid = poolusage > 1 ? stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].type), 1) : REPOKEY_TYPE_CONSTANTID;
1499 cbdata.mykeys[n].size = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].size), 1);
1500 needid[cbdata.mykeys[n].size].need++;
1504 cbdata.mykeys[n].name = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].name), 1);
1505 cbdata.mykeys[n].type = stringpool_str2id(spool, id2str(repo->pool, cbdata.mykeys[n].type), 1);
1507 needid[cbdata.mykeys[n].name].need++;
1508 needid[cbdata.mykeys[n].type].need++;
1512 for (i = 0; i < cbdata.myschemadatalen; i++)
1513 cbdata.myschemadata[i] = keyused[cbdata.myschemadata[i]];
1514 for (i = 0; i < cbdata.nkeymap; i++)
1515 cbdata.keymap[i] = keyused[cbdata.keymap[i]];
1516 keyused = sat_free(keyused);
1518 /********************************************************************/
1520 /* increment need id for used dir components */
1521 if (cbdata.dirused && !cbdata.dirused[0])
1523 /* no dirs used at all */
1524 cbdata.dirused = sat_free(cbdata.dirused);
1529 for (i = 1; i < dirpool->ndirs; i++)
1532 fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
1534 id = dirpool->dirs[i];
1537 if (cbdata.dirused && !cbdata.dirused[i])
1539 if (cbdata.ownspool && dirpooldata && id > 1)
1541 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1542 needid = cbdata.needid;
1548 reloff = needid[0].map;
1551 /********************************************************************/
1554 * create mapping table, new keys are sorted by needid[].need
1556 * needid[key].need : old key -> new key
1557 * needid[key].map : new key -> old key
1560 /* zero out id 0 and rel 0 just in case */
1563 needid[reloff].need = 0;
1565 for (i = 1; i < reloff + pool->nrels; i++)
1569 sat_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
1571 /* make first entry '' */
1573 sat_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
1575 sat_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
1578 for (i = 1; i < reloff; i++)
1580 if (!needid[i].need)
1583 sizeid += strlen(spool->stringspace + spool->strings[needid[i].map]) + 1;
1587 for (i = 1; i < nstrings; i++)
1588 needid[needid[i].map].need = i;
1590 for (i = 0; i < pool->nrels; i++)
1592 if (!needid[reloff + i].need)
1595 needid[reloff + i].need = 0;
1599 for (i = 0; i < nrels; i++)
1600 needid[needid[reloff + i].map].need = nstrings + i;
1603 /********************************************************************/
1605 /* create dir map */
1610 if (cbdata.dirused && !cbdata.dirused[1])
1611 cbdata.dirused[1] = 1; /* always want / entry */
1612 dirmap = sat_calloc(dirpool->ndirs, sizeof(Id));
1614 ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
1615 if (!cbdata.dirused)
1616 cbdata.dirused = sat_malloc2(dirpool->ndirs, sizeof(Id));
1617 memset(cbdata.dirused, 0, dirpool->ndirs * sizeof(Id));
1618 for (i = 1; i < ndirmap; i++)
1622 cbdata.dirused[dirmap[i]] = i;
1623 id = dirpool->dirs[dirmap[i]];
1624 if (cbdata.ownspool && dirpooldata && id > 1)
1625 id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
1626 dirmap[i] = needid[id].need;
1630 /********************************************************************/
1631 cbdata.extdata = sat_calloc(cbdata.nmykeys, sizeof(struct extdata));
1633 xd = cbdata.extdata;
1634 cbdata.current_sub = 0;
1635 /* write main schema */
1637 data_addid(xd, mainschema);
1640 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1642 if (!repodataused[j])
1644 repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1648 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1649 cbdata.maxdata = xd->len - cbdata.lastlen;
1650 cbdata.lastlen = xd->len;
1652 if (repo->nsolvables)
1653 data_addid(xd, repo->nsolvables); /* FLEXARRAY nentries */
1654 cbdata.doingsolvables = 1;
1655 for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
1657 if (s->repo != repo)
1659 data_addid(xd, cbdata.solvschemata[n]);
1660 if (cbdata.keymap[SOLVABLE_NAME])
1661 data_addid(xd, needid[s->name].need);
1662 if (cbdata.keymap[SOLVABLE_ARCH])
1663 data_addid(xd, needid[s->arch].need);
1664 if (cbdata.keymap[SOLVABLE_EVR])
1665 data_addid(xd, needid[s->evr].need);
1666 if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
1667 data_addid(xd, needid[s->vendor].need);
1668 if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
1669 data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
1670 if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
1671 data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
1672 if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
1673 data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
1674 if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
1675 data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
1676 if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
1677 data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
1678 if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
1679 data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
1680 if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
1681 data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
1682 if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
1683 data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
1684 if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
1685 data_addu32(xd, repo->rpmdbid[i - repo->start]);
1686 if (anyrepodataused)
1689 for (j = 0, data = repo->repodata; j < repo->nrepodata; j++, data++)
1691 if (!repodataused[j])
1693 if (i < data->start || i >= data->end)
1695 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
1698 if (xd->len - cbdata.lastlen > cbdata.maxdata)
1699 cbdata.maxdata = xd->len - cbdata.lastlen;
1700 cbdata.lastlen = xd->len;
1703 cbdata.doingsolvables = 0;
1705 assert(cbdata.current_sub == cbdata.nsubschemata);
1706 if (cbdata.subschemata)
1708 cbdata.subschemata = sat_free(cbdata.subschemata);
1709 cbdata.nsubschemata = 0;
1713 if (repo->nextra && anyrepodataused)
1714 for (i = -1; i >= -repo->nextra; i--)
1717 dataiterator_init(&di, repo, i, 0, 0, SEARCH_EXTRA | SEARCH_NO_STORAGE_SOLVABLE);
1718 entrysize = xd->len;
1719 data_addid(xd, cbdata.extraschemata[-1 - i]);
1721 while (dataiterator_step(&di))
1722 repo_write_adddata(&cbdata, di.data, di.key, &di.kv);
1723 entrysize = xd->len - entrysize;
1724 if (entrysize > maxentrysize)
1725 maxentrysize = entrysize;
1729 /********************************************************************/
1733 /* write file header */
1734 write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
1735 write_u32(fp, SOLV_VERSION_8);
1739 write_u32(fp, nstrings);
1740 write_u32(fp, nrels);
1741 write_u32(fp, ndirmap);
1742 write_u32(fp, repo->nsolvables);
1743 write_u32(fp, cbdata.nmykeys);
1744 write_u32(fp, cbdata.nmyschemata);
1746 solv_flags |= SOLV_FLAG_PREFIX_POOL;
1747 write_u32(fp, solv_flags);
1749 /* Build the prefix-encoding of the string pool. We need to know
1750 the size of that before writing it to the file, so we have to
1751 build a separate buffer for that. As it's temporarily possible
1752 that this actually is an expansion we can't easily reuse the
1753 stringspace for this. The max expansion per string is 1 byte,
1754 so it will fit into sizeid+nstrings bytes. */
1755 char *prefix = sat_malloc(sizeid + nstrings);
1758 for (i = 1; i < nstrings; i++)
1760 char *str = spool->stringspace + spool->strings[needid[i].map];
1763 for (same = 0; same < 255; same++)
1764 if (!old_str[same] || !str[same] || old_str[same] != str[same])
1767 len = strlen(str + same) + 1;
1768 memcpy (pp, str + same, len);
1776 write_u32(fp, sizeid);
1777 write_u32(fp, pp - prefix);
1780 if (fwrite(prefix, pp - prefix, 1, fp) != 1)
1782 perror("write error prefix");
1791 for (i = 0; i < nrels; i++)
1793 ran = pool->rels + (needid[reloff + i].map - reloff);
1794 write_id(fp, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
1795 write_id(fp, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
1796 write_u8(fp, ran->flags);
1800 * write dirs (skip both root and / entry)
1802 for (i = 2; i < ndirmap; i++)
1805 write_id(fp, dirmap[i]);
1807 write_id(fp, nstrings - dirmap[i]);
1815 *keyarrayp = sat_calloc(2 * cbdata.nmykeys + 1, sizeof(Id));
1816 for (i = 1; i < cbdata.nmykeys; i++)
1818 write_id(fp, needid[cbdata.mykeys[i].name].need);
1819 write_id(fp, needid[cbdata.mykeys[i].type].need);
1820 if (cbdata.mykeys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
1822 if (cbdata.mykeys[i].type == type_constantid)
1823 write_id(fp, needid[cbdata.mykeys[i].size].need);
1825 write_id(fp, cbdata.mykeys[i].size);
1828 write_id(fp, cbdata.extdata[i].len);
1829 write_id(fp, cbdata.mykeys[i].storage);
1832 (*keyarrayp)[2 * i - 2] = cbdata.mykeys[i].name;
1833 (*keyarrayp)[2 * i - 1] = cbdata.mykeys[i].type;
1840 write_id(fp, cbdata.myschemadatalen);
1841 if (cbdata.nmyschemata)
1843 for (i = 1; i < cbdata.nmyschemata; i++)
1844 write_idarray(fp, pool, 0, cbdata.myschemadata + cbdata.myschemata[i]);
1859 for (i = 0; i < nsubfiles; i++)
1864 data_addid(&xd, repodataschemata[i]);
1865 if (fileinfo[i].addedfileprovides || fileinfo[i].rpmdbcookie)
1867 if (fileinfo[i].addedfileprovides)
1868 data_addidarray_sort(&xd, pool, needid, fileinfo[i].addedfileprovides, 0);
1869 if (fileinfo[i].rpmdbcookie)
1870 data_addblob(&xd, fileinfo[i].rpmdbcookie, 32);
1874 /* key,type array + location, write idarray */
1875 for (j = 1; j < fileinfo[i].nkeys; j++)
1877 data_addideof(&xd, needid[fileinfo[i].keys[j].name].need, 0);
1878 data_addideof(&xd, needid[fileinfo[i].keys[j].type].need, j == fileinfo[i].nkeys - 1);
1880 if (fileinfo[i].location)
1881 data_addblob(&xd, (unsigned char *)fileinfo[i].location, strlen(fileinfo[i].location) + 1);
1888 write_id(fp, xd.len);
1889 write_blob(fp, xd.buf, xd.len);
1894 /********************************************************************/
1896 write_id(fp, cbdata.maxdata);
1897 write_id(fp, cbdata.extdata[0].len);
1898 if (cbdata.extdata[0].len)
1899 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1900 sat_free(cbdata.extdata[0].buf);
1904 * write Solvable data
1906 if (repo->nsolvables || repo->nextra)
1908 write_id(fp, maxentrysize);
1909 write_id(fp, cbdata.extdata[0].len);
1910 write_blob(fp, cbdata.extdata[0].buf, cbdata.extdata[0].len);
1912 sat_free(cbdata.extdata[0].buf);
1915 /* write vertical data */
1916 for (i = 1; i < cbdata.nmykeys; i++)
1917 if (cbdata.extdata[i].len)
1919 if (i < cbdata.nmykeys)
1921 unsigned char *dp, vpage[BLOB_PAGESIZE];
1922 int l, ll, lpage = 0;
1924 write_u32(fp, BLOB_PAGESIZE);
1925 for (i = 1; i < cbdata.nmykeys; i++)
1927 if (!cbdata.extdata[i].len)
1929 l = cbdata.extdata[i].len;
1930 dp = cbdata.extdata[i].buf;
1933 ll = BLOB_PAGESIZE - lpage;
1936 memcpy(vpage + lpage, dp, ll);
1940 if (lpage == BLOB_PAGESIZE)
1942 write_compressed_page(fp, vpage, lpage);
1948 write_compressed_page(fp, vpage, lpage);
1952 /* write vertical_offset entries */
1953 write_u32(fp, 0); /* no paging */
1954 for (i = 1; i < cbdata.nmykeys; i++)
1955 if (cbdata.extdata[i].len)
1956 write_blob(fp, cbdata.extdata[i].buf, cbdata.extdata[i].len);
1958 /* Fill fileinfo for our caller. */
1961 fileinfo->checksum = 0;
1962 fileinfo->nchecksum = 0;
1963 fileinfo->checksumtype = 0;
1964 fileinfo->location = 0;
1968 for (i = 1; i < cbdata.nmykeys; i++)
1969 sat_free(cbdata.extdata[i].buf);
1970 sat_free(cbdata.extdata);
1972 if (cbdata.ownspool)
1974 sat_free(cbdata.ownspool->strings);
1975 sat_free(cbdata.ownspool->stringspace);
1976 sat_free(cbdata.ownspool->stringhashtbl);
1978 if (cbdata.owndirpool)
1980 sat_free(cbdata.owndirpool->dirs);
1981 sat_free(cbdata.owndirpool->dirtraverse);
1984 sat_free(cbdata.extraschemata);
1985 sat_free(cbdata.solvschemata);
1986 sat_free(cbdata.myschemadata);
1987 sat_free(cbdata.myschemata);
1988 sat_free(cbdata.schema);
1990 sat_free(cbdata.mykeys);
1991 sat_free(cbdata.keymap);
1992 sat_free(cbdata.keymapstart);
1993 sat_free(cbdata.dirused);
1994 sat_free(repodataused);
1995 sat_free(repodataschemata);