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

transaction.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
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 }

Generated on Thu Oct 13 04:19:56 2005 for rpm by  doxygen 1.4.1