05fed66180d57a62d6eb6b38db6974430bfffd79
[platform/upstream/libsolv.git] / src / repo.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.c
10  *
11  * Manage metadata coming from one repository
12  * 
13  */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include "repo.h"
20 #include "pool.h"
21 #include "poolid_private.h"
22 #include "util.h"
23
24 #define IDARRAY_BLOCK     4095
25
26
27 /*
28  * create empty repo
29  * and add to pool
30  */
31
32 Repo *
33 repo_create(Pool *pool, const char *name)
34 {
35   Repo *repo;
36
37   pool_freewhatprovides(pool);
38   repo = (Repo *)xcalloc(1, sizeof(*repo));
39   pool->repos = (Repo **)xrealloc(pool->repos, (pool->nrepos + 1) * sizeof(Repo *));
40   pool->repos[pool->nrepos++] = repo;
41   repo->name = name ? strdup(name) : 0;
42   repo->pool = pool;
43   repo->start = pool->nsolvables;
44   repo->end = pool->nsolvables;
45   repo->nsolvables = 0;
46   return repo;
47 }
48
49 static void
50 repo_freedata(Repo *repo)
51 {
52   xfree(repo->idarraydata);
53   xfree(repo->rpmdbid);
54   xfree((char *)repo->name);
55   xfree(repo);
56 }
57
58 /*
59  * add Id to repo
60  * olddeps = old array to extend
61  * 
62  */
63
64 Offset
65 repo_addid(Repo *repo, Offset olddeps, Id id)
66 {
67   Id *idarray;
68   int idarraysize;
69   int i;
70   
71   idarray = repo->idarraydata;
72   idarraysize = repo->idarraysize;
73
74   if (!idarray)                        /* alloc idarray if not done yet */
75     {
76       idarray = (Id *)xmalloc((1 + IDARRAY_BLOCK) * sizeof(Id));
77       idarray[0] = 0;
78       idarraysize = 1;
79       repo->lastoff = 0;
80     }
81
82   if (!olddeps)                         /* no deps yet */
83     {   
84       olddeps = idarraysize;
85       if ((idarraysize & IDARRAY_BLOCK) == 0)
86         idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
87     }   
88   else if (olddeps == repo->lastoff)    /* extend at end */
89     idarraysize--;
90   else                                  /* can't extend, copy old */
91     {
92       i = olddeps;
93       olddeps = idarraysize;
94       for (; idarray[i]; i++)
95         {
96           if ((idarraysize & IDARRAY_BLOCK) == 0)
97             idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
98           idarray[idarraysize++] = idarray[i];
99         }
100       if ((idarraysize & IDARRAY_BLOCK) == 0)
101         idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
102     }
103   
104   idarray[idarraysize++] = id;          /* insert Id into array */
105
106   if ((idarraysize & IDARRAY_BLOCK) == 0)   /* realloc if at block boundary */
107     idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
108
109   idarray[idarraysize++] = 0;           /* ensure NULL termination */
110
111   repo->idarraydata = idarray;
112   repo->idarraysize = idarraysize;
113   repo->lastoff = olddeps;
114
115   return olddeps;
116 }
117
118
119 /*
120  * add dependency (as Id) to repo
121  * olddeps = offset into idarraydata
122  * isreq = 0 for normal dep
123  * isreq = 1 for requires
124  * isreq = 2 for pre-requires
125  * 
126  */
127
128 Offset
129 repo_addid_dep(Repo *repo, Offset olddeps, Id id, int isreq)
130 {
131   Id oid, *oidp, *marker = 0;
132
133   if (!olddeps)
134     return repo_addid(repo, olddeps, id);
135
136   if (!isreq)
137     {
138       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
139         {
140           if (oid == id)
141             return olddeps;
142         }
143       return repo_addid(repo, olddeps, id);
144     }
145
146   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
147     {
148       if (oid == SOLVABLE_PREREQMARKER)
149         marker = oidp;
150       else if (oid == id)
151         break;
152     }
153
154   if (oid)
155     {
156       if (marker || isreq == 1)
157         return olddeps;
158       marker = oidp++;
159       for (; (oid = *oidp) != ID_NULL; oidp++)
160         if (oid == SOLVABLE_PREREQMARKER)
161           break;
162       if (!oid)
163         {
164           oidp--;
165           if (marker < oidp)
166             memmove(marker, marker + 1, (oidp - marker) * sizeof(Id));
167           *oidp = SOLVABLE_PREREQMARKER;
168           return repo_addid(repo, olddeps, id);
169         }
170       while (oidp[1])
171         oidp++;
172       memmove(marker, marker + 1, (oidp - marker) * sizeof(Id));
173       *oidp = id;
174       return olddeps;
175     }
176   if (isreq == 2 && !marker)
177     olddeps = repo_addid(repo, olddeps, SOLVABLE_PREREQMARKER);
178   else if (isreq == 1 && marker)
179     {
180       *marker++ = id;
181       id = *--oidp;
182       if (marker < oidp)
183         memmove(marker + 1, marker, (oidp - marker) * sizeof(Id));
184       *marker = SOLVABLE_PREREQMARKER;
185     }
186   return repo_addid(repo, olddeps, id);
187 }
188
189
190 /*
191  * reserve Ids
192  * make space for 'num' more dependencies
193  */
194
195 Offset
196 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
197 {
198   num++;        /* room for trailing ID_NULL */
199
200   if (!repo->idarraysize)              /* ensure buffer space */
201     {
202       repo->idarraysize = 1;
203       repo->idarraydata = (Id *)xmalloc(((1 + num + IDARRAY_BLOCK) & ~IDARRAY_BLOCK) * sizeof(Id));
204       repo->idarraydata[0] = 0;
205       repo->lastoff = 1;
206       return 1;
207     }
208
209   if (olddeps && olddeps != repo->lastoff)   /* if not appending */
210     {
211       /* can't insert into idarray, this would invalidate all 'larger' offsets
212        * so create new space at end and move existing deps there.
213        * Leaving 'hole' at old position.
214        */
215       
216       Id *idstart, *idend;
217       int count;
218
219       for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
220         ;
221       count = idend - idstart - 1 + num;               /* new size */
222
223       /* realloc if crossing block boundary */
224       if (((repo->idarraysize - 1) | IDARRAY_BLOCK) != ((repo->idarraysize + count - 1) | IDARRAY_BLOCK))
225         repo->idarraydata = (Id *)xrealloc(repo->idarraydata, ((repo->idarraysize + count + IDARRAY_BLOCK) & ~IDARRAY_BLOCK) * sizeof(Id));
226
227       /* move old deps to end */
228       olddeps = repo->lastoff = repo->idarraysize;
229       memcpy(repo->idarraydata + olddeps, idstart, count - num);
230       repo->idarraysize = olddeps + count - num;
231
232       return olddeps;
233     }
234
235   if (olddeps)                         /* appending */
236     repo->idarraysize--;
237
238   /* realloc if crossing block boundary */
239   if (((repo->idarraysize - 1) | IDARRAY_BLOCK) != ((repo->idarraysize + num - 1) | IDARRAY_BLOCK))
240     repo->idarraydata = (Id *)xrealloc(repo->idarraydata, ((repo->idarraysize + num + IDARRAY_BLOCK) & ~IDARRAY_BLOCK) * sizeof(Id));
241
242   /* appending or new */
243   repo->lastoff = olddeps ? olddeps : repo->idarraysize;
244
245   return repo->lastoff;
246 }
247
248
249 /*
250  * remove repo from pool, zero out solvables 
251  * 
252  */
253
254 void
255 repo_free(Repo *repo, int reuseids)
256 {
257   Pool *pool = repo->pool;
258   Solvable *s;
259   int i;
260
261   pool_freewhatprovides(pool);
262
263   if (reuseids && repo->end == pool->nsolvables)
264     {
265       /* it's ok to reuse the ids. As this is the last repo, we can
266          just shrink the solvable array */
267       for (i = repo->end - 1, s = pool->solvables + i; i >= repo->start; i--, s--)
268         if (s->repo != repo)
269           break;
270       repo->end = i + 1;
271       pool->nsolvables = i + 1;
272     }
273   /* zero out solvables belonging to this repo */
274   for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
275     if (s->repo == repo)
276       memset(s, 0, sizeof(*s));
277   for (i = 0; i < pool->nrepos; i++)    /* find repo in pool */
278     if (pool->repos[i] == repo)
279       break;
280   if (i == pool->nrepos)               /* repo not in pool, return */
281     return;
282   if (i < pool->nrepos - 1)
283     memmove(pool->repos + i, pool->repos + i + 1, (pool->nrepos - 1 - i) * sizeof(Repo *));
284   pool->nrepos--;
285   repo_freedata(repo);
286 }
287
288 void
289 repo_freeallrepos(Pool *pool, int reuseids)
290 {
291   int i;
292
293   pool_freewhatprovides(pool);
294   for (i = 0; i < pool->nrepos; i++)
295     repo_freedata(pool->repos[i]);
296   pool->repos = xfree(pool->repos);
297   pool->nrepos = 0;
298   /* the first two solvables don't belong to a repo */
299   pool_free_solvable_block(pool, 2, pool->nsolvables - 2, reuseids);
300 }
301
302 Offset
303 repo_fix_legacy(Repo *repo, Offset provides, Offset supplements)
304 {
305   Pool *pool = repo->pool;
306   Id id, idp, idl, idns;
307   char buf[1024], *p, *dep;
308   int i;
309
310   if (provides)
311     {
312       for (i = provides; repo->idarraydata[i]; i++)
313         {
314           id = repo->idarraydata[i];
315           if (ISRELDEP(id))
316             continue;
317           dep = (char *)id2str(pool, id);
318           if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
319             {
320               idp = 0;
321               strcpy(buf + 2, dep);
322               dep = buf + 2 + 7;
323               if ((p = strchr(dep, ':')) != 0 && p != dep)
324                 {
325                   *p++ = 0;
326                   idp = str2id(pool, dep, 1);
327                   dep = p;
328                 }
329               id = 0;
330               while ((p = strchr(dep, ';')) != 0)
331                 {
332                   if (p == dep)
333                     {
334                       dep = p + 1;
335                       continue;
336                     }
337                   strncpy(dep - 9, "language:", 9);
338                   *p++ = 0;
339                   idl = str2id(pool, dep - 9, 1);
340                   if (id)
341                     id = rel2id(pool, id, idl, REL_OR, 1);
342                   else
343                     id = idl;
344                   dep = p;
345                 }
346               if (dep[0] && dep[1])
347                 {
348                   for (p = dep; *p && *p != ')'; p++)
349                     ;
350                   *p = 0;
351                   strncpy(dep - 9, "language:", 9);
352                   idl = str2id(pool, dep - 9, 1);
353                   if (id)
354                     id = rel2id(pool, id, idl, REL_OR, 1);
355                   else
356                     id = idl;
357                 }
358               if (idp)
359                 id = rel2id(pool, idp, id, REL_AND, 1);
360               if (id)
361                 supplements = repo_addid_dep(repo, supplements, id, 0);
362             }
363           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
364             {
365               strcpy(buf, dep);
366               p = buf + (p - dep);
367               *p++ = 0;
368               idp = str2id(pool, buf, 1);
369               idns = str2id(pool, "namespace:installed", 1);
370               id = str2id(pool, p, 1);
371               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
372               id = rel2id(pool, idp, id, REL_AND, 1);
373               supplements = repo_addid_dep(repo, supplements, id, 0);
374             }
375         }
376     }
377   if (!supplements)
378     return 0;
379   for (i = supplements; repo->idarraydata[i]; i++)
380     {
381       id = repo->idarraydata[i];
382       if (ISRELDEP(id))
383         continue;
384       dep = (char *)id2str(pool, id);
385       if (!strncmp(dep, "system:modalias(", 16))
386         dep += 7;
387       if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
388         {
389           strcpy(buf, dep);
390           p = strchr(buf + 9, ':');
391           idns = str2id(pool, "namespace:modalias", 1);
392           if (p && p != buf + 9 && strchr(p + 1, ':'))
393             {
394               *p++ = 0;
395               idp = str2id(pool, buf + 9, 1);
396               p[strlen(p) - 1] = 0;
397               id = str2id(pool, p, 1);
398               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
399               id = rel2id(pool, idp, id, REL_AND, 1);
400             }
401           else
402             {
403               p = buf + 9;
404               p[strlen(p) - 1] = 0;
405               id = str2id(pool, p, 1);
406               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
407             }
408           if (id)
409             repo->idarraydata[i] = id;
410         }
411       else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
412         {
413           strcpy(buf, dep);
414           id = 0;
415           dep = buf + 11;
416           while ((p = strchr(dep, ':')) != 0)
417             {
418               if (p == dep)
419                 {
420                   dep = p + 1;
421                   continue;
422                 }
423               *p++ = 0;
424               idp = str2id(pool, dep, 1);
425               if (id)
426                 id = rel2id(pool, id, idp, REL_AND, 1);
427               else
428                 id = idp;
429               dep = p;
430             }
431           if (dep[0] && dep[1])
432             {
433               dep[strlen(dep) - 1] = 0;
434               idp = str2id(pool, dep, 1);
435               if (id)
436                 id = rel2id(pool, id, idp, REL_AND, 1);
437               else
438                 id = idp;
439             }
440           if (id)
441             repo->idarraydata[i] = id;
442         }
443     }
444   return supplements;
445 }
446
447 #if 0
448 void
449 repodata_search(Repodata *data, Id key)
450 {
451 }
452
453 const char *
454 repodata_lookup_id(Repodata *data, Id num, Id key)
455 {
456   Id id, k, *kp, *keyp;
457
458   fseek(data->fp, data->itemoffsets[num] , SEEK_SET);
459   Id *keyp = data->schemadata + data->schemata[read_id(data->fp, data->numschemata)];
460   /* make sure our schema contains the key */
461   for (kp = keyp; (k = *kp++) != 0)
462     if (k == key)
463       break;
464   if (k == 0)
465     return 0;
466   /* get it */
467   while ((k = *keyp++) != 0)
468     {
469       if (k == key)
470         break;
471       switch (keys[key].type)
472         {
473         case TYPE_ID:
474           while ((read_u8(data->fp) & 0x80) != 0)
475             ;
476           break;
477         case TYPE_U32:
478           read_u32(data->fp);
479           break;
480         case TYPE_STR:
481           while(read_u8(data->fp) != 0)
482             ;
483           break;
484         case TYPE_IDARRAY:
485           while ((read_u8(data->fp) & 0xc0) != 0)
486             ;
487           break;
488         }
489     }
490   id = read_id(data->fp, 0);
491   return data->ss.stringspace + data->ss.strings[id];
492 }
493
494 Id
495 repo_lookup_id(Solvable *s, Id key)
496 {
497   Solvable *rs;
498   Repo *repo = s->repo;
499   Repodata *data;
500   int i, j, n;
501
502   switch(key)
503     {
504     case SOLVABLE_NAME:
505       return s->name;
506     case SOLVABLE_ARCH:
507       return s->arch;
508     case SOLVABLE_EVR:
509       return s->evr;
510     case SOLVABLE_VENDOR:
511       return s->vendor;
512     }
513   /* convert solvable id into repo item count */
514   if (repo->end - repo->start + 1 == repo->nsolvables)
515     {
516       n = (s - pool->solvables);
517       if (n < repo->start || n > repo->end)
518         return 0;
519       n -= repo->start;
520     }
521   else
522     {
523       for (i = repo->start, rs = pool->solvables + i, n = 0; i < repo->end; i++, rs++)
524         {
525           if (rs->repo != repo)
526             continue;
527           if (rs == s)
528             break;
529           n++;
530         }
531       if (i == repo->end)
532         return 0;
533     }
534   for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++)
535     {
536       for (j = 0; j < data->nkeys; j++)
537         {
538           if (data->keys[j].name == key && data->keys[j].type == TYPE_ID)
539             return repodata_lookup_id(data, n, j);
540         }
541     }
542   return 0;
543 }
544 #endif
545
546 // EOF