- simplify specfile query linkage loop.
[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     int_32 * ep;
96     const char * arch, * os;
97     int xx;
98
99     p->NEVR = hGetNEVR(h, NULL);
100     p->name = xstrdup(p->NEVR);
101     if ((p->release = strrchr(p->name, '-')) != NULL)
102         *p->release++ = '\0';
103     if ((p->version = strrchr(p->name, '-')) != NULL)
104         *p->version++ = '\0';
105
106     arch = NULL;
107     xx = hge(h, RPMTAG_ARCH, NULL, (void **)&arch, NULL);
108     p->arch = (arch != NULL ? xstrdup(arch) : NULL);
109     os = NULL;
110     xx = hge(h, RPMTAG_OS, NULL, (void **)&os, NULL);
111     p->os = (os != NULL ? xstrdup(os) : NULL);
112
113     ep = NULL;
114     xx = hge(h, RPMTAG_EPOCH, NULL, (void **)&ep, NULL);
115 /*@-branchstate@*/
116     if (ep) {
117         p->epoch = xmalloc(20);
118         sprintf(p->epoch, "%d", *ep);
119     } else
120         p->epoch = NULL;
121 /*@=branchstate@*/
122
123     p->this = rpmdsThis(h, RPMTAG_PROVIDENAME, RPMSENSE_EQUAL);
124     p->provides = rpmdsNew(h, RPMTAG_PROVIDENAME, scareMem);
125     p->fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
126     p->requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
127     p->conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
128     p->obsoletes = rpmdsNew(h, RPMTAG_OBSOLETENAME, scareMem);
129
130     p->key = key;
131
132     p->fd = NULL;
133
134     p->multiLib = 0;
135
136     if (relocs != NULL) {
137         rpmRelocation * r;
138         int i;
139
140         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++)
141             {};
142         p->relocs = xmalloc((i + 1) * sizeof(*p->relocs));
143
144         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) {
145             p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL;
146             p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL;
147         }
148         p->relocs[i].oldPath = NULL;
149         p->relocs[i].newPath = NULL;
150     } else {
151         p->relocs = NULL;
152     }
153 }
154 /*@=bounds@*/
155
156 rpmte rpmteFree(rpmte te)
157 {
158     if (te != NULL) {
159         delTE(te);
160         memset(te, 0, sizeof(*te));     /* XXX trash and burn */
161         te = _free(te);
162     }
163     return NULL;
164 }
165
166 rpmte rpmteNew(const rpmts ts, Header h,
167                 rpmElementType type,
168                 fnpyKey key,
169                 rpmRelocation * relocs,
170                 int dboffset,
171                 alKey pkgKey)
172 {
173     rpmte te = xcalloc(1, sizeof(*te));
174
175     addTE(ts, te, h, key, relocs);
176     switch (type) {
177     case TR_ADDED:
178         te->type = type;
179         te->u.addedKey = pkgKey;
180         break;
181     case TR_REMOVED:
182         te->type = type;
183         te->u.removed.dependsOnKey = pkgKey;
184         te->u.removed.dboffset = dboffset;
185         break;
186     }
187     return te;
188 }
189
190 rpmElementType rpmteType(rpmte te)
191 {
192     return (te != NULL ? te->type : -1);
193 }
194
195 const char * rpmteN(rpmte te)
196 {
197     return (te != NULL ? te->name : NULL);
198 }
199
200 const char * rpmteE(rpmte te)
201 {
202     return (te != NULL ? te->epoch : NULL);
203 }
204
205 const char * rpmteV(rpmte te)
206 {
207     return (te != NULL ? te->version : NULL);
208 }
209
210 const char * rpmteR(rpmte te)
211 {
212     return (te != NULL ? te->release : NULL);
213 }
214
215 const char * rpmteA(rpmte te)
216 {
217     return (te != NULL ? te->arch : NULL);
218 }
219
220 const char * rpmteO(rpmte te)
221 {
222     return (te != NULL ? te->os : NULL);
223 }
224
225 int rpmteMultiLib(rpmte te)
226 {
227     return (te != NULL ? te->multiLib : 0);
228 }
229
230 int rpmteSetMultiLib(rpmte te, int nmultiLib)
231 {
232     int omultiLib = 0;
233     if (te != NULL) {
234         omultiLib = te->multiLib;
235         te->multiLib = nmultiLib;
236     }
237     return omultiLib;
238 }
239
240 int rpmteDepth(rpmte te)
241 {
242     return (te != NULL ? te->depth : 0);
243 }
244
245 int rpmteSetDepth(rpmte te, int ndepth)
246 {
247     int odepth = 0;
248     if (te != NULL) {
249         odepth = te->depth;
250         te->depth = ndepth;
251     }
252     return odepth;
253 }
254
255 int rpmteNpreds(rpmte te)
256 {
257     return (te != NULL ? te->npreds : 0);
258 }
259
260 int rpmteSetNpreds(rpmte te, int npreds)
261 {
262     int opreds = 0;
263     if (te != NULL) {
264         opreds = te->npreds;
265         te->npreds = npreds;
266     }
267     return opreds;
268 }
269
270 int rpmteTree(rpmte te)
271 {
272     return (te != NULL ? te->tree : 0);
273 }
274
275 int rpmteSetTree(rpmte te, int ntree)
276 {
277     int otree = 0;
278     if (te != NULL) {
279         otree = te->tree;
280         te->tree = ntree;
281     }
282     return otree;
283 }
284
285 rpmte rpmteParent(rpmte te)
286 {
287     return (te != NULL ? te->parent : NULL);
288 }
289
290 rpmte rpmteSetParent(rpmte te, rpmte pte)
291 {
292     rpmte opte = NULL;
293 /*@-branchstate@*/
294     if (te != NULL) {
295         opte = te->parent;
296         /*@-assignexpose -temptrans@*/
297         te->parent = pte;
298         /*@=assignexpose =temptrans@*/
299     }
300 /*@=branchstate@*/
301     return opte;
302 }
303
304 int rpmteDegree(rpmte te)
305 {
306     return (te != NULL ? te->degree : 0);
307 }
308
309 int rpmteSetDegree(rpmte te, int ndegree)
310 {
311     int odegree = 0;
312     if (te != NULL) {
313         odegree = te->degree;
314         te->degree = ndegree;
315     }
316     return odegree;
317 }
318
319 tsortInfo rpmteTSI(rpmte te)
320 {
321     /*@-compdef -retalias -retexpose -usereleased @*/
322     return te->tsi;
323     /*@=compdef =retalias =retexpose =usereleased @*/
324 }
325
326 void rpmteFreeTSI(rpmte te)
327 {
328     if (te != NULL && rpmteTSI(te) != NULL) {
329         tsortInfo tsi;
330
331         /* Clean up tsort remnants (if any). */
332         while ((tsi = rpmteTSI(te)->tsi_next) != NULL) {
333             rpmteTSI(te)->tsi_next = tsi->tsi_next;
334             tsi->tsi_next = NULL;
335             tsi = _free(tsi);
336         }
337         te->tsi = _free(te->tsi);
338     }
339     /*@-nullstate@*/ /* FIX: te->tsi is NULL */
340     return;
341     /*@=nullstate@*/
342 }
343
344 void rpmteNewTSI(rpmte te)
345 {
346     if (te != NULL) {
347         rpmteFreeTSI(te);
348         te->tsi = xcalloc(1, sizeof(*te->tsi));
349     }
350 }
351
352 alKey rpmteAddedKey(rpmte te)
353 {
354     return (te != NULL ? te->u.addedKey : RPMAL_NOMATCH);
355 }
356
357 alKey rpmteSetAddedKey(rpmte te, alKey npkgKey)
358 {
359     alKey opkgKey = RPMAL_NOMATCH;
360     if (te != NULL) {
361         opkgKey = te->u.addedKey;
362         te->u.addedKey = npkgKey;
363     }
364     return opkgKey;
365 }
366
367
368 alKey rpmteDependsOnKey(rpmte te)
369 {
370     return (te != NULL ? te->u.removed.dependsOnKey : RPMAL_NOMATCH);
371 }
372
373 int rpmteDBOffset(rpmte te)
374 {
375     return (te != NULL ? te->u.removed.dboffset : 0);
376 }
377
378 const char * rpmteNEVR(rpmte te)
379 {
380     return (te != NULL ? te->NEVR : NULL);
381 }
382
383 FD_t rpmteFd(rpmte te)
384 {
385     /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
386     return (te != NULL ? te->fd : NULL);
387     /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
388 }
389
390 fnpyKey rpmteKey(rpmte te)
391 {
392     return (te != NULL ? te->key : NULL);
393 }
394
395 rpmds rpmteDS(rpmte te, rpmTag tag)
396 {
397     /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
398     if (te == NULL)
399         return NULL;
400
401     if (tag == RPMTAG_NAME)
402         return te->this;
403     else
404     if (tag == RPMTAG_PROVIDENAME)
405         return te->provides;
406     else
407     if (tag == RPMTAG_REQUIRENAME)
408         return te->requires;
409     else
410     if (tag == RPMTAG_CONFLICTNAME)
411         return te->conflicts;
412     else
413     if (tag == RPMTAG_OBSOLETENAME)
414         return te->obsoletes;
415     else
416         return NULL;
417     /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
418 }
419
420 rpmfi rpmteFI(rpmte te, rpmTag tag)
421 {
422     /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
423     if (te == NULL)
424         return NULL;
425
426     if (tag == RPMTAG_BASENAMES)
427         return te->fi;
428     else
429         return NULL;
430     /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
431 }
432
433 int rpmtsiOc(rpmtsi tsi)
434 {
435     return tsi->ocsave;
436 }
437
438 rpmtsi XrpmtsiFree(/*@only@*//*@null@*/ rpmtsi tsi,
439                 const char * fn, unsigned int ln)
440 {
441     /* XXX watchout: a funky recursion segfaults here iff nrefs is wrong. */
442     if (tsi)
443         tsi->ts = rpmtsFree(tsi->ts);
444
445 /*@-modfilesys@*/
446 if (_rpmte_debug)
447 fprintf(stderr, "*** tsi %p -- %s:%d\n", tsi, fn, ln);
448 /*@=modfilesys@*/
449     return _free(tsi);
450 }
451
452 rpmtsi XrpmtsiInit(rpmts ts, const char * fn, unsigned int ln)
453 {
454     rpmtsi tsi = NULL;
455
456     tsi = xcalloc(1, sizeof(*tsi));
457     tsi->ts = rpmtsLink(ts, "rpmtsi");
458     tsi->reverse = ((rpmtsFlags(ts) & RPMTRANS_FLAG_REVERSE) ? 1 : 0);
459     tsi->oc = (tsi->reverse ? (rpmtsNElements(ts) - 1) : 0);
460     tsi->ocsave = tsi->oc;
461 /*@-modfilesys@*/
462 if (_rpmte_debug)
463 fprintf(stderr, "*** tsi %p ++ %s:%d\n", tsi, fn, ln);
464 /*@=modfilesys@*/
465     return tsi;
466 }
467
468 /**
469  * Return next transaction element.
470  * @param tsi           transaction element iterator
471  * @return              transaction element, NULL on termination
472  */
473 static /*@dependent@*/ /*@null@*/
474 rpmte rpmtsiNextElement(rpmtsi tsi)
475         /*@modifies tsi @*/
476 {
477     rpmte te = NULL;
478     int oc = -1;
479
480     if (tsi == NULL || tsi->ts == NULL || rpmtsNElements(tsi->ts) <= 0)
481         return te;
482
483     if (tsi->reverse) {
484         if (tsi->oc >= 0)               oc = tsi->oc--;
485     } else {
486         if (tsi->oc < rpmtsNElements(tsi->ts))  oc = tsi->oc++;
487     }
488     tsi->ocsave = oc;
489 /*@-branchstate@*/
490     if (oc != -1)
491         te = rpmtsElement(tsi->ts, oc);
492 /*@=branchstate@*/
493     return te;
494 }
495
496 rpmte rpmtsiNext(rpmtsi tsi, rpmElementType type)
497 {
498     rpmte te;
499
500     while ((te = rpmtsiNextElement(tsi)) != NULL) {
501         if (type == 0 || (te->type & type) != 0)
502             break;
503     }
504     return te;
505 }