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