- cleanup repo handlin API
[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->nsolvables = 0;
45   return repo;
46 }
47
48 static void
49 repo_freedata(Repo *repo)
50 {
51   xfree(repo->idarraydata);
52   xfree(repo->rpmdbid);
53   xfree((char *)repo->name);
54   xfree(repo);
55 }
56
57 /*
58  * add Id to repo
59  * olddeps = old array to extend
60  * 
61  */
62
63 Offset
64 repo_addid(Repo *repo, Offset olddeps, Id id)
65 {
66   Id *idarray;
67   int idarraysize;
68   int i;
69   
70   idarray = repo->idarraydata;
71   idarraysize = repo->idarraysize;
72
73   if (!idarray)                        /* alloc idarray if not done yet */
74     {
75       idarray = (Id *)xmalloc((1 + IDARRAY_BLOCK) * sizeof(Id));
76       idarray[0] = 0;
77       idarraysize = 1;
78       repo->lastoff = 0;
79     }
80
81   if (!olddeps)                         /* no deps yet */
82     {   
83       olddeps = idarraysize;
84       if ((idarraysize & IDARRAY_BLOCK) == 0)
85         idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
86     }   
87   else if (olddeps == repo->lastoff)    /* extend at end */
88     idarraysize--;
89   else                                  /* can't extend, copy old */
90     {
91       i = olddeps;
92       olddeps = idarraysize;
93       for (; idarray[i]; i++)
94         {
95           if ((idarraysize & IDARRAY_BLOCK) == 0)
96             idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
97           idarray[idarraysize++] = idarray[i];
98         }
99       if ((idarraysize & IDARRAY_BLOCK) == 0)
100         idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
101     }
102   
103   idarray[idarraysize++] = id;          /* insert Id into array */
104
105   if ((idarraysize & IDARRAY_BLOCK) == 0)   /* realloc if at block boundary */
106     idarray = (Id *)xrealloc(idarray, (idarraysize + 1 + IDARRAY_BLOCK) * sizeof(Id));
107
108   idarray[idarraysize++] = 0;           /* ensure NULL termination */
109
110   repo->idarraydata = idarray;
111   repo->idarraysize = idarraysize;
112   repo->lastoff = olddeps;
113
114   return olddeps;
115 }
116
117
118 /*
119  * add dependency (as Id) to repo
120  * olddeps = offset into idarraydata
121  * isreq = 0 for normal dep
122  * isreq = 1 for requires
123  * isreq = 2 for pre-requires
124  * 
125  */
126
127 Offset
128 repo_addid_dep(Repo *repo, Offset olddeps, Id id, int isreq)
129 {
130   Id oid, *oidp, *marker = 0;
131
132   if (!olddeps)
133     return repo_addid(repo, olddeps, id);
134
135   if (!isreq)
136     {
137       for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
138         {
139           if (oid == id)
140             return olddeps;
141         }
142       return repo_addid(repo, olddeps, id);
143     }
144
145   for (oidp = repo->idarraydata + olddeps; (oid = *oidp) != ID_NULL; oidp++)
146     {
147       if (oid == SOLVABLE_PREREQMARKER)
148         marker = oidp;
149       else if (oid == id)
150         break;
151     }
152
153   if (oid)
154     {
155       if (marker || isreq == 1)
156         return olddeps;
157       marker = oidp++;
158       for (; (oid = *oidp) != ID_NULL; oidp++)
159         if (oid == SOLVABLE_PREREQMARKER)
160           break;
161       if (!oid)
162         {
163           oidp--;
164           if (marker < oidp)
165             memmove(marker, marker + 1, (oidp - marker) * sizeof(Id));
166           *oidp = SOLVABLE_PREREQMARKER;
167           return repo_addid(repo, olddeps, id);
168         }
169       while (oidp[1])
170         oidp++;
171       memmove(marker, marker + 1, (oidp - marker) * sizeof(Id));
172       *oidp = id;
173       return olddeps;
174     }
175   if (isreq == 2 && !marker)
176     olddeps = repo_addid(repo, olddeps, SOLVABLE_PREREQMARKER);
177   else if (isreq == 1 && marker)
178     {
179       *marker++ = id;
180       id = *--oidp;
181       if (marker < oidp)
182         memmove(marker + 1, marker, (oidp - marker) * sizeof(Id));
183       *marker = SOLVABLE_PREREQMARKER;
184     }
185   return repo_addid(repo, olddeps, id);
186 }
187
188
189 /*
190  * reserve Ids
191  * make space for 'num' more dependencies
192  */
193
194 Offset
195 repo_reserve_ids(Repo *repo, Offset olddeps, int num)
196 {
197   num++;        /* room for trailing ID_NULL */
198
199   if (!repo->idarraysize)              /* ensure buffer space */
200     {
201       repo->idarraysize = 1;
202       repo->idarraydata = (Id *)xmalloc(((1 + num + IDARRAY_BLOCK) & ~IDARRAY_BLOCK) * sizeof(Id));
203       repo->idarraydata[0] = 0;
204       repo->lastoff = 1;
205       return 1;
206     }
207
208   if (olddeps && olddeps != repo->lastoff)   /* if not appending */
209     {
210       /* can't insert into idarray, this would invalidate all 'larger' offsets
211        * so create new space at end and move existing deps there.
212        * Leaving 'hole' at old position.
213        */
214       
215       Id *idstart, *idend;
216       int count;
217
218       for (idstart = idend = repo->idarraydata + olddeps; *idend++; )   /* find end */
219         ;
220       count = idend - idstart - 1 + num;               /* new size */
221
222       /* realloc if crossing block boundary */
223       if (((repo->idarraysize - 1) | IDARRAY_BLOCK) != ((repo->idarraysize + count - 1) | IDARRAY_BLOCK))
224         repo->idarraydata = (Id *)xrealloc(repo->idarraydata, ((repo->idarraysize + count + IDARRAY_BLOCK) & ~IDARRAY_BLOCK) * sizeof(Id));
225
226       /* move old deps to end */
227       olddeps = repo->lastoff = repo->idarraysize;
228       memcpy(repo->idarraydata + olddeps, idstart, count - num);
229       repo->idarraysize = olddeps + count - num;
230
231       return olddeps;
232     }
233
234   if (olddeps)                         /* appending */
235     repo->idarraysize--;
236
237   /* realloc if crossing block boundary */
238   if (((repo->idarraysize - 1) | IDARRAY_BLOCK) != ((repo->idarraysize + num - 1) | IDARRAY_BLOCK))
239     repo->idarraydata = (Id *)xrealloc(repo->idarraydata, ((repo->idarraysize + num + IDARRAY_BLOCK) & ~IDARRAY_BLOCK) * sizeof(Id));
240
241   /* appending or new */
242   repo->lastoff = olddeps ? olddeps : repo->idarraysize;
243
244   return repo->lastoff;
245 }
246
247
248 /*
249  * remove repo from pool
250  * 
251  */
252
253 void
254 repo_free(Repo *repo)
255 {
256   Pool *pool = repo->pool;
257   int i, nsolvables;
258
259   pool_freewhatprovides(pool);
260
261   for (i = 0; i < pool->nrepos; i++)    /* find repo in pool */
262     {
263       if (pool->repos[i] == repo)
264         break;
265     }
266   if (i == pool->nrepos)               /* repo not in pool, return */
267     return;
268
269   /* close gap
270    * all repos point into pool->solvables _relatively_ to repo->start
271    * so closing the gap only needs adaption of repo->start for all
272    * other repos.
273    */
274   
275   nsolvables = repo->nsolvables;
276   if (pool->nsolvables > repo->start + nsolvables)
277     memmove(pool->solvables + repo->start, pool->solvables + repo->start + nsolvables, (pool->nsolvables - repo->start - nsolvables) * sizeof(Solvable));
278   pool->nsolvables -= nsolvables;
279
280   for (; i < pool->nrepos - 1; i++)
281     {
282       pool->repos[i] = pool->repos[i + 1];   /* remove repo */
283       pool->repos[i]->start -= nsolvables;     /* adapt start offset of remaining repos */
284     }
285   pool->nrepos = i;
286   repo_freedata(repo);
287 }
288
289 void
290 pool_freeallrepos(Pool *pool)
291 {
292   int i;
293   for (i = 0; i < pool->nrepos; i++)
294     repo_freedata(pool->repos[i]);
295   pool->repos = xfree(pool->repos);
296   pool->nrepos = 0;
297 }
298
299 Offset
300 repo_fix_legacy(Repo *repo, Offset provides, Offset supplements)
301 {
302   Pool *pool = repo->pool;
303   Id id, idp, idl, idns;
304   char buf[1024], *p, *dep;
305   int i;
306
307   if (provides)
308     {
309       for (i = provides; repo->idarraydata[i]; i++)
310         {
311           id = repo->idarraydata[i];
312           if (ISRELDEP(id))
313             continue;
314           dep = (char *)id2str(pool, id);
315           if (!strncmp(dep, "locale(", 7) && strlen(dep) < sizeof(buf) - 2)
316             {
317               idp = 0;
318               strcpy(buf + 2, dep);
319               dep = buf + 2 + 7;
320               if ((p = strchr(dep, ':')) != 0 && p != dep)
321                 {
322                   *p++ = 0;
323                   idp = str2id(pool, dep, 1);
324                   dep = p;
325                 }
326               id = 0;
327               while ((p = strchr(dep, ';')) != 0)
328                 {
329                   if (p == dep)
330                     {
331                       dep = p + 1;
332                       continue;
333                     }
334                   strncpy(dep - 9, "language:", 9);
335                   *p++ = 0;
336                   idl = str2id(pool, dep - 9, 1);
337                   if (id)
338                     id = rel2id(pool, id, idl, REL_OR, 1);
339                   else
340                     id = idl;
341                   dep = p;
342                 }
343               if (dep[0] && dep[1])
344                 {
345                   for (p = dep; *p && *p != ')'; p++)
346                     ;
347                   *p = 0;
348                   strncpy(dep - 9, "language:", 9);
349                   idl = str2id(pool, dep - 9, 1);
350                   if (id)
351                     id = rel2id(pool, id, idl, REL_OR, 1);
352                   else
353                     id = idl;
354                 }
355               if (idp)
356                 id = rel2id(pool, idp, id, REL_AND, 1);
357               if (id)
358                 supplements = repo_addid_dep(repo, supplements, id, 0);
359             }
360           else if ((p = strchr(dep, ':')) != 0 && p != dep && p[1] == '/' && strlen(dep) < sizeof(buf))
361             {
362               strcpy(buf, dep);
363               p = buf + (p - dep);
364               *p++ = 0;
365               idp = str2id(pool, buf, 1);
366               idns = str2id(pool, "namespace:installed", 1);
367               id = str2id(pool, p, 1);
368               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
369               id = rel2id(pool, idp, id, REL_AND, 1);
370               supplements = repo_addid_dep(repo, supplements, id, 0);
371             }
372         }
373     }
374   if (!supplements)
375     return 0;
376   for (i = supplements; repo->idarraydata[i]; i++)
377     {
378       id = repo->idarraydata[i];
379       if (ISRELDEP(id))
380         continue;
381       dep = (char *)id2str(pool, id);
382       if (!strncmp(dep, "system:modalias(", 16))
383         dep += 7;
384       if (!strncmp(dep, "modalias(", 9) && dep[9] && dep[10] && strlen(dep) < sizeof(buf))
385         {
386           strcpy(buf, dep);
387           p = strchr(buf + 9, ':');
388           idns = str2id(pool, "namespace:modalias", 1);
389           if (p && p != buf + 9 && strchr(p + 1, ':'))
390             {
391               *p++ = 0;
392               idp = str2id(pool, buf + 9, 1);
393               p[strlen(p) - 1] = 0;
394               id = str2id(pool, p, 1);
395               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
396               id = rel2id(pool, idp, id, REL_AND, 1);
397             }
398           else
399             {
400               p = buf + 9;
401               p[strlen(p) - 1] = 0;
402               id = str2id(pool, p, 1);
403               id = rel2id(pool, idns, id, REL_NAMESPACE, 1);
404             }
405           if (id)
406             repo->idarraydata[i] = id;
407         }
408       else if (!strncmp(dep, "packageand(", 11) && strlen(dep) < sizeof(buf))
409         {
410           strcpy(buf, dep);
411           id = 0;
412           dep = buf + 11;
413           while ((p = strchr(dep, ':')) != 0)
414             {
415               if (p == dep)
416                 {
417                   dep = p + 1;
418                   continue;
419                 }
420               *p++ = 0;
421               idp = str2id(pool, dep, 1);
422               if (id)
423                 id = rel2id(pool, id, idp, REL_AND, 1);
424               else
425                 id = idp;
426               dep = p;
427             }
428           if (dep[0] && dep[1])
429             {
430               dep[strlen(dep) - 1] = 0;
431               idp = str2id(pool, dep, 1);
432               if (id)
433                 id = rel2id(pool, id, idp, REL_AND, 1);
434               else
435                 id = idp;
436             }
437           if (id)
438             repo->idarraydata[i] = id;
439         }
440     }
441   return supplements;
442 }
443
444 // EOF