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