Splint fiddles.
[platform/upstream/rpm.git] / lib / transaction.c
1 /** \ingroup rpmts
2  * \file lib/transaction.c
3  */
4
5 #include "system.h"
6 #include <rpmlib.h>
7
8 #include <rpmmacro.h>   /* XXX for rpmExpand */
9
10 #include "fsm.h"
11 #include "psm.h"
12
13 #include "rpmdb.h"
14
15 #include "rpmds.h"
16
17 #define _RPMFI_INTERNAL
18 #include "rpmfi.h"
19
20 #define _RPMTE_INTERNAL
21 #include "rpmte.h"
22
23 #define _RPMTS_INTERNAL
24 #include "rpmts.h"
25
26 #include "cpio.h"
27 #include "fprint.h"
28 #include "legacy.h"     /* XXX domd5 */
29 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
30
31 #include "debug.h"
32
33 /*@access FD_t @*/              /* XXX compared with NULL */
34 /*@access Header @*/            /* XXX compared with NULL */
35 /*@access rpmps @*/     /* XXX need rpmProblemSetOK() */
36 /*@access dbiIndexSet @*/
37 /*@access rpmdb @*/
38
39 /*@access rpmpsm @*/
40
41 /*@access alKey @*/
42 /*@access fnpyKey @*/
43
44 /*@access rpmfi @*/
45
46 /*@access rpmte @*/
47 /*@access rpmtsi @*/
48 /*@access rpmts @*/
49
50 /**
51  */
52 static int archOkay(/*@null@*/ const char * pkgArch)
53         /*@*/
54 {
55     if (pkgArch == NULL) return 0;
56     return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
57 }
58
59 /**
60  */
61 static int osOkay(/*@null@*/ const char * pkgOs)
62         /*@*/
63 {
64     if (pkgOs == NULL) return 0;
65     return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
66 }
67
68 /**
69  */
70 static int sharedCmp(const void * one, const void * two)
71         /*@*/
72 {
73     sharedFileInfo a = (sharedFileInfo) one;
74     sharedFileInfo b = (sharedFileInfo) two;
75
76     if (a->otherPkg < b->otherPkg)
77         return -1;
78     else if (a->otherPkg > b->otherPkg)
79         return 1;
80
81     return 0;
82 }
83
84 /**
85  */
86 /*@-boundsread@*/
87 static fileAction decideFileFate(const rpmts ts,
88                 const rpmfi ofi, rpmfi nfi)
89         /*@globals fileSystem, internalState @*/
90         /*@modifies nfi, fileSystem, internalState @*/
91 {
92     const char * fn = rpmfiFN(nfi);
93     int newFlags = rpmfiFFlags(nfi);
94     char buffer[1024];
95     fileTypes dbWhat, newWhat, diskWhat;
96     struct stat sb;
97     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
98
99     if (lstat(fn, &sb)) {
100         /*
101          * The file doesn't exist on the disk. Create it unless the new
102          * package has marked it as missingok, or allfiles is requested.
103          */
104         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES)
105          && (newFlags & RPMFILE_MISSINGOK))
106         {
107             rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
108                         fn);
109             return FA_SKIP;
110         } else {
111             return FA_CREATE;
112         }
113     }
114
115     diskWhat = whatis((int_16)sb.st_mode);
116     dbWhat = whatis(rpmfiFMode(ofi));
117     newWhat = whatis(rpmfiFMode(nfi));
118
119     /*
120      * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
121      * them in older packages as well.
122      */
123     if (newWhat == XDIR)
124         return FA_CREATE;
125
126     if (diskWhat != newWhat)
127         return save;
128     else if (newWhat != dbWhat && diskWhat != dbWhat)
129         return save;
130     else if (dbWhat != newWhat)
131         return FA_CREATE;
132     else if (dbWhat != LINK && dbWhat != REG)
133         return FA_CREATE;
134
135     /*
136      * This order matters - we'd prefer to CREATE the file if at all
137      * possible in case something else (like the timestamp) has changed.
138      */
139     if (dbWhat == REG) {
140         const unsigned char * omd5, * nmd5;
141         if (domd5(fn, buffer, 0, NULL))
142             return FA_CREATE;   /* assume file has been removed */
143         omd5 = rpmfiMD5(ofi);
144         if (omd5 && !memcmp(omd5, buffer, 16))
145             return FA_CREATE;   /* unmodified config file, replace. */
146         nmd5 = rpmfiMD5(nfi);
147 /*@-nullpass@*/
148         if (omd5 && nmd5 && !memcmp(omd5, nmd5, 16))
149             return FA_SKIP;     /* identical file, don't bother. */
150 /*@=nullpass@*/
151     } else /* dbWhat == LINK */ {
152         const char * oFLink, * nFLink;
153         memset(buffer, 0, sizeof(buffer));
154         if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
155             return FA_CREATE;   /* assume file has been removed */
156         oFLink = rpmfiFLink(ofi);
157         if (oFLink && !strcmp(oFLink, buffer))
158             return FA_CREATE;   /* unmodified config file, replace. */
159         nFLink = rpmfiFLink(nfi);
160 /*@-nullpass@*/
161         if (oFLink && nFLink && !strcmp(oFLink, nFLink))
162             return FA_SKIP;     /* identical file, don't bother. */
163 /*@=nullpass@*/
164     }
165
166     /*
167      * The config file on the disk has been modified, but
168      * the ones in the two packages are different. It would
169      * be nice if RPM was smart enough to at least try and
170      * merge the difference ala CVS, but...
171      */
172     return save;
173 }
174 /*@=boundsread@*/
175
176 /**
177  */
178 /*@-boundsread@*/
179 static int filecmp(rpmfi afi, rpmfi bfi)
180         /*@*/
181 {
182     fileTypes awhat = whatis(rpmfiFMode(afi));
183     fileTypes bwhat = whatis(rpmfiFMode(bfi));
184
185     if (awhat != bwhat) return 1;
186
187     if (awhat == LINK) {
188         const char * alink = rpmfiFLink(afi);
189         const char * blink = rpmfiFLink(bfi);
190         if (alink == blink) return 0;
191         if (alink == NULL) return 1;
192         if (blink == NULL) return -1;
193         return strcmp(alink, blink);
194     } else if (awhat == REG) {
195         const unsigned char * amd5 = rpmfiMD5(afi);
196         const unsigned char * bmd5 = rpmfiMD5(bfi);
197         if (amd5 == bmd5) return 0;
198         if (amd5 == NULL) return 1;
199         if (bmd5 == NULL) return -1;
200         return memcmp(amd5, bmd5, 16);
201     }
202
203     return 0;
204 }
205 /*@=boundsread@*/
206
207 /**
208  */
209 /* XXX only ts->{probs,rpmdb} modified */
210 /*@-bounds@*/
211 static int handleInstInstalledFiles(const rpmts ts,
212                 rpmte p, rpmfi fi,
213                 sharedFileInfo shared,
214                 int sharedCount, int reportConflicts)
215         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
216         /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
217 {
218     uint_32 tscolor = rpmtsColor(ts);
219     uint_32 otecolor, tecolor;
220     uint_32 oficolor, ficolor;
221     const char * altNEVR = NULL;
222     rpmfi otherFi = NULL;
223     int numReplaced = 0;
224     rpmps ps;
225     int i;
226
227     {   rpmdbMatchIterator mi;
228         Header h;
229         int scareMem = 0;
230
231         mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
232                         &shared->otherPkg, sizeof(shared->otherPkg));
233         while ((h = rpmdbNextIterator(mi)) != NULL) {
234             altNEVR = hGetNEVR(h, NULL);
235             otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
236             break;
237         }
238         mi = rpmdbFreeIterator(mi);
239     }
240
241     /* Compute package color. */
242     tecolor = rpmteColor(p);
243     tecolor &= tscolor;
244
245     /* Compute other pkg color. */
246     otecolor = 0;
247     otherFi = rpmfiInit(otherFi, 0);
248     if (otherFi != NULL)
249     while (rpmfiNext(otherFi) >= 0)
250         otecolor |= rpmfiFColor(otherFi);
251     otecolor &= tscolor;
252
253     if (otherFi == NULL)
254         return 1;
255
256     fi->replaced = xcalloc(sharedCount, sizeof(*fi->replaced));
257
258     ps = rpmtsProblems(ts);
259     for (i = 0; i < sharedCount; i++, shared++) {
260         int otherFileNum, fileNum;
261         int isCfgFile;
262
263         otherFileNum = shared->otherFileNum;
264         (void) rpmfiSetFX(otherFi, otherFileNum);
265         oficolor = rpmfiFColor(otherFi);
266         oficolor &= tscolor;
267
268         fileNum = shared->pkgFileNum;
269         (void) rpmfiSetFX(fi, fileNum);
270         ficolor = rpmfiFColor(fi);
271         ficolor &= tscolor;
272
273         isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
274
275 #ifdef  DYING
276         /* XXX another tedious segfault, assume file state normal. */
277         if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
278             continue;
279 #endif
280
281         if (XFA_SKIPPING(fi->actions[fileNum]))
282             continue;
283
284         if (filecmp(otherFi, fi)) {
285             /* Report conflicts only for packages/files of same color. */
286             if (tscolor == 0 || (tecolor == otecolor && ficolor == oficolor))
287             if (reportConflicts) {
288                 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
289                         rpmteNEVR(p), rpmteKey(p),
290                         rpmfiDN(fi), rpmfiBN(fi),
291                         altNEVR,
292                         0);
293             }
294             if (!isCfgFile) {
295                 /*@-assignexpose@*/ /* FIX: p->replaced, not fi */
296                 if (!shared->isRemoved)
297                     fi->replaced[numReplaced++] = *shared;
298                 /*@=assignexpose@*/
299             }
300         }
301
302         if (isCfgFile) {
303             fileAction action;
304             action = decideFileFate(ts, otherFi, fi);
305             fi->actions[fileNum] = action;
306         }
307         fi->replacedSizes[fileNum] = rpmfiFSize(otherFi);
308     }
309     ps = rpmpsFree(ps);
310
311     altNEVR = _free(altNEVR);
312     otherFi = rpmfiFree(otherFi);
313
314     fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
315                            sizeof(*fi->replaced) * (numReplaced + 1));
316     fi->replaced[numReplaced].otherPkg = 0;
317
318     return 0;
319 }
320 /*@=bounds@*/
321
322 /**
323  */
324 /* XXX only ts->rpmdb modified */
325 static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
326                 sharedFileInfo shared, int sharedCount)
327         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
328         /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
329 {
330     HGE_t hge = fi->hge;
331     Header h;
332     const char * otherStates;
333     int i, xx;
334    
335     rpmdbMatchIterator mi;
336
337     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
338                         &shared->otherPkg, sizeof(shared->otherPkg));
339     h = rpmdbNextIterator(mi);
340     if (h == NULL) {
341         mi = rpmdbFreeIterator(mi);
342         return 1;
343     }
344
345     xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
346
347 /*@-boundswrite@*/
348     for (i = 0; i < sharedCount; i++, shared++) {
349         int otherFileNum, fileNum;
350         otherFileNum = shared->otherFileNum;
351         fileNum = shared->pkgFileNum;
352
353         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
354             continue;
355
356         fi->actions[fileNum] = FA_SKIP;
357     }
358 /*@=boundswrite@*/
359
360     mi = rpmdbFreeIterator(mi);
361
362     return 0;
363 }
364
365 #define ISROOT(_d)      (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
366
367 /*@unchecked@*/
368 int _fps_debug = 0;
369
370 static int fpsCompare (const void * one, const void * two)
371         /*@*/
372 {
373     const struct fingerPrint_s * a = (const struct fingerPrint_s *)one;
374     const struct fingerPrint_s * b = (const struct fingerPrint_s *)two;
375     int adnlen = strlen(a->entry->dirName);
376     int asnlen = (a->subDir ? strlen(a->subDir) : 0);
377     int abnlen = strlen(a->baseName);
378     int bdnlen = strlen(b->entry->dirName);
379     int bsnlen = (b->subDir ? strlen(b->subDir) : 0);
380     int bbnlen = strlen(b->baseName);
381     char * afn, * bfn, * t;
382     int rc = 0;
383
384     if (adnlen == 1 && asnlen != 0) adnlen = 0;
385     if (bdnlen == 1 && bsnlen != 0) bdnlen = 0;
386
387 /*@-boundswrite@*/
388     afn = t = alloca(adnlen+asnlen+abnlen+2);
389     if (adnlen) t = stpcpy(t, a->entry->dirName);
390     *t++ = '/';
391     if (a->subDir && asnlen) t = stpcpy(t, a->subDir);
392     if (abnlen) t = stpcpy(t, a->baseName);
393     if (afn[0] == '/' && afn[1] == '/') afn++;
394
395     bfn = t = alloca(bdnlen+bsnlen+bbnlen+2);
396     if (bdnlen) t = stpcpy(t, b->entry->dirName);
397     *t++ = '/';
398     if (b->subDir && bsnlen) t = stpcpy(t, b->subDir);
399     if (bbnlen) t = stpcpy(t, b->baseName);
400     if (bfn[0] == '/' && bfn[1] == '/') bfn++;
401 /*@=boundswrite@*/
402
403     rc = strcmp(afn, bfn);
404 /*@-modfilesys@*/
405 if (_fps_debug)
406 fprintf(stderr, "\trc(%d) = strcmp(\"%s\", \"%s\")\n", rc, afn, bfn);
407 /*@=modfilesys@*/
408
409 /*@-modfilesys@*/
410 if (_fps_debug)
411 fprintf(stderr, "\t%s/%s%s\trc %d\n",
412 ISROOT(b->entry->dirName),
413 (b->subDir ? b->subDir : ""),
414 b->baseName,
415 rc
416 );
417 /*@=modfilesys@*/
418
419     return rc;
420 }
421
422 /*@unchecked@*/
423 static int _linear_fps_search = 0;
424
425 static int findFps(const struct fingerPrint_s * fiFps,
426                 const struct fingerPrint_s * otherFps,
427                 int otherFc)
428         /*@*/
429 {
430     int otherFileNum;
431
432 /*@-modfilesys@*/
433 if (_fps_debug)
434 fprintf(stderr, "==> %s/%s%s\n",
435 ISROOT(fiFps->entry->dirName),
436 (fiFps->subDir ? fiFps->subDir : ""),
437 fiFps->baseName);
438 /*@=modfilesys@*/
439
440   if (_linear_fps_search) {
441
442 linear:
443     for (otherFileNum = 0; otherFileNum < otherFc; otherFileNum++, otherFps++) {
444
445 /*@-modfilesys@*/
446 if (_fps_debug)
447 fprintf(stderr, "\t%4d %s/%s%s\n", otherFileNum,
448 ISROOT(otherFps->entry->dirName),
449 (otherFps->subDir ? otherFps->subDir : ""),
450 otherFps->baseName);
451 /*@=modfilesys@*/
452
453         /* If the addresses are the same, so are the values. */
454         if (fiFps == otherFps)
455             break;
456
457         /* Otherwise, compare fingerprints by value. */
458         /*@-nullpass@*/ /* LCL: looks good to me */
459         if (FP_EQUAL((*fiFps), (*otherFps)))
460             break;
461         /*@=nullpass@*/
462     }
463
464 if (otherFileNum == otherFc) {
465 /*@-modfilesys@*/
466 if (_fps_debug)
467 fprintf(stderr, "*** FP_EQUAL NULL %s/%s%s\n",
468 ISROOT(fiFps->entry->dirName),
469 (fiFps->subDir ? fiFps->subDir : ""),
470 fiFps->baseName);
471 /*@=modfilesys@*/
472 }
473
474     return otherFileNum;
475
476   } else {
477
478     const struct fingerPrint_s * bingoFps;
479
480 /*@-boundswrite@*/
481     bingoFps = bsearch(fiFps, otherFps, otherFc, sizeof(*otherFps), fpsCompare);
482 /*@=boundswrite@*/
483     if (bingoFps == NULL) {
484 /*@-modfilesys@*/
485 if (_fps_debug)
486 fprintf(stderr, "*** bingoFps NULL %s/%s%s\n",
487 ISROOT(fiFps->entry->dirName),
488 (fiFps->subDir ? fiFps->subDir : ""),
489 fiFps->baseName);
490 /*@=modfilesys@*/
491         goto linear;
492     }
493
494     /* If the addresses are the same, so are the values. */
495     /*@-nullpass@*/     /* LCL: looks good to me */
496     if (!(fiFps == bingoFps || FP_EQUAL((*fiFps), (*bingoFps)))) {
497 /*@-modfilesys@*/
498 if (_fps_debug)
499 fprintf(stderr, "***  BAD %s/%s%s\n",
500 ISROOT(bingoFps->entry->dirName),
501 (bingoFps->subDir ? bingoFps->subDir : ""),
502 bingoFps->baseName);
503 /*@=modfilesys@*/
504         goto linear;
505     }
506
507     otherFileNum = (bingoFps != NULL ? (bingoFps - otherFps) : 0);
508
509   }
510
511     return otherFileNum;
512 }
513
514 /**
515  * Update disk space needs on each partition for this package's files.
516  */
517 /* XXX only ts->{probs,di} modified */
518 static void handleOverlappedFiles(const rpmts ts,
519                 const rpmte p, rpmfi fi)
520         /*@globals fileSystem, internalState @*/
521         /*@modifies ts, fi, fileSystem, internalState @*/
522 {
523     uint_32 fixupSize = 0;
524     rpmps ps;
525     const char * fn;
526     int i, j;
527   
528     ps = rpmtsProblems(ts);
529     fi = rpmfiInit(fi, 0);
530     if (fi != NULL)
531     while ((i = rpmfiNext(fi)) >= 0) {
532         struct fingerPrint_s * fiFps;
533         int otherPkgNum, otherFileNum;
534         rpmfi otherFi;
535         int_32 FFlags;
536         int_16 FMode;
537         const rpmfi * recs;
538         int numRecs;
539
540         if (XFA_SKIPPING(fi->actions[i]))
541             continue;
542
543         fn = rpmfiFN(fi);
544         fiFps = fi->fps + i;
545         FFlags = rpmfiFFlags(fi);
546         FMode = rpmfiFMode(fi);
547
548         fixupSize = 0;
549
550         /*
551          * Retrieve all records that apply to this file. Note that the
552          * file info records were built in the same order as the packages
553          * will be installed and removed so the records for an overlapped
554          * files will be sorted in exactly the same order.
555          */
556         (void) htGetEntry(ts->ht, fiFps,
557                         (const void ***) &recs, &numRecs, NULL);
558
559         /*
560          * If this package is being added, look only at other packages
561          * being added -- removed packages dance to a different tune.
562          *
563          * If both this and the other package are being added, overlapped
564          * files must be identical (or marked as a conflict). The
565          * disposition of already installed config files leads to
566          * a small amount of extra complexity.
567          *
568          * If this package is being removed, then there are two cases that
569          * need to be worried about:
570          * If the other package is being added, then skip any overlapped files
571          * so that this package removal doesn't nuke the overlapped files
572          * that were just installed.
573          * If both this and the other package are being removed, then each
574          * file removal from preceding packages needs to be skipped so that
575          * the file removal occurs only on the last occurence of an overlapped
576          * file in the transaction set.
577          *
578          */
579
580         /* Locate this overlapped file in the set of added/removed packages. */
581         for (j = 0; j < numRecs && recs[j] != fi; j++)
582             {};
583
584         /* Find what the previous disposition of this file was. */
585         otherFileNum = -1;                      /* keep gcc quiet */
586         otherFi = NULL;
587         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
588             struct fingerPrint_s * otherFps;
589             int otherFc;
590
591             otherFi = recs[otherPkgNum];
592
593             /* Added packages need only look at other added packages. */
594             if (rpmteType(p) == TR_ADDED && rpmteType(otherFi->te) != TR_ADDED)
595                 /*@innercontinue@*/ continue;
596
597             otherFps = otherFi->fps;
598             otherFc = rpmfiFC(otherFi);
599
600             otherFileNum = findFps(fiFps, otherFps, otherFc);
601             (void) rpmfiSetFX(otherFi, otherFileNum);
602
603             /* XXX Happens iff fingerprint for incomplete package install. */
604             if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
605                 /*@innerbreak@*/ break;
606         }
607
608 /*@-boundswrite@*/
609         switch (rpmteType(p)) {
610         case TR_ADDED:
611           { struct stat sb;
612             if (otherPkgNum < 0) {
613                 /* XXX is this test still necessary? */
614                 if (fi->actions[i] != FA_UNKNOWN)
615                     /*@switchbreak@*/ break;
616                 if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
617                     /* Here is a non-overlapped pre-existing config file. */
618                     fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
619                         ? FA_ALTNAME : FA_BACKUP;
620                 } else {
621                     fi->actions[i] = FA_CREATE;
622                 }
623                 /*@switchbreak@*/ break;
624             }
625
626 assert(otherFi != NULL);
627             /* Mark added overlapped non-identical files as a conflict. */
628             if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES)
629              && filecmp(otherFi, fi))
630             {
631                 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
632                         rpmteNEVR(p), rpmteKey(p),
633                         fn, NULL,
634                         rpmteNEVR(otherFi->te),
635                         0);
636             }
637
638             /* Try to get the disk accounting correct even if a conflict. */
639             fixupSize = rpmfiFSize(otherFi);
640
641             if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
642                 /* Here is an overlapped  pre-existing config file. */
643                 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
644                         ? FA_ALTNAME : FA_SKIP;
645             } else {
646                 fi->actions[i] = FA_CREATE;
647             }
648           } /*@switchbreak@*/ break;
649
650         case TR_REMOVED:
651             if (otherPkgNum >= 0) {
652 assert(otherFi != NULL);
653                 /* Here is an overlapped added file we don't want to nuke. */
654                 if (otherFi->actions[otherFileNum] != FA_ERASE) {
655                     /* On updates, don't remove files. */
656                     fi->actions[i] = FA_SKIP;
657                     /*@switchbreak@*/ break;
658                 }
659                 /* Here is an overlapped removed file: skip in previous. */
660                 otherFi->actions[otherFileNum] = FA_SKIP;
661             }
662             if (XFA_SKIPPING(fi->actions[i]))
663                 /*@switchbreak@*/ break;
664             if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
665                 /*@switchbreak@*/ break;
666             if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
667                 fi->actions[i] = FA_ERASE;
668                 /*@switchbreak@*/ break;
669             }
670                 
671             /* Here is a pre-existing modified config file that needs saving. */
672             {   char md5sum[50];
673                 const unsigned char * MD5 = rpmfiMD5(fi);
674                 if (!domd5(fn, md5sum, 0, NULL) && memcmp(MD5, md5sum, 16)) {
675                     fi->actions[i] = FA_BACKUP;
676                     /*@switchbreak@*/ break;
677                 }
678             }
679             fi->actions[i] = FA_ERASE;
680             /*@switchbreak@*/ break;
681         }
682 /*@=boundswrite@*/
683
684         /* Update disk space info for a file. */
685         rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
686                 fi->replacedSizes[i], fixupSize, fi->actions[i]);
687
688     }
689     ps = rpmpsFree(ps);
690 }
691
692 /**
693  * Ensure that current package is newer than installed package.
694  * @param ts            transaction set
695  * @param p             current transaction element
696  * @param h             installed header
697  * @return              0 if not newer, 1 if okay
698  */
699 static int ensureOlder(rpmts ts,
700                 const rpmte p, const Header h)
701         /*@modifies ts @*/
702 {
703     int_32 reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
704     const char * reqEVR;
705     rpmds req;
706     char * t;
707     int nb;
708     int rc;
709
710     if (p == NULL || h == NULL)
711         return 1;
712
713 /*@-boundswrite@*/
714     nb = strlen(rpmteNEVR(p)) + (rpmteE(p) != NULL ? strlen(rpmteE(p)) : 0) + 1;
715     t = alloca(nb);
716     *t = '\0';
717     reqEVR = t;
718     if (rpmteE(p) != NULL)      t = stpcpy( stpcpy(t, rpmteE(p)), ":");
719     if (rpmteV(p) != NULL)      t = stpcpy(t, rpmteV(p));
720     *t++ = '-';
721     if (rpmteR(p) != NULL)      t = stpcpy(t, rpmteR(p));
722 /*@=boundswrite@*/
723     
724     req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
725     rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
726     req = rpmdsFree(req);
727
728     if (rc == 0) {
729         rpmps ps = rpmtsProblems(ts);
730         const char * altNEVR = hGetNEVR(h, NULL);
731         rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
732                 rpmteNEVR(p), rpmteKey(p),
733                 NULL, NULL,
734                 altNEVR,
735                 0);
736         altNEVR = _free(altNEVR);
737         ps = rpmpsFree(ps);
738         rc = 1;
739     } else
740         rc = 0;
741
742     return rc;
743 }
744
745 /**
746  * Skip any files that do not match install policies.
747  * @param ts            transaction set
748  * @param fi            file info set
749  */
750 /*@-mustmod@*/ /* FIX: fi->actions is modified. */
751 /*@-bounds@*/
752 static void skipFiles(const rpmts ts, rpmfi fi)
753         /*@globals rpmGlobalMacroContext @*/
754         /*@modifies fi, rpmGlobalMacroContext @*/
755 {
756     uint_32 tscolor = rpmtsColor(ts);
757     uint_32 ficolor;
758     int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
759     int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
760     char ** netsharedPaths = NULL;
761     const char ** languages;
762     const char * dn, * bn;
763     int dnlen, bnlen, ix;
764     const char * s;
765     int * drc;
766     char * dff;
767     int dc;
768     int i, j;
769
770     if (!noDocs)
771         noDocs = rpmExpandNumeric("%{_excludedocs}");
772
773     {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
774         /*@-branchstate@*/
775         if (tmpPath && *tmpPath != '%')
776             netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
777         /*@=branchstate@*/
778         tmpPath = _free(tmpPath);
779     }
780
781     s = rpmExpand("%{_install_langs}", NULL);
782     /*@-branchstate@*/
783     if (!(s && *s != '%'))
784         s = _free(s);
785     if (s) {
786         languages = (const char **) splitString(s, strlen(s), ':');
787         s = _free(s);
788     } else
789         languages = NULL;
790     /*@=branchstate@*/
791
792     /* Compute directory refcount, skip directory if now empty. */
793     dc = rpmfiDC(fi);
794     drc = alloca(dc * sizeof(*drc));
795     memset(drc, 0, dc * sizeof(*drc));
796     dff = alloca(dc * sizeof(*dff));
797     memset(dff, 0, dc * sizeof(*dff));
798
799     fi = rpmfiInit(fi, 0);
800     if (fi != NULL)     /* XXX lclint */
801     while ((i = rpmfiNext(fi)) >= 0)
802     {
803         char ** nsp;
804
805         bn = rpmfiBN(fi);
806         bnlen = strlen(bn);
807         ix = rpmfiDX(fi);
808         dn = rpmfiDN(fi);
809         dnlen = strlen(dn);
810         if (dn == NULL)
811             continue;   /* XXX can't happen */
812
813         drc[ix]++;
814
815         /* Don't bother with skipped files */
816         if (XFA_SKIPPING(fi->actions[i])) {
817             drc[ix]--; dff[ix] = 1;
818             continue;
819         }
820
821         /* Ignore colored files not in our rainbow. */
822         ficolor = rpmfiFColor(fi);
823         if (tscolor && ficolor && !(tscolor & ficolor)) {
824             drc[ix]--;  dff[ix] = 1;
825             fi->actions[i] = FA_SKIPCOLOR;
826             continue;
827         }
828
829         /*
830          * Skip net shared paths.
831          * Net shared paths are not relative to the current root (though
832          * they do need to take package relocations into account).
833          */
834         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
835             int len;
836
837             len = strlen(*nsp);
838             if (dnlen >= len) {
839                 if (strncmp(dn, *nsp, len))
840                     /*@innercontinue@*/ continue;
841                 /* Only directories or complete file paths can be net shared */
842                 if (!(dn[len] == '/' || dn[len] == '\0'))
843                     /*@innercontinue@*/ continue;
844             } else {
845                 if (len < (dnlen + bnlen))
846                     /*@innercontinue@*/ continue;
847                 if (strncmp(dn, *nsp, dnlen))
848                     /*@innercontinue@*/ continue;
849                 if (strncmp(bn, (*nsp) + dnlen, bnlen))
850                     /*@innercontinue@*/ continue;
851                 len = dnlen + bnlen;
852                 /* Only directories or complete file paths can be net shared */
853                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
854                     /*@innercontinue@*/ continue;
855             }
856
857             /*@innerbreak@*/ break;
858         }
859
860         if (nsp && *nsp) {
861             drc[ix]--;  dff[ix] = 1;
862             fi->actions[i] = FA_SKIPNETSHARED;
863             continue;
864         }
865
866         /*
867          * Skip i18n language specific files.
868          */
869         if (fi->flangs && languages && *fi->flangs[i]) {
870             const char **lang, *l, *le;
871             for (lang = languages; *lang != NULL; lang++) {
872                 if (!strcmp(*lang, "all"))
873                     /*@innerbreak@*/ break;
874                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
875                     for (le = l; *le != '\0' && *le != '|'; le++)
876                         {};
877                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
878                         /*@innerbreak@*/ break;
879                     if (*le == '|') le++;       /* skip over | */
880                 }
881                 if (*l != '\0')
882                     /*@innerbreak@*/ break;
883             }
884             if (*lang == NULL) {
885                 drc[ix]--;      dff[ix] = 1;
886                 fi->actions[i] = FA_SKIPNSTATE;
887                 continue;
888             }
889         }
890
891         /*
892          * Skip config files if requested.
893          */
894         if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
895             drc[ix]--;  dff[ix] = 1;
896             fi->actions[i] = FA_SKIPNSTATE;
897             continue;
898         }
899
900         /*
901          * Skip documentation if requested.
902          */
903         if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
904             drc[ix]--;  dff[ix] = 1;
905             fi->actions[i] = FA_SKIPNSTATE;
906             continue;
907         }
908     }
909
910     /* Skip (now empty) directories that had skipped files. */
911 #ifndef NOTYET
912     if (fi != NULL)     /* XXX can't happen */
913     for (j = 0; j < dc; j++)
914 #else
915     if ((fi = rpmfiInitD(fi)) != NULL)
916     while (j = rpmfiNextD(fi) >= 0)
917 #endif
918     {
919
920         if (drc[j]) continue;   /* dir still has files. */
921         if (!dff[j]) continue;  /* dir was not emptied here. */
922         
923         /* Find parent directory and basename. */
924         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
925         bn = dn + dnlen;        bnlen = 0;
926         while (bn > dn && bn[-1] != '/') {
927                 bnlen++;
928                 dnlen--;
929                 bn--;
930         }
931
932         /* If explicitly included in the package, skip the directory. */
933         fi = rpmfiInit(fi, 0);
934         if (fi != NULL)         /* XXX lclint */
935         while ((i = rpmfiNext(fi)) >= 0) {
936             const char * fdn, * fbn;
937             int_16 fFMode;
938
939             if (XFA_SKIPPING(fi->actions[i]))
940                 /*@innercontinue@*/ continue;
941
942             fFMode = rpmfiFMode(fi);
943
944             if (whatis(fFMode) != XDIR)
945                 /*@innercontinue@*/ continue;
946             fdn = rpmfiDN(fi);
947             if (strlen(fdn) != dnlen)
948                 /*@innercontinue@*/ continue;
949             if (strncmp(fdn, dn, dnlen))
950                 /*@innercontinue@*/ continue;
951             fbn = rpmfiBN(fi);
952             if (strlen(fbn) != bnlen)
953                 /*@innercontinue@*/ continue;
954             if (strncmp(fbn, bn, bnlen))
955                 /*@innercontinue@*/ continue;
956             rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
957             fi->actions[i] = FA_SKIPNSTATE;
958             /*@innerbreak@*/ break;
959         }
960     }
961
962     if (netsharedPaths) freeSplitString(netsharedPaths);
963 #ifdef  DYING   /* XXX freeFi will deal with this later. */
964     fi->flangs = _free(fi->flangs);
965 #endif
966     if (languages) freeSplitString((char **)languages);
967 }
968 /*@=bounds@*/
969 /*@=mustmod@*/
970
971 /**
972  * Return transaction element's file info.
973  * @todo Take a rpmfi refcount here.
974  * @param tsi           transaction element iterator
975  * @return              transaction element file info
976  */
977 static /*@null@*/
978 rpmfi rpmtsiFi(const rpmtsi tsi)
979         /*@*/
980 {
981     rpmfi fi = NULL;
982
983     if (tsi != NULL && tsi->ocsave != -1) {
984         /*@-type -abstract@*/ /* FIX: rpmte not opaque */
985         rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
986         /*@-assignexpose@*/
987         if (te != NULL && (fi = te->fi) != NULL)
988             fi->te = te;
989         /*@=assignexpose@*/
990         /*@=type =abstract@*/
991     }
992     /*@-compdef -refcounttrans -usereleased @*/
993     return fi;
994     /*@=compdef =refcounttrans =usereleased @*/
995 }
996
997 #define NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
998
999 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
1000 {
1001     uint_32 tscolor = rpmtsColor(ts);
1002     int i, j;
1003     int ourrc = 0;
1004     int totalFileCount = 0;
1005     rpmfi fi;
1006     sharedFileInfo shared, sharedList;
1007     int numShared;
1008     int nexti;
1009     alKey lastFailKey;
1010     fingerPrintCache fpc;
1011     rpmps ps;
1012     rpmpsm psm;
1013     rpmtsi pi;  rpmte p;
1014     rpmtsi qi;  rpmte q;
1015     int numAdded;
1016     int numRemoved;
1017     int xx;
1018
1019     /* XXX programmer error segfault avoidance. */
1020     if (rpmtsNElements(ts) <= 0)
1021         return -1;
1022
1023     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
1024         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1025     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
1026         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
1027
1028     /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
1029     if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
1030         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1031
1032     ts->probs = rpmpsFree(ts->probs);
1033     ts->probs = rpmpsCreate();
1034
1035     /* XXX Make sure the database is open RDWR for package install/erase. */
1036     {   int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1037                 ? O_RDONLY : (O_RDWR|O_CREAT);
1038
1039         /* Open database RDWR for installing packages. */
1040         if (rpmtsOpenDB(ts, dbmode))
1041             return -1;  /* XXX W2DO? */
1042     }
1043
1044     ts->ignoreSet = ignoreSet;
1045     {   const char * currDir = currentDirectory();
1046         rpmtsSetCurrDir(ts, currDir);
1047         currDir = _free(currDir);
1048     }
1049
1050     (void) rpmtsSetChrootDone(ts, 0);
1051
1052     {   int_32 tid = (int_32) time(NULL);
1053         (void) rpmtsSetTid(ts, tid);
1054     }
1055
1056     /* Get available space on mounted file systems. */
1057     xx = rpmtsInitDSI(ts);
1058
1059     /* ===============================================
1060      * For packages being installed:
1061      * - verify package arch/os.
1062      * - verify package epoch:version-release is newer.
1063      * - count files.
1064      * For packages being removed:
1065      * - count files.
1066      */
1067
1068 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
1069     ps = rpmtsProblems(ts);
1070     /* The ordering doesn't matter here */
1071     pi = rpmtsiInit(ts);
1072     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1073         rpmdbMatchIterator mi;
1074         int fc;
1075
1076         if ((fi = rpmtsiFi(pi)) == NULL)
1077             continue;   /* XXX can't happen */
1078         fc = rpmfiFC(fi);
1079
1080         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
1081             if (!archOkay(rpmteA(p)))
1082                 rpmpsAppend(ps, RPMPROB_BADARCH,
1083                         rpmteNEVR(p), rpmteKey(p),
1084                         rpmteA(p), NULL,
1085                         NULL, 0);
1086
1087         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1088             if (!osOkay(rpmteO(p)))
1089                 rpmpsAppend(ps, RPMPROB_BADOS,
1090                         rpmteNEVR(p), rpmteKey(p),
1091                         rpmteO(p), NULL,
1092                         NULL, 0);
1093
1094         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1095             Header h;
1096             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1097             while ((h = rpmdbNextIterator(mi)) != NULL)
1098                 xx = ensureOlder(ts, p, h);
1099             mi = rpmdbFreeIterator(mi);
1100         }
1101
1102         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
1103             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1104             xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
1105                                 rpmteE(p));
1106             xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1107                                 rpmteV(p));
1108             xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1109                                 rpmteR(p));
1110             if (tscolor) {
1111                 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT,
1112                                 rpmteA(p));
1113                 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_DEFAULT,
1114                                 rpmteO(p));
1115             }
1116
1117             while (rpmdbNextIterator(mi) != NULL) {
1118                 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1119                         rpmteNEVR(p), rpmteKey(p),
1120                         NULL, NULL,
1121                         NULL, 0);
1122                 /*@innerbreak@*/ break;
1123             }
1124             mi = rpmdbFreeIterator(mi);
1125         }
1126
1127         /* Count no. of files (if any). */
1128         totalFileCount += fc;
1129
1130     }
1131     pi = rpmtsiFree(pi);
1132     ps = rpmpsFree(ps);
1133
1134     /* The ordering doesn't matter here */
1135     pi = rpmtsiInit(ts);
1136     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1137         int fc;
1138
1139         if ((fi = rpmtsiFi(pi)) == NULL)
1140             continue;   /* XXX can't happen */
1141         fc = rpmfiFC(fi);
1142
1143         totalFileCount += fc;
1144     }
1145     pi = rpmtsiFree(pi);
1146
1147     /* ===============================================
1148      * Initialize transaction element file info for package:
1149      */
1150
1151     /*
1152      * FIXME?: we'd be better off assembling one very large file list and
1153      * calling fpLookupList only once. I'm not sure that the speedup is
1154      * worth the trouble though.
1155      */
1156 rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
1157     numAdded = numRemoved = 0;
1158     pi = rpmtsiInit(ts);
1159     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1160         int fc;
1161
1162         if ((fi = rpmtsiFi(pi)) == NULL)
1163             continue;   /* XXX can't happen */
1164         fc = rpmfiFC(fi);
1165
1166         /*@-branchstate@*/
1167         switch (rpmteType(p)) {
1168         case TR_ADDED:
1169             numAdded++;
1170             fi->record = 0;
1171             /* Skip netshared paths, not our i18n files, and excluded docs */
1172             if (fc > 0)
1173                 skipFiles(ts, fi);
1174             /*@switchbreak@*/ break;
1175         case TR_REMOVED:
1176             numRemoved++;
1177             fi->record = rpmteDBOffset(p);
1178             /*@switchbreak@*/ break;
1179         }
1180         /*@=branchstate@*/
1181
1182         fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
1183     }
1184     pi = rpmtsiFree(pi);
1185
1186     if (!rpmtsChrootDone(ts)) {
1187         const char * rootDir = rpmtsRootDir(ts);
1188         xx = chdir("/");
1189         /*@-superuser -noeffect @*/
1190         if (rootDir != NULL)
1191             xx = chroot(rootDir);
1192         /*@=superuser =noeffect @*/
1193         (void) rpmtsSetChrootDone(ts, 1);
1194     }
1195
1196     ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1197     fpc = fpCacheCreate(totalFileCount);
1198
1199     /* ===============================================
1200      * Add fingerprint for each file not skipped.
1201      */
1202     pi = rpmtsiInit(ts);
1203     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1204         int fc;
1205
1206         (void) rpmdbCheckSignals();
1207
1208         if ((fi = rpmtsiFi(pi)) == NULL)
1209             continue;   /* XXX can't happen */
1210         fc = rpmfiFC(fi);
1211
1212         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1213         /*@-branchstate@*/
1214         fi = rpmfiInit(fi, 0);
1215         if (fi != NULL)         /* XXX lclint */
1216         while ((i = rpmfiNext(fi)) >= 0) {
1217             if (XFA_SKIPPING(fi->actions[i]))
1218                 /*@innercontinue@*/ continue;
1219             /*@-dependenttrans@*/
1220             htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1221             /*@=dependenttrans@*/
1222         }
1223         /*@=branchstate@*/
1224     }
1225     pi = rpmtsiFree(pi);
1226
1227     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1228         NULL, ts->notifyData));
1229
1230     /* ===============================================
1231      * Compute file disposition for each package in transaction set.
1232      */
1233 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
1234     ps = rpmtsProblems(ts);
1235     pi = rpmtsiInit(ts);
1236     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1237         dbiIndexSet * matches;
1238         int knownBad;
1239         int fc;
1240
1241         (void) rpmdbCheckSignals();
1242
1243         if ((fi = rpmtsiFi(pi)) == NULL)
1244             continue;   /* XXX can't happen */
1245         fc = rpmfiFC(fi);
1246
1247         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1248                         ts->orderCount, NULL, ts->notifyData));
1249
1250         if (fc == 0) continue;
1251
1252         /* Extract file info for all files in this package from the database. */
1253         matches = xcalloc(fc, sizeof(*matches));
1254         if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1255             ps = rpmpsFree(ps);
1256             return 1;   /* XXX WTFO? */
1257         }
1258
1259         numShared = 0;
1260         fi = rpmfiInit(fi, 0);
1261         while ((i = rpmfiNext(fi)) >= 0)
1262             numShared += dbiIndexSetCount(matches[i]);
1263
1264         /* Build sorted file info list for this package. */
1265         shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1266
1267         fi = rpmfiInit(fi, 0);
1268         while ((i = rpmfiNext(fi)) >= 0) {
1269             /*
1270              * Take care not to mark files as replaced in packages that will
1271              * have been removed before we will get here.
1272              */
1273             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1274                 int ro;
1275                 ro = dbiIndexRecordOffset(matches[i], j);
1276                 knownBad = 0;
1277                 qi = rpmtsiInit(ts);
1278                 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1279                     if (ro == knownBad)
1280                         /*@innerbreak@*/ break;
1281                     if (rpmteDBOffset(q) == ro)
1282                         knownBad = ro;
1283                 }
1284                 qi = rpmtsiFree(qi);
1285
1286                 shared->pkgFileNum = i;
1287                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1288                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1289                 shared->isRemoved = (knownBad == ro);
1290                 shared++;
1291             }
1292             matches[i] = dbiFreeIndexSet(matches[i]);
1293         }
1294         numShared = shared - sharedList;
1295         shared->otherPkg = -1;
1296         matches = _free(matches);
1297
1298         /* Sort file info by other package index (otherPkg) */
1299         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1300
1301         /* For all files from this package that are in the database ... */
1302         /*@-branchstate@*/
1303         for (i = 0; i < numShared; i = nexti) {
1304             int beingRemoved;
1305
1306             shared = sharedList + i;
1307
1308             /* Find the end of the files in the other package. */
1309             for (nexti = i + 1; nexti < numShared; nexti++) {
1310                 if (sharedList[nexti].otherPkg != shared->otherPkg)
1311                     /*@innerbreak@*/ break;
1312             }
1313
1314             /* Is this file from a package being removed? */
1315             beingRemoved = 0;
1316             if (ts->removedPackages != NULL)
1317             for (j = 0; j < ts->numRemovedPackages; j++) {
1318                 if (ts->removedPackages[j] != shared->otherPkg)
1319                     /*@innercontinue@*/ continue;
1320                 beingRemoved = 1;
1321                 /*@innerbreak@*/ break;
1322             }
1323
1324             /* Determine the fate of each file. */
1325             switch (rpmteType(p)) {
1326             case TR_ADDED:
1327                 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1328         !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1329                 /*@switchbreak@*/ break;
1330             case TR_REMOVED:
1331                 if (!beingRemoved)
1332                     xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1333                 /*@switchbreak@*/ break;
1334             }
1335         }
1336         /*@=branchstate@*/
1337
1338         free(sharedList);
1339
1340         /* Update disk space needs on each partition for this package. */
1341         handleOverlappedFiles(ts, p, fi);
1342
1343         /* Check added package has sufficient space on each partition used. */
1344         switch (rpmteType(p)) {
1345         case TR_ADDED:
1346             rpmtsCheckDSIProblems(ts, p);
1347             /*@switchbreak@*/ break;
1348         case TR_REMOVED:
1349             /*@switchbreak@*/ break;
1350         }
1351     }
1352     pi = rpmtsiFree(pi);
1353     ps = rpmpsFree(ps);
1354
1355     if (rpmtsChrootDone(ts)) {
1356         const char * currDir = rpmtsCurrDir(ts);
1357         /*@-superuser -noeffect @*/
1358         xx = chroot(".");
1359         /*@=superuser =noeffect @*/
1360         (void) rpmtsSetChrootDone(ts, 0);
1361         if (currDir != NULL)
1362             xx = chdir(currDir);
1363     }
1364
1365     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1366         NULL, ts->notifyData));
1367
1368     /* ===============================================
1369      * Free unused memory as soon as possible.
1370      */
1371     pi = rpmtsiInit(ts);
1372     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1373         if ((fi = rpmtsiFi(pi)) == NULL)
1374             continue;   /* XXX can't happen */
1375         if (rpmfiFC(fi) == 0)
1376             continue;
1377         fi->fps = _free(fi->fps);
1378     }
1379     pi = rpmtsiFree(pi);
1380
1381     fpc = fpCacheFree(fpc);
1382     ts->ht = htFree(ts->ht);
1383
1384     /* ===============================================
1385      * If unfiltered problems exist, free memory and return.
1386      */
1387     if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1388      || (ts->probs->numProblems &&
1389                 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1390        )
1391     {
1392         return ts->orderCount;
1393     }
1394
1395     /* ===============================================
1396      * Save removed files before erasing.
1397      */
1398     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1399         int progress;
1400         progress = 0;
1401         pi = rpmtsiInit(ts);
1402         while ((p = rpmtsiNext(pi, 0)) != NULL) {
1403
1404             (void) rpmdbCheckSignals();
1405
1406             if ((fi = rpmtsiFi(pi)) == NULL)
1407                 continue;       /* XXX can't happen */
1408             switch (rpmteType(p)) {
1409             case TR_ADDED:
1410                 /*@switchbreak@*/ break;
1411             case TR_REMOVED:
1412                 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1413                     /*@switchbreak@*/ break;
1414                 if (!progress)
1415                     NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
1416                                 7, numRemoved, NULL, ts->notifyData));
1417
1418                 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
1419                         numRemoved, NULL, ts->notifyData));
1420                 progress++;
1421
1422         /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1423                 fi->mapflags |= CPIO_MAP_ABSOLUTE;
1424                 fi->mapflags |= CPIO_MAP_ADDDOT;
1425                 fi->mapflags |= CPIO_ALL_HARDLINKS;
1426                 psm = rpmpsmNew(ts, p, fi);
1427                 xx = rpmpsmStage(psm, PSM_PKGSAVE);
1428                 psm = rpmpsmFree(psm);
1429                 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
1430                 fi->mapflags &= ~CPIO_MAP_ADDDOT;
1431                 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
1432
1433                 /*@switchbreak@*/ break;
1434             }
1435         }
1436         pi = rpmtsiFree(pi);
1437         if (progress) {
1438             NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
1439                         NULL, ts->notifyData));
1440         }
1441     }
1442
1443     /* ===============================================
1444      * Install and remove packages.
1445      */
1446     lastFailKey = (alKey)-2;    /* erased packages have -1 */
1447     pi = rpmtsiInit(ts);
1448     /*@-branchstate@*/ /* FIX: fi reload needs work */
1449     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1450         alKey pkgKey;
1451         int gotfd;
1452
1453         (void) rpmdbCheckSignals();
1454
1455         gotfd = 0;
1456         if ((fi = rpmtsiFi(pi)) == NULL)
1457             continue;   /* XXX can't happen */
1458         
1459         psm = rpmpsmNew(ts, p, fi);
1460         psm->unorderedSuccessor =
1461                 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
1462
1463         switch (rpmteType(p)) {
1464         case TR_ADDED:
1465
1466             pkgKey = rpmteAddedKey(p);
1467
1468             rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1469             p->h = NULL;
1470             /*@-type@*/ /* FIX: rpmte not opaque */
1471             {
1472                 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1473                 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1474                                 rpmteKey(p), ts->notifyData);
1475                 /*@=noeffectuncon@*/
1476                 if (rpmteFd(p) != NULL) {
1477                     rpmVSFlags ovsflags = rpmtsVSFlags(ts);
1478                     rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
1479                     rpmRC rpmrc;
1480
1481                     ovsflags = rpmtsSetVSFlags(ts, vsflags);
1482                     rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1483                                 rpmteNEVR(p), &p->h);
1484                     vsflags = rpmtsSetVSFlags(ts, ovsflags);
1485
1486                     switch (rpmrc) {
1487                     default:
1488                         /*@-noeffectuncon@*/ /* FIX: notify annotations */
1489                         p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
1490                                         0, 0,
1491                                         rpmteKey(p), ts->notifyData);
1492                         /*@=noeffectuncon@*/
1493                         p->fd = NULL;
1494                         ourrc++;
1495                         /*@innerbreak@*/ break;
1496                     case RPMRC_NOTTRUSTED:
1497                     case RPMRC_NOKEY:
1498                     case RPMRC_OK:
1499                         /*@innerbreak@*/ break;
1500                     }
1501                     if (rpmteFd(p) != NULL) gotfd = 1;
1502                 }
1503             }
1504             /*@=type@*/
1505
1506             if (rpmteFd(p) != NULL) {
1507                 /*
1508                  * XXX Sludge necessary to tranfer existing fstates/actions
1509                  * XXX around a recreated file info set.
1510                  */
1511                 psm->fi = rpmfiFree(psm->fi);
1512                 {
1513                     char * fstates = fi->fstates;
1514                     fileAction * actions = fi->actions;
1515                     rpmte savep;
1516
1517                     fi->fstates = NULL;
1518                     fi->actions = NULL;
1519                     fi = rpmfiFree(fi);
1520
1521                     savep = rpmtsSetRelocateElement(ts, p);
1522                     fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
1523                     (void) rpmtsSetRelocateElement(ts, savep);
1524
1525                     if (fi != NULL) {   /* XXX can't happen */
1526                         fi->te = p;
1527                         fi->fstates = _free(fi->fstates);
1528                         fi->fstates = fstates;
1529                         fi->actions = _free(fi->actions);
1530                         fi->actions = actions;
1531                         p->fi = fi;
1532                     }
1533                 }
1534                 psm->fi = rpmfiLink(p->fi, NULL);
1535
1536 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1537                 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
1538                     ourrc++;
1539                     lastFailKey = pkgKey;
1540                 }
1541 /*@=nullstate@*/
1542             } else {
1543                 ourrc++;
1544                 lastFailKey = pkgKey;
1545             }
1546
1547             if (gotfd) {
1548                 /*@-noeffectuncon @*/ /* FIX: check rc */
1549                 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1550                         rpmteKey(p), ts->notifyData);
1551                 /*@=noeffectuncon @*/
1552                 /*@-type@*/
1553                 p->fd = NULL;
1554                 /*@=type@*/
1555             }
1556
1557             p->h = headerFree(p->h);
1558
1559             /*@switchbreak@*/ break;
1560         case TR_REMOVED:
1561             rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1562             /*
1563              * XXX This has always been a hack, now mostly broken.
1564              * If install failed, then we shouldn't erase.
1565              */
1566             if (rpmteDependsOnKey(p) != lastFailKey) {
1567                 if (rpmpsmStage(psm, PSM_PKGERASE))
1568                     ourrc++;
1569             }
1570             /*@switchbreak@*/ break;
1571         }
1572         xx = rpmdbSync(rpmtsGetRdb(ts));
1573
1574 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1575         psm = rpmpsmFree(psm);
1576 /*@=nullstate@*/
1577
1578 /*@-type@*/ /* FIX: p is almost opaque */
1579         p->fi = rpmfiFree(p->fi);
1580 /*@=type@*/
1581
1582     }
1583     /*@=branchstate@*/
1584     pi = rpmtsiFree(pi);
1585
1586     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1587     if (ourrc)
1588         return -1;
1589     else
1590         return 0;
1591     /*@=nullstate@*/
1592 }