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