cleanup code now that the vendorcheck callback is in the pool
[platform/upstream/libsolv.git] / src / solvable.c
1 /*
2  * Copyright (c) 2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solvable.c
10  *
11  * set/retrieve data from solvables
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <unistd.h>
18 #include <string.h>
19
20 #include "pool.h"
21 #include "repo.h"
22 #include "util.h"
23 #include "policy.h"
24 #include "poolvendor.h"
25 #include "chksum.h"
26
27 const char *
28 pool_solvable2str(Pool *pool, Solvable *s)
29 {
30   const char *n, *e, *a;
31   int nl, el, al;
32   char *p;
33   n = pool_id2str(pool, s->name);
34   e = pool_id2str(pool, s->evr);
35   /* XXX: may want to skip the epoch here */
36   a = pool_id2str(pool, s->arch);
37   nl = strlen(n);
38   el = strlen(e);
39   al = strlen(a);
40   if (pool->havedistepoch)
41     {
42       /* strip the distepoch from the evr */
43       const char *de = strrchr(e, '-');
44       if (de && (de = strchr(de, ':')) != 0)
45         el = de - e;
46     }
47   p = pool_alloctmpspace(pool, nl + el + al + 3);
48   strcpy(p, n);
49   p[nl] = '-';
50   strncpy(p + nl + 1, e, el);
51   p[nl + 1 + el] = '.';
52   strcpy(p + nl + 1 + el + 1, a);
53   return p;
54 }
55
56 Id
57 solvable_lookup_type(Solvable *s, Id keyname)
58 {
59   if (!s->repo)
60     return 0;
61   return repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname);
62 }
63
64 Id
65 solvable_lookup_id(Solvable *s, Id keyname)
66 {
67   if (!s->repo)
68     return 0;
69   return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname);
70 }
71
72 int
73 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q)
74 {
75   if (!s->repo)
76     {
77       queue_empty(q);
78       return 0;
79     }
80   return repo_lookup_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
81 }
82
83 int
84 solvable_lookup_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
85 {
86   if (!s->repo)
87     {
88       queue_empty(q);
89       return 0;
90     }
91   return repo_lookup_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
92 }
93
94 const char *
95 solvable_lookup_str(Solvable *s, Id keyname)
96 {
97   if (!s->repo)
98     return 0;
99   return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname);
100 }
101
102 static const char *
103 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase)
104 {
105   Pool *pool;
106   const char *str, *basestr;
107   Id p, pp;
108   Solvable *s2;
109   int pass;
110
111   if (!s->repo)
112     return 0;
113   pool = s->repo->pool;
114   str = solvable_lookup_str(s, keyname);
115   if (str || keyname == basekeyname)
116     return str;
117   basestr = solvable_lookup_str(s, basekeyname);
118   if (!basestr)
119     return 0;
120   /* search for a solvable with same name and same base that has the
121    * translation */
122   if (!pool->whatprovides)
123     return usebase ? basestr : 0;
124   /* we do this in two passes, first same vendor, then all other vendors */
125   for (pass = 0; pass < 2; pass++)
126     {
127       FOR_PROVIDES(p, pp, s->name)
128         {
129           s2 = pool->solvables + p;
130           if (s2->name != s->name)
131             continue;
132           if ((s->vendor == s2->vendor) != (pass == 0))
133             continue;
134           str = solvable_lookup_str(s2, basekeyname);
135           if (!str || strcmp(str, basestr))
136             continue;
137           str = solvable_lookup_str(s2, keyname);
138           if (str)
139             return str;
140         }
141     }
142   return usebase ? basestr : 0;
143 }
144
145 const char *
146 solvable_lookup_str_poollang(Solvable *s, Id keyname)
147 {
148   Pool *pool;
149   int i, cols;
150   const char *str;
151   Id *row;
152
153   if (!s->repo)
154     return 0;
155   pool = s->repo->pool;
156   if (!pool->nlanguages)
157     return solvable_lookup_str(s, keyname);
158   cols = pool->nlanguages + 1;
159   if (!pool->languagecache)
160     {
161       pool->languagecache = solv_calloc(cols * ID_NUM_INTERNAL, sizeof(Id));
162       pool->languagecacheother = 0;
163     }
164   if (keyname >= ID_NUM_INTERNAL)
165     {
166       row = pool->languagecache + ID_NUM_INTERNAL * cols;
167       for (i = 0; i < pool->languagecacheother; i++, row += cols)
168         if (*row == keyname)
169           break;
170       if (i >= pool->languagecacheother)
171         {
172           pool->languagecache = solv_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id));
173           row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++);
174           *row = keyname;
175         }
176     }
177   else
178     row = pool->languagecache + keyname * cols;
179   row++;        /* skip keyname */
180   for (i = 0; i < pool->nlanguages; i++, row++)
181     {
182       if (!*row)
183         *row = pool_id2langid(pool, keyname, pool->languages[i], 1);
184       str = solvable_lookup_str_base(s, *row, keyname, 0);
185       if (str)
186         return str;
187     }
188   return solvable_lookup_str(s, keyname);
189 }
190
191 const char *
192 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase)
193 {
194   if (s->repo)
195     {
196       Id id = pool_id2langid(s->repo->pool, keyname, lang, 0);
197       if (id)
198         return solvable_lookup_str_base(s, id, keyname, usebase);
199       if (!usebase)
200         return 0;
201     }
202   return solvable_lookup_str(s, keyname);
203 }
204
205 unsigned long long
206 solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound)
207 {
208   if (!s->repo)
209     return notfound;
210   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
211 }
212
213 unsigned int
214 solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound)
215 {
216   unsigned long long size;
217   if (!s->repo)
218     return notfound;
219   size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10);
220   return (unsigned int)((size + 1023) >> 10);
221 }
222
223 int
224 solvable_lookup_void(Solvable *s, Id keyname)
225 {
226   if (!s->repo)
227     return 0;
228   return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname);
229 }
230
231 int
232 solvable_lookup_bool(Solvable *s, Id keyname)
233 {
234   if (!s->repo)
235     return 0;
236   /* historic nonsense: there are two ways of storing a bool, as num == 1 or void. test both. */
237   if (repo_lookup_type(s->repo, s - s->repo->pool->solvables, keyname) == REPOKEY_TYPE_VOID)
238     return 1;
239   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, 0) == 1;
240 }
241
242 const unsigned char *
243 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep)
244 {
245   Repo *repo = s->repo;
246
247   if (!repo)
248     {
249       *typep = 0;
250       return 0;
251     }
252   return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep);
253 }
254
255 const char *
256 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep)
257 {
258   const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep);
259   return chk ? pool_bin2hex(s->repo->pool, chk, solv_chksum_len(*typep)) : 0;
260 }
261
262 static inline const char *
263 evrid2vrstr(Pool *pool, Id evrid)
264 {
265   const char *p, *evr = pool_id2str(pool, evrid);
266   if (!evr)
267     return evr;
268   for (p = evr; *p >= '0' && *p <= '9'; p++)
269     ;
270   return p != evr && *p == ':' && p[1] ? p + 1 : evr;
271 }
272
273 const char *
274 solvable_lookup_location(Solvable *s, unsigned int *medianrp)
275 {
276   Pool *pool;
277   int l = 0;
278   char *loc;
279   const char *mediadir, *mediafile;
280
281   if (medianrp)
282     *medianrp = 0;
283   if (!s->repo)
284     return 0;
285   pool = s->repo->pool;
286   if (medianrp)
287     *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 0);
288   if (solvable_lookup_void(s, SOLVABLE_MEDIADIR))
289     mediadir = pool_id2str(pool, s->arch);
290   else
291     mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR);
292   if (mediadir)
293     l = strlen(mediadir) + 1;
294   if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE))
295     {
296       const char *name, *evr, *arch;
297       name = pool_id2str(pool, s->name);
298       evr = evrid2vrstr(pool, s->evr);
299       arch = pool_id2str(pool, s->arch);
300       /* name-vr.arch.rpm */
301       loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7);
302       if (mediadir)
303         sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch);
304       else
305         sprintf(loc, "%s-%s.%s.rpm", name, evr, arch);
306     }
307   else
308     {
309       mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE);
310       if (!mediafile)
311         return 0;
312       loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1);
313       if (mediadir)
314         sprintf(loc, "%s/%s", mediadir, mediafile);
315       else
316         strcpy(loc, mediafile);
317     }
318   return loc;
319 }
320
321 const char *
322 solvable_get_location(Solvable *s, unsigned int *medianrp)
323 {
324   const char *loc = solvable_lookup_location(s, medianrp);
325   if (medianrp && *medianrp == 0)
326     *medianrp = 1;      /* compat, to be removed */
327   return loc;
328 }
329
330 const char *
331 solvable_lookup_sourcepkg(Solvable *s)
332 {
333   Pool *pool;
334   const char *evr, *name;
335   Id archid;
336
337   if (!s->repo)
338     return 0;
339   pool = s->repo->pool;
340   if (solvable_lookup_void(s, SOLVABLE_SOURCENAME))
341     name = pool_id2str(pool, s->name);
342   else
343     name = solvable_lookup_str(s, SOLVABLE_SOURCENAME);
344   if (!name)
345     return 0;
346   archid = solvable_lookup_id(s, SOLVABLE_SOURCEARCH);
347   if (solvable_lookup_void(s, SOLVABLE_SOURCEEVR))
348     evr = evrid2vrstr(pool, s->evr);
349   else
350     evr = solvable_lookup_str(s, SOLVABLE_SOURCEEVR);
351   if (archid == ARCH_SRC || archid == ARCH_NOSRC)
352     {
353       char *str;
354       str = pool_tmpjoin(pool, name, evr ? "-" : 0, evr);
355       str = pool_tmpappend(pool, str, ".", pool_id2str(pool, archid));
356       return pool_tmpappend(pool, str, ".rpm", 0);
357     }
358   else 
359     return name;        /* FIXME */
360 }
361
362
363 /*****************************************************************************/
364
365 static inline Id dep2name(Pool *pool, Id dep)
366 {
367   while (ISRELDEP(dep))
368     {
369       Reldep *rd = rd = GETRELDEP(pool, dep);
370       dep = rd->name;
371     }
372   return dep;
373 }
374
375 static int providedbyinstalled_multiversion(Pool *pool, Map *installed, Id n, Id con) 
376 {
377   Id p, pp;
378   Solvable *sn = pool->solvables + n; 
379
380   FOR_PROVIDES(p, pp, sn->name)
381     {    
382       Solvable *s = pool->solvables + p; 
383       if (s->name != sn->name || s->arch != sn->arch)
384         continue;
385       if (!MAPTST(installed, p))
386         continue;
387       if (pool_match_nevr(pool, pool->solvables + p, con))
388         continue;
389       return 1;         /* found installed package that doesn't conflict */
390     }    
391   return 0;
392 }
393
394 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep, int ispatch, Map *noobsoletesmap)
395 {
396   Id p, pp;
397   FOR_PROVIDES(p, pp, dep)
398     {
399       if (p == SYSTEMSOLVABLE)
400         return -1;
401       if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep))
402         continue;
403       if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep))
404         if (providedbyinstalled_multiversion(pool, installed, p, dep))
405           continue;
406       if (MAPTST(installed, p))
407         return 1;
408     }
409   return 0;
410 }
411
412 /*
413  * solvable_trivial_installable_map - anwers is a solvable is installable
414  * without any other installs/deinstalls.
415  * The packages considered to be installed are provided via the
416  * installedmap bitmap. A additional "conflictsmap" bitmap providing
417  * information about the conflicts of the installed packages can be
418  * used for extra speed up. Provide a NULL pointer if you do not
419  * have this information.
420  * Both maps can be created with pool_create_state_maps() or
421  * solver_create_state_maps().
422  *
423  * returns:
424  * 1:  solvable is installable without any other package changes
425  * 0:  solvable is not installable
426  * -1: solvable is installable, but doesn't constrain any installed packages
427  */
428 int
429 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *noobsoletesmap)
430 {
431   Pool *pool = s->repo->pool;
432   Solvable *s2;
433   Id p, *dp;
434   Id *reqp, req;
435   Id *conp, con;
436   int r, interesting = 0;
437
438   if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables))
439     return 0;
440   if (s->requires)
441     {
442       reqp = s->repo->idarraydata + s->requires;
443       while ((req = *reqp++) != 0)
444         {
445           if (req == SOLVABLE_PREREQMARKER)
446             continue;
447           r = providedbyinstalled(pool, installedmap, req, 0, 0);
448           if (!r)
449             return 0;
450           if (r > 0)
451             interesting = 1;
452         }
453     }
454   if (s->conflicts)
455     {
456       int ispatch = 0;
457
458       if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
459         ispatch = 1;
460       conp = s->repo->idarraydata + s->conflicts;
461       while ((con = *conp++) != 0)
462         {
463           if (providedbyinstalled(pool, installedmap, con, ispatch, noobsoletesmap))
464             {
465               if (ispatch && solvable_is_irrelevant_patch(s, installedmap))
466                 return -1;
467               return 0;
468             }
469           if (!interesting && ISRELDEP(con))
470             {
471               con = dep2name(pool, con);
472               if (providedbyinstalled(pool, installedmap, con, ispatch, noobsoletesmap))
473                 interesting = 1;
474             }
475         }
476       if (ispatch && interesting && solvable_is_irrelevant_patch(s, installedmap))
477         interesting = 0;
478     }
479 #if 0
480   if (s->repo)
481     {
482       Id *obsp, obs;
483       Repo *installed = 0;
484       if (s->obsoletes && s->repo != installed)
485         {
486           obsp = s->repo->idarraydata + s->obsoletes;
487           while ((obs = *obsp++) != 0)
488             {
489               if (providedbyinstalled(pool, installedmap, obs, 0, 0))
490                 return 0;
491             }
492         }
493       if (s->repo != installed)
494         {
495           Id pp;
496           FOR_PROVIDES(p, pp, s->name)
497             {
498               s2 = pool->solvables + p;
499               if (s2->repo == installed && s2->name == s->name)
500                 return 0;
501             }
502         }
503     }
504 #endif
505   if (!conflictsmap)
506     {
507       int i;
508
509       p = s - pool->solvables;
510       for (i = 1; i < pool->nsolvables; i++)
511         {
512           if (!MAPTST(installedmap, i))
513             continue;
514           s2 = pool->solvables + i;
515           if (!s2->conflicts)
516             continue;
517           conp = s2->repo->idarraydata + s2->conflicts;
518           while ((con = *conp++) != 0)
519             {
520               dp = pool_whatprovides_ptr(pool, con);
521               for (; *dp; dp++)
522                 if (*dp == p)
523                   return 0;
524             }
525         }
526      }
527   return interesting ? 1 : -1;
528 }
529
530 /*
531  * different interface for solvable_trivial_installable_map, where
532  * the information about the installed packages is provided
533  * by a queue.
534  */
535 int
536 solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *noobsoletesmap)
537 {
538   Pool *pool = s->repo->pool;
539   int i;
540   Id p;
541   Map installedmap;
542   int r;
543
544   map_init(&installedmap, pool->nsolvables);
545   for (i = 0; i < installed->count; i++)
546     {
547       p = installed->elements[i];
548       if (p > 0)                /* makes it work with decisionq */
549         MAPSET(&installedmap, p);
550     }
551   r = solvable_trivial_installable_map(s, &installedmap, 0, noobsoletesmap);
552   map_free(&installedmap);
553   return r;
554 }
555
556 /*
557  * different interface for solvable_trivial_installable_map, where
558  * the information about the installed packages is provided
559  * by a repo containing the installed solvables.
560  */
561 int
562 solvable_trivial_installable_repo(Solvable *s, Repo *installed, Map *noobsoletesmap)
563 {
564   Pool *pool = s->repo->pool;
565   Id p;
566   Solvable *s2;
567   Map installedmap;
568   int r;
569
570   map_init(&installedmap, pool->nsolvables);
571   FOR_REPO_SOLVABLES(installed, p, s2)
572     MAPSET(&installedmap, p);
573   r = solvable_trivial_installable_map(s, &installedmap, 0, noobsoletesmap);
574   map_free(&installedmap);
575   return r;
576 }
577
578 /* FIXME: this mirrors policy_illegal_vendorchange */
579 static int
580 pool_illegal_vendorchange(Pool *pool, Solvable *s1, Solvable *s2)
581 {
582   Id v1, v2; 
583   Id vendormask1, vendormask2;
584
585   if (pool->custom_vendorcheck)
586     return pool->custom_vendorcheck(pool, s1, s2);
587   /* treat a missing vendor as empty string */
588   v1 = s1->vendor ? s1->vendor : ID_EMPTY;
589   v2 = s2->vendor ? s2->vendor : ID_EMPTY;
590   if (v1 == v2) 
591     return 0;
592   vendormask1 = pool_vendor2mask(pool, v1);
593   if (!vendormask1)
594     return 1;   /* can't match */
595   vendormask2 = pool_vendor2mask(pool, v2);
596   if ((vendormask1 & vendormask2) != 0)
597     return 0;
598   return 1;     /* no class matches */
599 }
600
601 /* check if this patch is relevant according to the vendor. To bad that patches
602  * don't have a vendor, so we need to do some careful repo testing. */
603 int
604 solvable_is_irrelevant_patch(Solvable *s, Map *installedmap)
605 {
606   Pool *pool = s->repo->pool;
607   Id con, *conp;
608   int hadpatchpackage = 0;
609
610   if (!s->conflicts)
611     return 0;
612   conp = s->repo->idarraydata + s->conflicts;
613   while ((con = *conp++) != 0)
614     {
615       Reldep *rd;
616       Id p, pp, p2, pp2;
617       if (!ISRELDEP(con))
618         continue;
619       rd = GETRELDEP(pool, con);
620       if (rd->flags != REL_LT)
621         continue;
622       FOR_PROVIDES(p, pp, con)
623         {
624           Solvable *si;
625           if (!MAPTST(installedmap, p))
626             continue;
627           si = pool->solvables + p;
628           if (!pool_match_nevr(pool, si, con))
629             continue;
630           FOR_PROVIDES(p2, pp2, rd->name)
631             {
632               Solvable *s2 = pool->solvables + p2;
633               if (!pool_match_nevr(pool, s2, rd->name))
634                 continue;
635               if (pool_match_nevr(pool, s2, con))
636                 continue;       /* does not fulfill patch */
637               if (s2->repo == s->repo)
638                 {
639                   hadpatchpackage = 1;
640                   /* ok, we have a package from the patch repo that solves the conflict. check vendor */
641                   if (si->vendor == s2->vendor)
642                     return 0;
643                   if (!pool_illegal_vendorchange(pool, si, s2))
644                     return 0;
645                   /* vendor change was illegal, ignore conflict */
646                 }
647             }
648         }
649     }
650   /* if we didn't find a patchpackage don't claim that the patch is irrelevant */
651   if (!hadpatchpackage)
652     return 0;
653   return 1;
654 }
655
656 /*****************************************************************************/
657
658 /*
659  * Create maps containing the state of each solvable. Input is a "installed" queue,
660  * it contains all solvable ids that are considered to be installed.
661  * 
662  * The created maps can be used for solvable_trivial_installable_map(),
663  * pool_calc_duchanges(), pool_calc_installsizechange().
664  *
665  */
666 void
667 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap)
668 {
669   int i;
670   Solvable *s;
671   Id p, *dp;
672   Id *conp, con;
673
674   map_init(installedmap, pool->nsolvables);
675   if (conflictsmap)
676     map_init(conflictsmap, pool->nsolvables);
677   for (i = 0; i < installed->count; i++)
678     {
679       p = installed->elements[i];
680       if (p <= 0)       /* makes it work with decisionq */
681         continue;
682       MAPSET(installedmap, p);
683       if (!conflictsmap)
684         continue;
685       s = pool->solvables + p;
686       if (!s->conflicts)
687         continue;
688       conp = s->repo->idarraydata + s->conflicts;
689       while ((con = *conp++) != 0)
690         {
691           dp = pool_whatprovides_ptr(pool, con);
692           for (; *dp; dp++)
693             MAPSET(conflictsmap, *dp);
694         }
695     }
696 }
697
698 /* Tests if two solvables have identical content. Currently
699  * both solvables need to come from the same pool
700  */
701 int
702 solvable_identical(Solvable *s1, Solvable *s2)
703 {
704   unsigned int bt1, bt2;
705   Id rq1, rq2;
706   Id *reqp;
707
708   if (s1->name != s2->name)
709     return 0;
710   if (s1->arch != s2->arch)
711     return 0;
712   if (s1->evr != s2->evr)
713     return 0;
714   /* map missing vendor to empty string */
715   if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1))
716     return 0;
717
718   /* looking good, try some fancier stuff */
719   /* might also look up the package checksum here */
720   bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0);
721   bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0);
722   if (bt1 && bt2)
723     {
724       if (bt1 != bt2)
725         return 0;
726     }
727   else
728     {
729       /* look at requires in a last attempt to find recompiled packages */
730       rq1 = rq2 = 0;
731       if (s1->requires)
732         for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
733           rq1 ^= *reqp;
734       if (s2->requires)
735         for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
736           rq2 ^= *reqp;
737       if (rq1 != rq2)
738          return 0;
739     }
740   return 1;
741 }
742
743 /* return the self provide dependency of a solvable */
744 Id
745 solvable_selfprovidedep(Solvable *s)
746 {
747   Pool *pool;
748   Reldep *rd;
749   Id prov, *provp;
750
751   if (!s->repo)
752     return s->name;
753   pool = s->repo->pool;
754   if (s->provides)
755     {
756       provp = s->repo->idarraydata + s->provides;
757       while ((prov = *provp++) != 0)
758         {
759           if (!ISRELDEP(prov))
760             continue;
761           rd = GETRELDEP(pool, prov);
762           if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ)
763             return prov;
764         }
765     }
766   return pool_rel2id(pool, s->name, s->evr, REL_EQ, 1);
767 }
768
769 /* setter functions, simply call the repo variants */
770 void
771 solvable_set_id(Solvable *s, Id keyname, Id id)
772 {
773   repo_set_id(s->repo, s - s->repo->pool->solvables, keyname, id);
774 }
775
776 void
777 solvable_set_num(Solvable *s, Id keyname, unsigned long long num)
778 {
779   repo_set_num(s->repo, s - s->repo->pool->solvables, keyname, num);
780 }
781
782 void
783 solvable_set_str(Solvable *s, Id keyname, const char *str)
784 {
785   repo_set_str(s->repo, s - s->repo->pool->solvables, keyname, str);
786 }
787
788 void
789 solvable_set_poolstr(Solvable *s, Id keyname, const char *str)
790 {
791   repo_set_poolstr(s->repo, s - s->repo->pool->solvables, keyname, str);
792 }
793
794 void
795 solvable_add_poolstr_array(Solvable *s, Id keyname, const char *str)
796 {
797   repo_add_poolstr_array(s->repo, s - s->repo->pool->solvables, keyname, str);
798 }
799
800 void
801 solvable_add_idarray(Solvable *s, Id keyname, Id id)
802 {
803   repo_add_idarray(s->repo, s - s->repo->pool->solvables, keyname, id);
804 }
805
806 void
807 solvable_add_deparray(Solvable *s, Id keyname, Id dep, Id marker)
808 {
809   repo_add_deparray(s->repo, s - s->repo->pool->solvables, keyname, dep, marker);
810 }
811
812 void
813 solvable_set_idarray(Solvable *s, Id keyname, Queue *q)
814 {
815   repo_set_idarray(s->repo, s - s->repo->pool->solvables, keyname, q);
816 }
817
818 void
819 solvable_set_deparray(Solvable *s, Id keyname, Queue *q, Id marker)
820 {
821   repo_set_deparray(s->repo, s - s->repo->pool->solvables, keyname, q, marker);
822 }
823
824 void
825 solvable_unset(Solvable *s, Id keyname)
826 {
827   repo_unset(s->repo, s - s->repo->pool->solvables, keyname);
828 }