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