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