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