# lib/transaction.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include <rpmmacro.h>   /* XXX for rpmExpand */
    00008
    00009 #include "psm.h"
    00010
    00011 #include "rpmdb.h"
    00012 #include "fprint.h"
    00013 #include "rpmhash.h"
    00014 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
    00015
    00016 #ifdef  DYING
    00017 /*@-redecl -exportheadervar@*/
    00018 extern const char * chroot_prefix;
    00019 /*@=redecl =exportheadervar@*/
    00020 #endif
    00021
    00022 /* XXX FIXME: merge with existing (broken?) tests in system.h */
    00023 /* portability fiddles */
    00024 #if STATFS_IN_SYS_STATVFS
    00025 # include <sys/statvfs.h>
    00026 #else
    00027 # if STATFS_IN_SYS_VFS
    00028 #  include <sys/vfs.h>
    00029 # else
    00030 #  if STATFS_IN_SYS_MOUNT
    00031 #   include <sys/mount.h>
    00032 #  else
    00033 #   if STATFS_IN_SYS_STATFS
    00034 #    include <sys/statfs.h>
    00035 #   endif
    00036 #  endif
    00037 # endif
    00038 #endif
    00039
    00040 #include "debug.h"
    00041
    00042 /*@access FD_t@*/               /* XXX compared with NULL */
    00043 /*@access Header@*/             /* XXX compared with NULL */
    00044 /*@access dbiIndexSet@*/
    00045 /*@access rpmdb@*/
    00046 /*@access rpmTransactionSet@*/
    00047 /*@access TFI_t@*/
    00048 /*@access PSM_t@*/
    00049 /*@access rpmProblemSet@*/
    00050 /*@access rpmProblem@*/
    00051
    00052 struct diskspaceInfo {
    00053     dev_t dev;
    00054     signed long bneeded;
    00055     signed long ineeded;
    00056     int bsize;
    00057     signed long bavail;
    00058     signed long iavail;
    00059 };
    00060
    00061 /* Adjust for root only reserved space. On linux e2fs, this is 5%. */
    00062 #define adj_fs_blocks(_nb)      (((_nb) * 21) / 20)
    00063
    00064 /* argon thought a shift optimization here was a waste of time...  he's
    00065    probably right :-( */
    00066 #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
    00067
    00068 #define XSTRCMP(a, b) ((!(a) && !(b)) || ((a) && (b) && !strcmp((a), (b))))
    00069
    00070 static /*@null@*/ void * freeFl(rpmTransactionSet ts,
    00071                 /*@only@*/ /*@null@*/ TFI_t flList)
    00072         /*@*/
    00073 {
    00074     if (flList) {
    00075         TFI_t fi;
    00076         int oc;
    00077
    00078         /*@-usereleased@*/
    00079         for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
    00080             freeFi(fi);
    00081         flList = _free(flList);
    00082         /*@=usereleased@*/
    00083     }
    00084     return NULL;
    00085 }
    00086
    00087 void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
    00088 {
    00089     ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
    00090 }
    00091
    00092 int rpmtransGetKeys(const rpmTransactionSet ts, const void *** ep, int * nep)
    00093 {
    00094     int rc = 0;
    00095
    00096     if (nep) *nep = ts->orderCount;
    00097     if (ep) {
    00098         const void ** e;
    00099         int oc;
    00100
    00101         *ep = e = xmalloc(ts->orderCount * sizeof(*e));
    00102         for (oc = 0; oc < ts->orderCount; oc++, e++) {
    00103             switch (ts->order[oc].type) {
    00104             case TR_ADDED:
    00105                 if (ts->addedPackages.list) {
    00106                     struct availablePackage * alp;
    00107                     alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
    00108                     *e = alp->key;
    00109                     break;
    00110                 }
    00111                 /*@fallthrough@*/
    00112             default:
    00113             case TR_REMOVED:
    00114                 /*@-mods@*/     /* FIX: double indirection. */
    00115                 *e = NULL;
    00116                 /*@=mods@*/
    00117                 break;
    00118             }
    00119         }
    00120     }
    00121     return rc;
    00122 }
    00123
    00124 static rpmProblemSet psCreate(void)
    00125         /*@*/
    00126 {
    00127     rpmProblemSet probs;
    00128
    00129     probs = xmalloc(sizeof(*probs));    /* XXX memory leak */
    00130     probs->numProblems = probs->numProblemsAlloced = 0;
    00131     probs->probs = NULL;
    00132
    00133     return probs;
    00134 }
    00135
    00136 static void psAppend(rpmProblemSet probs, rpmProblemType type,
    00137                 const struct availablePackage * alp,
    00138                 const char * dn, const char *bn,
    00139                 Header altH, unsigned long ulong1)
    00140         /*@modifies probs, alp @*/
    00141 {
    00142     rpmProblem p;
    00143     char *t;
    00144
    00145     if (probs->numProblems == probs->numProblemsAlloced) {
    00146         if (probs->numProblemsAlloced)
    00147             probs->numProblemsAlloced *= 2;
    00148         else
    00149             probs->numProblemsAlloced = 2;
    00150         probs->probs = xrealloc(probs->probs,
    00151                         probs->numProblemsAlloced * sizeof(*probs->probs));
    00152     }
    00153
    00154     p = probs->probs + probs->numProblems++;
    00155     p->type = type;
    00156     /*@-assignexpose@*/
    00157     p->key = alp->key;
    00158     /*@=assignexpose@*/
    00159     p->ulong1 = ulong1;
    00160     p->ignoreProblem = 0;
    00161
    00162     if (dn || bn) {
    00163         p->str1 =
    00164             t = xmalloc((dn ? strlen(dn) : 0) + (bn ? strlen(bn) : 0) + 1);
    00165         if (dn) t = stpcpy(t, dn);
    00166         if (bn) t = stpcpy(t, bn);
    00167     } else
    00168         p->str1 = NULL;
    00169
    00170     if (alp) {
    00171         p->h = headerLink(alp->h);
    00172         p->pkgNEVR =
    00173             t = xmalloc(strlen(alp->name) +
    00174                         strlen(alp->version) +
    00175                         strlen(alp->release) + sizeof("--"));
    00176         t = stpcpy(t, alp->name);
    00177         t = stpcpy(t, "-");
    00178         t = stpcpy(t, alp->version);
    00179         t = stpcpy(t, "-");
    00180         t = stpcpy(t, alp->release);
    00181     } else {
    00182         p->h = NULL;
    00183         p->pkgNEVR = NULL;
    00184     }
    00185
    00186     if (altH) {
    00187         const char * n, * v, * r;
    00188         (void) headerNVR(altH, &n, &v, &r);
    00189         p->altNEVR =
    00190             t = xmalloc(strlen(n) + strlen(v) + strlen(r) + sizeof("--"));
    00191         t = stpcpy(t, n);
    00192         t = stpcpy(t, "-");
    00193         t = stpcpy(t, v);
    00194         t = stpcpy(t, "-");
    00195         t = stpcpy(t, r);
    00196     } else
    00197         p->altNEVR = NULL;
    00198 }
    00199
    00200 static int archOkay(Header h)
    00201         /*@*/
    00202 {
    00203     void * pkgArch;
    00204     int type, count;
    00205
    00206     /* make sure we're trying to install this on the proper architecture */
    00207     (void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
    00208 #ifndef DYING
    00209     if (type == RPM_INT8_TYPE) {
    00210         int_8 * pkgArchNum;
    00211         int archNum;
    00212
    00213         /* old arch handling */
    00214         rpmGetArchInfo(NULL, &archNum);
    00215         pkgArchNum = pkgArch;
    00216         if (archNum != *pkgArchNum) {
    00217             return 0;
    00218         }
    00219     } else
    00220 #endif
    00221     {
    00222         /* new arch handling */
    00223         if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
    00224             return 0;
    00225         }
    00226     }
    00227
    00228     return 1;
    00229 }
    00230
    00231 static int osOkay(Header h)
    00232         /*@*/
    00233 {
    00234     void * pkgOs;
    00235     int type, count;
    00236
    00237     /* make sure we're trying to install this on the proper os */
    00238     (void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
    00239 #ifndef DYING
    00240     if (type == RPM_INT8_TYPE) {
    00241         /* v1 packages and v2 packages both used improper OS numbers, so just
    00242            deal with it hope things work */
    00243         return 1;
    00244     } else
    00245 #endif
    00246     {
    00247         /* new os handling */
    00248         if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
    00249             return 0;
    00250         }
    00251     }
    00252
    00253     return 1;
    00254 }
    00255
    00256 void rpmProblemSetFree(rpmProblemSet probs)
    00257 {
    00258     int i;
    00259
    00260     for (i = 0; i < probs->numProblems; i++) {
    00261         rpmProblem p = probs->probs + i;
    00262         p->h = headerFree(p->h);
    00263         p->pkgNEVR = _free(p->pkgNEVR);
    00264         p->altNEVR = _free(p->altNEVR);
    00265         p->str1 = _free(p->str1);
    00266     }
    00267     free(probs);
    00268 }
    00269
    00270 static /*@observer@*/ const char *const ftstring (fileTypes ft)
    00271         /*@*/
    00272 {
    00273     switch (ft) {
    00274     case XDIR:  return "directory";
    00275     case CDEV:  return "char dev";
    00276     case BDEV:  return "block dev";
    00277     case LINK:  return "link";
    00278     case SOCK:  return "sock";
    00279     case PIPE:  return "fifo/pipe";
    00280     case REG:   return "file";
    00281     default:    return "unknown file type";
    00282     }
    00283     /*@notreached@*/
    00284 }
    00285
    00286 static fileTypes whatis(uint_16 mode)
    00287         /*@*/
    00288 {
    00289     if (S_ISDIR(mode))  return XDIR;
    00290     if (S_ISCHR(mode))  return CDEV;
    00291     if (S_ISBLK(mode))  return BDEV;
    00292     if (S_ISLNK(mode))  return LINK;
    00293     if (S_ISSOCK(mode)) return SOCK;
    00294     if (S_ISFIFO(mode)) return PIPE;
    00295     return REG;
    00296 }
    00297
    00298 #define alloca_strdup(_s)       strcpy(alloca(strlen(_s)+1), (_s))
    00299
    00310 static Header relocateFileList(const rpmTransactionSet ts, TFI_t fi,
    00311                 struct availablePackage * alp,
    00312                 Header origH, fileAction * actions)
    00313         /*@modifies ts, fi, alp, origH, actions @*/
    00314 {
    00315     HGE_t hge = fi->hge;
    00316     HAE_t hae = fi->hae;
    00317     HME_t hme = fi->hme;
    00318     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
    00319     static int _printed = 0;
    00320     rpmProblemSet probs = ts->probs;
    00321     int allowBadRelocate = (ts->ignoreSet & RPMPROB_FILTER_FORCERELOCATE);
    00322     rpmRelocation * rawRelocations = alp->relocs;
    00323     rpmRelocation * relocations = NULL;
    00324     int numRelocations;
    00325     const char ** validRelocations;
    00326     rpmTagType validType;
    00327     int numValid;
    00328     const char ** baseNames;
    00329     const char ** dirNames;
    00330     int_32 * dirIndexes;
    00331     int_32 * newDirIndexes;
    00332     int_32 fileCount;
    00333     int_32 dirCount;
    00334     uint_32 * fFlags = NULL;
    00335     uint_16 * fModes = NULL;
    00336     char * skipDirList;
    00337     Header h;
    00338     int nrelocated = 0;
    00339     int fileAlloced = 0;
    00340     char * fn = NULL;
    00341     int haveRelocatedFile = 0;
    00342     int reldel = 0;
    00343     int len;
    00344     int i, j;
    00345
    00346     if (!hge(origH, RPMTAG_PREFIXES, &validType,
    00347                         (void **) &validRelocations, &numValid))
    00348         numValid = 0;
    00349
    00350     numRelocations = 0;
    00351     if (rawRelocations)
    00352         while (rawRelocations[numRelocations].newPath ||
    00353                rawRelocations[numRelocations].oldPath)
    00354             numRelocations++;
    00355
    00356     /*
    00357      * If no relocations are specified (usually the case), then return the
    00358      * original header. If there are prefixes, however, then INSTPREFIXES
    00359      * should be added, but, since relocateFileList() can be called more
    00360      * than once for the same header, don't bother if already present.
    00361      */
    00362     if (rawRelocations == NULL || numRelocations == 0) {
    00363         if (numValid) {
    00364             if (!headerIsEntry(origH, RPMTAG_INSTPREFIXES))
    00365                 (void) hae(origH, RPMTAG_INSTPREFIXES,
    00366                         validType, validRelocations, numValid);
    00367             validRelocations = hfd(validRelocations, validType);
    00368         }
    00369         /* XXX FIXME multilib file actions need to be checked. */
    00370         return headerLink(origH);
    00371     }
    00372
    00373 #ifdef DYING
    00374     h = headerCopy(origH);
    00375 #else
    00376     h = headerLink(origH);
    00377 #endif
    00378
    00379     relocations = alloca(sizeof(*relocations) * numRelocations);
    00380
    00381     /* Build sorted relocation list from raw relocations. */
    00382     for (i = 0; i < numRelocations; i++) {
    00383         char * t;
    00384
    00385         /*
    00386          * Default relocations (oldPath == NULL) are handled in the UI,
    00387          * not rpmlib.
    00388          */
    00389         if (rawRelocations[i].oldPath == NULL) continue; /* XXX can't happen */
    00390
    00391         /* FIXME: Trailing /'s will confuse us greatly. Internal ones will
    00392            too, but those are more trouble to fix up. :-( */
    00393         t = alloca_strdup(rawRelocations[i].oldPath);
    00394         relocations[i].oldPath = (t[0] == '/' && t[1] == '\0')
    00395             ? t
    00396             : stripTrailingChar(t, '/');
    00397
    00398         /* An old path w/o a new path is valid, and indicates exclusion */
    00399         if (rawRelocations[i].newPath) {
    00400             int del;
    00401
    00402             t = alloca_strdup(rawRelocations[i].newPath);
    00403             relocations[i].newPath = (t[0] == '/' && t[1] == '\0')
    00404                 ? t
    00405                 : stripTrailingChar(t, '/');
    00406
    00407             /*@-nullpass@*/     /* FIX:  relocations[i].oldPath == NULL */
    00408             /* Verify that the relocation's old path is in the header. */
    00409             for (j = 0; j < numValid; j++)
    00410                 if (!strcmp(validRelocations[j], relocations[i].oldPath))
    00411                     /*@innerbreak@*/ break;
    00412             /* XXX actions check prevents problem from being appended twice. */
    00413             if (j == numValid && !allowBadRelocate && actions)
    00414                 psAppend(probs, RPMPROB_BADRELOCATE, alp,
    00415                          relocations[i].oldPath, NULL, NULL, 0);
    00416             del =
    00417                 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
    00418             /*@=nullpass@*/
    00419
    00420             if (del > reldel)
    00421                 reldel = del;
    00422         } else {
    00423             relocations[i].newPath = NULL;
    00424         }
    00425     }
    00426
    00427     /* stupid bubble sort, but it's probably faster here */
    00428     for (i = 0; i < numRelocations; i++) {
    00429         int madeSwap;
    00430         madeSwap = 0;
    00431         for (j = 1; j < numRelocations; j++) {
    00432             rpmRelocation tmpReloc;
    00433             if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
    00434                 relocations[j    ].oldPath == NULL || /* XXX can't happen */
    00435         strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
    00436                 continue;
    00437             tmpReloc = relocations[j - 1];
    00438             relocations[j - 1] = relocations[j];
    00439             relocations[j] = tmpReloc;
    00440             madeSwap = 1;
    00441         }
    00442         if (!madeSwap) break;
    00443     }
    00444
    00445     if (!_printed) {
    00446         _printed = 1;
    00447         rpmMessage(RPMMESS_DEBUG, _("========== relocations\n"));
    00448         for (i = 0; i < numRelocations; i++) {
    00449             if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
    00450             if (relocations[i].newPath == NULL)
    00451                 rpmMessage(RPMMESS_DEBUG, _("%5d exclude  %s\n"),
    00452                         i, relocations[i].oldPath);
    00453             else
    00454                 rpmMessage(RPMMESS_DEBUG, _("%5d relocate %s -> %s\n"),
    00455                         i, relocations[i].oldPath, relocations[i].newPath);
    00456         }
    00457     }
    00458
    00459     /* Add relocation values to the header */
    00460     if (numValid) {
    00461         const char ** actualRelocations;
    00462         int numActual;
    00463
    00464         actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
    00465         numActual = 0;
    00466         for (i = 0; i < numValid; i++) {
    00467             for (j = 0; j < numRelocations; j++) {
    00468                 if (relocations[j].oldPath == NULL || /* XXX can't happen */
    00469                     strcmp(validRelocations[i], relocations[j].oldPath))
    00470                     continue;
    00471                 /* On install, a relocate to NULL means skip the path. */
    00472                 if (relocations[j].newPath) {
    00473                     actualRelocations[numActual] = relocations[j].newPath;
    00474                     numActual++;
    00475                 }
    00476                 /*@innerbreak@*/ break;
    00477             }
    00478             if (j == numRelocations) {
    00479                 actualRelocations[numActual] = validRelocations[i];
    00480                 numActual++;
    00481             }
    00482         }
    00483
    00484         if (numActual)
    00485             (void) hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
    00486                        (void **) actualRelocations, numActual);
    00487
    00488         actualRelocations = _free(actualRelocations);
    00489         validRelocations = hfd(validRelocations, validType);
    00490     }
    00491
    00492     (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &baseNames, &fileCount);
    00493     (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
    00494     (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, &dirCount);
    00495     (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fFlags, NULL);
    00496     (void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &fModes, NULL);
    00497
    00498     skipDirList = alloca(dirCount * sizeof(*skipDirList));
    00499     memset(skipDirList, 0, dirCount * sizeof(*skipDirList));
    00500
    00501     newDirIndexes = alloca(sizeof(*newDirIndexes) * fileCount);
    00502     memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
    00503     dirIndexes = newDirIndexes;
    00504
    00505     /*
    00506      * For all relocations, we go through sorted file/relocation lists
    00507      * backwards so that /usr/local relocations take precedence over /usr
    00508      * ones.
    00509      */
    00510
    00511     /* Relocate individual paths. */
    00512
    00513     for (i = fileCount - 1; i >= 0; i--) {
    00514         fileTypes ft;
    00515         int fnlen;
    00516
    00517         /*
    00518          * If only adding libraries of different arch into an already
    00519          * installed package, skip all other files.
    00520          */
    00521         if (alp->multiLib && !isFileMULTILIB((fFlags[i]))) {
    00522             if (actions) {
    00523                 actions[i] = FA_SKIPMULTILIB;
    00524                 rpmMessage(RPMMESS_DEBUG, _("excluding multilib path %s%s\n"),
    00525                         dirNames[dirIndexes[i]], baseNames[i]);
    00526             }
    00527             continue;
    00528         }
    00529
    00530         len = reldel +
    00531                 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
    00532         if (len >= fileAlloced) {
    00533             fileAlloced = len * 2;
    00534             fn = xrealloc(fn, fileAlloced);
    00535         }
    00536         *fn = '\0';
    00537         fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
    00538
    00539         /*
    00540          * See if this file path needs relocating.
    00541          */
    00542         /*
    00543          * XXX FIXME: Would a bsearch of the (already sorted)
    00544          * relocation list be a good idea?
    00545          */
    00546         for (j = numRelocations - 1; j >= 0; j--) {
    00547             if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
    00548             len = strcmp(relocations[j].oldPath, "/")
    00549                 ? strlen(relocations[j].oldPath)
    00550                 : 0;
    00551
    00552             if (fnlen < len)
    00553                 continue;
    00554             /*
    00555              * Only subdirectories or complete file paths may be relocated. We
    00556              * don't check for '\0' as our directory names all end in '/'.
    00557              */
    00558             if (!(fn[len] == '/' || fnlen == len))
    00559                 continue;
    00560
    00561             if (strncmp(relocations[j].oldPath, fn, len))
    00562                 continue;
    00563             /*@innerbreak@*/ break;
    00564         }
    00565         if (j < 0) continue;
    00566
    00567         ft = whatis(fModes[i]);
    00568
    00569         /* On install, a relocate to NULL means skip the path. */
    00570         if (relocations[j].newPath == NULL) {
    00571             if (ft == XDIR) {
    00572                 /* Start with the parent, looking for directory to exclude. */
    00573                 for (j = dirIndexes[i]; j < dirCount; j++) {
    00574                     len = strlen(dirNames[j]) - 1;
    00575                     while (len > 0 && dirNames[j][len-1] == '/') len--;
    00576                     if (fnlen != len)
    00577                         continue;
    00578                     if (strncmp(fn, dirNames[j], fnlen))
    00579                         continue;
    00580                     /*@innerbreak@*/ break;
    00581                 }
    00582                 if (j < dirCount)
    00583                     skipDirList[j] = 1;
    00584             }
    00585             if (actions) {
    00586                 actions[i] = FA_SKIPNSTATE;
    00587                 rpmMessage(RPMMESS_DEBUG, _("excluding %s %s\n"),
    00588                         ftstring(ft), fn);
    00589             }
    00590             continue;
    00591         }
    00592
    00593         /* Relocation on full paths only, please. */
    00594         if (fnlen != len) continue;
    00595
    00596         if (actions)
    00597             rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
    00598                     fn, relocations[j].newPath);
    00599         nrelocated++;
    00600
    00601         strcpy(fn, relocations[j].newPath);
    00602         {   char * te = strrchr(fn, '/');
    00603             if (te) {
    00604                 if (te > fn) te++;      /* root is special */
    00605                 fnlen = te - fn;
    00606             } else
    00607                 te = fn + strlen(fn);
    00608             /*@-nullpass -nullderef@*/  /* LCL: te != NULL here. */
    00609             if (strcmp(baseNames[i], te)) /* basename changed too? */
    00610                 baseNames[i] = alloca_strdup(te);
    00611             *te = '\0';                 /* terminate new directory name */
    00612             /*@=nullpass =nullderef@*/
    00613         }
    00614
    00615         /* Does this directory already exist in the directory list? */
    00616         for (j = 0; j < dirCount; j++) {
    00617             if (fnlen != strlen(dirNames[j]))
    00618                 continue;
    00619             if (strncmp(fn, dirNames[j], fnlen))
    00620                 continue;
    00621             /*@innerbreak@*/ break;
    00622         }
    00623
    00624         if (j < dirCount) {
    00625             dirIndexes[i] = j;
    00626             continue;
    00627         }
    00628
    00629         /* Creating new paths is a pita */
    00630         if (!haveRelocatedFile) {
    00631             const char ** newDirList;
    00632
    00633             haveRelocatedFile = 1;
    00634             newDirList = xmalloc((dirCount + 1) * sizeof(*newDirList));
    00635             for (j = 0; j < dirCount; j++)
    00636                 newDirList[j] = alloca_strdup(dirNames[j]);
    00637             dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
    00638             dirNames = newDirList;
    00639         } else {
    00640             dirNames = xrealloc(dirNames,
    00641                                sizeof(*dirNames) * (dirCount + 1));
    00642         }
    00643
    00644         dirNames[dirCount] = alloca_strdup(fn);
    00645         dirIndexes[i] = dirCount;
    00646         dirCount++;
    00647     }
    00648
    00649     /* Finish off by relocating directories. */
    00650     for (i = dirCount - 1; i >= 0; i--) {
    00651         for (j = numRelocations - 1; j >= 0; j--) {
    00652
    00653             if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
    00654             len = strcmp(relocations[j].oldPath, "/")
    00655                 ? strlen(relocations[j].oldPath)
    00656                 : 0;
    00657
    00658             if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
    00659                 continue;
    00660
    00661             /*
    00662              * Only subdirectories or complete file paths may be relocated. We
    00663              * don't check for '\0' as our directory names all end in '/'.
    00664              */
    00665             if (dirNames[i][len] != '/')
    00666                 continue;
    00667
    00668             if (relocations[j].newPath) { /* Relocate the path */
    00669                 const char * s = relocations[j].newPath;
    00670                 char * t = alloca(strlen(s) + strlen(dirNames[i]) - len + 1);
    00671
    00672                 (void) stpcpy( stpcpy(t, s) , dirNames[i] + len);
    00673                 if (actions)
    00674                     rpmMessage(RPMMESS_DEBUG,
    00675                         _("relocating directory %s to %s\n"), dirNames[i], t);
    00676                 dirNames[i] = t;
    00677                 nrelocated++;
    00678             }
    00679         }
    00680     }
    00681
    00682     /* Save original filenames in header and replace (relocated) filenames. */
    00683     if (nrelocated) {
    00684         int c;
    00685         void * p;
    00686         rpmTagType t;
    00687
    00688         p = NULL;
    00689         (void) hge(h, RPMTAG_BASENAMES, &t, &p, &c);
    00690         (void) hae(h, RPMTAG_ORIGBASENAMES, t, p, c);
    00691         p = hfd(p, t);
    00692
    00693         p = NULL;
    00694         (void) hge(h, RPMTAG_DIRNAMES, &t, &p, &c);
    00695         (void) hae(h, RPMTAG_ORIGDIRNAMES, t, p, c);
    00696         p = hfd(p, t);
    00697
    00698         p = NULL;
    00699         (void) hge(h, RPMTAG_DIRINDEXES, &t, &p, &c);
    00700         (void) hae(h, RPMTAG_ORIGDIRINDEXES, t, p, c);
    00701         p = hfd(p, t);
    00702
    00703         (void) hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
    00704                           baseNames, fileCount);
    00705         fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
    00706         (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc);
    00707
    00708         (void) hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
    00709                           dirNames, dirCount);
    00710         fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
    00711         (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
    00712
    00713         (void) hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
    00714                           dirIndexes, fileCount);
    00715         (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
    00716     }
    00717
    00718     baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
    00719     dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
    00720     fn = _free(fn);
    00721
    00722     return h;
    00723 }
    00724
    00725 /*
    00726  * As the problem sets are generated in an order solely dependent
    00727  * on the ordering of the packages in the transaction, and that
    00728  * ordering can't be changed, the problem sets must be parallel to
    00729  * one another. Additionally, the filter set must be a subset of the
    00730  * target set, given the operations available on transaction set.
    00731  * This is good, as it lets us perform this trim in linear time, rather
    00732  * then logarithmic or quadratic.
    00733  */
    00734 static int psTrim(rpmProblemSet filter, rpmProblemSet target)
    00735         /*@modifies target @*/
    00736 {
    00737     rpmProblem f = filter->probs;
    00738     rpmProblem t = target->probs;
    00739     int gotProblems = 0;
    00740
    00741     while ((f - filter->probs) < filter->numProblems) {
    00742         if (!f->ignoreProblem) {
    00743             f++;
    00744             continue;
    00745         }
    00746         while ((t - target->probs) < target->numProblems) {
    00747             /*@-nullpass@*/     /* LCL: looks good to me */
    00748             if (f->h == t->h && f->type == t->type && t->key == f->key &&
    00749                      XSTRCMP(f->str1, t->str1))
    00750                 /*@innerbreak@*/ break;
    00751             /*@=nullpass@*/
    00752             t++;
    00753             gotProblems = 1;
    00754         }
    00755
    00756         if ((t - target->probs) == target->numProblems) {
    00757             /* this can't happen ;-) lets be sane if it doesn though */
    00758             break;
    00759         }
    00760
    00761         t->ignoreProblem = f->ignoreProblem;
    00762         t++, f++;
    00763     }
    00764
    00765     if ((t - target->probs) < target->numProblems)
    00766         gotProblems = 1;
    00767
    00768     return gotProblems;
    00769 }
    00770
    00771 static int sharedCmp(const void * one, const void * two)
    00772         /*@*/
    00773 {
    00774     const struct sharedFileInfo * a = one;
    00775     const struct sharedFileInfo * b = two;
    00776
    00777     if (a->otherPkg < b->otherPkg)
    00778         return -1;
    00779     else if (a->otherPkg > b->otherPkg)
    00780         return 1;
    00781
    00782     return 0;
    00783 }
    00784
    00785 static fileAction decideFileFate(const char * dirName,
    00786                         const char * baseName, short dbMode,
    00787                         const char * dbMd5, const char * dbLink, short newMode,
    00788                         const char * newMd5, const char * newLink, int newFlags,
    00789                         rpmtransFlags transFlags)
    00790         /*@*/
    00791 {
    00792     char buffer[1024];
    00793     const char * dbAttr, * newAttr;
    00794     fileTypes dbWhat, newWhat, diskWhat;
    00795     struct stat sb;
    00796     int i, rc;
    00797     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
    00798     char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
    00799
    00800     (void) stpcpy( stpcpy(filespec, dirName), baseName);
    00801
    00802     if (lstat(filespec, &sb)) {
    00803         /*
    00804          * The file doesn't exist on the disk. Create it unless the new
    00805          * package has marked it as missingok, or allfiles is requested.
    00806          */
    00807         if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
    00808            (newFlags & RPMFILE_MISSINGOK)) {
    00809             rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
    00810                         filespec);
    00811             return FA_SKIP;
    00812         } else {
    00813             return FA_CREATE;
    00814         }
    00815     }
    00816
    00817     diskWhat = whatis(sb.st_mode);
    00818     dbWhat = whatis(dbMode);
    00819     newWhat = whatis(newMode);
    00820
    00821     /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
    00822        them in older packages as well */
    00823     if (newWhat == XDIR) {
    00824         return FA_CREATE;
    00825     }
    00826
    00827     if (diskWhat != newWhat) {
    00828         return save;
    00829     } else if (newWhat != dbWhat && diskWhat != dbWhat) {
    00830         return save;
    00831     } else if (dbWhat != newWhat) {
    00832         return FA_CREATE;
    00833     } else if (dbWhat != LINK && dbWhat != REG) {
    00834         return FA_CREATE;
    00835     }
    00836
    00837     if (dbWhat == REG) {
    00838         rc = domd5(filespec, buffer, 0);
    00839         if (rc) {
    00840             /* assume the file has been removed, don't freak */
    00841             return FA_CREATE;
    00842         }
    00843         dbAttr = dbMd5;
    00844         newAttr = newMd5;
    00845     } else /* dbWhat == LINK */ {
    00846         memset(buffer, 0, sizeof(buffer));
    00847         i = readlink(filespec, buffer, sizeof(buffer) - 1);
    00848         if (i == -1) {
    00849             /* assume the file has been removed, don't freak */
    00850             return FA_CREATE;
    00851         }
    00852         dbAttr = dbLink;
    00853         newAttr = newLink;
    00854      }
    00855
    00856     /* this order matters - we'd prefer to CREATE the file if at all
    00857        possible in case something else (like the timestamp) has changed */
    00858
    00859     if (!strcmp(dbAttr, buffer)) {
    00860         /* this config file has never been modified, so just replace it */
    00861         return FA_CREATE;
    00862     }
    00863
    00864     if (!strcmp(dbAttr, newAttr)) {
    00865         /* this file is the same in all versions of this package */
    00866         return FA_SKIP;
    00867     }
    00868
    00869     /*
    00870      * The config file on the disk has been modified, but
    00871      * the ones in the two packages are different. It would
    00872      * be nice if RPM was smart enough to at least try and
    00873      * merge the difference ala CVS, but...
    00874      */
    00875     return save;
    00876 }
    00877
    00878 static int filecmp(short mode1, const char * md51, const char * link1,
    00879                    short mode2, const char * md52, const char * link2)
    00880         /*@*/
    00881 {
    00882     fileTypes what1 = whatis(mode1);
    00883     fileTypes what2 = whatis(mode2);
    00884
    00885     if (what1 != what2) return 1;
    00886
    00887     if (what1 == LINK)
    00888         return strcmp(link1, link2);
    00889     else if (what1 == REG)
    00890         return strcmp(md51, md52);
    00891
    00892     return 0;
    00893 }
    00894
    00895 static int handleInstInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
    00896                                     struct sharedFileInfo * shared,
    00897                                     int sharedCount, int reportConflicts,
    00898                                     rpmProblemSet probs,
    00899                                     rpmtransFlags transFlags)
    00900         /*@modifies fi, db, probs @*/
    00901 {
    00902     HGE_t hge = fi->hge;
    00903     HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
    00904     rpmTagType oltype, omtype;
    00905     Header h;
    00906     int i;
    00907     const char ** otherMd5s;
    00908     const char ** otherLinks;
    00909     const char * otherStates;
    00910     uint_32 * otherFlags;
    00911     uint_32 * otherSizes;
    00912     uint_16 * otherModes;
    00913     int numReplaced = 0;
    00914
    00915     rpmdbMatchIterator mi;
    00916
    00917     mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &shared->otherPkg, sizeof(shared->otherPkg));
    00918     h = rpmdbNextIterator(mi);
    00919     if (h == NULL) {
    00920         mi = rpmdbFreeIterator(mi);
    00921         return 1;
    00922     }
    00923
    00924     (void) hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
    00925     (void) hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
    00926     (void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
    00927     (void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
    00928     (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
    00929     (void) hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
    00930
    00931     fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
    00932
    00933     for (i = 0; i < sharedCount; i++, shared++) {
    00934         int otherFileNum, fileNum;
    00935         otherFileNum = shared->otherFileNum;
    00936         fileNum = shared->pkgFileNum;
    00937
    00938         /* XXX another tedious segfault, assume file state normal. */
    00939         if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
    00940             continue;
    00941
    00942         if (XFA_SKIPPING(fi->actions[fileNum]))
    00943             continue;
    00944
    00945         if (filecmp(otherModes[otherFileNum],
    00946                         otherMd5s[otherFileNum],
    00947                         otherLinks[otherFileNum],
    00948                         fi->fmodes[fileNum],
    00949                         fi->fmd5s[fileNum],
    00950                         fi->flinks[fileNum])) {
    00951             if (reportConflicts)
    00952                 psAppend(probs, RPMPROB_FILE_CONFLICT, fi->ap,
    00953                         fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum], h, 0);
    00954             if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
    00955                         & RPMFILE_CONFIG) {
    00956                 /*@-assignexpose@*/
    00957                 if (!shared->isRemoved)
    00958                     fi->replaced[numReplaced++] = *shared;
    00959                 /*@=assignexpose@*/
    00960             }
    00961         }
    00962
    00963         if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
    00964             fi->actions[fileNum] = decideFileFate(
    00965                         fi->dnl[fi->dil[fileNum]],
    00966                         fi->bnl[fileNum],
    00967                         otherModes[otherFileNum],
    00968                         otherMd5s[otherFileNum],
    00969                         otherLinks[otherFileNum],
    00970                         fi->fmodes[fileNum],
    00971                         fi->fmd5s[fileNum],
    00972                         fi->flinks[fileNum],
    00973                         fi->fflags[fileNum],
    00974                         transFlags);
    00975         }
    00976
    00977         fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
    00978     }
    00979
    00980     otherMd5s = hfd(otherMd5s, omtype);
    00981     otherLinks = hfd(otherLinks, oltype);
    00982     mi = rpmdbFreeIterator(mi);
    00983
    00984     fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
    00985                            sizeof(*fi->replaced) * (numReplaced + 1));
    00986     fi->replaced[numReplaced].otherPkg = 0;
    00987
    00988     return 0;
    00989 }
    00990
    00991 static int handleRmvdInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
    00992                                     struct sharedFileInfo * shared,
    00993                                     int sharedCount)
    00994         /*@modifies fi, db @*/
    00995 {
    00996     HGE_t hge = fi->hge;
    00997     Header h;
    00998     const char * otherStates;
    00999     int i;
    01000
    01001     rpmdbMatchIterator mi;
    01002
    01003     mi = rpmdbInitIterator(db, RPMDBI_PACKAGES,
    01004                         &shared->otherPkg, sizeof(shared->otherPkg));
    01005     h = rpmdbNextIterator(mi);
    01006     if (h == NULL) {
    01007         mi = rpmdbFreeIterator(mi);
    01008         return 1;
    01009     }
    01010
    01011     (void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
    01012
    01013     for (i = 0; i < sharedCount; i++, shared++) {
    01014         int otherFileNum, fileNum;
    01015         otherFileNum = shared->otherFileNum;
    01016         fileNum = shared->pkgFileNum;
    01017
    01018         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
    01019             continue;
    01020
    01021         fi->actions[fileNum] = FA_SKIP;
    01022     }
    01023
    01024     mi = rpmdbFreeIterator(mi);
    01025
    01026     return 0;
    01027 }
    01028
    01032 static void handleOverlappedFiles(TFI_t fi, hashTable ht,
    01033                            rpmProblemSet probs, struct diskspaceInfo * dsl)
    01034         /*@modifies fi, probs, dsl @*/
    01035 {
    01036     int i, j;
    01037     struct diskspaceInfo * ds = NULL;
    01038     uint_32 fixupSize = 0;
    01039     char * filespec = NULL;
    01040     int fileSpecAlloced = 0;
    01041
    01042     for (i = 0; i < fi->fc; i++) {
    01043         int otherPkgNum, otherFileNum;
    01044         const TFI_t * recs;
    01045         int numRecs;
    01046
    01047         if (XFA_SKIPPING(fi->actions[i]))
    01048             continue;
    01049
    01050         j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
    01051         if (j > fileSpecAlloced) {
    01052             fileSpecAlloced = j * 2;
    01053             filespec = xrealloc(filespec, fileSpecAlloced);
    01054         }
    01055
    01056         (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
    01057
    01058         if (dsl) {
    01059             ds = dsl;
    01060             while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
    01061             if (!ds->bsize) ds = NULL;
    01062             fixupSize = 0;
    01063         }
    01064
    01065         /*
    01066          * Retrieve all records that apply to this file. Note that the
    01067          * file info records were built in the same order as the packages
    01068          * will be installed and removed so the records for an overlapped
    01069          * files will be sorted in exactly the same order.
    01070          */
    01071         (void) htGetEntry(ht, &fi->fps[i], (const void ***) &recs, &numRecs, NULL);
    01072
    01073         /*
    01074          * If this package is being added, look only at other packages
    01075          * being added -- removed packages dance to a different tune.
    01076          * If both this and the other package are being added, overlapped
    01077          * files must be identical (or marked as a conflict). The
    01078          * disposition of already installed config files leads to
    01079          * a small amount of extra complexity.
    01080          *
    01081          * If this package is being removed, then there are two cases that
    01082          * need to be worried about:
    01083          * If the other package is being added, then skip any overlapped files
    01084          * so that this package removal doesn't nuke the overlapped files
    01085          * that were just installed.
    01086          * If both this and the other package are being removed, then each
    01087          * file removal from preceding packages needs to be skipped so that
    01088          * the file removal occurs only on the last occurence of an overlapped
    01089          * file in the transaction set.
    01090          *
    01091          */
    01092
    01093         /* Locate this overlapped file in the set of added/removed packages. */
    01094         for (j = 0; j < numRecs && recs[j] != fi; j++)
    01095             {};
    01096
    01097         /* Find what the previous disposition of this file was. */
    01098         otherFileNum = -1;                      /* keep gcc quiet */
    01099         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
    01100             /* Added packages need only look at other added packages. */
    01101             if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
    01102                 continue;
    01103
    01104             /* TESTME: there are more efficient searches in the world... */
    01105             for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
    01106                  otherFileNum++) {
    01107
    01108                 /* If the addresses are the same, so are the values. */
    01109                 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
    01110                     /*@innerbreak@*/ break;
    01111
    01112                 /* Otherwise, compare fingerprints by value. */
    01113                 /*@-nullpass@*/ /* LCL: looks good to me */
    01114                 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
    01115                     /*@innerbreak@*/ break;
    01116                 /*@=nullpass@*/
    01117
    01118             }
    01119             /* XXX is this test still necessary? */
    01120             if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
    01121                 /*@innerbreak@*/ break;
    01122         }
    01123
    01124         switch (fi->type) {
    01125         case TR_ADDED:
    01126           { struct stat sb;
    01127             if (otherPkgNum < 0) {
    01128                 /* XXX is this test still necessary? */
    01129                 if (fi->actions[i] != FA_UNKNOWN)
    01130                     break;
    01131                 if ((fi->fflags[i] & RPMFILE_CONFIG) &&
    01132                         !lstat(filespec, &sb)) {
    01133                     /* Here is a non-overlapped pre-existing config file. */
    01134                     fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
    01135                         ? FA_ALTNAME : FA_BACKUP;
    01136                 } else {
    01137                     fi->actions[i] = FA_CREATE;
    01138                 }
    01139                 break;
    01140             }
    01141
    01142             /* Mark added overlapped non-identical files as a conflict. */
    01143             if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
    01144                         recs[otherPkgNum]->fmd5s[otherFileNum],
    01145                         recs[otherPkgNum]->flinks[otherFileNum],
    01146                         fi->fmodes[i],
    01147                         fi->fmd5s[i],
    01148                         fi->flinks[i])) {
    01149                 psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap,
    01150                                 filespec, NULL, recs[otherPkgNum]->ap->h, 0);
    01151             }
    01152
    01153             /* Try to get the disk accounting correct even if a conflict. */
    01154             fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
    01155
    01156             if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
    01157                 /* Here is an overlapped  pre-existing config file. */
    01158                 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
    01159                         ? FA_ALTNAME : FA_SKIP;
    01160             } else {
    01161                 fi->actions[i] = FA_CREATE;
    01162             }
    01163           } break;
    01164         case TR_REMOVED:
    01165             if (otherPkgNum >= 0) {
    01166                 /* Here is an overlapped added file we don't want to nuke. */
    01167                 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
    01168                     /* On updates, don't remove files. */
    01169                     fi->actions[i] = FA_SKIP;
    01170                     break;
    01171                 }
    01172                 /* Here is an overlapped removed file: skip in previous. */
    01173                 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
    01174             }
    01175             if (XFA_SKIPPING(fi->actions[i]))
    01176                 break;
    01177             if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
    01178                 break;
    01179             if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
    01180                 fi->actions[i] = FA_ERASE;
    01181                 break;
    01182             }
    01183
    01184             /* Here is a pre-existing modified config file that needs saving. */
    01185             {   char mdsum[50];
    01186                 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
    01187                     fi->actions[i] = FA_BACKUP;
    01188                     break;
    01189                 }
    01190             }
    01191             fi->actions[i] = FA_ERASE;
    01192             break;
    01193         }
    01194
    01195         if (ds) {
    01196             uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
    01197
    01198             switch (fi->actions[i]) {
    01199               case FA_BACKUP:
    01200               case FA_SAVE:
    01201               case FA_ALTNAME:
    01202                 ds->ineeded++;
    01203                 ds->bneeded += s;
    01204                 break;
    01205
    01206             /*
    01207              * FIXME: If two packages share a file (same md5sum), and
    01208              * that file is being replaced on disk, will ds->bneeded get
    01209              * decremented twice? Quite probably!
    01210              */
    01211               case FA_CREATE:
    01212                 ds->bneeded += s;
    01213                 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
    01214                 break;
    01215
    01216               case FA_ERASE:
    01217                 ds->ineeded--;
    01218                 ds->bneeded -= s;
    01219                 break;
    01220
    01221               default:
    01222                 break;
    01223             }
    01224
    01225             ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
    01226         }
    01227     }
    01228     if (filespec) free(filespec);
    01229 }
    01230
    01231 static int ensureOlder(struct availablePackage * alp, Header old,
    01232                 rpmProblemSet probs)
    01233         /*@modifies alp, probs @*/
    01234 {
    01235     int result, rc = 0;
    01236
    01237     if (old == NULL) return 1;
    01238
    01239     result = rpmVersionCompare(old, alp->h);
    01240     if (result <= 0)
    01241         rc = 0;
    01242     else if (result > 0) {
    01243         rc = 1;
    01244         psAppend(probs, RPMPROB_OLDPACKAGE, alp, NULL, NULL, old, 0);
    01245     }
    01246
    01247     return rc;
    01248 }
    01249
    01250 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
    01251         /*@globals rpmGlobalMacroContext @*/
    01252         /*@modifies fi, rpmGlobalMacroContext @*/
    01253 {
    01254     int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
    01255     char ** netsharedPaths = NULL;
    01256     const char ** languages;
    01257     const char * dn, * bn;
    01258     int dnlen, bnlen, ix;
    01259     const char * s;
    01260     int * drc;
    01261     char * dff;
    01262     int i, j;
    01263
    01264     if (!noDocs)
    01265         noDocs = rpmExpandNumeric("%{_excludedocs}");
    01266
    01267     {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
    01268         if (tmpPath && *tmpPath != '%')
    01269             netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
    01270         tmpPath = _free(tmpPath);
    01271     }
    01272
    01273     s = rpmExpand("%{_install_langs}", NULL);
    01274     if (!(s && *s != '%'))
    01275         s = _free(s);
    01276     if (s) {
    01277         languages = (const char **) splitString(s, strlen(s), ':');
    01278         s = _free(s);
    01279     } else
    01280         languages = NULL;
    01281
    01282     /* Compute directory refcount, skip directory if now empty. */
    01283     drc = alloca(fi->dc * sizeof(*drc));
    01284     memset(drc, 0, fi->dc * sizeof(*drc));
    01285     dff = alloca(fi->dc * sizeof(*dff));
    01286     memset(dff, 0, fi->dc * sizeof(*dff));
    01287
    01288     for (i = 0; i < fi->fc; i++) {
    01289         char **nsp;
    01290
    01291         bn = fi->bnl[i];
    01292         bnlen = strlen(bn);
    01293         ix = fi->dil[i];
    01294         dn = fi->dnl[ix];
    01295         dnlen = strlen(dn);
    01296
    01297         drc[ix]++;
    01298
    01299         /* Don't bother with skipped files */
    01300         if (XFA_SKIPPING(fi->actions[i])) {
    01301             drc[ix]--;
    01302             continue;
    01303         }
    01304
    01305         /*
    01306          * Skip net shared paths.
    01307          * Net shared paths are not relative to the current root (though
    01308          * they do need to take package relocations into account).
    01309          */
    01310         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
    01311             int len;
    01312
    01313             len = strlen(*nsp);
    01314             if (dnlen >= len) {
    01315                 if (strncmp(dn, *nsp, len)) continue;
    01316                 /* Only directories or complete file paths can be net shared */
    01317                 if (!(dn[len] == '/' || dn[len] == '\0')) continue;
    01318             } else {
    01319                 if (len < (dnlen + bnlen)) continue;
    01320                 if (strncmp(dn, *nsp, dnlen)) continue;
    01321                 if (strncmp(bn, (*nsp) + dnlen, bnlen)) continue;
    01322                 len = dnlen + bnlen;
    01323                 /* Only directories or complete file paths can be net shared */
    01324                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0')) continue;
    01325             }
    01326
    01327             /*@innerbreak@*/ break;
    01328         }
    01329
    01330         if (nsp && *nsp) {
    01331             drc[ix]--;  dff[ix] = 1;
    01332             fi->actions[i] = FA_SKIPNETSHARED;
    01333             continue;
    01334         }
    01335
    01336         /*
    01337          * Skip i18n language specific files.
    01338          */
    01339         if (fi->flangs && languages && *fi->flangs[i]) {
    01340             const char **lang, *l, *le;
    01341             for (lang = languages; *lang != '\0'; lang++) {
    01342                 if (!strcmp(*lang, "all"))
    01343                     /*@innerbreak@*/ break;
    01344                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
    01345                     for (le = l; *le != '\0' && *le != '|'; le++)
    01346                         {};
    01347                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
    01348                         /*@innerbreak@*/ break;
    01349                     if (*le == '|') le++;       /* skip over | */
    01350                 }
    01351                 if (*l != '\0')
    01352                     /*@innerbreak@*/ break;
    01353             }
    01354             if (*lang == NULL) {
    01355                 drc[ix]--;      dff[ix] = 1;
    01356                 fi->actions[i] = FA_SKIPNSTATE;
    01357                 continue;
    01358             }
    01359         }
    01360
    01361         /*
    01362          * Skip documentation if requested.
    01363          */
    01364         if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
    01365             drc[ix]--;  dff[ix] = 1;
    01366             fi->actions[i] = FA_SKIPNSTATE;
    01367             continue;
    01368         }
    01369     }
    01370
    01371     /* Skip (now empty) directories that had skipped files. */
    01372     for (j = 0; j < fi->dc; j++) {
    01373
    01374         if (drc[j]) continue;   /* dir still has files. */
    01375         if (!dff[j]) continue;  /* dir was not emptied here. */
    01376
    01377         /* Find parent directory and basename. */
    01378         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
    01379         bn = dn + dnlen;        bnlen = 0;
    01380         while (bn > dn && bn[-1] != '/') {
    01381                 bnlen++;
    01382                 dnlen--;
    01383                 bn--;
    01384         }
    01385
    01386         /* If explicitly included in the package, skip the directory. */
    01387         for (i = 0; i < fi->fc; i++) {
    01388             const char * dir;
    01389
    01390             if (XFA_SKIPPING(fi->actions[i]))
    01391                 continue;
    01392             if (whatis(fi->fmodes[i]) != XDIR)
    01393                 continue;
    01394             dir = fi->dnl[fi->dil[i]];
    01395             if (strlen(dir) != dnlen)
    01396                 continue;
    01397             if (strncmp(dir, dn, dnlen))
    01398                 continue;
    01399             if (strlen(fi->bnl[i]) != bnlen)
    01400                 continue;
    01401             if (strncmp(fi->bnl[i], bn, bnlen))
    01402                 continue;
    01403             rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
    01404             fi->actions[i] = FA_SKIPNSTATE;
    01405             /*@innerbreak@*/ break;
    01406         }
    01407     }
    01408
    01409     if (netsharedPaths) freeSplitString(netsharedPaths);
    01410 #ifdef  DYING   /* XXX freeFi will deal with this later. */
    01411     fi->flangs = _free(fi->flangs);
    01412 #endif
    01413     if (languages) freeSplitString((char **)languages);
    01414 }
    01415
    01419 struct tsIterator_s {
    01420 /*@kept@*/ rpmTransactionSet ts;
    01421     int reverse;
    01422     int ocsave;
    01423     int oc;
    01424 };
    01425
    01431 static int tsGetOc(void * a)
    01432         /*@*/
    01433 {
    01434     struct tsIterator_s * iter = a;
    01435     int oc = iter->ocsave;
    01436     return oc;
    01437 }
    01438
    01444 static /*@dependent@*/ struct availablePackage * tsGetAlp(void * a)
    01445         /*@*/
    01446 {
    01447     struct tsIterator_s * iter = a;
    01448     struct availablePackage * alp = NULL;
    01449     int oc = iter->ocsave;
    01450
    01451     if (oc != -1) {
    01452         rpmTransactionSet ts = iter->ts;
    01453         TFI_t fi = ts->flList + oc;
    01454         if (ts->addedPackages.list && fi->type == TR_ADDED)
    01455             alp = ts->addedPackages.list + ts->order[oc].u.addedIndex;
    01456     }
    01457     return alp;
    01458 }
    01459
    01465 static /*@null@*/ void * tsFreeIterator(/*@only@*//*@null@*/ const void * a)
    01466         /*@modifies a @*/
    01467 {
    01468     return _free(a);
    01469 }
    01470
    01476 static void * tsInitIterator(/*@kept@*/ const void * a)
    01477         /*@*/
    01478 {
    01479     rpmTransactionSet ts = (void *)a;
    01480     struct tsIterator_s * iter = NULL;
    01481
    01482     iter = xcalloc(1, sizeof(*iter));
    01483     iter->ts = ts;
    01484     iter->reverse = ((ts->transFlags & RPMTRANS_FLAG_REVERSE) ? 1 : 0);
    01485     iter->oc = (iter->reverse ? (ts->orderCount - 1) : 0);
    01486     iter->ocsave = iter->oc;
    01487     return iter;
    01488 }
    01489
    01495 static /*@dependent@*/ TFI_t tsNextIterator(void * a)
    01496         /*@*/
    01497 {
    01498     struct tsIterator_s * iter = a;
    01499     rpmTransactionSet ts = iter->ts;
    01500     TFI_t fi = NULL;
    01501     int oc = -1;
    01502
    01503     if (iter->reverse) {
    01504         if (iter->oc >= 0)              oc = iter->oc--;
    01505     } else {
    01506         if (iter->oc < ts->orderCount)  oc = iter->oc++;
    01507     }
    01508     iter->ocsave = oc;
    01509     if (oc != -1)
    01510         fi = ts->flList + oc;
    01511     return fi;
    01512 }
    01513
    01514 #define NOTIFY(_ts, _al)        if ((_ts)->notify) (void) (_ts)->notify _al
    01515
    01516 int rpmRunTransactions( rpmTransactionSet ts,
    01517                         rpmCallbackFunction notify, rpmCallbackData notifyData,
    01518                         rpmProblemSet okProbs, rpmProblemSet * newProbs,
    01519                         rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
    01520 {
    01521     int i, j;
    01522     int ourrc = 0;
    01523     struct availablePackage * alp;
    01524     int totalFileCount = 0;
    01525     hashTable ht;
    01526     TFI_t fi;
    01527     struct diskspaceInfo * dip;
    01528     struct sharedFileInfo * shared, * sharedList;
    01529     int numShared;
    01530     int nexti;
    01531     int lastFailed;
    01532     int oc;
    01533     fingerPrintCache fpc;
    01534     struct psm_s psmbuf;
    01535     PSM_t psm = &psmbuf;
    01536     void * tsi;
    01537
    01538     /* FIXME: what if the same package is included in ts twice? */
    01539
    01540     ts->transFlags = transFlags;
    01541     if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
    01542         ts->transFlags |= (_noTransScripts | _noTransTriggers);
    01543     if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
    01544         ts->transFlags |= _noTransTriggers;
    01545
    01546     /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
    01547     if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
    01548         ts->transFlags |= (_noTransScripts | _noTransTriggers);
    01549
    01550     ts->notify = notify;
    01551     ts->notifyData = notifyData;
    01552     /*@-assignexpose@*/
    01553     ts->probs = *newProbs = psCreate();
    01554     /*@=assignexpose@*/
    01555     ts->ignoreSet = ignoreSet;
    01556     ts->currDir = _free(ts->currDir);
    01557     ts->currDir = currentDirectory();
    01558     ts->chrootDone = 0;
    01559     if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
    01560     ts->id = (int_32) time(NULL);
    01561
    01562     memset(psm, 0, sizeof(*psm));
    01563     /*@-assignexpose@*/
    01564     psm->ts = ts;
    01565     /*@=assignexpose@*/
    01566
    01567     /* Get available space on mounted file systems. */
    01568     if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
    01569                 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
    01570         struct stat sb;
    01571
    01572         ts->di = _free(ts->di);
    01573         dip = ts->di = xcalloc(sizeof(*ts->di), ts->filesystemCount + 1);
    01574
    01575         for (i = 0; (i < ts->filesystemCount) && dip; i++) {
    01576 #if STATFS_IN_SYS_STATVFS
    01577             struct statvfs sfb;
    01578             memset(&sfb, 0, sizeof(sfb));
    01579             if (statvfs(ts->filesystems[i], &sfb))
    01580 #else
    01581             struct statfs sfb;
    01582 #  if STAT_STATFS4
    01583 /* This platform has the 4-argument version of the statfs call.  The last two
    01584  * should be the size of struct statfs and 0, respectively.  The 0 is the
    01585  * filesystem type, and is always 0 when statfs is called on a mounted
    01586  * filesystem, as we're doing.
    01587  */
    01588             memset(&sfb, 0, sizeof(sfb));
    01589             if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
    01590 #  else
    01591             memset(&sfb, 0, sizeof(sfb));
    01592             if (statfs(ts->filesystems[i], &sfb))
    01593 #  endif
    01594 #endif
    01595             {
    01596                 dip = NULL;
    01597             } else {
    01598                 ts->di[i].bsize = sfb.f_bsize;
    01599                 ts->di[i].bneeded = 0;
    01600                 ts->di[i].ineeded = 0;
    01601 #ifdef STATFS_HAS_F_BAVAIL
    01602                 ts->di[i].bavail = sfb.f_bavail;
    01603 #else
    01604 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
    01605  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
    01606  * it's about all we can do.
    01607  */
    01608                 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
    01609 #endif
    01610                 /* XXX Avoid FAT and other file systems that have not inodes. */
    01611                 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
    01612                                 ? sfb.f_ffree : -1;
    01613
    01614                 (void) stat(ts->filesystems[i], &sb);
    01615                 ts->di[i].dev = sb.st_dev;
    01616             }
    01617         }
    01618
    01619         if (dip) ts->di[i].bsize = 0;
    01620     }
    01621
    01622     /* ===============================================
    01623      * For packages being installed:
    01624      * - verify package arch/os.
    01625      * - verify package epoch:version-release is newer.
    01626      * - count files.
    01627      * For packages being removed:
    01628      * - count files.
    01629      */
    01630     /* The ordering doesn't matter here */
    01631     if (ts->addedPackages.list != NULL)
    01632     for (alp = ts->addedPackages.list;
    01633         (alp - ts->addedPackages.list) < ts->addedPackages.size;
    01634         alp++)
    01635     {
    01636         if (!archOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
    01637             psAppend(ts->probs, RPMPROB_BADARCH, alp, NULL, NULL, NULL, 0);
    01638
    01639         if (!osOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
    01640             psAppend(ts->probs, RPMPROB_BADOS, alp, NULL, NULL, NULL, 0);
    01641
    01642         if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
    01643             rpmdbMatchIterator mi;
    01644             Header oldH;
    01645             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
    01646             while ((oldH = rpmdbNextIterator(mi)) != NULL)
    01647                 (void) ensureOlder(alp, oldH, ts->probs);
    01648             mi = rpmdbFreeIterator(mi);
    01649         }
    01650
    01651         /* XXX multilib should not display "already installed" problems */
    01652         if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG) && !alp->multiLib) {
    01653             rpmdbMatchIterator mi;
    01654             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
    01655             (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
    01656                         RPMMIRE_DEFAULT, alp->version);
    01657             (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
    01658                         RPMMIRE_DEFAULT, alp->release);
    01659
    01660             while (rpmdbNextIterator(mi) != NULL) {
    01661                 psAppend(ts->probs, RPMPROB_PKG_INSTALLED, alp,
    01662                         NULL, NULL, NULL, 0);
    01663                 /*@innerbreak@*/ break;
    01664             }
    01665             mi = rpmdbFreeIterator(mi);
    01666         }
    01667
    01668         totalFileCount += alp->filesCount;
    01669
    01670     }
    01671
    01672     /* FIXME: it seems a bit silly to read in all of these headers twice */
    01673     /* The ordering doesn't matter here */
    01674     if (ts->numRemovedPackages > 0) {
    01675         rpmdbMatchIterator mi;
    01676         Header h;
    01677         int fileCount;
    01678
    01679         mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
    01680         (void) rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
    01681         while ((h = rpmdbNextIterator(mi)) != NULL) {
    01682             if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
    01683                 totalFileCount += fileCount;
    01684         }
    01685         mi = rpmdbFreeIterator(mi);
    01686     }
    01687
    01688     /* ===============================================
    01689      * Initialize file list:
    01690      */
    01691     ts->flEntries = ts->addedPackages.size + ts->numRemovedPackages;
    01692     ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
    01693
    01694     /*
    01695      * FIXME?: we'd be better off assembling one very large file list and
    01696      * calling fpLookupList only once. I'm not sure that the speedup is
    01697      * worth the trouble though.
    01698      */
    01699     tsi = tsInitIterator(ts);
    01700     while ((fi = tsNextIterator(tsi)) != NULL) {
    01701         oc = tsGetOc(tsi);
    01702         fi->magic = TFIMAGIC;
    01703
    01704         /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
    01705         fi->type = ts->order[oc].type;
    01706         switch (fi->type) {
    01707         case TR_ADDED:
    01708             i = ts->order[oc].u.addedIndex;
    01709             /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
    01710             fi->ap = tsGetAlp(tsi);
    01711             fi->record = 0;
    01712             loadFi(fi->ap->h, fi);
    01713             if (fi->fc == 0)
    01714                 continue;
    01715
    01716             {   Header foo = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
    01717                 foo = headerFree(foo);
    01718             }
    01719
    01720             /* Skip netshared paths, not our i18n files, and excluded docs */
    01721             skipFiles(ts, fi);
    01722             break;
    01723         case TR_REMOVED:
    01724             fi->ap = NULL;
    01725             fi->record = ts->order[oc].u.removed.dboffset;
    01726             {   rpmdbMatchIterator mi;
    01727
    01728                 mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
    01729                                 &fi->record, sizeof(fi->record));
    01730                 if ((fi->h = rpmdbNextIterator(mi)) != NULL)
    01731                     fi->h = headerLink(fi->h);
    01732                 mi = rpmdbFreeIterator(mi);
    01733             }
    01734             if (fi->h == NULL) {
    01735                 /* ACK! */
    01736                 continue;
    01737             }
    01738             /* XXX header arg unused. */
    01739             loadFi(fi->h, fi);
    01740             break;
    01741         }
    01742
    01743         if (fi->fc)
    01744             fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
    01745     }
    01746     tsi = tsFreeIterator(tsi);
    01747
    01748     if (!ts->chrootDone) {
    01749         (void) chdir("/");
    01750         /*@-unrecog -superuser @*/
    01751         (void) chroot(ts->rootDir);
    01752         /*@=unrecog =superuser @*/
    01753         ts->chrootDone = 1;
    01754         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
    01755 #ifdef  DYING
    01756         /*@-onlytrans@*/
    01757         chroot_prefix = ts->rootDir;
    01758         /*@=onlytrans@*/
    01759 #endif
    01760     }
    01761
    01762     ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
    01763     fpc = fpCacheCreate(totalFileCount);
    01764
    01765     /* ===============================================
    01766      * Add fingerprint for each file not skipped.
    01767      */
    01768     tsi = tsInitIterator(ts);
    01769     while ((fi = tsNextIterator(tsi)) != NULL) {
    01770         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
    01771         for (i = 0; i < fi->fc; i++) {
    01772             if (XFA_SKIPPING(fi->actions[i]))
    01773                 continue;
    01774             /*@-dependenttrans@*/
    01775             htAddEntry(ht, fi->fps + i, fi);
    01776             /*@=dependenttrans@*/
    01777         }
    01778     }
    01779     tsi = tsFreeIterator(tsi);
    01780
    01781     /*@-moduncon@*/
    01782     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
    01783         NULL, ts->notifyData));
    01784     /*@=moduncon@*/
    01785
    01786     /* ===============================================
    01787      * Compute file disposition for each package in transaction set.
    01788      */
    01789     tsi = tsInitIterator(ts);
    01790     while ((fi = tsNextIterator(tsi)) != NULL) {
    01791         dbiIndexSet * matches;
    01792         int knownBad;
    01793
    01794         /*@-moduncon@*/
    01795         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
    01796                         ts->flEntries, NULL, ts->notifyData));
    01797         /*@=moduncon@*/
    01798
    01799         if (fi->fc == 0) continue;
    01800
    01801         /* Extract file info for all files in this package from the database. */
    01802         matches = xcalloc(sizeof(*matches), fi->fc);
    01803         if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc))
    01804             return 1;   /* XXX WTFO? */
    01805
    01806         numShared = 0;
    01807         for (i = 0; i < fi->fc; i++)
    01808             numShared += dbiIndexSetCount(matches[i]);
    01809
    01810         /* Build sorted file info list for this package. */
    01811         shared = sharedList = xmalloc((numShared + 1) * sizeof(*sharedList));
    01812         for (i = 0; i < fi->fc; i++) {
    01813             /*
    01814              * Take care not to mark files as replaced in packages that will
    01815              * have been removed before we will get here.
    01816              */
    01817             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
    01818                 int k, ro;
    01819                 ro = dbiIndexRecordOffset(matches[i], j);
    01820                 knownBad = 0;
    01821                 for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
    01822                     switch (ts->order[k].type) {
    01823                     case TR_REMOVED:
    01824                         if (ts->order[k].u.removed.dboffset == ro)
    01825                             knownBad = ro;
    01826                         break;
    01827                     case TR_ADDED:
    01828                         break;
    01829                     }
    01830                 }
    01831
    01832                 shared->pkgFileNum = i;
    01833                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
    01834                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
    01835                 shared->isRemoved = (knownBad == ro);
    01836                 shared++;
    01837             }
    01838             matches[i] = dbiFreeIndexSet(matches[i]);
    01839         }
    01840         numShared = shared - sharedList;
    01841         shared->otherPkg = -1;
    01842         matches = _free(matches);
    01843
    01844         /* Sort file info by other package index (otherPkg) */
    01845         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
    01846
    01847         /* For all files from this package that are in the database ... */
    01848         for (i = 0; i < numShared; i = nexti) {
    01849             int beingRemoved;
    01850
    01851             shared = sharedList + i;
    01852
    01853             /* Find the end of the files in the other package. */
    01854             for (nexti = i + 1; nexti < numShared; nexti++) {
    01855                 if (sharedList[nexti].otherPkg != shared->otherPkg)
    01856                     /*@innerbreak@*/ break;
    01857             }
    01858
    01859             /* Is this file from a package being removed? */
    01860             beingRemoved = 0;
    01861             for (j = 0; j < ts->numRemovedPackages; j++) {
    01862                 if (ts->removedPackages[j] != shared->otherPkg)
    01863                     continue;
    01864                 beingRemoved = 1;
    01865                 /*@innerbreak@*/ break;
    01866             }
    01867
    01868             /* Determine the fate of each file. */
    01869             switch (fi->type) {
    01870             case TR_ADDED:
    01871                 (void) handleInstInstalledFiles(fi, ts->rpmdb, shared, nexti - i,
    01872                 !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)),
    01873                          ts->probs, ts->transFlags);
    01874                 break;
    01875             case TR_REMOVED:
    01876                 if (!beingRemoved)
    01877                     (void) handleRmvdInstalledFiles(fi, ts->rpmdb, shared, nexti - i);
    01878                 break;
    01879             }
    01880         }
    01881
    01882         free(sharedList);
    01883
    01884         /* Update disk space needs on each partition for this package. */
    01885         handleOverlappedFiles(fi, ht,
    01886                ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
    01887                     ? NULL : ts->probs), ts->di);
    01888
    01889         /* Check added package has sufficient space on each partition used. */
    01890         switch (fi->type) {
    01891         case TR_ADDED:
    01892             if (!(ts->di && fi->fc))
    01893                 break;
    01894             for (i = 0; i < ts->filesystemCount; i++) {
    01895
    01896                 dip = ts->di + i;
    01897
    01898                 /* XXX Avoid FAT and other file systems that have not inodes. */
    01899                 if (dip->iavail <= 0)
    01900                     continue;
    01901
    01902                 if (adj_fs_blocks(dip->bneeded) > dip->bavail)
    01903                     psAppend(ts->probs, RPMPROB_DISKSPACE, fi->ap,
    01904                                 ts->filesystems[i], NULL, NULL,
    01905                    (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
    01906
    01907                 if (adj_fs_blocks(dip->ineeded) > dip->iavail)
    01908                     psAppend(ts->probs, RPMPROB_DISKNODES, fi->ap,
    01909                                 ts->filesystems[i], NULL, NULL,
    01910                     (adj_fs_blocks(dip->ineeded) - dip->iavail));
    01911             }
    01912             break;
    01913         case TR_REMOVED:
    01914             break;
    01915         }
    01916     }
    01917     tsi = tsFreeIterator(tsi);
    01918
    01919     if (ts->chrootDone) {
    01920         /*@-unrecog -superuser @*/
    01921         (void) chroot(".");
    01922         /*@=unrecog =superuser @*/
    01923         ts->chrootDone = 0;
    01924         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
    01925 #ifdef  DYING
    01926         chroot_prefix = NULL;
    01927 #endif
    01928         (void) chdir(ts->currDir);
    01929     }
    01930
    01931     /*@-moduncon@*/
    01932     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
    01933         NULL, ts->notifyData));
    01934     /*@=moduncon@*/
    01935
    01936     /* ===============================================
    01937      * Free unused memory as soon as possible.
    01938      */
    01939
    01940     tsi = tsInitIterator(ts);
    01941     while ((fi = tsNextIterator(tsi)) != NULL) {
    01942         psm->fi = fi;
    01943         if (fi->fc == 0)
    01944             continue;
    01945         fi->fps = _free(fi->fps);
    01946     }
    01947     tsi = tsFreeIterator(tsi);
    01948
    01949     fpCacheFree(fpc);
    01950     htFree(ht);
    01951
    01952     /* ===============================================
    01953      * If unfiltered problems exist, free memory and return.
    01954      */
    01955     if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS) ||
    01956            (ts->probs->numProblems && (!okProbs || psTrim(okProbs, ts->probs))))
    01957     {
    01958         *newProbs = ts->probs;
    01959
    01960         ts->flList = freeFl(ts, ts->flList);
    01961         ts->flEntries = 0;
    01962         /*@-nullstate@*/
    01963         return ts->orderCount;
    01964         /*@=nullstate@*/
    01965     }
    01966
    01967     /* ===============================================
    01968      * Save removed files before erasing.
    01969      */
    01970     if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
    01971         tsi = tsInitIterator(ts);
    01972         while ((fi = tsNextIterator(tsi)) != NULL) {
    01973             psm->fi = fi;
    01974             switch (fi->type) {
    01975             case TR_ADDED:
    01976                 break;
    01977             case TR_REMOVED:
    01978                 if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE)
    01979                     (void) psmStage(psm, PSM_PKGSAVE);
    01980                 break;
    01981             }
    01982         }
    01983         tsi = tsFreeIterator(tsi);
    01984     }
    01985
    01986     /* ===============================================
    01987      * Install and remove packages.
    01988      */
    01989
    01990     lastFailed = -2;    /* erased packages have -1 */
    01991     tsi = tsInitIterator(ts);
    01992     while ((fi = tsNextIterator(tsi)) != NULL) {
    01993         Header h;
    01994         int gotfd;
    01995
    01996         gotfd = 0;
    01997         psm->fi = fi;
    01998         switch (fi->type)
    01999         {
    02000         case TR_ADDED:
    02001             alp = tsGetAlp(tsi);
    02002 assert(alp == fi->ap);
    02003             i = alp - ts->addedPackages.list;
    02004
    02005             h = headerLink(fi->h);
    02006             if (alp->fd == NULL) {
    02007                 alp->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
    02008                             alp->key, ts->notifyData);
    02009                 if (alp->fd) {
    02010                     rpmRC rpmrc;
    02011
    02012                     h = headerFree(h);
    02013
    02014                     /*@-mustmod@*/      /* LCL: segfault */
    02015                     rpmrc = rpmReadPackageHeader(alp->fd, &h, NULL, NULL, NULL);
    02016                     /*@=mustmod@*/
    02017                     if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
    02018                         (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
    02019                                         0, 0, alp->key, ts->notifyData);
    02020                         alp->fd = NULL;
    02021                         ourrc++;
    02022                     } else {
    02023                         Header foo = relocateFileList(ts, fi, alp, h, NULL);
    02024                         h = headerFree(h);
    02025                         h = headerLink(foo);
    02026                         foo = headerFree(foo);
    02027                     }
    02028                     if (alp->fd) gotfd = 1;
    02029                 }
    02030             }
    02031
    02032             if (alp->fd) {
    02033                 Header hsave = NULL;
    02034
    02035                 if (fi->h) {
    02036                     hsave = headerLink(fi->h);
    02037                     fi->h = headerFree(fi->h);
    02038                 }
    02039                 fi->h = headerLink(h);
    02040                 if (alp->multiLib)
    02041                     ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
    02042
    02043 assert(alp == fi->ap);
    02044                 if (psmStage(psm, PSM_PKGINSTALL)) {
    02045                     ourrc++;
    02046                     lastFailed = i;
    02047                 }
    02048                 fi->h = headerFree(fi->h);
    02049                 if (hsave) {
    02050                     fi->h = headerLink(hsave);
    02051                     hsave = headerFree(hsave);
    02052                 }
    02053             } else {
    02054                 ourrc++;
    02055                 lastFailed = i;
    02056             }
    02057
    02058             h = headerFree(h);
    02059
    02060             if (gotfd) {
    02061                 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
    02062                         alp->key, ts->notifyData);
    02063                 alp->fd = NULL;
    02064             }
    02065             break;
    02066         case TR_REMOVED:
    02067             oc = tsGetOc(tsi);
    02068             /* If install failed, then we shouldn't erase. */
    02069             if (ts->order[oc].u.removed.dependsOnIndex == lastFailed)
    02070                 break;
    02071
    02072             if (psmStage(psm, PSM_PKGERASE))
    02073                 ourrc++;
    02074
    02075             break;
    02076         }
    02077         (void) rpmdbSync(ts->rpmdb);
    02078     }
    02079     tsi = tsFreeIterator(tsi);
    02080
    02081     ts->flList = freeFl(ts, ts->flList);
    02082     ts->flEntries = 0;
    02083
    02084     /*@-nullstate@*/
    02085     if (ourrc)
    02086         return -1;
    02087     else
    02088         return 0;
    02089     /*@=nullstate@*/
    02090 }