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