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