- no-brainer refcounts for rpmDepSet and rpmFNSet objects.
[platform/upstream/rpm.git] / lib / transaction.c
1 /** \ingroup rpmtrans
2  * \file lib/transaction.c
3  */
4
5 #include "system.h"
6
7 #define _NEED_TEITERATOR        1
8 #include "psm.h"
9 #include "rpmds.h"
10
11 #include "rpmal.h"
12 #include <rpmmacro.h>   /* XXX for rpmExpand */
13
14 #include "fprint.h"
15 #include "legacy.h"     /* XXX mdfile */
16 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
17 #include "rpmdb.h"
18
19 /*@-redecl -exportheadervar@*/
20 /*@unchecked@*/
21 extern const char * chroot_prefix;
22 /*@=redecl =exportheadervar@*/
23
24 /* XXX FIXME: merge with existing (broken?) tests in system.h */
25 /* portability fiddles */
26 #if STATFS_IN_SYS_STATVFS
27 /*@-incondefs@*/
28 # include <sys/statvfs.h>
29 #if defined(__LCLINT__)
30 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
31 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
32         /*@globals fileSystem @*/
33         /*@modifies *buf, fileSystem @*/;
34 /*@=declundef =exportheader =protoparammatch @*/
35 /*@=incondefs@*/
36 #endif
37 #else
38 # if STATFS_IN_SYS_VFS
39 #  include <sys/vfs.h>
40 # else
41 #  if STATFS_IN_SYS_MOUNT
42 #   include <sys/mount.h>
43 #  else
44 #   if STATFS_IN_SYS_STATFS
45 #    include <sys/statfs.h>
46 #   endif
47 #  endif
48 # endif
49 #endif
50
51 #include "debug.h"
52
53 /*@access FD_t @*/              /* XXX compared with NULL */
54 /*@access Header @*/            /* XXX compared with NULL */
55 /*@access rpmProblemSet @*/     /* XXX need rpmProblemSetOK() */
56 /*@access dbiIndexSet @*/
57 /*@access rpmdb @*/
58
59 /*@access PSM_t @*/
60
61 /*@access alKey @*/
62 /*@access fnpyKey @*/
63
64 /*@access rpmFNSet @*/
65 /*@access TFI_t @*/
66
67 /*@access teIterator @*/
68 /*@access transactionElement @*/
69 /*@access rpmTransactionSet @*/
70
71 /**
72  */
73 struct diskspaceInfo {
74     dev_t dev;                  /*!< file system device number. */
75     signed long bneeded;        /*!< no. of blocks needed. */
76     signed long ineeded;        /*!< no. of inodes needed. */
77     int bsize;                  /*!< file system block size. */
78     signed long bavail;         /*!< no. of blocks available. */
79     signed long iavail;         /*!< no. of inodes available. */
80 };
81
82 /**
83  * Adjust for root only reserved space. On linux e2fs, this is 5%.
84  */
85 #define adj_fs_blocks(_nb)      (((_nb) * 21) / 20)
86
87 /* argon thought a shift optimization here was a waste of time...  he's
88    probably right :-( */
89 #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
90
91 /**
92  */
93 static /*@null@*/ void * freeFl(rpmTransactionSet ts,
94                 /*@only@*/ /*@null@*/ TFI_t flList)
95         /*@*/
96 {
97     if (flList) {
98         TFI_t fi;
99         int oc;
100
101         /*@-usereleased -onlytrans @*/ /* FIX: fi needs to be only */
102         for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
103             freeFi(fi);
104         flList = _free(flList);
105         /*@=usereleased =onlytrans @*/
106     }
107     return NULL;
108 }
109
110 void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
111 {
112     /*@-type@*/ /* FIX: cast? */
113     ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
114     /*@=type@*/
115 }
116
117 int rpmtransGetKeys(const rpmTransactionSet ts, fnpyKey ** ep, int * nep)
118 {
119     int rc = 0;
120
121     if (nep) *nep = ts->orderCount;
122     if (ep) {
123         fnpyKey * e;
124         int oc;
125
126         *ep = e = xmalloc(ts->orderCount * sizeof(*e));
127         for (oc = 0; oc < ts->orderCount; oc++, e++) {
128             switch (ts->order[oc].type) {
129             case TR_ADDED:
130                 *e = ts->order[oc].key;
131                 /*@switchbreak@*/ break;
132             default:
133             case TR_REMOVED:
134                 /*@-mods@*/     /* FIX: double indirection. */
135                 *e = NULL;
136                 /*@=mods@*/
137                 /*@switchbreak@*/ break;
138             }
139         }
140     }
141     return rc;
142 }
143
144 /**
145  */
146 static int archOkay(Header h, /*@out@*/ const char ** pkgArchPtr)
147         /*@modifies *pkgArchPtr @*/
148 {
149     const char * pkgArch;
150     int type, count;
151     int rc = 1; /* assume AOK */
152
153     if (pkgArchPtr != NULL) *pkgArchPtr = pkgArch = NULL;
154
155     /* make sure we're trying to install this on the proper architecture */
156     (void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
157
158 #ifdef  DYING
159     if (type == RPM_INT8_TYPE) {
160         int_8 * pkgArchNum;
161         int archNum;
162
163         /* old arch handling */
164         rpmGetArchInfo(NULL, &archNum);
165         pkgArchNum = pkgArch;
166         if (archNum != *pkgArchNum)
167             rc = 0;
168     } else
169 #endif
170
171     if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
172         rc = 0;
173         if (pkgArchPtr != NULL) *pkgArchPtr = pkgArch;
174     }
175
176     return rc;
177 }
178
179 /**
180  */
181 static int osOkay(Header h, /*@out@*/ const char ** pkgOsPtr)
182         /*@modifies *pkgOsPtr @*/
183 {
184     const char * pkgOs;
185     int type, count;
186     int rc = 1; /* assume AOK */
187
188     if (pkgOsPtr != NULL) *pkgOsPtr = pkgOs = NULL;
189
190     /* make sure we're trying to install this on the proper os */
191     (void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
192
193 #ifdef  DYING
194     if (type == RPM_INT8_TYPE) {
195         /* v1 packages and v2 packages both used improper OS numbers, so just
196            deal with it hope things work */
197         return 1;
198     } else
199 #endif
200
201     if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
202         rc = 0;
203         if (pkgOsPtr != NULL) *pkgOsPtr = pkgOs;
204     }
205
206     return rc;
207 }
208
209 /**
210  */
211 static int sharedCmp(const void * one, const void * two)
212         /*@*/
213 {
214     const struct sharedFileInfo * a = one;
215     const struct sharedFileInfo * b = two;
216
217     if (a->otherPkg < b->otherPkg)
218         return -1;
219     else if (a->otherPkg > b->otherPkg)
220         return 1;
221
222     return 0;
223 }
224
225 /**
226  */
227 static fileAction decideFileFate(const char * dirName,
228                         const char * baseName, short dbMode,
229                         const char * dbMd5, const char * dbLink, short newMode,
230                         const char * newMd5, const char * newLink, int newFlags,
231                         rpmtransFlags transFlags)
232         /*@globals fileSystem @*/
233         /*@modifies fileSystem @*/
234 {
235     char buffer[1024];
236     const char * dbAttr, * newAttr;
237     fileTypes dbWhat, newWhat, diskWhat;
238     struct stat sb;
239     int i, rc;
240     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
241     char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
242
243     (void) stpcpy( stpcpy(filespec, dirName), baseName);
244
245     if (lstat(filespec, &sb)) {
246         /*
247          * The file doesn't exist on the disk. Create it unless the new
248          * package has marked it as missingok, or allfiles is requested.
249          */
250         if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
251            (newFlags & RPMFILE_MISSINGOK)) {
252             rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
253                         filespec);
254             return FA_SKIP;
255         } else {
256             return FA_CREATE;
257         }
258     }
259
260     diskWhat = whatis(sb.st_mode);
261     dbWhat = whatis(dbMode);
262     newWhat = whatis(newMode);
263
264     /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
265        them in older packages as well */
266     if (newWhat == XDIR) {
267         return FA_CREATE;
268     }
269
270     if (diskWhat != newWhat) {
271         return save;
272     } else if (newWhat != dbWhat && diskWhat != dbWhat) {
273         return save;
274     } else if (dbWhat != newWhat) {
275         return FA_CREATE;
276     } else if (dbWhat != LINK && dbWhat != REG) {
277         return FA_CREATE;
278     }
279
280     if (dbWhat == REG) {
281         rc = mdfile(filespec, buffer);
282
283         if (rc) {
284             /* assume the file has been removed, don't freak */
285             return FA_CREATE;
286         }
287         dbAttr = dbMd5;
288         newAttr = newMd5;
289     } else /* dbWhat == LINK */ {
290         memset(buffer, 0, sizeof(buffer));
291         i = readlink(filespec, buffer, sizeof(buffer) - 1);
292         if (i == -1) {
293             /* assume the file has been removed, don't freak */
294             return FA_CREATE;
295         }
296         dbAttr = dbLink;
297         newAttr = newLink;
298      }
299
300     /* this order matters - we'd prefer to CREATE the file if at all
301        possible in case something else (like the timestamp) has changed */
302
303     if (!strcmp(dbAttr, buffer)) {
304         /* this config file has never been modified, so just replace it */
305         return FA_CREATE;
306     }
307
308     if (!strcmp(dbAttr, newAttr)) {
309         /* this file is the same in all versions of this package */
310         return FA_SKIP;
311     }
312
313     /*
314      * The config file on the disk has been modified, but
315      * the ones in the two packages are different. It would
316      * be nice if RPM was smart enough to at least try and
317      * merge the difference ala CVS, but...
318      */
319     return save;
320 }
321
322 /**
323  */
324 static int filecmp(short mode1, const char * md51, const char * link1,
325                    short mode2, const char * md52, const char * link2)
326         /*@*/
327 {
328     fileTypes what1 = whatis(mode1);
329     fileTypes what2 = whatis(mode2);
330
331     if (what1 != what2) return 1;
332
333     if (what1 == LINK)
334         return strcmp(link1, link2);
335     else if (what1 == REG)
336         return strcmp(md51, md52);
337
338     return 0;
339 }
340
341 /**
342  */
343 /* XXX only ts->{probs,rpmdb} modified */
344 static int handleInstInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
345                 struct sharedFileInfo * shared,
346                 int sharedCount, int reportConflicts)
347         /*@globals fileSystem @*/
348         /*@modifies ts, fi, fileSystem @*/
349 {
350     HGE_t hge = fi->hge;
351     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
352     rpmtransFlags transFlags = ts->transFlags;
353     rpmTagType oltype, omtype;
354     Header h;
355     int i;
356     const char ** otherMd5s;
357     const char ** otherLinks;
358     const char * otherStates;
359     uint_32 * otherFlags;
360     uint_32 * otherSizes;
361     uint_16 * otherModes;
362     int numReplaced = 0;
363     int xx;
364
365     rpmdbMatchIterator mi;
366
367     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
368                         &shared->otherPkg, sizeof(shared->otherPkg));
369     h = rpmdbNextIterator(mi);
370     if (h == NULL) {
371         mi = rpmdbFreeIterator(mi);
372         return 1;
373     }
374
375     xx = hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
376     xx = hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
377     xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
378     xx = hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
379     xx = hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
380     xx = hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
381
382     fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
383
384     for (i = 0; i < sharedCount; i++, shared++) {
385         int otherFileNum, fileNum;
386         otherFileNum = shared->otherFileNum;
387         fileNum = shared->pkgFileNum;
388
389         /* XXX another tedious segfault, assume file state normal. */
390         if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
391             continue;
392
393         if (XFA_SKIPPING(fi->actions[fileNum]))
394             continue;
395
396         if (filecmp(otherModes[otherFileNum],
397                         otherMd5s[otherFileNum],
398                         otherLinks[otherFileNum],
399                         fi->fmodes[fileNum],
400                         fi->fmd5s[fileNum],
401                         fi->flinks[fileNum])) {
402             /*@-compdef@*/ /* FIX: *fi->replaced undefined */
403             if (reportConflicts) {
404                 const char * pkgNEVR = fiGetNEVR(fi);
405                 const char * altNEVR = hGetNEVR(h, NULL);
406                 rpmProblemSetAppend(ts->probs, RPMPROB_FILE_CONFLICT,
407                         pkgNEVR, fi->key,
408                         fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum],
409                         altNEVR,
410                         0);
411                 pkgNEVR = _free(pkgNEVR);
412                 altNEVR = _free(altNEVR);
413             }
414             /*@=compdef@*/
415             if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
416                         & RPMFILE_CONFIG) {
417                 /*@-assignexpose@*/
418                 if (!shared->isRemoved)
419                     fi->replaced[numReplaced++] = *shared;
420                 /*@=assignexpose@*/
421             }
422         }
423
424         if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
425             fi->actions[fileNum] = decideFileFate(
426                         fi->dnl[fi->dil[fileNum]],
427                         fi->bnl[fileNum],
428                         otherModes[otherFileNum],
429                         otherMd5s[otherFileNum],
430                         otherLinks[otherFileNum],
431                         fi->fmodes[fileNum],
432                         fi->fmd5s[fileNum],
433                         fi->flinks[fileNum],
434                         fi->fflags[fileNum],
435                         transFlags);
436         }
437
438         fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
439     }
440
441     otherMd5s = hfd(otherMd5s, omtype);
442     otherLinks = hfd(otherLinks, oltype);
443     mi = rpmdbFreeIterator(mi);
444
445     fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
446                            sizeof(*fi->replaced) * (numReplaced + 1));
447     fi->replaced[numReplaced].otherPkg = 0;
448
449     return 0;
450 }
451
452 /**
453  */
454 /* XXX only ts->rpmdb modified */
455 static int handleRmvdInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
456                 struct sharedFileInfo * shared, int sharedCount)
457         /*@globals fileSystem @*/
458         /*@modifies fi, fileSystem @*/
459 {
460     HGE_t hge = fi->hge;
461     Header h;
462     const char * otherStates;
463     int i, xx;
464    
465     rpmdbMatchIterator mi;
466
467     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
468                         &shared->otherPkg, sizeof(shared->otherPkg));
469     h = rpmdbNextIterator(mi);
470     if (h == NULL) {
471         mi = rpmdbFreeIterator(mi);
472         return 1;
473     }
474
475     xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
476
477     for (i = 0; i < sharedCount; i++, shared++) {
478         int otherFileNum, fileNum;
479         otherFileNum = shared->otherFileNum;
480         fileNum = shared->pkgFileNum;
481
482         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
483             continue;
484
485         fi->actions[fileNum] = FA_SKIP;
486     }
487
488     mi = rpmdbFreeIterator(mi);
489
490     return 0;
491 }
492
493 /**
494  * Update disk space needs on each partition for this package.
495  */
496 /* XXX only ts->{probs,di} modified */
497 static void handleOverlappedFiles(const rpmTransactionSet ts, TFI_t fi)
498         /*@globals fileSystem @*/
499         /*@modifies ts, fi, fileSystem @*/
500 {
501     struct diskspaceInfo * ds = NULL;
502     uint_32 fixupSize = 0;
503     char * filespec = NULL;
504     int fileSpecAlloced = 0;
505     int i, j;
506   
507     for (i = 0; i < fi->fc; i++) {
508         int otherPkgNum, otherFileNum;
509         const TFI_t * recs;
510         int numRecs;
511
512         if (XFA_SKIPPING(fi->actions[i]))
513             continue;
514
515         j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
516         /*@-branchstate@*/
517         if (j > fileSpecAlloced) {
518             fileSpecAlloced = j * 2;
519             filespec = xrealloc(filespec, fileSpecAlloced);
520         }
521         /*@=branchstate@*/
522
523         (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
524
525         if (ts->di) {
526             ds = ts->di;
527             while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
528             if (!ds->bsize) ds = NULL;
529             fixupSize = 0;
530         }
531
532         /*
533          * Retrieve all records that apply to this file. Note that the
534          * file info records were built in the same order as the packages
535          * will be installed and removed so the records for an overlapped
536          * files will be sorted in exactly the same order.
537          */
538         (void) htGetEntry(ts->ht, &fi->fps[i],
539                         (const void ***) &recs, &numRecs, NULL);
540
541         /*
542          * If this package is being added, look only at other packages
543          * being added -- removed packages dance to a different tune.
544          * If both this and the other package are being added, overlapped
545          * files must be identical (or marked as a conflict). The
546          * disposition of already installed config files leads to
547          * a small amount of extra complexity.
548          *
549          * If this package is being removed, then there are two cases that
550          * need to be worried about:
551          * If the other package is being added, then skip any overlapped files
552          * so that this package removal doesn't nuke the overlapped files
553          * that were just installed.
554          * If both this and the other package are being removed, then each
555          * file removal from preceding packages needs to be skipped so that
556          * the file removal occurs only on the last occurence of an overlapped
557          * file in the transaction set.
558          *
559          */
560
561         /* Locate this overlapped file in the set of added/removed packages. */
562         for (j = 0; j < numRecs && recs[j] != fi; j++)
563             {};
564
565         /* Find what the previous disposition of this file was. */
566         otherFileNum = -1;                      /* keep gcc quiet */
567         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
568             /* Added packages need only look at other added packages. */
569             if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
570                 /*@innercontinue@*/ continue;
571
572             /* TESTME: there are more efficient searches in the world... */
573             for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
574                  otherFileNum++) {
575
576                 /* If the addresses are the same, so are the values. */
577                 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
578                     /*@innerbreak@*/ break;
579
580                 /* Otherwise, compare fingerprints by value. */
581                 /*@-nullpass@*/ /* LCL: looks good to me */
582                 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
583                     /*@innerbreak@*/ break;
584                 /*@=nullpass@*/
585
586             }
587             /* XXX is this test still necessary? */
588             if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
589                 /*@innerbreak@*/ break;
590         }
591
592         switch (fi->type) {
593         case TR_ADDED:
594           { struct stat sb;
595             if (otherPkgNum < 0) {
596                 /* XXX is this test still necessary? */
597                 if (fi->actions[i] != FA_UNKNOWN)
598                     /*@switchbreak@*/ break;
599                 if ((fi->fflags[i] & RPMFILE_CONFIG) && 
600                         !lstat(filespec, &sb)) {
601                     /* Here is a non-overlapped pre-existing config file. */
602                     fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
603                         ? FA_ALTNAME : FA_BACKUP;
604                 } else {
605                     fi->actions[i] = FA_CREATE;
606                 }
607                 /*@switchbreak@*/ break;
608             }
609
610             /* Mark added overlapped non-identical files as a conflict. */
611             if ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
612              && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
613                         recs[otherPkgNum]->fmd5s[otherFileNum],
614                         recs[otherPkgNum]->flinks[otherFileNum],
615                         fi->fmodes[i],
616                         fi->fmd5s[i],
617                         fi->flinks[i]))
618             {
619                 const char * pkgNEVR = fiGetNEVR(fi);
620                 const char * altNEVR = fiGetNEVR(recs[otherPkgNum]);
621                 rpmProblemSetAppend(ts->probs, RPMPROB_NEW_FILE_CONFLICT,
622                         pkgNEVR, fi->key,
623                         filespec, NULL,
624                         altNEVR,
625                         0);
626                 pkgNEVR = _free(pkgNEVR);
627                 altNEVR = _free(altNEVR);
628             }
629
630             /* Try to get the disk accounting correct even if a conflict. */
631             fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
632
633             if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
634                 /* Here is an overlapped  pre-existing config file. */
635                 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
636                         ? FA_ALTNAME : FA_SKIP;
637             } else {
638                 fi->actions[i] = FA_CREATE;
639             }
640           } /*@switchbreak@*/ break;
641         case TR_REMOVED:
642             if (otherPkgNum >= 0) {
643                 /* Here is an overlapped added file we don't want to nuke. */
644                 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
645                     /* On updates, don't remove files. */
646                     fi->actions[i] = FA_SKIP;
647                     /*@switchbreak@*/ break;
648                 }
649                 /* Here is an overlapped removed file: skip in previous. */
650                 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
651             }
652             if (XFA_SKIPPING(fi->actions[i]))
653                 /*@switchbreak@*/ break;
654             if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
655                 /*@switchbreak@*/ break;
656             if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
657                 fi->actions[i] = FA_ERASE;
658                 /*@switchbreak@*/ break;
659             }
660                 
661             /* Here is a pre-existing modified config file that needs saving. */
662             {   char mdsum[50];
663                 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
664                     fi->actions[i] = FA_BACKUP;
665                     /*@switchbreak@*/ break;
666                 }
667             }
668             fi->actions[i] = FA_ERASE;
669             /*@switchbreak@*/ break;
670         }
671
672         if (ds) {
673             uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
674
675             switch (fi->actions[i]) {
676               case FA_BACKUP:
677               case FA_SAVE:
678               case FA_ALTNAME:
679                 ds->ineeded++;
680                 ds->bneeded += s;
681                 /*@switchbreak@*/ break;
682
683             /*
684              * FIXME: If two packages share a file (same md5sum), and
685              * that file is being replaced on disk, will ds->bneeded get
686              * decremented twice? Quite probably!
687              */
688               case FA_CREATE:
689                 ds->bneeded += s;
690                 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
691                 /*@switchbreak@*/ break;
692
693               case FA_ERASE:
694                 ds->ineeded--;
695                 ds->bneeded -= s;
696                 /*@switchbreak@*/ break;
697
698               default:
699                 /*@switchbreak@*/ break;
700             }
701
702             ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
703         }
704     }
705     filespec = _free(filespec);
706 }
707
708 /**
709  */
710 static int ensureOlder(rpmTransactionSet ts,
711                 const Header h, /*@null@*/ const Header old,
712                 /*@dependent@*/ /*@null@*/ const void * key)
713         /*@modifies ts @*/
714 {
715     int result, rc = 0;
716
717     if (old == NULL) return 1;
718
719     result = rpmVersionCompare(old, h);
720     if (result <= 0)
721         rc = 0;
722     else if (result > 0) {
723         const char * pkgNEVR = hGetNEVR(h, NULL);
724         const char * altNEVR = hGetNEVR(old, NULL);
725         /*@-evalorder@*/ /* LCL: is confused */
726         rpmProblemSetAppend(ts->probs, RPMPROB_OLDPACKAGE,
727                 pkgNEVR, key,
728                 NULL, NULL,
729                 altNEVR,
730                 0);
731         /*@=evalorder@*/
732         pkgNEVR = _free(pkgNEVR);
733         altNEVR = _free(altNEVR);
734         rc = 1;
735     }
736
737     return rc;
738 }
739
740 /**
741  */
742 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
743         /*@globals rpmGlobalMacroContext @*/
744         /*@modifies fi, rpmGlobalMacroContext @*/
745 {
746     int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
747     char ** netsharedPaths = NULL;
748     const char ** languages;
749     const char * dn, * bn;
750     int dnlen, bnlen, ix;
751     const char * s;
752     int * drc;
753     char * dff;
754     int i, j;
755
756     if (!noDocs)
757         noDocs = rpmExpandNumeric("%{_excludedocs}");
758
759     {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
760         /*@-branchstate@*/
761         if (tmpPath && *tmpPath != '%')
762             netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
763         /*@=branchstate@*/
764         tmpPath = _free(tmpPath);
765     }
766
767     s = rpmExpand("%{_install_langs}", NULL);
768     /*@-branchstate@*/
769     if (!(s && *s != '%'))
770         s = _free(s);
771     if (s) {
772         languages = (const char **) splitString(s, strlen(s), ':');
773         s = _free(s);
774     } else
775         languages = NULL;
776     /*@=branchstate@*/
777
778     /* Compute directory refcount, skip directory if now empty. */
779     drc = alloca(fi->dc * sizeof(*drc));
780     memset(drc, 0, fi->dc * sizeof(*drc));
781     dff = alloca(fi->dc * sizeof(*dff));
782     memset(dff, 0, fi->dc * sizeof(*dff));
783
784     for (i = 0; i < fi->fc; i++) {
785         char **nsp;
786
787         bn = fi->bnl[i];
788         bnlen = strlen(bn);
789         ix = fi->dil[i];
790         dn = fi->dnl[ix];
791         dnlen = strlen(dn);
792
793         drc[ix]++;
794
795         /* Don't bother with skipped files */
796         if (XFA_SKIPPING(fi->actions[i])) {
797             drc[ix]--;
798             continue;
799         }
800
801         /*
802          * Skip net shared paths.
803          * Net shared paths are not relative to the current root (though
804          * they do need to take package relocations into account).
805          */
806         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
807             int len;
808
809             len = strlen(*nsp);
810             if (dnlen >= len) {
811                 if (strncmp(dn, *nsp, len))
812                     /*@innercontinue@*/ continue;
813                 /* Only directories or complete file paths can be net shared */
814                 if (!(dn[len] == '/' || dn[len] == '\0'))
815                     /*@innercontinue@*/ continue;
816             } else {
817                 if (len < (dnlen + bnlen))
818                     /*@innercontinue@*/ continue;
819                 if (strncmp(dn, *nsp, dnlen))
820                     /*@innercontinue@*/ continue;
821                 if (strncmp(bn, (*nsp) + dnlen, bnlen))
822                     /*@innercontinue@*/ continue;
823                 len = dnlen + bnlen;
824                 /* Only directories or complete file paths can be net shared */
825                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
826                     /*@innercontinue@*/ continue;
827             }
828
829             /*@innerbreak@*/ break;
830         }
831
832         if (nsp && *nsp) {
833             drc[ix]--;  dff[ix] = 1;
834             fi->actions[i] = FA_SKIPNETSHARED;
835             continue;
836         }
837
838         /*
839          * Skip i18n language specific files.
840          */
841         if (fi->flangs && languages && *fi->flangs[i]) {
842             const char **lang, *l, *le;
843             for (lang = languages; *lang != NULL; lang++) {
844                 if (!strcmp(*lang, "all"))
845                     /*@innerbreak@*/ break;
846                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
847                     for (le = l; *le != '\0' && *le != '|'; le++)
848                         {};
849                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
850                         /*@innerbreak@*/ break;
851                     if (*le == '|') le++;       /* skip over | */
852                 }
853                 if (*l != '\0')
854                     /*@innerbreak@*/ break;
855             }
856             if (*lang == NULL) {
857                 drc[ix]--;      dff[ix] = 1;
858                 fi->actions[i] = FA_SKIPNSTATE;
859                 continue;
860             }
861         }
862
863         /*
864          * Skip documentation if requested.
865          */
866         if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
867             drc[ix]--;  dff[ix] = 1;
868             fi->actions[i] = FA_SKIPNSTATE;
869             continue;
870         }
871     }
872
873     /* Skip (now empty) directories that had skipped files. */
874     for (j = 0; j < fi->dc; j++) {
875
876         if (drc[j]) continue;   /* dir still has files. */
877         if (!dff[j]) continue;  /* dir was not emptied here. */
878         
879         /* Find parent directory and basename. */
880         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
881         bn = dn + dnlen;        bnlen = 0;
882         while (bn > dn && bn[-1] != '/') {
883                 bnlen++;
884                 dnlen--;
885                 bn--;
886         }
887
888         /* If explicitly included in the package, skip the directory. */
889         for (i = 0; i < fi->fc; i++) {
890             const char * dir;
891
892             if (XFA_SKIPPING(fi->actions[i]))
893                 /*@innercontinue@*/ continue;
894             if (whatis(fi->fmodes[i]) != XDIR)
895                 /*@innercontinue@*/ continue;
896             dir = fi->dnl[fi->dil[i]];
897             if (strlen(dir) != dnlen)
898                 /*@innercontinue@*/ continue;
899             if (strncmp(dir, dn, dnlen))
900                 /*@innercontinue@*/ continue;
901             if (strlen(fi->bnl[i]) != bnlen)
902                 /*@innercontinue@*/ continue;
903             if (strncmp(fi->bnl[i], bn, bnlen))
904                 /*@innercontinue@*/ continue;
905             rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
906             fi->actions[i] = FA_SKIPNSTATE;
907             /*@innerbreak@*/ break;
908         }
909     }
910
911     if (netsharedPaths) freeSplitString(netsharedPaths);
912 #ifdef  DYING   /* XXX freeFi will deal with this later. */
913     fi->flangs = _free(fi->flangs);
914 #endif
915     if (languages) freeSplitString((char **)languages);
916 }
917
918 /**
919  * Return next transaction element's file info.
920  * @param tei           transaction element iterator
921  * @return              nest transaction element file info, NULL on termination
922  */
923 /*@unused@*/ static inline
924 TFI_t teNextFi(teIterator tei)
925         /*@modifies tei @*/
926 {
927     TFI_t fi = NULL;
928
929     if (teNextIterator(tei) != NULL && tei->ocsave != -1)
930         fi = tei->ts->flList + tei->ocsave;
931     /*@-compdef -onlytrans -usereleased@*/ /* FIX: ts->flList may be released */
932     return fi;
933     /*@=compdef =onlytrans =usereleased@*/
934 }
935
936 #define NOTIFY(_ts, _al)        if ((_ts)->notify) (void) (_ts)->notify _al
937
938 int rpmRunTransactions( rpmTransactionSet ts,
939                         rpmCallbackFunction notify, rpmCallbackData notifyData,
940                         rpmProblemSet okProbs, rpmProblemSet * newProbs,
941                         rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
942 {
943     int i, j;
944     int ourrc = 0;
945     int totalFileCount = 0;
946     TFI_t fi;
947     struct diskspaceInfo * dip;
948     struct sharedFileInfo * shared, * sharedList;
949     int numShared;
950     int nexti;
951     alKey pkgKey, lastKey;
952     int oc;
953     transactionElement p;
954     fingerPrintCache fpc;
955     struct psm_s psmbuf;
956     PSM_t psm = &psmbuf;
957     teIterator tei;
958     int xx;
959
960 int keep_header = 1;    /* XXX rpmProblemSetAppend prevents dumping headers. */
961
962     /* FIXME: what if the same package is included in ts twice? */
963
964     ts->transFlags = transFlags;
965     if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
966         ts->transFlags |= (_noTransScripts | _noTransTriggers);
967     if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
968         ts->transFlags |= _noTransTriggers;
969
970     /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
971     if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
972         ts->transFlags |= (_noTransScripts | _noTransTriggers);
973
974     ts->notify = notify;
975     ts->notifyData = notifyData;
976     /*@-assignexpose@*/
977     ts->probs = *newProbs = rpmProblemSetCreate();
978     *newProbs = rpmpsLink(ts->probs, "RunTransactions");
979     /*@=assignexpose@*/
980     ts->ignoreSet = ignoreSet;
981     ts->currDir = _free(ts->currDir);
982     ts->currDir = currentDirectory();
983     ts->chrootDone = 0;
984     if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
985     ts->id = (int_32) time(NULL);
986
987     memset(psm, 0, sizeof(*psm));
988     /*@-assignexpose@*/
989     psm->ts = rpmtsLink(ts, "tsRun");
990     /*@=assignexpose@*/
991
992     /* Get available space on mounted file systems. */
993     if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
994                 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
995         struct stat sb;
996
997         ts->di = _free(ts->di);
998         dip = ts->di = xcalloc((ts->filesystemCount + 1), sizeof(*ts->di));
999
1000         for (i = 0; (i < ts->filesystemCount) && dip; i++) {
1001 #if STATFS_IN_SYS_STATVFS
1002             struct statvfs sfb;
1003             memset(&sfb, 0, sizeof(sfb));
1004             if (statvfs(ts->filesystems[i], &sfb))
1005 #else
1006             struct statfs sfb;
1007 #  if STAT_STATFS4
1008 /* This platform has the 4-argument version of the statfs call.  The last two
1009  * should be the size of struct statfs and 0, respectively.  The 0 is the
1010  * filesystem type, and is always 0 when statfs is called on a mounted
1011  * filesystem, as we're doing.
1012  */
1013             memset(&sfb, 0, sizeof(sfb));
1014             if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
1015 #  else
1016             memset(&sfb, 0, sizeof(sfb));
1017             if (statfs(ts->filesystems[i], &sfb))
1018 #  endif
1019 #endif
1020             {
1021                 dip = NULL;
1022             } else {
1023                 ts->di[i].bsize = sfb.f_bsize;
1024                 ts->di[i].bneeded = 0;
1025                 ts->di[i].ineeded = 0;
1026 #ifdef STATFS_HAS_F_BAVAIL
1027                 ts->di[i].bavail = sfb.f_bavail;
1028 #else
1029 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1030  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
1031  * it's about all we can do.
1032  */
1033                 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
1034 #endif
1035                 /* XXX Avoid FAT and other file systems that have not inodes. */
1036                 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1037                                 ? sfb.f_ffree : -1;
1038
1039                 xx = stat(ts->filesystems[i], &sb);
1040                 ts->di[i].dev = sb.st_dev;
1041             }
1042         }
1043
1044         if (dip) ts->di[i].bsize = 0;
1045     }
1046
1047     /* ===============================================
1048      * For packages being installed:
1049      * - verify package arch/os.
1050      * - verify package epoch:version-release is newer.
1051      * - count files.
1052      * For packages being removed:
1053      * - count files.
1054      */
1055     /* The ordering doesn't matter here */
1056     tei = teInitIterator(ts);
1057     while ((p = teNext(tei, TR_ADDED)) != NULL) {
1058         const char * n, * v, * r;
1059         fnpyKey key;
1060         rpmdbMatchIterator mi;
1061         const char * str1;
1062         Header h;
1063
1064         pkgKey = p->u.addedKey;
1065
1066         h = alGetHeader(ts->addedPackages, pkgKey, 0);
1067         if (h == NULL)  /* XXX can't happen */
1068             continue;
1069
1070         (void) headerNVR(h, &n, &v, &r);
1071         key = p->key;
1072
1073         str1 = NULL;
1074         if (!archOkay(h, &str1) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH)) {
1075             const char * pkgNEVR = hGetNEVR(h, NULL);
1076             rpmProblemSetAppend(ts->probs, RPMPROB_BADARCH,
1077                         pkgNEVR, key,
1078                         str1, NULL,
1079                         NULL, 0);
1080             pkgNEVR = _free(pkgNEVR);
1081         }
1082
1083         str1 = NULL;
1084         if (!osOkay(h, &str1) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS)) {
1085             const char * pkgNEVR = hGetNEVR(h, NULL);
1086             rpmProblemSetAppend(ts->probs, RPMPROB_BADOS,
1087                         pkgNEVR, key,
1088                         str1, NULL,
1089                         NULL, 0);
1090             pkgNEVR = _free(pkgNEVR);
1091         }
1092
1093         if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
1094             Header oldH;
1095             mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1096             while ((oldH = rpmdbNextIterator(mi)) != NULL)
1097                 xx = ensureOlder(ts, h, oldH, key);
1098             mi = rpmdbFreeIterator(mi);
1099         }
1100
1101         /* XXX multilib should not display "already installed" problems */
1102         if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG)
1103 #ifdef DYING    /* XXX MULTILIB multiLib from transactionElement */
1104          && !alGetMultiLib(ts->addedPackages, i)
1105 #endif
1106         ) {
1107             mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1108             xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, v);
1109             xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, r);
1110
1111             while (rpmdbNextIterator(mi) != NULL) {
1112                 const char * pkgNEVR = hGetNEVR(h, NULL);
1113                 rpmProblemSetAppend(ts->probs, RPMPROB_PKG_INSTALLED,
1114                         pkgNEVR, key,
1115                         NULL, NULL,
1116                         NULL, 0);
1117                 pkgNEVR = _free(pkgNEVR);
1118                 /*@innerbreak@*/ break;
1119             }
1120             mi = rpmdbFreeIterator(mi);
1121         }
1122
1123         /* Count no. of files (if any). */
1124         if (p->fns != NULL)
1125             totalFileCount += p->fns->fc;
1126
1127         h = headerFree(h, "alGetHeader (rpmtsRun sanity)");
1128
1129     }
1130     tei = teFreeIterator(tei);
1131
1132     /* FIXME: it seems a bit silly to read in all of these headers twice */
1133     /* The ordering doesn't matter here */
1134     if (ts->numRemovedPackages > 0) {
1135         rpmdbMatchIterator mi;
1136         Header h;
1137         int fileCount;
1138
1139         mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
1140         xx = rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
1141         while ((h = rpmdbNextIterator(mi)) != NULL) {
1142             if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
1143                 totalFileCount += fileCount;
1144         }
1145         mi = rpmdbFreeIterator(mi);
1146     }
1147
1148     /* ===============================================
1149      * Initialize transaction element file info for package:
1150      */
1151     ts->flEntries = alGetSize(ts->addedPackages) + ts->numRemovedPackages;
1152     ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
1153
1154     /*
1155      * FIXME?: we'd be better off assembling one very large file list and
1156      * calling fpLookupList only once. I'm not sure that the speedup is
1157      * worth the trouble though.
1158      */
1159     tei = teInitIterator(ts);
1160     while ((fi = teNextFi(tei)) != NULL) {
1161
1162         oc = teGetOc(tei);
1163         fi->magic = TFIMAGIC;
1164
1165         fi->type = ts->order[oc].type;
1166
1167         /*@-branchstate@*/
1168         switch (fi->type) {
1169         case TR_ADDED:
1170             fi->record = 0;
1171
1172             pkgKey = ts->order[oc].u.addedKey;
1173
1174             fi->h = alGetHeader(ts->addedPackages, pkgKey, 1);
1175 #ifdef DYING    /* XXX MULTILIB multiLib from transactionElement */
1176             fi->multiLib = alGetMultiLib(ts->addedPackages, i);
1177 #else
1178             fi->multiLib = ts->order[oc].multiLib;
1179 #endif
1180
1181 /*@i@*/     fi->key = ts->order[oc].key;
1182             fi->relocs = ts->order[oc].relocs;
1183 /*@i@*/     fi->fd = ts->order[oc].fd;
1184
1185             /* XXX availablePackage can be dumped here XXX */
1186
1187             /* XXX header arg unused. */
1188             loadFi(ts, fi, fi->h, keep_header);
1189
1190             if (fi->fc == 0)
1191                 continue;
1192
1193             /* Skip netshared paths, not our i18n files, and excluded docs */
1194             skipFiles(ts, fi);
1195             /*@switchbreak@*/ break;
1196         case TR_REMOVED:
1197             fi->record = ts->order[oc].u.removed.dboffset;
1198             /* Retrieve erased package header from the database. */
1199             {   rpmdbMatchIterator mi;
1200
1201                 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
1202                                 &fi->record, sizeof(fi->record));
1203                 if ((fi->h = rpmdbNextIterator(mi)) != NULL)
1204                     fi->h = headerLink(fi->h,  "TR_REMOVED loadFi");
1205                 mi = rpmdbFreeIterator(mi);
1206             }
1207             if (fi->h == NULL) {
1208                 /* ACK! */
1209                 continue;
1210             }
1211             /* XXX header arg unused. */
1212             loadFi(ts, fi, fi->h, 0);
1213             /*@switchbreak@*/ break;
1214         }
1215         /*@=branchstate@*/
1216
1217         if (fi->fc)
1218             fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
1219     }
1220     tei = teFreeIterator(tei);
1221
1222     if (!ts->chrootDone) {
1223         xx = chdir("/");
1224         /*@-superuser -noeffect @*/
1225         xx = chroot(ts->rootDir);
1226         /*@=superuser =noeffect @*/
1227         ts->chrootDone = 1;
1228         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
1229         /*@-onlytrans@*/
1230         /*@-mods@*/
1231         chroot_prefix = ts->rootDir;
1232         /*@=mods@*/
1233         /*@=onlytrans@*/
1234     }
1235
1236     ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1237     fpc = fpCacheCreate(totalFileCount);
1238
1239     /* ===============================================
1240      * Add fingerprint for each file not skipped.
1241      */
1242     tei = teInitIterator(ts);
1243     while ((fi = teNextFi(tei)) != NULL) {
1244         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
1245         for (i = 0; i < fi->fc; i++) {
1246             if (XFA_SKIPPING(fi->actions[i]))
1247                 /*@innercontinue@*/ continue;
1248             /*@-dependenttrans@*/
1249             htAddEntry(ts->ht, fi->fps + i, fi);
1250             /*@=dependenttrans@*/
1251         }
1252     }
1253     tei = teFreeIterator(tei);
1254
1255     /*@-noeffectuncon @*/ /* FIX: check rc */
1256     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
1257         NULL, ts->notifyData));
1258     /*@=noeffectuncon@*/
1259
1260     /* ===============================================
1261      * Compute file disposition for each package in transaction set.
1262      */
1263     tei = teInitIterator(ts);
1264     while ((fi = teNextFi(tei)) != NULL) {
1265         dbiIndexSet * matches;
1266         int knownBad;
1267
1268         /*@-noeffectuncon @*/ /* FIX: check rc */
1269         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
1270                         ts->flEntries, NULL, ts->notifyData));
1271         /*@=noeffectuncon@*/
1272
1273         if (fi->fc == 0) continue;
1274
1275         /* Extract file info for all files in this package from the database. */
1276         matches = xcalloc(fi->fc, sizeof(*matches));
1277         if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc)) {
1278             psm->ts = rpmtsUnlink(ts, "tsRun (rpmFindFpList fail)");
1279             return 1;   /* XXX WTFO? */
1280         }
1281
1282         numShared = 0;
1283         for (i = 0; i < fi->fc; i++)
1284             numShared += dbiIndexSetCount(matches[i]);
1285
1286         /* Build sorted file info list for this package. */
1287         shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1288         for (i = 0; i < fi->fc; i++) {
1289             /*
1290              * Take care not to mark files as replaced in packages that will
1291              * have been removed before we will get here.
1292              */
1293             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1294                 int k, ro;
1295                 ro = dbiIndexRecordOffset(matches[i], j);
1296                 knownBad = 0;
1297                 for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
1298                     switch (ts->order[k].type) {
1299                     case TR_REMOVED:
1300                         if (ts->order[k].u.removed.dboffset == ro)
1301                             knownBad = ro;
1302                         /*@switchbreak@*/ break;
1303                     case TR_ADDED:
1304                         /*@switchbreak@*/ break;
1305                     }
1306                 }
1307
1308                 shared->pkgFileNum = i;
1309                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1310                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1311                 shared->isRemoved = (knownBad == ro);
1312                 shared++;
1313             }
1314             matches[i] = dbiFreeIndexSet(matches[i]);
1315         }
1316         numShared = shared - sharedList;
1317         shared->otherPkg = -1;
1318         matches = _free(matches);
1319
1320         /* Sort file info by other package index (otherPkg) */
1321         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1322
1323         /* For all files from this package that are in the database ... */
1324         for (i = 0; i < numShared; i = nexti) {
1325             int beingRemoved;
1326
1327             shared = sharedList + i;
1328
1329             /* Find the end of the files in the other package. */
1330             for (nexti = i + 1; nexti < numShared; nexti++) {
1331                 if (sharedList[nexti].otherPkg != shared->otherPkg)
1332                     /*@innerbreak@*/ break;
1333             }
1334
1335             /* Is this file from a package being removed? */
1336             beingRemoved = 0;
1337             for (j = 0; j < ts->numRemovedPackages; j++) {
1338                 if (ts->removedPackages[j] != shared->otherPkg)
1339                     /*@innercontinue@*/ continue;
1340                 beingRemoved = 1;
1341                 /*@innerbreak@*/ break;
1342             }
1343
1344             /* Determine the fate of each file. */
1345             switch (fi->type) {
1346             case TR_ADDED:
1347                 xx = handleInstInstalledFiles(ts, fi, shared, nexti - i,
1348         !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)));
1349                 /*@switchbreak@*/ break;
1350             case TR_REMOVED:
1351                 if (!beingRemoved)
1352                     xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1353                 /*@switchbreak@*/ break;
1354             }
1355         }
1356
1357         free(sharedList);
1358
1359         /* Update disk space needs on each partition for this package. */
1360         handleOverlappedFiles(ts, fi);
1361
1362         /* Check added package has sufficient space on each partition used. */
1363         switch (fi->type) {
1364         case TR_ADDED:
1365             if (!(ts->di && fi->fc))
1366                 /*@switchbreak@*/ break;
1367             for (i = 0; i < ts->filesystemCount; i++) {
1368
1369                 dip = ts->di + i;
1370
1371                 /* XXX Avoid FAT and other file systems that have not inodes. */
1372                 if (dip->iavail <= 0)
1373                     /*@innercontinue@*/ continue;
1374
1375                 if (adj_fs_blocks(dip->bneeded) > dip->bavail) {
1376                     const char * pkgNEVR = fiGetNEVR(fi);
1377                     rpmProblemSetAppend(ts->probs, RPMPROB_DISKSPACE,
1378                                 pkgNEVR, fi->key,
1379                                 ts->filesystems[i], NULL, NULL,
1380                    (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
1381                     pkgNEVR = _free(pkgNEVR);
1382                 }
1383
1384                 if (adj_fs_blocks(dip->ineeded) > dip->iavail) {
1385                     const char * pkgNEVR = fiGetNEVR(fi);
1386                     rpmProblemSetAppend(ts->probs, RPMPROB_DISKNODES,
1387                                 pkgNEVR, fi->key,
1388                                 ts->filesystems[i], NULL, NULL,
1389                     (adj_fs_blocks(dip->ineeded) - dip->iavail));
1390                     pkgNEVR = _free(pkgNEVR);
1391                 }
1392             }
1393             /*@switchbreak@*/ break;
1394         case TR_REMOVED:
1395             /*@switchbreak@*/ break;
1396         }
1397     }
1398     tei = teFreeIterator(tei);
1399
1400     if (ts->chrootDone) {
1401         /*@-superuser -noeffect @*/
1402         xx = chroot(".");
1403         /*@=superuser =noeffect @*/
1404         ts->chrootDone = 0;
1405         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
1406         /*@-mods@*/
1407         chroot_prefix = NULL;
1408         /*@=mods@*/
1409         xx = chdir(ts->currDir);
1410     }
1411
1412     /*@-noeffectuncon @*/ /* FIX: check rc */
1413     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
1414         NULL, ts->notifyData));
1415     /*@=noeffectuncon @*/
1416
1417     /* ===============================================
1418      * Free unused memory as soon as possible.
1419      */
1420
1421     tei = teInitIterator(ts);
1422     while ((fi = teNextFi(tei)) != NULL) {
1423         if (fi->fc == 0)
1424             continue;
1425         fi->fps = _free(fi->fps);
1426     }
1427     tei = teFreeIterator(tei);
1428
1429     fpCacheFree(fpc);
1430     htFree(ts->ht);
1431     ts->ht = NULL;
1432
1433     /* ===============================================
1434      * If unfiltered problems exist, free memory and return.
1435      */
1436     if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS)
1437      || (ts->probs->numProblems &&
1438                 (okProbs != NULL || rpmProblemSetTrim(ts->probs, okProbs)))
1439        )
1440     {
1441         ts->flList = freeFl(ts, ts->flList);
1442         ts->flEntries = 0;
1443         if (psm->ts != NULL)
1444             psm->ts = rpmtsUnlink(psm->ts, "tsRun (problems)");
1445         /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1446         return ts->orderCount;
1447         /*@=nullstate@*/
1448     }
1449
1450     /* ===============================================
1451      * Save removed files before erasing.
1452      */
1453     if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1454         tei = teInitIterator(ts);
1455         while ((fi = teNextFi(tei)) != NULL) {
1456             switch (fi->type) {
1457             case TR_ADDED:
1458                 /*@switchbreak@*/ break;
1459             case TR_REMOVED:
1460                 if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE) {
1461                     psm->fi = rpmfiLink(fi, "tsRepackage");
1462                     xx = psmStage(psm, PSM_PKGSAVE);
1463                     (void) rpmfiUnlink(fi, "tsRepackage");
1464                     psm->fi = NULL;
1465                 }
1466                 /*@switchbreak@*/ break;
1467             }
1468         }
1469         tei = teFreeIterator(tei);
1470     }
1471
1472     /* ===============================================
1473      * Install and remove packages.
1474      */
1475
1476     lastKey = (alKey)-2;        /* erased packages have -1 */
1477     tei = teInitIterator(ts);
1478     /*@-branchstate@*/ /* FIX: fi reload needs work */
1479     while ((fi = teNextFi(tei)) != NULL) {
1480         Header h;
1481         int gotfd;
1482
1483         oc = teGetOc(tei);
1484         gotfd = 0;
1485         psm->fi = rpmfiLink(fi, "tsInstall");
1486         switch (fi->type) {
1487         case TR_ADDED:
1488
1489             pkgKey = ts->order[oc].u.addedKey;
1490
1491             rpmMessage(RPMMESS_DEBUG, "========== +++ %s-%s-%s\n",
1492                         fi->name, fi->version, fi->release);
1493             h = (fi->h ? headerLink(fi->h, "TR_ADDED install") : NULL);
1494             /*@-branchstate@*/
1495             if (fi->fd == NULL) {
1496                 /*@-noeffectuncon @*/ /* FIX: ??? */
1497                 fi->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1498                                 fi->key, ts->notifyData);
1499                 /*@=noeffectuncon @*/
1500                 if (fi->fd != NULL) {
1501                     rpmRC rpmrc;
1502
1503                     h = headerFree(h, "TR_ADDED install");
1504
1505                     /*@-mustmod@*/      /* LCL: segfault */
1506                     rpmrc = rpmReadPackageFile(ts, fi->fd,
1507                                 "rpmRunTransactions", &h);
1508                     /*@=mustmod@*/
1509
1510                     if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
1511                         /*@-noeffectuncon @*/ /* FIX: check rc */
1512                         (void) ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
1513                                         0, 0,
1514                                         fi->key, ts->notifyData);
1515                         /*@=noeffectuncon @*/
1516                         fi->fd = NULL;
1517                         ourrc++;
1518                     } else if (fi->h != NULL) {
1519                         Header foo = relocateFileList(ts, fi, h, NULL);
1520                         h = headerFree(h, "TR_ADDED read free");
1521                         h = headerLink(foo, "TR_ADDED relocate xfer");
1522                         foo = headerFree(foo, "TR_ADDED relocate");
1523                     }
1524                     if (fi->fd != NULL) gotfd = 1;
1525                 }
1526             }
1527             /*@=branchstate@*/
1528
1529             if (fi->fd != NULL) {
1530                 Header hsave = NULL;
1531
1532                 if (fi->h) {
1533                     hsave = headerLink(fi->h, "TR_ADDED fi->h hsave");
1534                     fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1535                     fi->h = headerLink(h, "TR_ADDED fi->h link");
1536                 } else {
1537 char * fstates = fi->fstates;
1538 fileAction * actions = fi->actions;
1539 uint_32 multiLib = fi->multiLib;
1540 const void * key = fi->key;
1541 rpmRelocation * relocs = fi->relocs;
1542 FD_t fd = fi->fd;
1543
1544 fi->fstates = NULL;
1545 fi->actions = NULL;
1546 fi->key = NULL;
1547 fi->relocs = NULL;
1548 fi->fd = NULL;
1549                     freeFi(fi);
1550 oc = teGetOc(tei);
1551 fi->magic = TFIMAGIC;
1552 fi->type = ts->order[oc].type;
1553 fi->record = 0;
1554                     loadFi(ts, fi, h, 1);
1555 fi->fstates = _free(fi->fstates);
1556 fi->fstates = fstates;
1557 fi->actions = _free(fi->actions);
1558 fi->actions = actions;
1559 fi->multiLib = multiLib;
1560 fi->key = key;
1561 fi->relocs = relocs;
1562 /*@-newreftrans@*/
1563 /*@i@*/ fi->fd = fd;
1564 /*@=newreftrans@*/
1565
1566                 }
1567                 if (fi->multiLib)
1568                     ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
1569
1570                 if (psmStage(psm, PSM_PKGINSTALL)) {
1571                     ourrc++;
1572                     lastKey = pkgKey;
1573                 }
1574                 fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1575                 if (hsave) {
1576                     fi->h = headerLink(hsave, "TR_ADDED fi->h restore");
1577                     hsave = headerFree(hsave, "TR_ADDED hsave free");
1578                 }
1579             } else {
1580                 ourrc++;
1581                 lastKey = pkgKey;
1582             }
1583
1584             h = headerFree(h, "TR_ADDED h free");
1585
1586             if (gotfd) {
1587                 /*@-noeffectuncon @*/ /* FIX: check rc */
1588                 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1589                         fi->key, ts->notifyData);
1590                 /*@=noeffectuncon @*/
1591                 fi->fd = NULL;
1592             }
1593             freeFi(fi);
1594             /*@switchbreak@*/ break;
1595         case TR_REMOVED:
1596             rpmMessage(RPMMESS_DEBUG, "========== --- %s-%s-%s\n",
1597                         fi->name, fi->version, fi->release);
1598             oc = teGetOc(tei);
1599             /* If install failed, then we shouldn't erase. */
1600             if (ts->order[oc].u.removed.dependsOnKey != lastKey) {
1601                 if (psmStage(psm, PSM_PKGERASE))
1602                     ourrc++;
1603             }
1604             freeFi(fi);
1605             /*@switchbreak@*/ break;
1606         }
1607         xx = rpmdbSync(ts->rpmdb);
1608         (void) rpmfiUnlink(fi, "tsInstall");
1609         psm->fi = NULL;
1610     }
1611     /*@=branchstate@*/
1612     tei = teFreeIterator(tei);
1613
1614     ts->flList = freeFl(ts, ts->flList);
1615     ts->flEntries = 0;
1616
1617     psm->ts = rpmtsUnlink(psm->ts, "tsRun");
1618
1619     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1620     if (ourrc)
1621         return -1;
1622     else
1623         return 0;
1624     /*@=nullstate@*/
1625 }