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