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

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

Generated on Tue Sep 7 17:14:29 2010 for rpm by  doxygen 1.3.9.1