- allow repositories that don't consist of a single block of solvables
[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 pool_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   /* the first two solvables don't belong to a repo */
297   if (pool->nsolvables > 2 && !reuseids)
298     memset(pool->solvables + 2, 0, (pool->nsolvables - 2) * sizeof(Solvable));
299   pool->repos = xfree(pool->repos);
300   pool->nrepos = 0;
301   if (reuseids)
302     pool->nsolvables = 2;
303 }
304
305 Offset
306 repo_fix_legacy(Repo *repo, Offset provides, Offset supplements)
307 {
308   Pool *pool = repo->pool;
309   Id id, idp, idl, idns;
310   char buf[1024], *p, *dep;
311   int i;
312
313   if (provides)
314     {
315       for (i = provides; repo->idarraydata[i]; i++)
316         {
317           id = repo->idarraydata[i];
318           if (ISRELDEP(id))
319             continue;
320           dep = (char *)id2str(pool, id);
321           if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
322             {
323               idp = 0;
324               strcpy(buf + 2, dep);
325               dep = buf + 2 + 7;
326               if ((p = strchr(dep, ':')) != 0 && p != dep)
327                 {
328                   *p++ = 0;
329                   idp = str2id(pool, dep, 1);
330                   dep = p;
331                 }
332               id = 0;
333               while ((p = strchr(dep, ';')) != 0)
334                 {
335                   if (p == dep)
336                     {
337                       dep = p + 1;
338                       continue;
339                     }
340                   strncpy(dep - 9, "language:", 9);
341                   *p++ = 0;
342                   idl = str2id(pool, dep - 9, 1);
343                   if (id)
344                     id = rel2id(pool, id, idl, REL_OR, 1);
345                   else
346                     id = idl;
347                   dep = p;
348                 }
349               if (dep[0] && dep[1])
350                 {
351                   for (p = dep; *p && *p != ')'; p++)
352                     ;
353                   *p = 0;
354                   strncpy(dep - 9, "language:", 9);
355                   idl = str2id(pool, dep - 9, 1);
356                   if (id)
357                     id = rel2id(pool, id, idl, REL_OR, 1);
358                   else
359                     id = idl;
360                 }
361               if (idp)
362                 id = rel2id(pool, idp, id, REL_AND, 1);
363               if (id)
364                 supplements = repo_addid_dep(repo, supplements, id, 0);
365             }
366           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
367             {
368               strcpy(buf, dep);
369               p = buf + (p - dep);
370               *p++ = 0;
371               idp = str2id(pool, buf, 1);
372               idns = str2id(pool, "namespace:installed", 1);
373               id = str2id(pool, p, 1);
374               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
375               id = rel2id(pool, idp, id, REL_AND, 1);
376               supplements = repo_addid_dep(repo, supplements, id, 0);
377             }
378         }
379     }
380   if (!supplements)
381     return 0;
382   for (i = supplements; repo->idarraydata[i]; i++)
383     {
384       id = repo->idarraydata[i];
385       if (ISRELDEP(id))
386         continue;
387       dep = (char *)id2str(pool, id);
388       if (!strncmp(dep, "system:modalias(", 16))
389         dep += 7;
390       if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
391         {
392           strcpy(buf, dep);
393           p = strchr(buf + 9, ':');
394           idns = str2id(pool, "namespace:modalias", 1);
395           if (p && p != buf + 9 && strchr(p + 1, ':'))
396             {
397               *p++ = 0;
398               idp = str2id(pool, buf + 9, 1);
399               p[strlen(p) - 1] = 0;
400               id = str2id(pool, p, 1);
401               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
402               id = rel2id(pool, idp, id, REL_AND, 1);
403             }
404           else
405             {
406               p = buf + 9;
407               p[strlen(p) - 1] = 0;
408               id = str2id(pool, p, 1);
409               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
410             }
411           if (id)
412             repo->idarraydata[i] = id;
413         }
414       else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
415         {
416           strcpy(buf, dep);
417           id = 0;
418           dep = buf + 11;
419           while ((p = strchr(dep, ':')) != 0)
420             {
421               if (p == dep)
422                 {
423                   dep = p + 1;
424                   continue;
425                 }
426               *p++ = 0;
427               idp = str2id(pool, dep, 1);
428               if (id)
429                 id = rel2id(pool, id, idp, REL_AND, 1);
430               else
431                 id = idp;
432               dep = p;
433             }
434           if (dep[0] && dep[1])
435             {
436               dep[strlen(dep) - 1] = 0;
437               idp = str2id(pool, dep, 1);
438               if (id)
439                 id = rel2id(pool, id, idp, REL_AND, 1);
440               else
441                 id = idp;
442             }
443           if (id)
444             repo->idarraydata[i] = id;
445         }
446     }
447   return supplements;
448 }
449
450 // EOF