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