Main Page Modules Data Structures File List Data Fields Globals Related Pages

# lib/transaction.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006 #include <rpmlib.h>
    00007
    00008 #include <rpmmacro.h>   /* XXX for rpmExpand */
    00009
    00010 #include "fsm.h"
    00011 #include "psm.h"
    00012
    00013 #include "rpmdb.h"
    00014
    00015 #include "rpmds.h"
    00016
    00017 #define _RPMFI_INTERNAL
    00018 #include "rpmfi.h"
    00019
    00020 #define _RPMTE_INTERNAL
    00021 #include "rpmte.h"
    00022
    00023 #define _RPMTS_INTERNAL
    00024 #include "rpmts.h"
    00025
    00026 #include "cpio.h"
    00027 #include "fprint.h"
    00028 #include "legacy.h"     /* XXX domd5 */
    00029 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
    00030
    00031 #include "debug.h"
    00032
    00033 /*@access FD_t @*/              /* XXX compared with NULL */
    00034 /*@access Header @*/            /* XXX compared with NULL */
    00035 /*@access rpmps @*/     /* XXX need rpmProblemSetOK() */
    00036 /*@access dbiIndexSet @*/
    00037 /*@access rpmdb @*/
    00038
    00039 /*@access rpmpsm @*/
    00040
    00041 /*@access alKey @*/
    00042 /*@access fnpyKey @*/
    00043
    00044 /*@access rpmfi @*/
    00045
    00046 /*@access rpmte @*/
    00047 /*@access rpmtsi @*/
    00048 /*@access rpmts @*/
    00049
    00052 static int archOkay(/*@null@*/ const char * pkgArch)
    00053         /*@*/
    00054 {
    00055     if (pkgArch == NULL) return 0;
    00056     return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
    00057 }
    00058
    00061 static int osOkay(/*@null@*/ const char * pkgOs)
    00062         /*@*/
    00063 {
    00064     if (pkgOs == NULL) return 0;
    00065     return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
    00066 }
    00067
    00070 static int sharedCmp(const void * one, const void * two)
    00071         /*@*/
    00072 {
    00073     sharedFileInfo a = (sharedFileInfo) one;
    00074     sharedFileInfo b = (sharedFileInfo) two;
    00075
    00076     if (a->otherPkg < b->otherPkg)
    00077         return -1;
    00078     else if (a->otherPkg > b->otherPkg)
    00079         return 1;
    00080
    00081     return 0;
    00082 }
    00083
    00086 /*@-boundsread@*/
    00087 static fileAction decideFileFate(const rpmts ts,
    00088                 const rpmfi ofi, rpmfi nfi)
    00089         /*@globals fileSystem, internalState @*/
    00090         /*@modifies nfi, fileSystem, internalState @*/
    00091 {
    00092     const char * fn = rpmfiFN(nfi);
    00093     int newFlags = rpmfiFFlags(nfi);
    00094     char buffer[1024];
    00095     fileTypes dbWhat, newWhat, diskWhat;
    00096     struct stat sb;
    00097     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
    00098
    00099     if (lstat(fn, &sb)) {
    00100         /*
    00101          * The file doesn't exist on the disk. Create it unless the new
    00102          * package has marked it as missingok, or allfiles is requested.
    00103          */
    00104         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES)
    00105          && (newFlags & RPMFILE_MISSINGOK))
    00106         {
    00107             rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
    00108                         fn);
    00109             return FA_SKIP;
    00110         } else {
    00111             return FA_CREATE;
    00112         }
    00113     }
    00114
    00115     diskWhat = whatis((int_16)sb.st_mode);
    00116     dbWhat = whatis(rpmfiFMode(ofi));
    00117     newWhat = whatis(rpmfiFMode(nfi));
    00118
    00119     /*
    00120      * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
    00121      * them in older packages as well.
    00122      */
    00123     if (newWhat == XDIR)
    00124         return FA_CREATE;
    00125
    00126     if (diskWhat != newWhat)
    00127         return save;
    00128     else if (newWhat != dbWhat && diskWhat != dbWhat)
    00129         return save;
    00130     else if (dbWhat != newWhat)
    00131         return FA_CREATE;
    00132     else if (dbWhat != LINK && dbWhat != REG)
    00133         return FA_CREATE;
    00134
    00135     /*
    00136      * This order matters - we'd prefer to CREATE the file if at all
    00137      * possible in case something else (like the timestamp) has changed.
    00138      */
    00139     if (dbWhat == REG) {
    00140         const unsigned char * omd5, * nmd5;
    00141         if (domd5(fn, buffer, 0, NULL))
    00142             return FA_CREATE;   /* assume file has been removed */
    00143         omd5 = rpmfiMD5(ofi);
    00144         if (omd5 && !memcmp(omd5, buffer, 16))
    00145             return FA_CREATE;   /* unmodified config file, replace. */
    00146         nmd5 = rpmfiMD5(nfi);
    00147 /*@-nullpass@*/
    00148         if (omd5 && nmd5 && !memcmp(omd5, nmd5, 16))
    00149             return FA_SKIP;     /* identical file, don't bother. */
    00150 /*@=nullpass@*/
    00151     } else /* dbWhat == LINK */ {
    00152         const char * oFLink, * nFLink;
    00153         memset(buffer, 0, sizeof(buffer));
    00154         if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
    00155             return FA_CREATE;   /* assume file has been removed */
    00156         oFLink = rpmfiFLink(ofi);
    00157         if (oFLink && !strcmp(oFLink, buffer))
    00158             return FA_CREATE;   /* unmodified config file, replace. */
    00159         nFLink = rpmfiFLink(nfi);
    00160 /*@-nullpass@*/
    00161         if (oFLink && nFLink && !strcmp(oFLink, nFLink))
    00162             return FA_SKIP;     /* identical file, don't bother. */
    00163 /*@=nullpass@*/
    00164      }
    00165
    00166     /*
    00167      * The config file on the disk has been modified, but
    00168      * the ones in the two packages are different. It would
    00169      * be nice if RPM was smart enough to at least try and
    00170      * merge the difference ala CVS, but...
    00171      */
    00172     return save;
    00173 }
    00174 /*@=boundsread@*/
    00175
    00178 /*@-boundsread@*/
    00179 static int filecmp(rpmfi afi, rpmfi bfi)
    00180         /*@*/
    00181 {
    00182     fileTypes awhat = whatis(rpmfiFMode(afi));
    00183     fileTypes bwhat = whatis(rpmfiFMode(bfi));
    00184
    00185     if (awhat != bwhat) return 1;
    00186
    00187     if (awhat == LINK) {
    00188         const char * alink = rpmfiFLink(afi);
    00189         const char * blink = rpmfiFLink(bfi);
    00190         if (alink == blink) return 0;
    00191         if (alink == NULL) return 1;
    00192         if (blink == NULL) return -1;
    00193         return strcmp(alink, blink);
    00194     } else if (awhat == REG) {
    00195         const unsigned char * amd5 = rpmfiMD5(afi);
    00196         const unsigned char * bmd5 = rpmfiMD5(bfi);
    00197         if (amd5 == bmd5) return 0;
    00198         if (amd5 == NULL) return 1;
    00199         if (bmd5 == NULL) return -1;
    00200         return memcmp(amd5, bmd5, 16);
    00201     }
    00202
    00203     return 0;
    00204 }
    00205 /*@=boundsread@*/
    00206
    00209 /* XXX only ts->{probs,rpmdb} modified */
    00210 /*@-bounds@*/
    00211 static int handleInstInstalledFiles(const rpmts ts,
    00212                 rpmte p, rpmfi fi,
    00213                 sharedFileInfo shared,
    00214                 int sharedCount, int reportConflicts)
    00215         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    00216         /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
    00217 {
    00218     const char * altNEVR = NULL;
    00219     rpmfi otherFi = NULL;
    00220     int numReplaced = 0;
    00221     rpmps ps;
    00222     int i;
    00223
    00224     {   rpmdbMatchIterator mi;
    00225         Header h;
    00226         int scareMem = 0;
    00227
    00228         mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
    00229                         &shared->otherPkg, sizeof(shared->otherPkg));
    00230         while ((h = rpmdbNextIterator(mi)) != NULL) {
    00231             altNEVR = hGetNEVR(h, NULL);
    00232             otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
    00233             break;
    00234         }
    00235         mi = rpmdbFreeIterator(mi);
    00236     }
    00237
    00238     if (otherFi == NULL)
    00239         return 1;
    00240
    00241     fi->replaced = xcalloc(sharedCount, sizeof(*fi->replaced));
    00242
    00243     ps = rpmtsProblems(ts);
    00244     for (i = 0; i < sharedCount; i++, shared++) {
    00245         int otherFileNum, fileNum;
    00246         int isCfgFile;
    00247
    00248         otherFileNum = shared->otherFileNum;
    00249         (void) rpmfiSetFX(otherFi, otherFileNum);
    00250
    00251         fileNum = shared->pkgFileNum;
    00252         (void) rpmfiSetFX(fi, fileNum);
    00253
    00254         isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
    00255
    00256 #ifdef  DYING
    00257         /* XXX another tedious segfault, assume file state normal. */
    00258         if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
    00259             continue;
    00260 #endif
    00261
    00262         if (XFA_SKIPPING(fi->actions[fileNum]))
    00263             continue;
    00264
    00265         if (filecmp(otherFi, fi)) {
    00266             if (reportConflicts) {
    00267                 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
    00268                         rpmteNEVR(p), rpmteKey(p),
    00269                         rpmfiDN(fi), rpmfiBN(fi),
    00270                         altNEVR,
    00271                         0);
    00272             }
    00273             if (!isCfgFile) {
    00274                 /*@-assignexpose@*/ /* FIX: p->replaced, not fi */
    00275                 if (!shared->isRemoved)
    00276                     fi->replaced[numReplaced++] = *shared;
    00277                 /*@=assignexpose@*/
    00278             }
    00279         }
    00280
    00281         if (isCfgFile) {
    00282             fileAction action;
    00283             action = decideFileFate(ts, otherFi, fi);
    00284             fi->actions[fileNum] = action;
    00285         }
    00286         fi->replacedSizes[fileNum] = rpmfiFSize(otherFi);
    00287     }
    00288     ps = rpmpsFree(ps);
    00289
    00290     altNEVR = _free(altNEVR);
    00291     otherFi = rpmfiFree(otherFi);
    00292
    00293     fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
    00294                            sizeof(*fi->replaced) * (numReplaced + 1));
    00295     fi->replaced[numReplaced].otherPkg = 0;
    00296
    00297     return 0;
    00298 }
    00299 /*@=bounds@*/
    00300
    00303 /* XXX only ts->rpmdb modified */
    00304 static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
    00305                 sharedFileInfo shared, int sharedCount)
    00306         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    00307         /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
    00308 {
    00309     HGE_t hge = fi->hge;
    00310     Header h;
    00311     const char * otherStates;
    00312     int i, xx;
    00313
    00314     rpmdbMatchIterator mi;
    00315
    00316     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
    00317                         &shared->otherPkg, sizeof(shared->otherPkg));
    00318     h = rpmdbNextIterator(mi);
    00319     if (h == NULL) {
    00320         mi = rpmdbFreeIterator(mi);
    00321         return 1;
    00322     }
    00323
    00324     xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
    00325
    00326 /*@-boundswrite@*/
    00327     for (i = 0; i < sharedCount; i++, shared++) {
    00328         int otherFileNum, fileNum;
    00329         otherFileNum = shared->otherFileNum;
    00330         fileNum = shared->pkgFileNum;
    00331
    00332         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
    00333             continue;
    00334
    00335         fi->actions[fileNum] = FA_SKIP;
    00336     }
    00337 /*@=boundswrite@*/
    00338
    00339     mi = rpmdbFreeIterator(mi);
    00340
    00341     return 0;
    00342 }
    00343
    00344 #define ISROOT(_d)      (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
    00345
    00346 /*@unchecked@*/
    00347 int _fps_debug = 0;
    00348
    00349 static int fpsCompare (const void * one, const void * two)
    00350         /*@*/
    00351 {
    00352     const struct fingerPrint_s * a = (const struct fingerPrint_s *)one;
    00353     const struct fingerPrint_s * b = (const struct fingerPrint_s *)two;
    00354     int adnlen = strlen(a->entry->dirName);
    00355     int asnlen = (a->subDir ? strlen(a->subDir) : 0);
    00356     int abnlen = strlen(a->baseName);
    00357     int bdnlen = strlen(b->entry->dirName);
    00358     int bsnlen = (b->subDir ? strlen(b->subDir) : 0);
    00359     int bbnlen = strlen(b->baseName);
    00360     char * afn, * bfn, * t;
    00361     int rc = 0;
    00362
    00363     if (adnlen == 1 && asnlen != 0) adnlen = 0;
    00364     if (bdnlen == 1 && bsnlen != 0) bdnlen = 0;
    00365
    00366 /*@-boundswrite@*/
    00367     afn = t = alloca(adnlen+asnlen+abnlen+2);
    00368     if (adnlen) t = stpcpy(t, a->entry->dirName);
    00369     *t++ = '/';
    00370     if (a->subDir && asnlen) t = stpcpy(t, a->subDir);
    00371     if (abnlen) t = stpcpy(t, a->baseName);
    00372     if (afn[0] == '/' && afn[1] == '/') afn++;
    00373
    00374     bfn = t = alloca(bdnlen+bsnlen+bbnlen+2);
    00375     if (bdnlen) t = stpcpy(t, b->entry->dirName);
    00376     *t++ = '/';
    00377     if (b->subDir && bsnlen) t = stpcpy(t, b->subDir);
    00378     if (bbnlen) t = stpcpy(t, b->baseName);
    00379     if (bfn[0] == '/' && bfn[1] == '/') bfn++;
    00380 /*@=boundswrite@*/
    00381
    00382     rc = strcmp(afn, bfn);
    00383 /*@-modfilesys@*/
    00384 if (_fps_debug)
    00385 fprintf(stderr, "\trc(%d) = strcmp(\"%s\", \"%s\")\n", rc, afn, bfn);
    00386 /*@=modfilesys@*/
    00387
    00388 /*@-modfilesys@*/
    00389 if (_fps_debug)
    00390 fprintf(stderr, "\t%s/%s%s\trc %d\n",
    00391 ISROOT(b->entry->dirName),
    00392 (b->subDir ? b->subDir : ""),
    00393 b->baseName,
    00394 rc
    00395 );
    00396 /*@=modfilesys@*/
    00397
    00398     return rc;
    00399 }
    00400
    00401 /*@unchecked@*/
    00402 static int _linear_fps_search = 0;
    00403
    00404 static int findFps(const struct fingerPrint_s * fiFps,
    00405                 const struct fingerPrint_s * otherFps,
    00406                 int otherFc)
    00407         /*@*/
    00408 {
    00409     int otherFileNum;
    00410
    00411 /*@-modfilesys@*/
    00412 if (_fps_debug)
    00413 fprintf(stderr, "==> %s/%s%s\n",
    00414 ISROOT(fiFps->entry->dirName),
    00415 (fiFps->subDir ? fiFps->subDir : ""),
    00416 fiFps->baseName);
    00417 /*@=modfilesys@*/
    00418
    00419   if (_linear_fps_search) {
    00420
    00421 linear:
    00422     for (otherFileNum = 0; otherFileNum < otherFc; otherFileNum++, otherFps++) {
    00423
    00424 /*@-modfilesys@*/
    00425 if (_fps_debug)
    00426 fprintf(stderr, "\t%4d %s/%s%s\n", otherFileNum,
    00427 ISROOT(otherFps->entry->dirName),
    00428 (otherFps->subDir ? otherFps->subDir : ""),
    00429 otherFps->baseName);
    00430 /*@=modfilesys@*/
    00431
    00432         /* If the addresses are the same, so are the values. */
    00433         if (fiFps == otherFps)
    00434             break;
    00435
    00436         /* Otherwise, compare fingerprints by value. */
    00437         /*@-nullpass@*/ /* LCL: looks good to me */
    00438         if (FP_EQUAL((*fiFps), (*otherFps)))
    00439             break;
    00440         /*@=nullpass@*/
    00441     }
    00442
    00443 if (otherFileNum == otherFc) {
    00444 /*@-modfilesys@*/
    00445 if (_fps_debug)
    00446 fprintf(stderr, "*** FP_EQUAL NULL %s/%s%s\n",
    00447 ISROOT(fiFps->entry->dirName),
    00448 (fiFps->subDir ? fiFps->subDir : ""),
    00449 fiFps->baseName);
    00450 /*@=modfilesys@*/
    00451 }
    00452
    00453     return otherFileNum;
    00454
    00455   } else {
    00456
    00457     const struct fingerPrint_s * bingoFps;
    00458
    00459 /*@-boundswrite@*/
    00460     bingoFps = bsearch(fiFps, otherFps, otherFc, sizeof(*otherFps), fpsCompare);
    00461 /*@=boundswrite@*/
    00462     if (bingoFps == NULL) {
    00463 /*@-modfilesys@*/
    00464 if (_fps_debug)
    00465 fprintf(stderr, "*** bingoFps NULL %s/%s%s\n",
    00466 ISROOT(fiFps->entry->dirName),
    00467 (fiFps->subDir ? fiFps->subDir : ""),
    00468 fiFps->baseName);
    00469 /*@=modfilesys@*/
    00470         goto linear;
    00471     }
    00472
    00473     /* If the addresses are the same, so are the values. */
    00474     /*@-nullpass@*/     /* LCL: looks good to me */
    00475     if (!(fiFps == bingoFps || FP_EQUAL((*fiFps), (*bingoFps)))) {
    00476 /*@-modfilesys@*/
    00477 if (_fps_debug)
    00478 fprintf(stderr, "***  BAD %s/%s%s\n",
    00479 ISROOT(bingoFps->entry->dirName),
    00480 (bingoFps->subDir ? bingoFps->subDir : ""),
    00481 bingoFps->baseName);
    00482 /*@=modfilesys@*/
    00483         goto linear;
    00484     }
    00485
    00486     otherFileNum = (bingoFps != NULL ? (bingoFps - otherFps) : 0);
    00487
    00488   }
    00489
    00490     return otherFileNum;
    00491 }
    00492
    00496 /* XXX only ts->{probs,di} modified */
    00497 static void handleOverlappedFiles(const rpmts ts,
    00498                 const rpmte p, rpmfi fi)
    00499         /*@globals fileSystem, internalState @*/
    00500         /*@modifies ts, fi, fileSystem, internalState @*/
    00501 {
    00502     uint_32 fixupSize = 0;
    00503     rpmps ps;
    00504     const char * fn;
    00505     int i, j;
    00506
    00507     ps = rpmtsProblems(ts);
    00508     fi = rpmfiInit(fi, 0);
    00509     if (fi != NULL)
    00510     while ((i = rpmfiNext(fi)) >= 0) {
    00511         struct fingerPrint_s * fiFps;
    00512         int otherPkgNum, otherFileNum;
    00513         rpmfi otherFi;
    00514         int_32 FFlags;
    00515         int_16 FMode;
    00516         const rpmfi * recs;
    00517         int numRecs;
    00518
    00519         if (XFA_SKIPPING(fi->actions[i]))
    00520             continue;
    00521
    00522         fn = rpmfiFN(fi);
    00523         fiFps = fi->fps + i;
    00524         FFlags = rpmfiFFlags(fi);
    00525         FMode = rpmfiFMode(fi);
    00526
    00527         fixupSize = 0;
    00528
    00529         /*
    00530          * Retrieve all records that apply to this file. Note that the
    00531          * file info records were built in the same order as the packages
    00532          * will be installed and removed so the records for an overlapped
    00533          * files will be sorted in exactly the same order.
    00534          */
    00535         (void) htGetEntry(ts->ht, fiFps,
    00536                         (const void ***) &recs, &numRecs, NULL);
    00537
    00538         /*
    00539          * If this package is being added, look only at other packages
    00540          * being added -- removed packages dance to a different tune.
    00541          *
    00542          * If both this and the other package are being added, overlapped
    00543          * files must be identical (or marked as a conflict). The
    00544          * disposition of already installed config files leads to
    00545          * a small amount of extra complexity.
    00546          *
    00547          * If this package is being removed, then there are two cases that
    00548          * need to be worried about:
    00549          * If the other package is being added, then skip any overlapped files
    00550          * so that this package removal doesn't nuke the overlapped files
    00551          * that were just installed.
    00552          * If both this and the other package are being removed, then each
    00553          * file removal from preceding packages needs to be skipped so that
    00554          * the file removal occurs only on the last occurence of an overlapped
    00555          * file in the transaction set.
    00556          *
    00557          */
    00558
    00559         /* Locate this overlapped file in the set of added/removed packages. */
    00560         for (j = 0; j < numRecs && recs[j] != fi; j++)
    00561             {};
    00562
    00563         /* Find what the previous disposition of this file was. */
    00564         otherFileNum = -1;                      /* keep gcc quiet */
    00565         otherFi = NULL;
    00566         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
    00567             struct fingerPrint_s * otherFps;
    00568             int otherFc;
    00569
    00570             otherFi = recs[otherPkgNum];
    00571
    00572             /* Added packages need only look at other added packages. */
    00573             if (rpmteType(p) == TR_ADDED && rpmteType(otherFi->te) != TR_ADDED)
    00574                 /*@innercontinue@*/ continue;
    00575
    00576             otherFps = otherFi->fps;
    00577             otherFc = rpmfiFC(otherFi);
    00578
    00579             otherFileNum = findFps(fiFps, otherFps, otherFc);
    00580             (void) rpmfiSetFX(otherFi, otherFileNum);
    00581
    00582             /* XXX Happens iff fingerprint for incomplete package install. */
    00583             if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
    00584                 /*@innerbreak@*/ break;
    00585         }
    00586
    00587 /*@-boundswrite@*/
    00588         switch (rpmteType(p)) {
    00589         case TR_ADDED:
    00590           { struct stat sb;
    00591             if (otherPkgNum < 0) {
    00592                 /* XXX is this test still necessary? */
    00593                 if (fi->actions[i] != FA_UNKNOWN)
    00594                     /*@switchbreak@*/ break;
    00595                 if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
    00596                     /* Here is a non-overlapped pre-existing config file. */
    00597                     fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
    00598                         ? FA_ALTNAME : FA_BACKUP;
    00599                 } else {
    00600                     fi->actions[i] = FA_CREATE;
    00601                 }
    00602                 /*@switchbreak@*/ break;
    00603             }
    00604
    00605 assert(otherFi != NULL);
    00606             /* Mark added overlapped non-identical files as a conflict. */
    00607             if ((rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES)
    00608              && filecmp(otherFi, fi))
    00609             {
    00610                 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
    00611                         rpmteNEVR(p), rpmteKey(p),
    00612                         fn, NULL,
    00613                         rpmteNEVR(otherFi->te),
    00614                         0);
    00615             }
    00616
    00617             /* Try to get the disk accounting correct even if a conflict. */
    00618             fixupSize = rpmfiFSize(otherFi);
    00619
    00620             if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
    00621                 /* Here is an overlapped  pre-existing config file. */
    00622                 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
    00623                         ? FA_ALTNAME : FA_SKIP;
    00624             } else {
    00625                 fi->actions[i] = FA_CREATE;
    00626             }
    00627           } /*@switchbreak@*/ break;
    00628
    00629         case TR_REMOVED:
    00630             if (otherPkgNum >= 0) {
    00631 assert(otherFi != NULL);
    00632                 /* Here is an overlapped added file we don't want to nuke. */
    00633                 if (otherFi->actions[otherFileNum] != FA_ERASE) {
    00634                     /* On updates, don't remove files. */
    00635                     fi->actions[i] = FA_SKIP;
    00636                     /*@switchbreak@*/ break;
    00637                 }
    00638                 /* Here is an overlapped removed file: skip in previous. */
    00639                 otherFi->actions[otherFileNum] = FA_SKIP;
    00640             }
    00641             if (XFA_SKIPPING(fi->actions[i]))
    00642                 /*@switchbreak@*/ break;
    00643             if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
    00644                 /*@switchbreak@*/ break;
    00645             if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
    00646                 fi->actions[i] = FA_ERASE;
    00647                 /*@switchbreak@*/ break;
    00648             }
    00649
    00650             /* Here is a pre-existing modified config file that needs saving. */
    00651             {   char md5sum[50];
    00652                 const unsigned char * MD5 = rpmfiMD5(fi);
    00653                 if (!domd5(fn, md5sum, 0, NULL) && memcmp(MD5, md5sum, 16)) {
    00654                     fi->actions[i] = FA_BACKUP;
    00655                     /*@switchbreak@*/ break;
    00656                 }
    00657             }
    00658             fi->actions[i] = FA_ERASE;
    00659             /*@switchbreak@*/ break;
    00660         }
    00661 /*@=boundswrite@*/
    00662
    00663         /* Update disk space info for a file. */
    00664         rpmtsUpdateDSI(ts, fiFps->entry->dev,
    00665                 rpmfiFSize(fi), fi->replacedSizes[i], fixupSize, fi->actions[i]);
    00666
    00667     }
    00668     ps = rpmpsFree(ps);
    00669 }
    00670
    00678 static int ensureOlder(rpmts ts,
    00679                 const rpmte p, const Header h)
    00680         /*@modifies ts @*/
    00681 {
    00682     int_32 reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
    00683     const char * reqEVR;
    00684     rpmds req;
    00685     char * t;
    00686     int nb;
    00687     int rc;
    00688
    00689     if (p == NULL || h == NULL)
    00690         return 1;
    00691
    00692 /*@-boundswrite@*/
    00693     nb = strlen(rpmteNEVR(p)) + (rpmteE(p) != NULL ? strlen(rpmteE(p)) : 0) + 1;
    00694     t = alloca(nb);
    00695     *t = '\0';
    00696     reqEVR = t;
    00697     if (rpmteE(p) != NULL)      t = stpcpy( stpcpy(t, rpmteE(p)), ":");
    00698     if (rpmteV(p) != NULL)      t = stpcpy(t, rpmteV(p));
    00699     *t++ = '-';
    00700     if (rpmteR(p) != NULL)      t = stpcpy(t, rpmteR(p));
    00701 /*@=boundswrite@*/
    00702
    00703     req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
    00704     rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
    00705     req = rpmdsFree(req);
    00706
    00707     if (rc == 0) {
    00708         rpmps ps = rpmtsProblems(ts);
    00709         const char * altNEVR = hGetNEVR(h, NULL);
    00710         rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
    00711                 rpmteNEVR(p), rpmteKey(p),
    00712                 NULL, NULL,
    00713                 altNEVR,
    00714                 0);
    00715         altNEVR = _free(altNEVR);
    00716         ps = rpmpsFree(ps);
    00717         rc = 1;
    00718     } else
    00719         rc = 0;
    00720
    00721     return rc;
    00722 }
    00723
    00726 /*@-mustmod@*/ /* FIX: fi->actions is modified. */
    00727 /*@-bounds@*/
    00728 static void skipFiles(const rpmts ts, rpmfi fi)
    00729         /*@globals rpmGlobalMacroContext @*/
    00730         /*@modifies fi, rpmGlobalMacroContext @*/
    00731 {
    00732     int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
    00733     char ** netsharedPaths = NULL;
    00734     const char ** languages;
    00735     const char * dn, * bn;
    00736     int dnlen, bnlen, ix;
    00737     const char * s;
    00738     int * drc;
    00739     char * dff;
    00740     int dc;
    00741     int i, j;
    00742
    00743     if (!noDocs)
    00744         noDocs = rpmExpandNumeric("%{_excludedocs}");
    00745
    00746     {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
    00747         /*@-branchstate@*/
    00748         if (tmpPath && *tmpPath != '%')
    00749             netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
    00750         /*@=branchstate@*/
    00751         tmpPath = _free(tmpPath);
    00752     }
    00753
    00754     s = rpmExpand("%{_install_langs}", NULL);
    00755     /*@-branchstate@*/
    00756     if (!(s && *s != '%'))
    00757         s = _free(s);
    00758     if (s) {
    00759         languages = (const char **) splitString(s, strlen(s), ':');
    00760         s = _free(s);
    00761     } else
    00762         languages = NULL;
    00763     /*@=branchstate@*/
    00764
    00765     /* Compute directory refcount, skip directory if now empty. */
    00766     dc = rpmfiDC(fi);
    00767     drc = alloca(dc * sizeof(*drc));
    00768     memset(drc, 0, dc * sizeof(*drc));
    00769     dff = alloca(dc * sizeof(*dff));
    00770     memset(dff, 0, dc * sizeof(*dff));
    00771
    00772     fi = rpmfiInit(fi, 0);
    00773     if (fi != NULL)     /* XXX lclint */
    00774     while ((i = rpmfiNext(fi)) >= 0)
    00775     {
    00776         char **nsp;
    00777
    00778         bn = rpmfiBN(fi);
    00779         bnlen = strlen(bn);
    00780         ix = rpmfiDX(fi);
    00781         dn = rpmfiDN(fi);
    00782         dnlen = strlen(dn);
    00783         if (dn == NULL)
    00784             continue;   /* XXX can't happen */
    00785
    00786         drc[ix]++;
    00787
    00788         /* Don't bother with skipped files */
    00789         if (XFA_SKIPPING(fi->actions[i])) {
    00790             drc[ix]--;
    00791             continue;
    00792         }
    00793
    00794         /*
    00795          * Skip net shared paths.
    00796          * Net shared paths are not relative to the current root (though
    00797          * they do need to take package relocations into account).
    00798          */
    00799         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
    00800             int len;
    00801
    00802             len = strlen(*nsp);
    00803             if (dnlen >= len) {
    00804                 if (strncmp(dn, *nsp, len))
    00805                     /*@innercontinue@*/ continue;
    00806                 /* Only directories or complete file paths can be net shared */
    00807                 if (!(dn[len] == '/' || dn[len] == '\0'))
    00808                     /*@innercontinue@*/ continue;
    00809             } else {
    00810                 if (len < (dnlen + bnlen))
    00811                     /*@innercontinue@*/ continue;
    00812                 if (strncmp(dn, *nsp, dnlen))
    00813                     /*@innercontinue@*/ continue;
    00814                 if (strncmp(bn, (*nsp) + dnlen, bnlen))
    00815                     /*@innercontinue@*/ continue;
    00816                 len = dnlen + bnlen;
    00817                 /* Only directories or complete file paths can be net shared */
    00818                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
    00819                     /*@innercontinue@*/ continue;
    00820             }
    00821
    00822             /*@innerbreak@*/ break;
    00823         }
    00824
    00825         if (nsp && *nsp) {
    00826             drc[ix]--;  dff[ix] = 1;
    00827             fi->actions[i] = FA_SKIPNETSHARED;
    00828             continue;
    00829         }
    00830
    00831         /*
    00832          * Skip i18n language specific files.
    00833          */
    00834         if (fi->flangs && languages && *fi->flangs[i]) {
    00835             const char **lang, *l, *le;
    00836             for (lang = languages; *lang != NULL; lang++) {
    00837                 if (!strcmp(*lang, "all"))
    00838                     /*@innerbreak@*/ break;
    00839                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
    00840                     for (le = l; *le != '\0' && *le != '|'; le++)
    00841                         {};
    00842                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
    00843                         /*@innerbreak@*/ break;
    00844                     if (*le == '|') le++;       /* skip over | */
    00845                 }
    00846                 if (*l != '\0')
    00847                     /*@innerbreak@*/ break;
    00848             }
    00849             if (*lang == NULL) {
    00850                 drc[ix]--;      dff[ix] = 1;
    00851                 fi->actions[i] = FA_SKIPNSTATE;
    00852                 continue;
    00853             }
    00854         }
    00855
    00856         /*
    00857          * Skip documentation if requested.
    00858          */
    00859         if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
    00860             drc[ix]--;  dff[ix] = 1;
    00861             fi->actions[i] = FA_SKIPNSTATE;
    00862             continue;
    00863         }
    00864     }
    00865
    00866     /* Skip (now empty) directories that had skipped files. */
    00867 #ifndef NOTYET
    00868     if (fi != NULL)     /* XXX can't happen */
    00869     for (j = 0; j < dc; j++)
    00870 #else
    00871     if ((fi = rpmfiInitD(fi)) != NULL)
    00872     while (j = rpmfiNextD(fi) >= 0)
    00873 #endif
    00874     {
    00875
    00876         if (drc[j]) continue;   /* dir still has files. */
    00877         if (!dff[j]) continue;  /* dir was not emptied here. */
    00878
    00879         /* Find parent directory and basename. */
    00880         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
    00881         bn = dn + dnlen;        bnlen = 0;
    00882         while (bn > dn && bn[-1] != '/') {
    00883                 bnlen++;
    00884                 dnlen--;
    00885                 bn--;
    00886         }
    00887
    00888         /* If explicitly included in the package, skip the directory. */
    00889         fi = rpmfiInit(fi, 0);
    00890         if (fi != NULL)         /* XXX lclint */
    00891         while ((i = rpmfiNext(fi)) >= 0) {
    00892             const char * fdn, * fbn;
    00893             int_16 fFMode;
    00894
    00895             if (XFA_SKIPPING(fi->actions[i]))
    00896                 /*@innercontinue@*/ continue;
    00897
    00898             fFMode = rpmfiFMode(fi);
    00899
    00900             if (whatis(fFMode) != XDIR)
    00901                 /*@innercontinue@*/ continue;
    00902             fdn = rpmfiDN(fi);
    00903             if (strlen(fdn) != dnlen)
    00904                 /*@innercontinue@*/ continue;
    00905             if (strncmp(fdn, dn, dnlen))
    00906                 /*@innercontinue@*/ continue;
    00907             fbn = rpmfiBN(fi);
    00908             if (strlen(fbn) != bnlen)
    00909                 /*@innercontinue@*/ continue;
    00910             if (strncmp(fbn, bn, bnlen))
    00911                 /*@innercontinue@*/ continue;
    00912             rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
    00913             fi->actions[i] = FA_SKIPNSTATE;
    00914             /*@innerbreak@*/ break;
    00915         }
    00916     }
    00917
    00918     if (netsharedPaths) freeSplitString(netsharedPaths);
    00919 #ifdef  DYING   /* XXX freeFi will deal with this later. */
    00920     fi->flangs = _free(fi->flangs);
    00921 #endif
    00922     if (languages) freeSplitString((char **)languages);
    00923 }
    00924 /*@=bounds@*/
    00925 /*@=mustmod@*/
    00926
    00933 static /*@null@*/
    00934 rpmfi rpmtsiFi(const rpmtsi tsi)
    00935         /*@*/
    00936 {
    00937     rpmfi fi = NULL;
    00938
    00939     if (tsi != NULL && tsi->ocsave != -1) {
    00940         /*@-type -abstract@*/ /* FIX: rpmte not opaque */
    00941         rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
    00942         /*@-assignexpose@*/
    00943         if (te != NULL && (fi = te->fi) != NULL)
    00944             fi->te = te;
    00945         /*@=assignexpose@*/
    00946         /*@=type =abstract@*/
    00947     }
    00948     /*@-compdef -refcounttrans -usereleased @*/
    00949     return fi;
    00950     /*@=compdef =refcounttrans =usereleased @*/
    00951 }
    00952
    00953 #define NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
    00954
    00955 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
    00956 {
    00957     int i, j;
    00958     int ourrc = 0;
    00959     int totalFileCount = 0;
    00960     rpmfi fi;
    00961     sharedFileInfo shared, sharedList;
    00962     int numShared;
    00963     int nexti;
    00964     alKey lastFailKey;
    00965     fingerPrintCache fpc;
    00966     rpmps ps;
    00967     rpmpsm psm;
    00968     rpmtsi pi;  rpmte p;
    00969     rpmtsi qi;  rpmte q;
    00970     int numAdded;
    00971     int numRemoved;
    00972     int xx;
    00973
    00974     /* FIXME: what if the same package is included in ts twice? */
    00975
    00976     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
    00977         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
    00978     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
    00979         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
    00980
    00981     /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
    00982     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
    00983         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
    00984
    00985     ts->probs = rpmpsFree(ts->probs);
    00986     ts->probs = rpmpsCreate();
    00987
    00988     /* XXX Make sure the database is open RDWR for package install/erase. */
    00989     {   int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
    00990                 ? O_RDONLY : (O_RDWR|O_CREAT);
    00991
    00992         /* Open database RDWR for installing packages. */
    00993         if (rpmtsOpenDB(ts, dbmode))
    00994             return -1;  /* XXX W2DO? */
    00995     }
    00996
    00997     ts->ignoreSet = ignoreSet;
    00998     {   const char * currDir = currentDirectory();
    00999         rpmtsSetCurrDir(ts, currDir);
    01000         currDir = _free(currDir);
    01001     }
    01002
    01003     (void) rpmtsSetChrootDone(ts, 0);
    01004
    01005     {   int_32 tid = (int_32) time(NULL);
    01006         (void) rpmtsSetTid(ts, tid);
    01007     }
    01008
    01009     /* Get available space on mounted file systems. */
    01010     xx = rpmtsInitDSI(ts);
    01011
    01012     /* ===============================================
    01013      * For packages being installed:
    01014      * - verify package arch/os.
    01015      * - verify package epoch:version-release is newer.
    01016      * - count files.
    01017      * For packages being removed:
    01018      * - count files.
    01019      */
    01020
    01021 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elments\n"), rpmtsNElements(ts));
    01022     ps = rpmtsProblems(ts);
    01023     /* The ordering doesn't matter here */
    01024     pi = rpmtsiInit(ts);
    01025     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
    01026         rpmdbMatchIterator mi;
    01027         int fc;
    01028
    01029         if ((fi = rpmtsiFi(pi)) == NULL)
    01030             continue;   /* XXX can't happen */
    01031         fc = rpmfiFC(fi);
    01032
    01033         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
    01034             if (!archOkay(rpmteA(p)))
    01035                 rpmpsAppend(ps, RPMPROB_BADARCH,
    01036                         rpmteNEVR(p), rpmteKey(p),
    01037                         rpmteA(p), NULL,
    01038                         NULL, 0);
    01039
    01040         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
    01041             if (!osOkay(rpmteO(p)))
    01042                 rpmpsAppend(ps, RPMPROB_BADOS,
    01043                         rpmteNEVR(p), rpmteKey(p),
    01044                         rpmteO(p), NULL,
    01045                         NULL, 0);
    01046
    01047         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
    01048             Header h;
    01049             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
    01050             while ((h = rpmdbNextIterator(mi)) != NULL)
    01051                 xx = ensureOlder(ts, p, h);
    01052             mi = rpmdbFreeIterator(mi);
    01053         }
    01054
    01055         /* XXX multilib should not display "already installed" problems */
    01056         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG) && !rpmteMultiLib(p)) {
    01057             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
    01058             xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
    01059                                 rpmteE(p));
    01060             xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
    01061                                 rpmteV(p));
    01062             xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
    01063                                 rpmteR(p));
    01064
    01065             while (rpmdbNextIterator(mi) != NULL) {
    01066                 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
    01067                         rpmteNEVR(p), rpmteKey(p),
    01068                         NULL, NULL,
    01069                         NULL, 0);
    01070                 /*@innerbreak@*/ break;
    01071             }
    01072             mi = rpmdbFreeIterator(mi);
    01073         }
    01074
    01075         /* Count no. of files (if any). */
    01076         totalFileCount += fc;
    01077
    01078     }
    01079     pi = rpmtsiFree(pi);
    01080     ps = rpmpsFree(ps);
    01081
    01082     /* The ordering doesn't matter here */
    01083     pi = rpmtsiInit(ts);
    01084     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
    01085         int fc;
    01086
    01087         if ((fi = rpmtsiFi(pi)) == NULL)
    01088             continue;   /* XXX can't happen */
    01089         fc = rpmfiFC(fi);
    01090
    01091         totalFileCount += fc;
    01092     }
    01093     pi = rpmtsiFree(pi);
    01094
    01095     /* ===============================================
    01096      * Initialize transaction element file info for package:
    01097      */
    01098
    01099     /*
    01100      * FIXME?: we'd be better off assembling one very large file list and
    01101      * calling fpLookupList only once. I'm not sure that the speedup is
    01102      * worth the trouble though.
    01103      */
    01104 rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
    01105     numAdded = numRemoved = 0;
    01106     pi = rpmtsiInit(ts);
    01107     while ((p = rpmtsiNext(pi, 0)) != NULL) {
    01108         int fc;
    01109
    01110         if ((fi = rpmtsiFi(pi)) == NULL)
    01111             continue;   /* XXX can't happen */
    01112         fc = rpmfiFC(fi);
    01113
    01114         /*@-branchstate@*/
    01115         switch (rpmteType(p)) {
    01116         case TR_ADDED:
    01117             numAdded++;
    01118             fi->record = 0;
    01119             /* Skip netshared paths, not our i18n files, and excluded docs */
    01120             if (fc > 0)
    01121                 skipFiles(ts, fi);
    01122             /*@switchbreak@*/ break;
    01123         case TR_REMOVED:
    01124             numRemoved++;
    01125             fi->record = rpmteDBOffset(p);
    01126             /*@switchbreak@*/ break;
    01127         }
    01128         /*@=branchstate@*/
    01129
    01130         fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
    01131     }
    01132     pi = rpmtsiFree(pi);
    01133
    01134     if (!rpmtsChrootDone(ts)) {
    01135         const char * rootDir = rpmtsRootDir(ts);
    01136         xx = chdir("/");
    01137         /*@-superuser -noeffect @*/
    01138         if (rootDir != NULL)
    01139             xx = chroot(rootDir);
    01140         /*@=superuser =noeffect @*/
    01141         (void) rpmtsSetChrootDone(ts, 1);
    01142     }
    01143
    01144     ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
    01145     fpc = fpCacheCreate(totalFileCount);
    01146
    01147     /* ===============================================
    01148      * Add fingerprint for each file not skipped.
    01149      */
    01150     pi = rpmtsiInit(ts);
    01151     while ((p = rpmtsiNext(pi, 0)) != NULL) {
    01152         int fc;
    01153
    01154         (void) rpmdbCheckSignals();
    01155
    01156         if ((fi = rpmtsiFi(pi)) == NULL)
    01157             continue;   /* XXX can't happen */
    01158         fc = rpmfiFC(fi);
    01159
    01160         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
    01161         /*@-branchstate@*/
    01162         fi = rpmfiInit(fi, 0);
    01163         if (fi != NULL)         /* XXX lclint */
    01164         while ((i = rpmfiNext(fi)) >= 0) {
    01165             if (XFA_SKIPPING(fi->actions[i]))
    01166                 /*@innercontinue@*/ continue;
    01167             /*@-dependenttrans@*/
    01168             htAddEntry(ts->ht, fi->fps + i, (void *) fi);
    01169             /*@=dependenttrans@*/
    01170         }
    01171         /*@=branchstate@*/
    01172     }
    01173     pi = rpmtsiFree(pi);
    01174
    01175     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
    01176         NULL, ts->notifyData));
    01177
    01178     /* ===============================================
    01179      * Compute file disposition for each package in transaction set.
    01180      */
    01181 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
    01182     ps = rpmtsProblems(ts);
    01183     pi = rpmtsiInit(ts);
    01184     while ((p = rpmtsiNext(pi, 0)) != NULL) {
    01185         dbiIndexSet * matches;
    01186         int knownBad;
    01187         int fc;
    01188
    01189         (void) rpmdbCheckSignals();
    01190
    01191         if ((fi = rpmtsiFi(pi)) == NULL)
    01192             continue;   /* XXX can't happen */
    01193         fc = rpmfiFC(fi);
    01194
    01195         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
    01196                         ts->orderCount, NULL, ts->notifyData));
    01197
    01198         if (fc == 0) continue;
    01199
    01200         /* Extract file info for all files in this package from the database. */
    01201         matches = xcalloc(fc, sizeof(*matches));
    01202         if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
    01203             ps = rpmpsFree(ps);
    01204             return 1;   /* XXX WTFO? */
    01205         }
    01206
    01207         numShared = 0;
    01208         fi = rpmfiInit(fi, 0);
    01209         while ((i = rpmfiNext(fi)) >= 0)
    01210             numShared += dbiIndexSetCount(matches[i]);
    01211
    01212         /* Build sorted file info list for this package. */
    01213         shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
    01214
    01215         fi = rpmfiInit(fi, 0);
    01216         while ((i = rpmfiNext(fi)) >= 0) {
    01217             /*
    01218              * Take care not to mark files as replaced in packages that will
    01219              * have been removed before we will get here.
    01220              */
    01221             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
    01222                 int ro;
    01223                 ro = dbiIndexRecordOffset(matches[i], j);
    01224                 knownBad = 0;
    01225                 qi = rpmtsiInit(ts);
    01226                 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
    01227                     if (ro == knownBad)
    01228                         /*@innerbreak@*/ break;
    01229                     if (rpmteDBOffset(q) == ro)
    01230                         knownBad = ro;
    01231                 }
    01232                 qi = rpmtsiFree(qi);
    01233
    01234                 shared->pkgFileNum = i;
    01235                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
    01236                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
    01237                 shared->isRemoved = (knownBad == ro);
    01238                 shared++;
    01239             }
    01240             matches[i] = dbiFreeIndexSet(matches[i]);
    01241         }
    01242         numShared = shared - sharedList;
    01243         shared->otherPkg = -1;
    01244         matches = _free(matches);
    01245
    01246         /* Sort file info by other package index (otherPkg) */
    01247         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
    01248
    01249         /* For all files from this package that are in the database ... */
    01250         /*@-branchstate@*/
    01251         for (i = 0; i < numShared; i = nexti) {
    01252             int beingRemoved;
    01253
    01254             shared = sharedList + i;
    01255
    01256             /* Find the end of the files in the other package. */
    01257             for (nexti = i + 1; nexti < numShared; nexti++) {
    01258                 if (sharedList[nexti].otherPkg != shared->otherPkg)
    01259                     /*@innerbreak@*/ break;
    01260             }
    01261
    01262             /* Is this file from a package being removed? */
    01263             beingRemoved = 0;
    01264             if (ts->removedPackages != NULL)
    01265             for (j = 0; j < ts->numRemovedPackages; j++) {
    01266                 if (ts->removedPackages[j] != shared->otherPkg)
    01267                     /*@innercontinue@*/ continue;
    01268                 beingRemoved = 1;
    01269                 /*@innerbreak@*/ break;
    01270             }
    01271
    01272             /* Determine the fate of each file. */
    01273             switch (rpmteType(p)) {
    01274             case TR_ADDED:
    01275                 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
    01276         !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
    01277                 /*@switchbreak@*/ break;
    01278             case TR_REMOVED:
    01279                 if (!beingRemoved)
    01280                     xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
    01281                 /*@switchbreak@*/ break;
    01282             }
    01283         }
    01284         /*@=branchstate@*/
    01285
    01286         free(sharedList);
    01287
    01288         /* Update disk space needs on each partition for this package. */
    01289         handleOverlappedFiles(ts, p, fi);
    01290
    01291         /* Check added package has sufficient space on each partition used. */
    01292         switch (rpmteType(p)) {
    01293         case TR_ADDED:
    01294             rpmtsCheckDSIProblems(ts, p);
    01295             /*@switchbreak@*/ break;
    01296         case TR_REMOVED:
    01297             /*@switchbreak@*/ break;
    01298         }
    01299     }
    01300     pi = rpmtsiFree(pi);
    01301     ps = rpmpsFree(ps);
    01302
    01303     if (rpmtsChrootDone(ts)) {
    01304         const char * currDir = rpmtsCurrDir(ts);
    01305         /*@-superuser -noeffect @*/
    01306         xx = chroot(".");
    01307         /*@=superuser =noeffect @*/
    01308         (void) rpmtsSetChrootDone(ts, 0);
    01309         if (currDir != NULL)
    01310             xx = chdir(currDir);
    01311     }
    01312
    01313     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
    01314         NULL, ts->notifyData));
    01315
    01316     /* ===============================================
    01317      * Free unused memory as soon as possible.
    01318      */
    01319     pi = rpmtsiInit(ts);
    01320     while ((p = rpmtsiNext(pi, 0)) != NULL) {
    01321         if ((fi = rpmtsiFi(pi)) == NULL)
    01322             continue;   /* XXX can't happen */
    01323         if (rpmfiFC(fi) == 0)
    01324             continue;
    01325         fi->fps = _free(fi->fps);
    01326     }
    01327     pi = rpmtsiFree(pi);
    01328
    01329     fpc = fpCacheFree(fpc);
    01330     ts->ht = htFree(ts->ht);
    01331
    01332     /* ===============================================
    01333      * If unfiltered problems exist, free memory and return.
    01334      */
    01335     if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
    01336      || (ts->probs->numProblems &&
    01337                 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
    01338        )
    01339     {
    01340         return ts->orderCount;
    01341     }
    01342
    01343     /* ===============================================
    01344      * Save removed files before erasing.
    01345      */
    01346     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
    01347         int progress;
    01348         progress = 0;
    01349         pi = rpmtsiInit(ts);
    01350         while ((p = rpmtsiNext(pi, 0)) != NULL) {
    01351
    01352             (void) rpmdbCheckSignals();
    01353
    01354             if ((fi = rpmtsiFi(pi)) == NULL)
    01355                 continue;       /* XXX can't happen */
    01356             switch (rpmteType(p)) {
    01357             case TR_ADDED:
    01358                 /*@switchbreak@*/ break;
    01359             case TR_REMOVED:
    01360                 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
    01361                     /*@switchbreak@*/ break;
    01362                 if (!progress)
    01363                     NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
    01364                                 7, numRemoved, NULL, ts->notifyData));
    01365
    01366                 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
    01367                         numRemoved, NULL, ts->notifyData));
    01368                 progress++;
    01369
    01370         /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
    01371                 fi->mapflags |= CPIO_MAP_ABSOLUTE;
    01372                 fi->mapflags |= CPIO_MAP_ADDDOT;
    01373                 fi->mapflags |= CPIO_ALL_HARDLINKS;
    01374                 psm = rpmpsmNew(ts, p, fi);
    01375                 xx = rpmpsmStage(psm, PSM_PKGSAVE);
    01376                 psm = rpmpsmFree(psm);
    01377                 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
    01378                 fi->mapflags &= ~CPIO_MAP_ADDDOT;
    01379                 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
    01380
    01381                 /*@switchbreak@*/ break;
    01382             }
    01383         }
    01384         pi = rpmtsiFree(pi);
    01385         if (progress) {
    01386             NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
    01387                         NULL, ts->notifyData));
    01388         }
    01389     }
    01390
    01391     /* ===============================================
    01392      * Install and remove packages.
    01393      */
    01394     lastFailKey = (alKey)-2;    /* erased packages have -1 */
    01395     pi = rpmtsiInit(ts);
    01396     /*@-branchstate@*/ /* FIX: fi reload needs work */
    01397     while ((p = rpmtsiNext(pi, 0)) != NULL) {
    01398         alKey pkgKey;
    01399         int gotfd;
    01400
    01401         (void) rpmdbCheckSignals();
    01402
    01403         gotfd = 0;
    01404         if ((fi = rpmtsiFi(pi)) == NULL)
    01405             continue;   /* XXX can't happen */
    01406
    01407         psm = rpmpsmNew(ts, p, fi);
    01408         psm->unorderedSuccessor =
    01409                 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
    01410
    01411         switch (rpmteType(p)) {
    01412         case TR_ADDED:
    01413
    01414             pkgKey = rpmteAddedKey(p);
    01415
    01416             rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
    01417             p->h = NULL;
    01418             /*@-type@*/ /* FIX: rpmte not opaque */
    01419             {
    01420                 /*@-noeffectuncon@*/ /* FIX: notify annotations */
    01421                 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
    01422                                 rpmteKey(p), ts->notifyData);
    01423                 /*@=noeffectuncon@*/
    01424                 if (rpmteFd(p) != NULL) {
    01425                     rpmVSFlags ovsflags = rpmtsVSFlags(ts);
    01426                     rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
    01427                     rpmRC rpmrc;
    01428
    01429                     ovsflags = rpmtsSetVSFlags(ts, vsflags);
    01430                     rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
    01431                                 rpmteNEVR(p), &p->h);
    01432                     vsflags = rpmtsSetVSFlags(ts, ovsflags);
    01433
    01434                     switch (rpmrc) {
    01435                     default:
    01436                         /*@-noeffectuncon@*/ /* FIX: notify annotations */
    01437                         p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
    01438                                         0, 0,
    01439                                         rpmteKey(p), ts->notifyData);
    01440                         /*@=noeffectuncon@*/
    01441                         p->fd = NULL;
    01442                         ourrc++;
    01443                         /*@innerbreak@*/ break;
    01444                     case RPMRC_NOTTRUSTED:
    01445                     case RPMRC_NOKEY:
    01446                     case RPMRC_OK:
    01447                         /*@innerbreak@*/ break;
    01448                     }
    01449                     if (rpmteFd(p) != NULL) gotfd = 1;
    01450                 }
    01451             }
    01452             /*@=type@*/
    01453
    01454             if (rpmteFd(p) != NULL) {
    01455                 /*
    01456                  * XXX Sludge necessary to tranfer existing fstates/actions
    01457                  * XXX around a recreated file info set.
    01458                  */
    01459                 psm->fi = rpmfiFree(psm->fi);
    01460                 {
    01461                     char * fstates = fi->fstates;
    01462                     fileAction * actions = fi->actions;
    01463
    01464                     fi->fstates = NULL;
    01465                     fi->actions = NULL;
    01466                     fi = rpmfiFree(fi);
    01467                     fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
    01468                     if (fi != NULL) {   /* XXX can't happen */
    01469                         fi->te = p;
    01470                         fi->fstates = _free(fi->fstates);
    01471                         fi->fstates = fstates;
    01472                         fi->actions = _free(fi->actions);
    01473                         fi->actions = actions;
    01474                         p->fi = fi;
    01475                     }
    01476                 }
    01477                 psm->fi = rpmfiLink(p->fi, NULL);
    01478
    01479                 if (rpmteMultiLib(p))
    01480                     (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_MULTILIB));
    01481                 else
    01482                     (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) & ~RPMTRANS_FLAG_MULTILIB));
    01483
    01484 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
    01485                 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
    01486                     ourrc++;
    01487                     lastFailKey = pkgKey;
    01488                 }
    01489 /*@=nullstate@*/
    01490             } else {
    01491                 ourrc++;
    01492                 lastFailKey = pkgKey;
    01493             }
    01494
    01495             if (gotfd) {
    01496                 /*@-noeffectuncon @*/ /* FIX: check rc */
    01497                 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
    01498                         rpmteKey(p), ts->notifyData);
    01499                 /*@=noeffectuncon @*/
    01500                 /*@-type@*/
    01501                 p->fd = NULL;
    01502                 /*@=type@*/
    01503             }
    01504
    01505             p->h = headerFree(p->h);
    01506
    01507             /*@switchbreak@*/ break;
    01508         case TR_REMOVED:
    01509             rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
    01510             /*
    01511              * XXX This has always been a hack, now mostly broken.
    01512              * If install failed, then we shouldn't erase.
    01513              */
    01514             if (rpmteDependsOnKey(p) != lastFailKey) {
    01515                 if (rpmpsmStage(psm, PSM_PKGERASE))
    01516                     ourrc++;
    01517             }
    01518             /*@switchbreak@*/ break;
    01519         }
    01520         xx = rpmdbSync(rpmtsGetRdb(ts));
    01521
    01522 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
    01523         psm = rpmpsmFree(psm);
    01524 /*@=nullstate@*/
    01525
    01526 /*@-type@*/ /* FIX: p is almost opaque */
    01527         p->fi = rpmfiFree(p->fi);
    01528 /*@=type@*/
    01529
    01530     }
    01531     /*@=branchstate@*/
    01532     pi = rpmtsiFree(pi);
    01533
    01534     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
    01535     if (ourrc)
    01536         return -1;
    01537     else
    01538         return 0;
    01539     /*@=nullstate@*/
    01540 }