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 }

Generated on Tue Sep 17 15:56:42 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002