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