revert buildtime tie breaking, not the right thing to do.
[platform/upstream/rpm.git] / lib / rpmte.c
1 /** \ingroup rpmdep
2  * \file lib/rpmte.c
3  * Routine(s) to handle an "rpmte"  transaction element.
4  */
5 #include "system.h"
6 #include <rpmlib.h>
7
8 #include "psm.h"
9
10 #include "rpmds.h"
11 #include "rpmfi.h"
12
13 #define _RPMTE_INTERNAL
14 #include "rpmte.h"
15 #include "rpmts.h"
16
17 #include "debug.h"
18
19 /*@unchecked@*/
20 int _rpmte_debug = 0;
21
22 /*@access alKey @*/
23 /*@access rpmtsi @*/
24
25 void rpmteCleanDS(rpmte te)
26 {
27     te->this = rpmdsFree(te->this);
28     te->provides = rpmdsFree(te->provides);
29     te->requires = rpmdsFree(te->requires);
30     te->conflicts = rpmdsFree(te->conflicts);
31     te->obsoletes = rpmdsFree(te->obsoletes);
32 }
33
34 /**
35  * Destroy transaction element data.
36  * @param p             transaction element
37  */
38 static void delTE(rpmte p)
39         /*@globals fileSystem @*/
40         /*@modifies p, fileSystem @*/
41 {
42     rpmRelocation * r;
43
44     if (p->relocs) {
45         for (r = p->relocs; (r->oldPath || r->newPath); r++) {
46             r->oldPath = _free(r->oldPath);
47             r->newPath = _free(r->newPath);
48         }
49         p->relocs = _free(p->relocs);
50     }
51
52     rpmteCleanDS(p);
53
54     p->fi = rpmfiFree(p->fi);
55
56     if (p->fd != NULL)
57         p->fd = fdFree(p->fd, "delTE");
58
59     p->os = _free(p->os);
60     p->arch = _free(p->arch);
61     p->epoch = _free(p->epoch);
62     p->name = _free(p->name);
63     p->NEVR = _free(p->NEVR);
64     p->NEVRA = _free(p->NEVRA);
65
66     p->h = headerFree(p->h);
67
68 /*@-boundswrite@*/
69     memset(p, 0, sizeof(*p));   /* XXX trash and burn */
70 /*@=boundswrite@*/
71     /*@-nullstate@*/ /* FIX: p->{NEVR,name} annotations */
72     return;
73     /*@=nullstate@*/
74 }
75
76 /**
77  * Initialize transaction element data from header.
78  * @param ts            transaction set
79  * @param p             transaction element
80  * @param h             header
81  * @param key           (TR_ADDED) package retrieval key (e.g. file name)
82  * @param relocs        (TR_ADDED) package file relocations
83  */
84 /*@-bounds@*/
85 static void addTE(rpmts ts, rpmte p, Header h,
86                 /*@dependent@*/ /*@null@*/ fnpyKey key,
87                 /*@null@*/ rpmRelocation * relocs)
88         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
89         /*@modifies ts, p, h,
90                 rpmGlobalMacroContext, fileSystem, internalState @*/
91 {
92     int scareMem = 0;
93     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
94     rpmte savep;
95     int_32 * ep;
96     const char * arch, * os;
97     char * t;
98     size_t nb;
99     int xx;
100
101     p->NEVR = hGetNEVR(h, NULL);
102     p->name = xstrdup(p->NEVR);
103     if ((p->release = strrchr(p->name, '-')) != NULL)
104         *p->release++ = '\0';
105     if ((p->version = strrchr(p->name, '-')) != NULL)
106         *p->version++ = '\0';
107
108     /* Set db_instance to 0 as it has not been installed
109      * necessarily yet.
110      */
111     p->db_instance = 0;
112
113     arch = NULL;
114     xx = hge(h, RPMTAG_ARCH, NULL, (void **)&arch, NULL);
115     if (arch != NULL) {
116         p->arch = xstrdup(arch);
117         p->archScore = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
118     } else {
119         p->arch = NULL;
120         p->archScore = 0;
121     }
122     os = NULL;
123     xx = hge(h, RPMTAG_OS, NULL, (void **)&os, NULL);
124     if (os != NULL) {
125         p->os = xstrdup(os);
126         p->osScore = rpmMachineScore(RPM_MACHTABLE_INSTOS, os);
127     } else {
128         p->os = NULL;
129         p->osScore = 0;
130     }
131
132     nb = strlen(p->NEVR) + 1;
133     if (p->arch)
134         nb += strlen(p->arch) + 1;
135     t = xmalloc(nb);
136     p->NEVRA = t;
137     *t = '\0';
138     t = stpcpy(t, p->NEVR);
139     if (p->arch)
140         t = stpcpy( stpcpy( t, "."), p->arch);
141
142     ep = NULL;
143     xx = hge(h, RPMTAG_EPOCH, NULL, (void **)&ep, NULL);
144 /*@-branchstate@*/
145     if (ep) {
146         p->epoch = xmalloc(20);
147         sprintf(p->epoch, "%d", *ep);
148     } else
149         p->epoch = NULL;
150 /*@=branchstate@*/
151
152     p->nrelocs = 0;
153     p->relocs = NULL;
154     if (relocs != NULL) {
155         rpmRelocation * r;
156         int i;
157
158         for (r = relocs; r->oldPath || r->newPath; r++)
159             p->nrelocs++;
160         p->relocs = xmalloc((p->nrelocs + 1) * sizeof(*p->relocs));
161
162         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) {
163             p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL;
164             p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL;
165         }
166         p->relocs[i].oldPath = NULL;
167         p->relocs[i].newPath = NULL;
168     }
169     p->autorelocatex = -1;
170
171     p->key = key;
172     p->fd = NULL;
173
174     p->pkgFileSize = 0;
175
176     p->this = rpmdsThis(h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
177     p->provides = rpmdsNew(h, RPMTAG_PROVIDENAME, scareMem);
178     p->requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
179     p->conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
180     p->obsoletes = rpmdsNew(h, RPMTAG_OBSOLETENAME, scareMem);
181
182     savep = rpmtsSetRelocateElement(ts, p);
183     p->fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
184     (void) rpmtsSetRelocateElement(ts, savep);
185
186     rpmteColorDS(p, RPMTAG_PROVIDENAME);
187     rpmteColorDS(p, RPMTAG_REQUIRENAME);
188 /*@-compdef@*/
189     return;
190 /*@=compdef@*/
191 }
192 /*@=bounds@*/
193
194 rpmte rpmteFree(rpmte te)
195 {
196     if (te != NULL) {
197         delTE(te);
198         memset(te, 0, sizeof(*te));     /* XXX trash and burn */
199         te = _free(te);
200     }
201     return NULL;
202 }
203
204 rpmte rpmteNew(const rpmts ts, Header h,
205                 rpmElementType type,
206                 fnpyKey key,
207                 rpmRelocation * relocs,
208                 int dboffset,
209                 alKey pkgKey)
210 {
211     rpmte p = xcalloc(1, sizeof(*p));
212     int_32 * ep;
213     int xx;
214
215     p->type = type;
216     addTE(ts, p, h, key, relocs);
217     switch (type) {
218     case TR_ADDED:
219         p->u.addedKey = pkgKey;
220         ep = NULL;
221         xx = headerGetEntry(h, RPMTAG_SIGSIZE, NULL, (void **)&ep, NULL);
222         /* XXX 256 is only an estimate of signature header. */
223         if (ep != NULL)
224             p->pkgFileSize += 96 + 256 + *ep;
225         break;
226     case TR_REMOVED:
227         p->u.removed.dependsOnKey = pkgKey;
228         p->u.removed.dboffset = dboffset;
229         break;
230     }
231     return p;
232 }
233
234 /* Get the DB Instance value */
235 unsigned int rpmteDBInstance(rpmte te) 
236 {
237     return (te != NULL ? te->db_instance : 0);
238 }
239
240 /* Set the DB Instance value */
241 void rpmteSetDBInstance(rpmte te, unsigned int instance) 
242 {
243     if(te != NULL) 
244         te->db_instance = instance;
245 }
246
247 rpmElementType rpmteType(rpmte te)
248 {
249     return (te != NULL ? te->type : -1);
250 }
251
252 const char * rpmteN(rpmte te)
253 {
254     return (te != NULL ? te->name : NULL);
255 }
256
257 const char * rpmteE(rpmte te)
258 {
259     return (te != NULL ? te->epoch : NULL);
260 }
261
262 const char * rpmteV(rpmte te)
263 {
264     return (te != NULL ? te->version : NULL);
265 }
266
267 const char * rpmteR(rpmte te)
268 {
269     return (te != NULL ? te->release : NULL);
270 }
271
272 const char * rpmteA(rpmte te)
273 {
274     return (te != NULL ? te->arch : NULL);
275 }
276
277 const char * rpmteO(rpmte te)
278 {
279     return (te != NULL ? te->os : NULL);
280 }
281
282 uint_32 rpmteColor(rpmte te)
283 {
284     return (te != NULL ? te->color : 0);
285 }
286
287 uint_32 rpmteSetColor(rpmte te, uint_32 color)
288 {
289     int ocolor = 0;
290     if (te != NULL) {
291         ocolor = te->color;
292         te->color = color;
293     }
294     return ocolor;
295 }
296
297 uint_32 rpmtePkgFileSize(rpmte te)
298 {
299     return (te != NULL ? te->pkgFileSize : 0);
300 }
301
302 int rpmteDepth(rpmte te)
303 {
304     return (te != NULL ? te->depth : 0);
305 }
306
307 int rpmteSetDepth(rpmte te, int ndepth)
308 {
309     int odepth = 0;
310     if (te != NULL) {
311         odepth = te->depth;
312         te->depth = ndepth;
313     }
314     return odepth;
315 }
316
317 int rpmteNpreds(rpmte te)
318 {
319     return (te != NULL ? te->npreds : 0);
320 }
321
322 int rpmteSetNpreds(rpmte te, int npreds)
323 {
324     int opreds = 0;
325     if (te != NULL) {
326         opreds = te->npreds;
327         te->npreds = npreds;
328     }
329     return opreds;
330 }
331
332 int rpmteTree(rpmte te)
333 {
334     return (te != NULL ? te->tree : 0);
335 }
336
337 int rpmteSetTree(rpmte te, int ntree)
338 {
339     int otree = 0;
340     if (te != NULL) {
341         otree = te->tree;
342         te->tree = ntree;
343     }
344     return otree;
345 }
346
347 rpmte rpmteParent(rpmte te)
348 {
349     return (te != NULL ? te->parent : NULL);
350 }
351
352 rpmte rpmteSetParent(rpmte te, rpmte pte)
353 {
354     rpmte opte = NULL;
355 /*@-branchstate@*/
356     if (te != NULL) {
357         opte = te->parent;
358         /*@-assignexpose -temptrans@*/
359         te->parent = pte;
360         /*@=assignexpose =temptrans@*/
361     }
362 /*@=branchstate@*/
363     return opte;
364 }
365
366 int rpmteDegree(rpmte te)
367 {
368     return (te != NULL ? te->degree : 0);
369 }
370
371 int rpmteSetDegree(rpmte te, int ndegree)
372 {
373     int odegree = 0;
374     if (te != NULL) {
375         odegree = te->degree;
376         te->degree = ndegree;
377     }
378     return odegree;
379 }
380
381 tsortInfo rpmteTSI(rpmte te)
382 {
383     /*@-compdef -retalias -retexpose -usereleased @*/
384     return te->tsi;
385     /*@=compdef =retalias =retexpose =usereleased @*/
386 }
387
388 void rpmteFreeTSI(rpmte te)
389 {
390     if (te != NULL && rpmteTSI(te) != NULL) {
391         tsortInfo tsi;
392
393         /* Clean up tsort remnants (if any). */
394         while ((tsi = rpmteTSI(te)->tsi_next) != NULL) {
395             rpmteTSI(te)->tsi_next = tsi->tsi_next;
396             tsi->tsi_next = NULL;
397             tsi = _free(tsi);
398         }
399         te->tsi = _free(te->tsi);
400     }
401     /*@-nullstate@*/ /* FIX: te->tsi is NULL */
402     return;
403     /*@=nullstate@*/
404 }
405
406 void rpmteNewTSI(rpmte te)
407 {
408     if (te != NULL) {
409         rpmteFreeTSI(te);
410         te->tsi = xcalloc(1, sizeof(*te->tsi));
411     }
412 }
413
414 alKey rpmteAddedKey(rpmte te)
415 {
416     return (te != NULL ? te->u.addedKey : RPMAL_NOMATCH);
417 }
418
419 alKey rpmteSetAddedKey(rpmte te, alKey npkgKey)
420 {
421     alKey opkgKey = RPMAL_NOMATCH;
422     if (te != NULL) {
423         opkgKey = te->u.addedKey;
424         te->u.addedKey = npkgKey;
425     }
426     return opkgKey;
427 }
428
429
430 alKey rpmteDependsOnKey(rpmte te)
431 {
432     return (te != NULL ? te->u.removed.dependsOnKey : RPMAL_NOMATCH);
433 }
434
435 int rpmteDBOffset(rpmte te)
436 {
437     return (te != NULL ? te->u.removed.dboffset : 0);
438 }
439
440 const char * rpmteNEVR(rpmte te)
441 {
442     return (te != NULL ? te->NEVR : NULL);
443 }
444
445 const char * rpmteNEVRA(rpmte te)
446 {
447     return (te != NULL ? te->NEVRA : NULL);
448 }
449
450 FD_t rpmteFd(rpmte te)
451 {
452     /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
453     return (te != NULL ? te->fd : NULL);
454     /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
455 }
456
457 fnpyKey rpmteKey(rpmte te)
458 {
459     return (te != NULL ? te->key : NULL);
460 }
461
462 rpmds rpmteDS(rpmte te, rpmTag tag)
463 {
464     /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
465     if (te == NULL)
466         return NULL;
467
468     if (tag == RPMTAG_NAME)
469         return te->this;
470     else
471     if (tag == RPMTAG_PROVIDENAME)
472         return te->provides;
473     else
474     if (tag == RPMTAG_REQUIRENAME)
475         return te->requires;
476     else
477     if (tag == RPMTAG_CONFLICTNAME)
478         return te->conflicts;
479     else
480     if (tag == RPMTAG_OBSOLETENAME)
481         return te->obsoletes;
482     else
483         return NULL;
484     /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
485 }
486
487 rpmfi rpmteFI(rpmte te, rpmTag tag)
488 {
489     /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
490     if (te == NULL)
491         return NULL;
492
493     if (tag == RPMTAG_BASENAMES)
494         return te->fi;
495     else
496         return NULL;
497     /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
498 }
499
500 void rpmteColorDS(rpmte te, rpmTag tag)
501 {
502     rpmfi fi = rpmteFI(te, RPMTAG_BASENAMES);
503     rpmds ds = rpmteDS(te, tag);
504     char deptype = 'R';
505     char mydt;
506     const int_32 * ddict;
507     int_32 * colors;
508     int_32 * refs;
509     int_32 val;
510     int Count;
511     size_t nb;
512     unsigned ix;
513     int ndx, i;
514
515     if (!(te && (Count = rpmdsCount(ds)) > 0 && rpmfiFC(fi) > 0))
516         return;
517
518     switch (tag) {
519     default:
520         return;
521         /*@notreached@*/ break;
522     case RPMTAG_PROVIDENAME:
523         deptype = 'P';
524         break;
525     case RPMTAG_REQUIRENAME:
526         deptype = 'R';
527         break;
528     }
529
530     nb = Count * sizeof(*colors);
531     colors = memset(alloca(nb), 0, nb);
532     nb = Count * sizeof(*refs);
533     refs = memset(alloca(nb), -1, nb);
534
535     /* Calculate dependency color and reference count. */
536     fi = rpmfiInit(fi, 0);
537     if (fi != NULL)
538     while (rpmfiNext(fi) >= 0) {
539         val = rpmfiFColor(fi);
540         ddict = NULL;
541         ndx = rpmfiFDepends(fi, &ddict);
542         if (ddict != NULL)
543         while (ndx-- > 0) {
544             ix = *ddict++;
545             mydt = ((ix >> 24) & 0xff);
546             if (mydt != deptype)
547                 /*@innercontinue@*/ continue;
548             ix &= 0x00ffffff;
549 assert (ix < Count);
550             colors[ix] |= val;
551             refs[ix]++;
552         }
553     }
554
555     /* Set color/refs values in dependency set. */
556     ds = rpmdsInit(ds);
557     while ((i = rpmdsNext(ds)) >= 0) {
558         val = colors[i];
559         te->color |= val;
560         (void) rpmdsSetColor(ds, val);
561         val = refs[i];
562         if (val >= 0)
563             val++;
564         (void) rpmdsSetRefs(ds, val);
565     }
566 }
567
568 int rpmtsiOc(rpmtsi tsi)
569 {
570     return tsi->ocsave;
571 }
572
573 rpmtsi XrpmtsiFree(/*@only@*//*@null@*/ rpmtsi tsi,
574                 const char * fn, unsigned int ln)
575 {
576     /* XXX watchout: a funky recursion segfaults here iff nrefs is wrong. */
577 /*@-internalglobs@*/
578     if (tsi)
579         tsi->ts = rpmtsFree(tsi->ts);
580 /*@=internalglobs@*/
581
582 /*@-modfilesys@*/
583 if (_rpmte_debug)
584 fprintf(stderr, "*** tsi %p -- %s:%d\n", tsi, fn, ln);
585 /*@=modfilesys@*/
586     return _free(tsi);
587 }
588
589 rpmtsi XrpmtsiInit(rpmts ts, const char * fn, unsigned int ln)
590 {
591     rpmtsi tsi = NULL;
592
593     tsi = xcalloc(1, sizeof(*tsi));
594     tsi->ts = rpmtsLink(ts, "rpmtsi");
595     tsi->reverse = ((rpmtsFlags(ts) & RPMTRANS_FLAG_REVERSE) ? 1 : 0);
596     tsi->oc = (tsi->reverse ? (rpmtsNElements(ts) - 1) : 0);
597     tsi->ocsave = tsi->oc;
598 /*@-modfilesys@*/
599 if (_rpmte_debug)
600 fprintf(stderr, "*** tsi %p ++ %s:%d\n", tsi, fn, ln);
601 /*@=modfilesys@*/
602     return tsi;
603 }
604
605 /**
606  * Return next transaction element.
607  * @param tsi           transaction element iterator
608  * @return              transaction element, NULL on termination
609  */
610 static /*@null@*/ /*@dependent@*/
611 rpmte rpmtsiNextElement(rpmtsi tsi)
612         /*@modifies tsi @*/
613 {
614     rpmte te = NULL;
615     int oc = -1;
616
617     if (tsi == NULL || tsi->ts == NULL || rpmtsNElements(tsi->ts) <= 0)
618         return te;
619
620     if (tsi->reverse) {
621         if (tsi->oc >= 0)               oc = tsi->oc--;
622     } else {
623         if (tsi->oc < rpmtsNElements(tsi->ts))  oc = tsi->oc++;
624     }
625     tsi->ocsave = oc;
626 /*@-branchstate@*/
627     if (oc != -1)
628         te = rpmtsElement(tsi->ts, oc);
629 /*@=branchstate@*/
630     return te;
631 }
632
633 rpmte rpmtsiNext(rpmtsi tsi, rpmElementType type)
634 {
635     rpmte te;
636
637     while ((te = rpmtsiNextElement(tsi)) != NULL) {
638         if (type == 0 || (te->type & type) != 0)
639             break;
640     }
641     return te;
642 }