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