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

lib/transaction.c

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

Generated at Mon Dec 3 13:19:39 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001