b66fd201019708183048a771dc3868a52401f056
[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 repo_write(Repo *repo, FILE *fp)
193 {
194   Pool *pool = repo->pool;
195   int i, numsolvdata;
196   Solvable *s, *sstart;
197   NeedId *needid;
198   int nstrings, nrels;
199   unsigned int sizeid;
200   Reldep *ran;
201   Id *idarraydata;
202
203   int idsizes[RPM_RPMDBID + 1];
204   int bits, bitmaps;
205   int nsolvables;
206
207   nsolvables = repo->nsolvables;
208   sstart = pool->solvables + repo->start;
209   idarraydata = repo->idarraydata;
210
211   needid = (NeedId *)calloc(pool->nstrings + pool->nrels, sizeof(*needid));
212
213   memset(idsizes, 0, sizeof(idsizes));
214
215   for (i = 0; i < nsolvables; i++)
216     {
217       s = sstart + i;
218       needid[s->name].need++;
219       needid[s->arch].need++;
220       needid[s->evr].need++;
221       if (s->vendor)
222         {
223           needid[s->vendor].need++;
224           idsizes[SOLVABLE_VENDOR] = 1;
225         }
226       if (s->provides)
227         idsizes[SOLVABLE_PROVIDES]    += incneedid(pool, idarraydata + s->provides, needid);
228       if (s->requires)
229         idsizes[SOLVABLE_REQUIRES]    += incneedid(pool, idarraydata + s->requires, needid);
230       if (s->conflicts)
231         idsizes[SOLVABLE_CONFLICTS]   += incneedid(pool, idarraydata + s->conflicts, needid);
232       if (s->obsoletes)
233         idsizes[SOLVABLE_OBSOLETES]   += incneedid(pool, idarraydata + s->obsoletes, needid);
234       if (s->recommends)
235         idsizes[SOLVABLE_RECOMMENDS]  += incneedid(pool, idarraydata + s->recommends, needid);
236       if (s->suggests)
237         idsizes[SOLVABLE_SUGGESTS]    += incneedid(pool, idarraydata + s->suggests, needid);
238       if (s->supplements)
239         idsizes[SOLVABLE_SUPPLEMENTS] += incneedid(pool, idarraydata + s->supplements, needid);
240       if (s->enhances)
241         idsizes[SOLVABLE_ENHANCES]    += incneedid(pool, idarraydata + s->enhances, needid);
242       if (s->freshens)
243         idsizes[SOLVABLE_FRESHENS]    += incneedid(pool, idarraydata + s->freshens, needid);
244     }
245
246   idsizes[SOLVABLE_NAME] = 1;
247   idsizes[SOLVABLE_ARCH] = 1;
248   idsizes[SOLVABLE_EVR] = 1;
249   if (repo->rpmdbid)
250     idsizes[RPM_RPMDBID] = 1;
251
252   for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
253     {
254       if (idsizes[i])
255         needid[i].need++;
256     }
257
258   needid[0].need = 0;
259   needid[pool->nstrings].need = 0;
260   for (i = 0; i < pool->nstrings + pool->nrels; i++)
261     needid[i].map = i;
262
263   qsort(needid + 1, pool->nstrings - 1, sizeof(*needid), needid_cmp_need);
264   qsort(needid + pool->nstrings, pool->nrels, sizeof(*needid), needid_cmp_need);
265
266   sizeid = 0;
267   for (i = 1; i < pool->nstrings; i++)
268     {
269       if (!needid[i].need)
270         break;
271       needid[i].need = 0;
272       sizeid += strlen(pool->stringspace + pool->strings[needid[i].map]) + 1;
273     }
274
275   nstrings = i;
276   for (i = 0; i < nstrings; i++)
277     needid[needid[i].map].need = i;
278
279   for (i = 0; i < pool->nrels; i++)
280     {
281       if (!needid[pool->nstrings + i].need)
282         break;
283       else
284         needid[pool->nstrings + i].need = 0;
285     }
286
287   nrels = i;
288   for (i = 0; i < nrels; i++)
289     {
290       needid[needid[pool->nstrings + i].map].need = nstrings + i;
291     }
292
293   /* write file header */
294   write_u32(fp, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
295   write_u32(fp, SOLV_VERSION);
296
297   /* write counts */
298   write_u32(fp, nstrings);
299   write_u32(fp, nrels);
300   write_u32(fp, nsolvables);
301   write_u32(fp, sizeid);
302
303   /*
304    * write strings
305    */
306   for (i = 1; i < nstrings; i++)
307     {
308       char *str = pool->stringspace + pool->strings[needid[i].map];
309       if (fwrite(str, strlen(str) + 1, 1, fp) != 1)
310         {
311           perror("write error");
312           exit(1);
313         }
314     }
315
316   /*
317    * write RelDeps
318    */
319   for (i = 0; i < nrels; i++)
320     {
321       ran = pool->rels + (needid[pool->nstrings + i].map - pool->nstrings);
322       write_id(fp, needid[ISRELDEP(ran->name) ? GETRELID(pool, ran->name) : ran->name].need);
323       write_id(fp, needid[ISRELDEP(ran->evr) ? GETRELID(pool, ran->evr) : ran->evr].need);
324       write_u8( fp, ran->flags);
325     }
326
327   write_u32(fp, 0);     /* no repo data */
328
329   /*
330    * write Solvables
331    */
332   
333   numsolvdata = 0;
334   for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
335     {
336       if (idsizes[i])
337         numsolvdata++;
338     }
339   write_u32(fp, (unsigned int)numsolvdata);
340
341   bitmaps = 0;
342   for (i = SOLVABLE_NAME; i <= SOLVABLE_FRESHENS; i++)
343     {
344       if (!idsizes[i])
345         continue;
346       if (i >= SOLVABLE_PROVIDES && i <= SOLVABLE_FRESHENS)
347         {
348           write_u8(fp, TYPE_IDARRAY|TYPE_BITMAP);
349           bitmaps++;
350         }
351       else
352         write_u8(fp, TYPE_ID);
353       write_id(fp, needid[i].need);
354       if (i >= SOLVABLE_PROVIDES && i <= SOLVABLE_FRESHENS)
355         write_u32(fp, idsizes[i]);
356       else
357         write_u32(fp, 0);
358     }
359
360   if (repo->rpmdbid)
361     {
362       write_u8(fp, TYPE_U32);
363       write_id(fp, needid[RPM_RPMDBID].need);
364       write_u32(fp, 0);
365     }
366
367   for (i = 0; i < nsolvables; ++i)
368     {
369       s = sstart + i;
370       bits = 0;
371       if (idsizes[SOLVABLE_FRESHENS])
372         bits = (bits << 1) | (s->freshens ? 1 : 0);
373       if (idsizes[SOLVABLE_ENHANCES])
374         bits = (bits << 1) | (s->enhances ? 1 : 0);
375       if (idsizes[SOLVABLE_SUPPLEMENTS])
376         bits = (bits << 1) | (s->supplements ? 1 : 0);
377       if (idsizes[SOLVABLE_SUGGESTS])
378         bits = (bits << 1) | (s->suggests ? 1 : 0);
379       if (idsizes[SOLVABLE_RECOMMENDS])
380         bits = (bits << 1) | (s->recommends ? 1 : 0);
381       if (idsizes[SOLVABLE_REQUIRES])
382         bits = (bits << 1) | (s->requires ? 1 : 0);
383       if (idsizes[SOLVABLE_CONFLICTS])
384         bits = (bits << 1) | (s->conflicts ? 1 : 0);
385       if (idsizes[SOLVABLE_OBSOLETES])
386         bits = (bits << 1) | (s->obsoletes ? 1 : 0);
387       if (idsizes[SOLVABLE_PROVIDES])
388         bits = (bits << 1) | (s->provides ? 1 : 0);
389
390       if (bitmaps > 24)
391         write_u8(fp, bits >> 24);
392       if (bitmaps > 16)
393         write_u8(fp, bits >> 16);
394       if (bitmaps > 8)
395         write_u8(fp, bits >> 8);
396       if (bitmaps)
397         write_u8(fp, bits);
398
399       write_id(fp, needid[s->name].need);
400       write_id(fp, needid[s->arch].need);
401       write_id(fp, needid[s->evr].need);
402       if (idsizes[SOLVABLE_VENDOR])
403         write_id(fp, needid[s->vendor].need);
404
405       if (s->provides)
406         write_idarray(fp, pool, needid, idarraydata + s->provides);
407       if (s->obsoletes)
408         write_idarray(fp, pool, needid, idarraydata + s->obsoletes);
409       if (s->conflicts)
410         write_idarray(fp, pool, needid, idarraydata + s->conflicts);
411       if (s->requires)
412         write_idarray(fp, pool, needid, idarraydata + s->requires);
413       if (s->recommends)
414         write_idarray(fp, pool, needid, idarraydata + s->recommends);
415       if (s->suggests)
416         write_idarray(fp, pool, needid, idarraydata + s->suggests);
417       if (s->supplements)
418         write_idarray(fp, pool, needid, idarraydata + s->supplements);
419       if (s->enhances)
420         write_idarray(fp, pool, needid, idarraydata + s->enhances);
421       if (s->freshens)
422         write_idarray(fp, pool, needid, idarraydata + s->freshens);
423       if (repo->rpmdbid)
424         write_u32(fp, repo->rpmdbid[i]);
425     }
426
427   free(needid);
428 }
429
430 // EOF