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