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