fix: prevent segfault if malicious server sends 1 GB of data through ftpNLST.
[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 (languages != NULL && fi->flangs != NULL && *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 /*@-dependenttrans@*/
961     if (netsharedPaths) freeSplitString(netsharedPaths);
962 #ifdef  DYING   /* XXX freeFi will deal with this later. */
963     fi->flangs = _free(fi->flangs);
964 #endif
965     if (languages) freeSplitString((char **)languages);
966 /*@=dependenttrans@*/
967 }
968 /*@=bounds@*/
969 /*@=mustmod@*/
970
971 /**
972  * Return transaction element's file info.
973  * @todo Take a rpmfi refcount here.
974  * @param tsi           transaction element iterator
975  * @return              transaction element file info
976  */
977 static /*@null@*/
978 rpmfi rpmtsiFi(const rpmtsi tsi)
979         /*@*/
980 {
981     rpmfi fi = NULL;
982
983     if (tsi != NULL && tsi->ocsave != -1) {
984         /*@-type -abstract@*/ /* FIX: rpmte not opaque */
985         rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
986         /*@-assignexpose@*/
987         if (te != NULL && (fi = te->fi) != NULL)
988             fi->te = te;
989         /*@=assignexpose@*/
990         /*@=type =abstract@*/
991     }
992     /*@-compdef -refcounttrans -usereleased @*/
993     return fi;
994     /*@=compdef =refcounttrans =usereleased @*/
995 }
996
997 #define NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
998
999 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
1000 {
1001     uint_32 tscolor = rpmtsColor(ts);
1002     int i, j;
1003     int ourrc = 0;
1004     int totalFileCount = 0;
1005     rpmfi fi;
1006     sharedFileInfo shared, sharedList;
1007     int numShared;
1008     int nexti;
1009     alKey lastFailKey;
1010     fingerPrintCache fpc;
1011     rpmps ps;
1012     rpmpsm psm;
1013     rpmtsi pi;  rpmte p;
1014     rpmtsi qi;  rpmte q;
1015     int numAdded;
1016     int numRemoved;
1017     int xx;
1018
1019     /* XXX programmer error segfault avoidance. */
1020     if (rpmtsNElements(ts) <= 0)
1021         return -1;
1022
1023     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
1024         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1025     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
1026         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
1027
1028     if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
1029         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1030
1031     ts->probs = rpmpsFree(ts->probs);
1032     ts->probs = rpmpsCreate();
1033
1034     /* XXX Make sure the database is open RDWR for package install/erase. */
1035     {   int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1036                 ? O_RDONLY : (O_RDWR|O_CREAT);
1037
1038         /* Open database RDWR for installing packages. */
1039         if (rpmtsOpenDB(ts, dbmode))
1040             return -1;  /* XXX W2DO? */
1041     }
1042
1043     ts->ignoreSet = ignoreSet;
1044     {   const char * currDir = currentDirectory();
1045         rpmtsSetCurrDir(ts, currDir);
1046         currDir = _free(currDir);
1047     }
1048
1049     (void) rpmtsSetChrootDone(ts, 0);
1050
1051     {   int_32 tid = (int_32) time(NULL);
1052         (void) rpmtsSetTid(ts, tid);
1053     }
1054
1055     /* Get available space on mounted file systems. */
1056     xx = rpmtsInitDSI(ts);
1057
1058     /* ===============================================
1059      * For packages being installed:
1060      * - verify package arch/os.
1061      * - verify package epoch:version-release is newer.
1062      * - count files.
1063      * For packages being removed:
1064      * - count files.
1065      */
1066
1067 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
1068     ps = rpmtsProblems(ts);
1069     /* The ordering doesn't matter here */
1070     pi = rpmtsiInit(ts);
1071     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1072         rpmdbMatchIterator mi;
1073         int fc;
1074
1075         if ((fi = rpmtsiFi(pi)) == NULL)
1076             continue;   /* XXX can't happen */
1077         fc = rpmfiFC(fi);
1078
1079         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
1080             if (!archOkay(rpmteA(p)))
1081                 rpmpsAppend(ps, RPMPROB_BADARCH,
1082                         rpmteNEVR(p), rpmteKey(p),
1083                         rpmteA(p), NULL,
1084                         NULL, 0);
1085
1086         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1087             if (!osOkay(rpmteO(p)))
1088                 rpmpsAppend(ps, RPMPROB_BADOS,
1089                         rpmteNEVR(p), rpmteKey(p),
1090                         rpmteO(p), NULL,
1091                         NULL, 0);
1092
1093         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1094             Header h;
1095             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1096             while ((h = rpmdbNextIterator(mi)) != NULL)
1097                 xx = ensureOlder(ts, p, h);
1098             mi = rpmdbFreeIterator(mi);
1099         }
1100
1101         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
1102             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1103             xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
1104                                 rpmteE(p));
1105             xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1106                                 rpmteV(p));
1107             xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1108                                 rpmteR(p));
1109             if (tscolor) {
1110                 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT,
1111                                 rpmteA(p));
1112                 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_DEFAULT,
1113                                 rpmteO(p));
1114             }
1115
1116             while (rpmdbNextIterator(mi) != NULL) {
1117                 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1118                         rpmteNEVR(p), rpmteKey(p),
1119                         NULL, NULL,
1120                         NULL, 0);
1121                 /*@innerbreak@*/ break;
1122             }
1123             mi = rpmdbFreeIterator(mi);
1124         }
1125
1126         /* Count no. of files (if any). */
1127         totalFileCount += fc;
1128
1129     }
1130     pi = rpmtsiFree(pi);
1131     ps = rpmpsFree(ps);
1132
1133     /* The ordering doesn't matter here */
1134     pi = rpmtsiInit(ts);
1135     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1136         int fc;
1137
1138         if ((fi = rpmtsiFi(pi)) == NULL)
1139             continue;   /* XXX can't happen */
1140         fc = rpmfiFC(fi);
1141
1142         totalFileCount += fc;
1143     }
1144     pi = rpmtsiFree(pi);
1145
1146     /* ===============================================
1147      * Initialize transaction element file info for package:
1148      */
1149
1150     /*
1151      * FIXME?: we'd be better off assembling one very large file list and
1152      * calling fpLookupList only once. I'm not sure that the speedup is
1153      * worth the trouble though.
1154      */
1155 rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
1156
1157     numAdded = numRemoved = 0;
1158     pi = rpmtsiInit(ts);
1159     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1160         int fc;
1161
1162         if ((fi = rpmtsiFi(pi)) == NULL)
1163             continue;   /* XXX can't happen */
1164         fc = rpmfiFC(fi);
1165
1166         /*@-branchstate@*/
1167         switch (rpmteType(p)) {
1168         case TR_ADDED:
1169             numAdded++;
1170             fi->record = 0;
1171             /* Skip netshared paths, not our i18n files, and excluded docs */
1172             if (fc > 0)
1173                 skipFiles(ts, fi);
1174             /*@switchbreak@*/ break;
1175         case TR_REMOVED:
1176             numRemoved++;
1177             fi->record = rpmteDBOffset(p);
1178             /*@switchbreak@*/ break;
1179         }
1180         /*@=branchstate@*/
1181
1182         fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
1183     }
1184     pi = rpmtsiFree(pi);
1185
1186     if (!rpmtsChrootDone(ts)) {
1187         const char * rootDir = rpmtsRootDir(ts);
1188         xx = chdir("/");
1189         /*@-superuser -noeffect @*/
1190         if (rootDir != NULL)
1191             xx = chroot(rootDir);
1192         /*@=superuser =noeffect @*/
1193         (void) rpmtsSetChrootDone(ts, 1);
1194     }
1195
1196     ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1197     fpc = fpCacheCreate(totalFileCount);
1198
1199     /* ===============================================
1200      * Add fingerprint for each file not skipped.
1201      */
1202     pi = rpmtsiInit(ts);
1203     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1204         int fc;
1205
1206         (void) rpmdbCheckSignals();
1207
1208         if ((fi = rpmtsiFi(pi)) == NULL)
1209             continue;   /* XXX can't happen */
1210         fc = rpmfiFC(fi);
1211
1212         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1213         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1214         /*@-branchstate@*/
1215         fi = rpmfiInit(fi, 0);
1216         if (fi != NULL)         /* XXX lclint */
1217         while ((i = rpmfiNext(fi)) >= 0) {
1218             if (XFA_SKIPPING(fi->actions[i]))
1219                 /*@innercontinue@*/ continue;
1220             /*@-dependenttrans@*/
1221             htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1222             /*@=dependenttrans@*/
1223         }
1224         /*@=branchstate@*/
1225         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
1226
1227     }
1228     pi = rpmtsiFree(pi);
1229
1230     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1231         NULL, ts->notifyData));
1232
1233     /* ===============================================
1234      * Compute file disposition for each package in transaction set.
1235      */
1236 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
1237     ps = rpmtsProblems(ts);
1238     pi = rpmtsiInit(ts);
1239     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1240         dbiIndexSet * matches;
1241         int knownBad;
1242         int fc;
1243
1244         (void) rpmdbCheckSignals();
1245
1246         if ((fi = rpmtsiFi(pi)) == NULL)
1247             continue;   /* XXX can't happen */
1248         fc = rpmfiFC(fi);
1249
1250         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1251                         ts->orderCount, NULL, ts->notifyData));
1252
1253         if (fc == 0) continue;
1254
1255         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1256         /* Extract file info for all files in this package from the database. */
1257         matches = xcalloc(fc, sizeof(*matches));
1258         if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1259             ps = rpmpsFree(ps);
1260             return 1;   /* XXX WTFO? */
1261         }
1262
1263         numShared = 0;
1264         fi = rpmfiInit(fi, 0);
1265         while ((i = rpmfiNext(fi)) >= 0)
1266             numShared += dbiIndexSetCount(matches[i]);
1267
1268         /* Build sorted file info list for this package. */
1269         shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1270
1271         fi = rpmfiInit(fi, 0);
1272         while ((i = rpmfiNext(fi)) >= 0) {
1273             /*
1274              * Take care not to mark files as replaced in packages that will
1275              * have been removed before we will get here.
1276              */
1277             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1278                 int ro;
1279                 ro = dbiIndexRecordOffset(matches[i], j);
1280                 knownBad = 0;
1281                 qi = rpmtsiInit(ts);
1282                 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1283                     if (ro == knownBad)
1284                         /*@innerbreak@*/ break;
1285                     if (rpmteDBOffset(q) == ro)
1286                         knownBad = ro;
1287                 }
1288                 qi = rpmtsiFree(qi);
1289
1290                 shared->pkgFileNum = i;
1291                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1292                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1293                 shared->isRemoved = (knownBad == ro);
1294                 shared++;
1295             }
1296             matches[i] = dbiFreeIndexSet(matches[i]);
1297         }
1298         numShared = shared - sharedList;
1299         shared->otherPkg = -1;
1300         matches = _free(matches);
1301
1302         /* Sort file info by other package index (otherPkg) */
1303         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1304
1305         /* For all files from this package that are in the database ... */
1306         /*@-branchstate@*/
1307         for (i = 0; i < numShared; i = nexti) {
1308             int beingRemoved;
1309
1310             shared = sharedList + i;
1311
1312             /* Find the end of the files in the other package. */
1313             for (nexti = i + 1; nexti < numShared; nexti++) {
1314                 if (sharedList[nexti].otherPkg != shared->otherPkg)
1315                     /*@innerbreak@*/ break;
1316             }
1317
1318             /* Is this file from a package being removed? */
1319             beingRemoved = 0;
1320             if (ts->removedPackages != NULL)
1321             for (j = 0; j < ts->numRemovedPackages; j++) {
1322                 if (ts->removedPackages[j] != shared->otherPkg)
1323                     /*@innercontinue@*/ continue;
1324                 beingRemoved = 1;
1325                 /*@innerbreak@*/ break;
1326             }
1327
1328             /* Determine the fate of each file. */
1329             switch (rpmteType(p)) {
1330             case TR_ADDED:
1331                 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1332         !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1333                 /*@switchbreak@*/ break;
1334             case TR_REMOVED:
1335                 if (!beingRemoved)
1336                     xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1337                 /*@switchbreak@*/ break;
1338             }
1339         }
1340         /*@=branchstate@*/
1341
1342         free(sharedList);
1343
1344         /* Update disk space needs on each partition for this package. */
1345         handleOverlappedFiles(ts, p, fi);
1346
1347         /* Check added package has sufficient space on each partition used. */
1348         switch (rpmteType(p)) {
1349         case TR_ADDED:
1350             rpmtsCheckDSIProblems(ts, p);
1351             /*@switchbreak@*/ break;
1352         case TR_REMOVED:
1353             /*@switchbreak@*/ break;
1354         }
1355         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
1356     }
1357     pi = rpmtsiFree(pi);
1358     ps = rpmpsFree(ps);
1359
1360     if (rpmtsChrootDone(ts)) {
1361         const char * currDir = rpmtsCurrDir(ts);
1362         /*@-superuser -noeffect @*/
1363         xx = chroot(".");
1364         /*@=superuser =noeffect @*/
1365         (void) rpmtsSetChrootDone(ts, 0);
1366         if (currDir != NULL)
1367             xx = chdir(currDir);
1368     }
1369
1370     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1371         NULL, ts->notifyData));
1372
1373     /* ===============================================
1374      * Free unused memory as soon as possible.
1375      */
1376     pi = rpmtsiInit(ts);
1377     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1378         if ((fi = rpmtsiFi(pi)) == NULL)
1379             continue;   /* XXX can't happen */
1380         if (rpmfiFC(fi) == 0)
1381             continue;
1382         fi->fps = _free(fi->fps);
1383     }
1384     pi = rpmtsiFree(pi);
1385
1386     fpc = fpCacheFree(fpc);
1387     ts->ht = htFree(ts->ht);
1388
1389     /* ===============================================
1390      * If unfiltered problems exist, free memory and return.
1391      */
1392     if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1393      || (ts->probs->numProblems &&
1394                 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1395        )
1396     {
1397         return ts->orderCount;
1398     }
1399
1400     /* ===============================================
1401      * Save removed files before erasing.
1402      */
1403     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1404         int progress;
1405
1406         progress = 0;
1407         pi = rpmtsiInit(ts);
1408         while ((p = rpmtsiNext(pi, 0)) != NULL) {
1409
1410             (void) rpmdbCheckSignals();
1411
1412             if ((fi = rpmtsiFi(pi)) == NULL)
1413                 continue;       /* XXX can't happen */
1414             switch (rpmteType(p)) {
1415             case TR_ADDED:
1416                 /*@switchbreak@*/ break;
1417             case TR_REMOVED:
1418                 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1419                     /*@switchbreak@*/ break;
1420                 if (!progress)
1421                     NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
1422                                 7, numRemoved, NULL, ts->notifyData));
1423
1424                 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
1425                         numRemoved, NULL, ts->notifyData));
1426                 progress++;
1427
1428                 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
1429
1430         /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1431                 fi->mapflags |= CPIO_MAP_ABSOLUTE;
1432                 fi->mapflags |= CPIO_MAP_ADDDOT;
1433                 fi->mapflags |= CPIO_ALL_HARDLINKS;
1434                 psm = rpmpsmNew(ts, p, fi);
1435                 xx = rpmpsmStage(psm, PSM_PKGSAVE);
1436                 psm = rpmpsmFree(psm);
1437                 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
1438                 fi->mapflags &= ~CPIO_MAP_ADDDOT;
1439                 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
1440
1441                 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
1442
1443                 /*@switchbreak@*/ break;
1444             }
1445         }
1446         pi = rpmtsiFree(pi);
1447         if (progress) {
1448             NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
1449                         NULL, ts->notifyData));
1450         }
1451     }
1452
1453     /* ===============================================
1454      * Install and remove packages.
1455      */
1456     lastFailKey = (alKey)-2;    /* erased packages have -1 */
1457     pi = rpmtsiInit(ts);
1458     /*@-branchstate@*/ /* FIX: fi reload needs work */
1459     while ((p = rpmtsiNext(pi, 0)) != NULL) {
1460         alKey pkgKey;
1461         int gotfd;
1462
1463         (void) rpmdbCheckSignals();
1464
1465         gotfd = 0;
1466         if ((fi = rpmtsiFi(pi)) == NULL)
1467             continue;   /* XXX can't happen */
1468         
1469         psm = rpmpsmNew(ts, p, fi);
1470 assert(psm != NULL);
1471         psm->unorderedSuccessor =
1472                 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
1473
1474         switch (rpmteType(p)) {
1475         case TR_ADDED:
1476             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
1477
1478             pkgKey = rpmteAddedKey(p);
1479
1480             rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1481             p->h = NULL;
1482             /*@-type@*/ /* FIX: rpmte not opaque */
1483             {
1484                 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1485                 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1486                                 rpmteKey(p), ts->notifyData);
1487                 /*@=noeffectuncon@*/
1488                 if (rpmteFd(p) != NULL) {
1489                     rpmVSFlags ovsflags = rpmtsVSFlags(ts);
1490                     rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
1491                     rpmRC rpmrc;
1492
1493                     ovsflags = rpmtsSetVSFlags(ts, vsflags);
1494                     rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1495                                 rpmteNEVR(p), &p->h);
1496                     vsflags = rpmtsSetVSFlags(ts, ovsflags);
1497
1498                     switch (rpmrc) {
1499                     default:
1500                         /*@-noeffectuncon@*/ /* FIX: notify annotations */
1501                         p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
1502                                         0, 0,
1503                                         rpmteKey(p), ts->notifyData);
1504                         /*@=noeffectuncon@*/
1505                         p->fd = NULL;
1506                         ourrc++;
1507                         /*@innerbreak@*/ break;
1508                     case RPMRC_NOTTRUSTED:
1509                     case RPMRC_NOKEY:
1510                     case RPMRC_OK:
1511                         /*@innerbreak@*/ break;
1512                     }
1513                     if (rpmteFd(p) != NULL) gotfd = 1;
1514                 }
1515             }
1516             /*@=type@*/
1517
1518             if (rpmteFd(p) != NULL) {
1519                 /*
1520                  * XXX Sludge necessary to tranfer existing fstates/actions
1521                  * XXX around a recreated file info set.
1522                  */
1523                 psm->fi = rpmfiFree(psm->fi);
1524                 {
1525                     char * fstates = fi->fstates;
1526                     fileAction * actions = fi->actions;
1527                     rpmte savep;
1528
1529                     fi->fstates = NULL;
1530                     fi->actions = NULL;
1531 /*@-nullstate@*/ /* FIX: fi->actions is NULL */
1532                     fi = rpmfiFree(fi);
1533 /*@=nullstate@*/
1534
1535                     savep = rpmtsSetRelocateElement(ts, p);
1536                     fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
1537                     (void) rpmtsSetRelocateElement(ts, savep);
1538
1539                     if (fi != NULL) {   /* XXX can't happen */
1540                         fi->te = p;
1541                         fi->fstates = _free(fi->fstates);
1542                         fi->fstates = fstates;
1543                         fi->actions = _free(fi->actions);
1544                         fi->actions = actions;
1545                         p->fi = fi;
1546                     }
1547                 }
1548                 psm->fi = rpmfiLink(p->fi, NULL);
1549
1550 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1551                 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
1552                     ourrc++;
1553                     lastFailKey = pkgKey;
1554                 }
1555 /*@=nullstate@*/
1556             } else {
1557                 ourrc++;
1558                 lastFailKey = pkgKey;
1559             }
1560
1561             if (gotfd) {
1562                 /*@-noeffectuncon @*/ /* FIX: check rc */
1563                 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1564                         rpmteKey(p), ts->notifyData);
1565                 /*@=noeffectuncon @*/
1566                 /*@-type@*/
1567                 p->fd = NULL;
1568                 /*@=type@*/
1569             }
1570
1571             p->h = headerFree(p->h);
1572
1573             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
1574
1575             /*@switchbreak@*/ break;
1576
1577         case TR_REMOVED:
1578             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
1579
1580             rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1581             /*
1582              * XXX This has always been a hack, now mostly broken.
1583              * If install failed, then we shouldn't erase.
1584              */
1585             if (rpmteDependsOnKey(p) != lastFailKey) {
1586                 if (rpmpsmStage(psm, PSM_PKGERASE))
1587                     ourrc++;
1588             }
1589
1590             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
1591
1592             /*@switchbreak@*/ break;
1593         }
1594         xx = rpmdbSync(rpmtsGetRdb(ts));
1595
1596 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1597         psm = rpmpsmFree(psm);
1598 /*@=nullstate@*/
1599
1600 /*@-type@*/ /* FIX: p is almost opaque */
1601         p->fi = rpmfiFree(p->fi);
1602 /*@=type@*/
1603
1604     }
1605     /*@=branchstate@*/
1606     pi = rpmtsiFree(pi);
1607
1608     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1609     if (ourrc)
1610         return -1;
1611     else
1612         return 0;
1613     /*@=nullstate@*/
1614 }