81714986445a2b6994ec1a4db47c3a1534fb0558
[platform/upstream/libsolv.git] / tools / repo_write.c
1 /*
2  * Copyright (c) 2007, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * repo_write.c
10  * 
11  * Write Repo data out to binary file
12  * 
13  * See doc/README.format for a description 
14  * of the binary file format
15  * 
16  */
17
18 #include <sys/types.h>
19 #include <limits.h>
20 #include <fcntl.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "pool.h"
26 #include "repo_write.h"
27
28 /*------------------------------------------------------------------*/
29 /* Id map optimizations */
30
31 typedef struct needid {
32   Id need;
33   Id map;
34 } NeedId;
35
36 /*
37  * increment need Id
38  * idarray: array of Ids, ID_NULL terminated
39  * needid: array of Id->NeedId
40  * 
41  * return count
42  * 
43  */
44
45 static int
46 incneedid(Pool *pool, Id *idarray, NeedId *needid)
47 {
48   if (!idarray)
49     return 0;
50
51   Id id;
52   int n = 0;
53
54   while ((id = *idarray++) != 0)
55     {
56       n++;
57       while (ISRELDEP(id))
58         {
59           Reldep *rd = GETRELDEP(pool, id);
60           needid[GETRELID(pool, id)].need++;
61           if (ISRELDEP(rd->evr))
62             {
63               Id ida[2];
64               ida[0] = rd->evr;
65               ida[1] = 0;
66               incneedid(pool, ida, needid);
67             }
68           else
69             needid[rd->evr].need++;
70           id = rd->name;
71         }
72       needid[id].need++;
73     }
74   return n + 1;
75 }
76
77
78 /*
79  * 
80  */
81
82 static int
83 needid_cmp_need(const void *ap, const void *bp)
84 {
85   const NeedId *a = ap;
86   const NeedId *b = bp;
87   int r;
88   r = b->need - a->need;
89   if (r)
90     return r;
91   return a->map - b->map;
92 }
93
94
95 /*------------------------------------------------------------------*/
96 /* output routines */
97
98 /*
99  * unsigned 32-bit
100  */
101
102 static void
103 write_u32(FILE *fp, unsigned int x)
104 {
105   if (putc(x >> 24, fp) == EOF ||
106       putc(x >> 16, fp) == EOF ||
107       putc(x >> 8, fp) == EOF ||
108       putc(x, fp) == EOF)
109     {
110       perror("write error");
111       exit(1);
112     }
113 }
114
115
116 /*
117  * unsigned 8-bit
118  */
119
120 static void
121 write_u8(FILE *fp, unsigned int x)
122 {
123   if (putc(x, fp) == EOF)
124     {
125       perror("write error");
126       exit(1);
127     }
128 }
129
130
131 /*
132  * Id
133  */
134
135 static void
136 write_id(FILE *fp, Id x)
137 {
138   if (x >= (1 << 14))
139     {
140       if (x >= (1 << 28))
141         putc((x >> 28) | 128, fp);
142       if (x >= (1 << 21))
143         putc((x >> 21) | 128, fp);
144       putc((x >> 14) | 128, fp);
145     }
146   if (x >= (1 << 7))
147     putc((x >> 7) | 128, fp);
148   if (putc(x & 127, fp) == EOF)
149     {
150       perror("write error");
151       exit(1);
152     }
153 }
154
155
156 /*
157  * Array of Ids
158  */
159
160 static void
161 write_idarray(FILE *fp, Pool *pool, NeedId *needid, Id *ids)
162 {
163   Id id;
164   if (!ids)
165     return;
166   if (!*ids)
167     {
168       write_u8(fp, ID_NULL);
169       return;
170     }
171   for (;;)
172     {
173       id = *ids++;
174       id = needid[ISRELDEP(id) ? GETRELID(pool, id) : id].need;
175       if (id >= 64)
176         id = (id & 63) | ((id & ~63) << 1);
177       if (!*ids)
178         {
179           write_id(fp, id);
180           return;
181         }
182       write_id(fp, id | 64);
183     }
184 }
185
186
187 /*
188  * Repo
189  */
190
191 void
192 pool_writerepo(Pool *pool, Repo *repo, FILE *fp)
193 {
194   int i, numsolvdata;
195   Solvable *s, *sstart;
196   NeedId *needid;
197   int nstrings, nrels;
198   unsigned int sizeid;
199   Reldep *ran;
200   Id *idarraydata;
201
202   int idsizes[RPM_RPMDBID + 1];
203   int bits, bitmaps;
204   int nsolvables;
205
206   nsolvables = repo->nsolvables;
207   sstart = pool->solvables + repo->start;
208   idarraydata = repo->idarraydata;
209
210   needid = (NeedId *)calloc(pool->nstrings + pool->nrels, sizeof(*needid));
211
212   memset(idsizes, 0, sizeof(idsizes));
213
214   for (i = 0; i < nsolvables; i++)
215     {
216       s = sstart + i;
217       needid[s->name].need++;
218       needid[s->arch].need++;
219       needid[s->evr].need++;
220       if (s->vendor)
221         {
222           needid[s->vendor].need++;
223           idsizes[SOLVABLE_VENDOR] = 1;
224         }
225       if (s->provides)
226         idsizes[SOLVABLE_PROVIDES]    += incneedid(pool, idarraydata + s->provides, needid);
227       if (s->requires)
228         idsizes[SOLVABLE_REQUIRES]    += incneedid(pool, idarraydata + s->requires, needid);
229       if (s->conflicts)
230         idsizes[SOLVABLE_CONFLICTS]   += incneedid(pool, idarraydata + s->conflicts, needid);
231       if (s->obsoletes)
232         idsizes[SOLVABLE_OBSOLETES]   += incneedid(pool, idarraydata + s->obsoletes, needid);
233       if (s->recommends)
234         idsizes[SOLVABLE_RECOMMENDS]  += incneedid(pool, idarraydata + s->recommends, needid);
235       if (s->suggests)
236         idsizes[SOLVABLE_SUGGESTS]    += incneedid(pool, idarraydata + s->suggests, needid);
237       if (s->supplements)
238         idsizes[SOLVABLE_SUPPLEMENTS] += incneedid(pool, idarraydata + s->supplements, needid);
239       if (s->enhances)
240         idsizes[SOLVABLE_ENHANCES]    += incneedid(pool, idarraydata + s->enhances, needid);
241       if (s->freshens)
242         idsizes[SOLVABLE_FRESHENS]    += incneedid(pool, idarraydata + s->freshens, needid);
243     }
244
245   idsizes[SOLVABLE_NAME] = 1;
246   idsizes[SOLVABLE_ARCH] = 1;
247   idsizes[SOLVABLE_EVR] = 1;
248   if (repo->rpmdbid)
249     idsizes[RPM_RPMDBID] = 1;
250
251   for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
252     {
253       if (idsizes[i])
254         needid[i].need++;
255     }
256
257   needid[0].need = 0;
258   needid[pool->nstrings].need = 0;
259   for (i = 0; i < pool->nstrings + pool->nrels; i++)
260     needid[i].map = i;
261
262   qsort(needid + 1, pool->nstrings - 1, sizeof(*needid), needid_cmp_need);
263   qsort(needid + pool->nstrings, pool->nrels, sizeof(*needid), needid_cmp_need);
264
265   sizeid = 0;
266   for (i = 1; i < pool->nstrings; i++)
267     {
268       if (!needid[i].need)
269         break;
270       needid[i].need = 0;
271       sizeid += strlen(pool->stringspace + pool->strings[needid[i].map]) + 1;
272     }
273
274   nstrings = i;
275   for (i = 0; i < nstrings; i++)
276     needid[needid[i].map].need = i;
277
278   for (i = 0; i < pool->nrels; i++)
279     {
280       if (!needid[pool->nstrings + i].need)
281         break;
282       else
283         needid[pool->nstrings + i].need = 0;
284     }
285
286   nrels = i;
287   for (i = 0; i < nrels; i++)
288     {
289       needid[needid[pool->nstrings + i].map].need = nstrings + i;
290     }
291
292   /* write file header */
293   write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
294   write_u32(fp, SOLV_VERSION);
295
296   /* write counts */
297   write_u32(fp, nstrings);
298   write_u32(fp, nrels);
299   write_u32(fp, nsolvables);
300   write_u32(fp, sizeid);
301
302   /*
303    * write strings
304    */
305   for (i = 1; i < nstrings; i++)
306     {
307       char *str = pool->stringspace + pool->strings[needid[i].map];
308       if (fwrite(str, strlen(str) + 1, 1, fp) != 1)
309         {
310           perror("write error");
311           exit(1);
312         }
313     }
314
315   /*
316    * write RelDeps
317    */
318   for (i = 0; i < nrels; i++)
319     {
320       ran = pool->rels + (needid[pool->nstrings + i].map - pool->nstrings);
321       write_id(fp, needid[ISRELDEP(ran->name) ? GETRELID(pool, ran->name) : ran->name].need);
322       write_id(fp, needid[ISRELDEP(ran->evr) ? GETRELID(pool, ran->evr) : ran->evr].need);
323       write_u8( fp, ran->flags);
324     }
325
326   write_u32(fp, 0);     /* no repo data */
327
328   /*
329    * write Solvables
330    */
331   
332   numsolvdata = 0;
333   for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
334     {
335       if (idsizes[i])
336         numsolvdata++;
337     }
338   write_u32(fp, (unsigned int)numsolvdata);
339
340   bitmaps = 0;
341   for (i = SOLVABLE_NAME; i <= SOLVABLE_FRESHENS; i++)
342     {
343       if (!idsizes[i])
344         continue;
345       if (i >= SOLVABLE_PROVIDES && i <= SOLVABLE_FRESHENS)
346         {
347           write_u8(fp, TYPE_IDARRAY|TYPE_BITMAP);
348           bitmaps++;
349         }
350       else
351         write_u8(fp, TYPE_ID);
352       write_id(fp, needid[i].need);
353       if (i >= SOLVABLE_PROVIDES && i <= SOLVABLE_FRESHENS)
354         write_u32(fp, idsizes[i]);
355       else
356         write_u32(fp, 0);
357     }
358
359   if (repo->rpmdbid)
360     {
361       write_u8(fp, TYPE_U32);
362       write_id(fp, needid[RPM_RPMDBID].need);
363       write_u32(fp, 0);
364     }
365
366   for (i = 0; i < nsolvables; ++i)
367     {
368       s = sstart + i;
369       bits = 0;
370       if (idsizes[SOLVABLE_FRESHENS])
371         bits = (bits << 1) | (s->freshens ? 1 : 0);
372       if (idsizes[SOLVABLE_ENHANCES])
373         bits = (bits << 1) | (s->enhances ? 1 : 0);
374       if (idsizes[SOLVABLE_SUPPLEMENTS])
375         bits = (bits << 1) | (s->supplements ? 1 : 0);
376       if (idsizes[SOLVABLE_SUGGESTS])
377         bits = (bits << 1) | (s->suggests ? 1 : 0);
378       if (idsizes[SOLVABLE_RECOMMENDS])
379         bits = (bits << 1) | (s->recommends ? 1 : 0);
380       if (idsizes[SOLVABLE_REQUIRES])
381         bits = (bits << 1) | (s->requires ? 1 : 0);
382       if (idsizes[SOLVABLE_CONFLICTS])
383         bits = (bits << 1) | (s->conflicts ? 1 : 0);
384       if (idsizes[SOLVABLE_OBSOLETES])
385         bits = (bits << 1) | (s->obsoletes ? 1 : 0);
386       if (idsizes[SOLVABLE_PROVIDES])
387         bits = (bits << 1) | (s->provides ? 1 : 0);
388
389       if (bitmaps > 24)
390         write_u8(fp, bits >> 24);
391       if (bitmaps > 16)
392         write_u8(fp, bits >> 16);
393       if (bitmaps > 8)
394         write_u8(fp, bits >> 8);
395       if (bitmaps)
396         write_u8(fp, bits);
397
398       write_id(fp, needid[s->name].need);
399       write_id(fp, needid[s->arch].need);
400       write_id(fp, needid[s->evr].need);
401       if (idsizes[SOLVABLE_VENDOR])
402         write_id(fp, needid[s->vendor].need);
403
404       if (s->provides)
405         write_idarray(fp, pool, needid, idarraydata + s->provides);
406       if (s->obsoletes)
407         write_idarray(fp, pool, needid, idarraydata + s->obsoletes);
408       if (s->conflicts)
409         write_idarray(fp, pool, needid, idarraydata + s->conflicts);
410       if (s->requires)
411         write_idarray(fp, pool, needid, idarraydata + s->requires);
412       if (s->recommends)
413         write_idarray(fp, pool, needid, idarraydata + s->recommends);
414       if (s->suggests)
415         write_idarray(fp, pool, needid, idarraydata + s->suggests);
416       if (s->supplements)
417         write_idarray(fp, pool, needid, idarraydata + s->supplements);
418       if (s->enhances)
419         write_idarray(fp, pool, needid, idarraydata + s->enhances);
420       if (s->freshens)
421         write_idarray(fp, pool, needid, idarraydata + s->freshens);
422       if (repo->rpmdbid)
423         write_u32(fp, repo->rpmdbid[i]);
424     }
425
426   free(needid);
427 }
428
429 // EOF