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             /* Verify that the relocation's old path is in the header. */
00407             for (j = 0; j < numValid; j++)
00408                 if (!strcmp(validRelocations[j], relocations[i].oldPath))
00409                     /*@innerbreak@*/ break;
00410             /* XXX actions check prevents problem from being appended twice. */
00411             if (j == numValid && !allowBadRelocate && actions)
00412                 psAppend(probs, RPMPROB_BADRELOCATE, alp,
00413                          relocations[i].oldPath, NULL, NULL, 0);
00414             del =
00415                 strlen(relocations[i].newPath) - strlen(relocations[i].oldPath);
00416             if (del > reldel)
00417                 reldel = del;
00418         } else {
00419             relocations[i].newPath = NULL;
00420         }
00421     }
00422 
00423     /* stupid bubble sort, but it's probably faster here */
00424     for (i = 0; i < numRelocations; i++) {
00425         int madeSwap;
00426         madeSwap = 0;
00427         for (j = 1; j < numRelocations; j++) {
00428             rpmRelocation tmpReloc;
00429             if (relocations[j - 1].oldPath == NULL || /* XXX can't happen */
00430                 relocations[j    ].oldPath == NULL || /* XXX can't happen */
00431         strcmp(relocations[j - 1].oldPath, relocations[j].oldPath) <= 0)
00432                 continue;
00433             tmpReloc = relocations[j - 1];
00434             relocations[j - 1] = relocations[j];
00435             relocations[j] = tmpReloc;
00436             madeSwap = 1;
00437         }
00438         if (!madeSwap) break;
00439     }
00440 
00441     if (!_printed) {
00442         _printed = 1;
00443         rpmMessage(RPMMESS_DEBUG, _("========== relocations\n"));
00444         for (i = 0; i < numRelocations; i++) {
00445             if (relocations[i].oldPath == NULL) continue; /* XXX can't happen */
00446             if (relocations[i].newPath == NULL)
00447                 rpmMessage(RPMMESS_DEBUG, _("%5d exclude  %s\n"),
00448                         i, relocations[i].oldPath);
00449             else
00450                 rpmMessage(RPMMESS_DEBUG, _("%5d relocate %s -> %s\n"),
00451                         i, relocations[i].oldPath, relocations[i].newPath);
00452         }
00453     }
00454 
00455     /* Add relocation values to the header */
00456     if (numValid) {
00457         const char ** actualRelocations;
00458         int numActual;
00459 
00460         actualRelocations = xmalloc(numValid * sizeof(*actualRelocations));
00461         numActual = 0;
00462         for (i = 0; i < numValid; i++) {
00463             for (j = 0; j < numRelocations; j++) {
00464                 if (relocations[j].oldPath == NULL || /* XXX can't happen */
00465                     strcmp(validRelocations[i], relocations[j].oldPath))
00466                     continue;
00467                 /* On install, a relocate to NULL means skip the path. */
00468                 if (relocations[j].newPath) {
00469                     actualRelocations[numActual] = relocations[j].newPath;
00470                     numActual++;
00471                 }
00472                 /*@innerbreak@*/ break;
00473             }
00474             if (j == numRelocations) {
00475                 actualRelocations[numActual] = validRelocations[i];
00476                 numActual++;
00477             }
00478         }
00479 
00480         if (numActual)
00481             (void) hae(h, RPMTAG_INSTPREFIXES, RPM_STRING_ARRAY_TYPE,
00482                        (void **) actualRelocations, numActual);
00483 
00484         actualRelocations = _free(actualRelocations);
00485         validRelocations = hfd(validRelocations, validType);
00486     }
00487 
00488     (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &baseNames, &fileCount);
00489     (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00490     (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, &dirCount);
00491     (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fFlags, NULL);
00492     (void) hge(h, RPMTAG_FILEMODES, NULL, (void **) &fModes, NULL);
00493 
00494     skipDirList = alloca(dirCount * sizeof(*skipDirList));
00495     memset(skipDirList, 0, dirCount * sizeof(*skipDirList));
00496 
00497     newDirIndexes = alloca(sizeof(*newDirIndexes) * fileCount);
00498     memcpy(newDirIndexes, dirIndexes, sizeof(*newDirIndexes) * fileCount);
00499     dirIndexes = newDirIndexes;
00500 
00501     /*
00502      * For all relocations, we go through sorted file/relocation lists 
00503      * backwards so that /usr/local relocations take precedence over /usr 
00504      * ones.
00505      */
00506 
00507     /* Relocate individual paths. */
00508 
00509     for (i = fileCount - 1; i >= 0; i--) {
00510         fileTypes ft;
00511         int fnlen;
00512 
00513         /*
00514          * If only adding libraries of different arch into an already
00515          * installed package, skip all other files.
00516          */
00517         if (alp->multiLib && !isFileMULTILIB((fFlags[i]))) {
00518             if (actions) {
00519                 actions[i] = FA_SKIPMULTILIB;
00520                 rpmMessage(RPMMESS_DEBUG, _("excluding multilib path %s%s\n"), 
00521                         dirNames[dirIndexes[i]], baseNames[i]);
00522             }
00523             continue;
00524         }
00525 
00526         len = reldel +
00527                 strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
00528         if (len >= fileAlloced) {
00529             fileAlloced = len * 2;
00530             fn = xrealloc(fn, fileAlloced);
00531         }
00532         *fn = '\0';
00533         fnlen = stpcpy( stpcpy(fn, dirNames[dirIndexes[i]]), baseNames[i]) - fn;
00534 
00535         /*
00536          * See if this file path needs relocating.
00537          */
00538         /*
00539          * XXX FIXME: Would a bsearch of the (already sorted) 
00540          * relocation list be a good idea?
00541          */
00542         for (j = numRelocations - 1; j >= 0; j--) {
00543             if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
00544             len = strcmp(relocations[j].oldPath, "/")
00545                 ? strlen(relocations[j].oldPath)
00546                 : 0;
00547 
00548             if (fnlen < len)
00549                 continue;
00550             /*
00551              * Only subdirectories or complete file paths may be relocated. We
00552              * don't check for '\0' as our directory names all end in '/'.
00553              */
00554             if (!(fn[len] == '/' || fnlen == len))
00555                 continue;
00556 
00557             if (strncmp(relocations[j].oldPath, fn, len))
00558                 continue;
00559             /*@innerbreak@*/ break;
00560         }
00561         if (j < 0) continue;
00562 
00563         ft = whatis(fModes[i]);
00564 
00565         /* On install, a relocate to NULL means skip the path. */
00566         if (relocations[j].newPath == NULL) {
00567             if (ft == XDIR) {
00568                 /* Start with the parent, looking for directory to exclude. */
00569                 for (j = dirIndexes[i]; j < dirCount; j++) {
00570                     len = strlen(dirNames[j]) - 1;
00571                     while (len > 0 && dirNames[j][len-1] == '/') len--;
00572                     if (fnlen != len)
00573                         continue;
00574                     if (strncmp(fn, dirNames[j], fnlen))
00575                         continue;
00576                     /*@innerbreak@*/ break;
00577                 }
00578                 if (j < dirCount)
00579                     skipDirList[j] = 1;
00580             }
00581             if (actions) {
00582                 actions[i] = FA_SKIPNSTATE;
00583                 rpmMessage(RPMMESS_DEBUG, _("excluding %s %s\n"),
00584                         ftstring(ft), fn);
00585             }
00586             continue;
00587         }
00588 
00589         /* Relocation on full paths only, please. */
00590         if (fnlen != len) continue;
00591 
00592         if (actions)
00593             rpmMessage(RPMMESS_DEBUG, _("relocating %s to %s\n"),
00594                     fn, relocations[j].newPath);
00595         nrelocated++;
00596 
00597         strcpy(fn, relocations[j].newPath);
00598         {   char * te = strrchr(fn, '/');
00599             if (te) {
00600                 if (te > fn) te++;      /* root is special */
00601                 fnlen = te - fn;
00602             } else
00603                 te = fn + strlen(fn);
00604             /*@-nullpass -nullderef@*/  /* LCL: te != NULL here. */
00605             if (strcmp(baseNames[i], te)) /* basename changed too? */
00606                 baseNames[i] = alloca_strdup(te);
00607             *te = '\0';                 /* terminate new directory name */
00608             /*@=nullpass =nullderef@*/
00609         }
00610 
00611         /* Does this directory already exist in the directory list? */
00612         for (j = 0; j < dirCount; j++) {
00613             if (fnlen != strlen(dirNames[j]))
00614                 continue;
00615             if (strncmp(fn, dirNames[j], fnlen))
00616                 continue;
00617             /*@innerbreak@*/ break;
00618         }
00619         
00620         if (j < dirCount) {
00621             dirIndexes[i] = j;
00622             continue;
00623         }
00624 
00625         /* Creating new paths is a pita */
00626         if (!haveRelocatedFile) {
00627             const char ** newDirList;
00628 
00629             haveRelocatedFile = 1;
00630             newDirList = xmalloc((dirCount + 1) * sizeof(*newDirList));
00631             for (j = 0; j < dirCount; j++)
00632                 newDirList[j] = alloca_strdup(dirNames[j]);
00633             dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
00634             dirNames = newDirList;
00635         } else {
00636             dirNames = xrealloc(dirNames, 
00637                                sizeof(*dirNames) * (dirCount + 1));
00638         }
00639 
00640         dirNames[dirCount] = alloca_strdup(fn);
00641         dirIndexes[i] = dirCount;
00642         dirCount++;
00643     }
00644 
00645     /* Finish off by relocating directories. */
00646     for (i = dirCount - 1; i >= 0; i--) {
00647         for (j = numRelocations - 1; j >= 0; j--) {
00648 
00649             if (relocations[j].oldPath == NULL) continue; /* XXX can't happen */
00650             len = strcmp(relocations[j].oldPath, "/")
00651                 ? strlen(relocations[j].oldPath)
00652                 : 0;
00653 
00654             if (len && strncmp(relocations[j].oldPath, dirNames[i], len))
00655                 continue;
00656 
00657             /*
00658              * Only subdirectories or complete file paths may be relocated. We
00659              * don't check for '\0' as our directory names all end in '/'.
00660              */
00661             if (dirNames[i][len] != '/')
00662                 continue;
00663 
00664             if (relocations[j].newPath) { /* Relocate the path */
00665                 const char * s = relocations[j].newPath;
00666                 char * t = alloca(strlen(s) + strlen(dirNames[i]) - len + 1);
00667 
00668                 (void) stpcpy( stpcpy(t, s) , dirNames[i] + len);
00669                 if (actions)
00670                     rpmMessage(RPMMESS_DEBUG,
00671                         _("relocating directory %s to %s\n"), dirNames[i], t);
00672                 dirNames[i] = t;
00673                 nrelocated++;
00674             }
00675         }
00676     }
00677 
00678     /* Save original filenames in header and replace (relocated) filenames. */
00679     if (nrelocated) {
00680         int c;
00681         void * p;
00682         rpmTagType t;
00683 
00684         p = NULL;
00685         (void) hge(h, RPMTAG_BASENAMES, &t, &p, &c);
00686         (void) hae(h, RPMTAG_ORIGBASENAMES, t, p, c);
00687         p = hfd(p, t);
00688 
00689         p = NULL;
00690         (void) hge(h, RPMTAG_DIRNAMES, &t, &p, &c);
00691         (void) hae(h, RPMTAG_ORIGDIRNAMES, t, p, c);
00692         p = hfd(p, t);
00693 
00694         p = NULL;
00695         (void) hge(h, RPMTAG_DIRINDEXES, &t, &p, &c);
00696         (void) hae(h, RPMTAG_ORIGDIRINDEXES, t, p, c);
00697         p = hfd(p, t);
00698 
00699         (void) hme(h, RPMTAG_BASENAMES, RPM_STRING_ARRAY_TYPE,
00700                           baseNames, fileCount);
00701         fi->bnl = hfd(fi->bnl, RPM_STRING_ARRAY_TYPE);
00702         (void) hge(h, RPMTAG_BASENAMES, NULL, (void **) &fi->bnl, &fi->fc);
00703 
00704         (void) hme(h, RPMTAG_DIRNAMES, RPM_STRING_ARRAY_TYPE,
00705                           dirNames, dirCount);
00706         fi->dnl = hfd(fi->dnl, RPM_STRING_ARRAY_TYPE);
00707         (void) hge(h, RPMTAG_DIRNAMES, NULL, (void **) &fi->dnl, &fi->dc);
00708 
00709         (void) hme(h, RPMTAG_DIRINDEXES, RPM_INT32_TYPE,
00710                           dirIndexes, fileCount);
00711         (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fi->dil, NULL);
00712     }
00713 
00714     baseNames = hfd(baseNames, RPM_STRING_ARRAY_TYPE);
00715     dirNames = hfd(dirNames, RPM_STRING_ARRAY_TYPE);
00716     fn = _free(fn);
00717 
00718     return h;
00719 }
00720 
00721 /*
00722  * As the problem sets are generated in an order solely dependent
00723  * on the ordering of the packages in the transaction, and that
00724  * ordering can't be changed, the problem sets must be parallel to
00725  * one another. Additionally, the filter set must be a subset of the
00726  * target set, given the operations available on transaction set.
00727  * This is good, as it lets us perform this trim in linear time, rather
00728  * then logarithmic or quadratic.
00729  */
00730 static int psTrim(rpmProblemSet filter, rpmProblemSet target)
00731         /*@modifies target @*/
00732 {
00733     rpmProblem f = filter->probs;
00734     rpmProblem t = target->probs;
00735     int gotProblems = 0;
00736 
00737     while ((f - filter->probs) < filter->numProblems) {
00738         if (!f->ignoreProblem) {
00739             f++;
00740             continue;
00741         }
00742         while ((t - target->probs) < target->numProblems) {
00743             /*@-nullpass@*/     /* LCL: looks good to me */
00744             if (f->h == t->h && f->type == t->type && t->key == f->key &&
00745                      XSTRCMP(f->str1, t->str1))
00746                 /*@innerbreak@*/ break;
00747             /*@=nullpass@*/
00748             t++;
00749             gotProblems = 1;
00750         }
00751 
00752         if ((t - target->probs) == target->numProblems) {
00753             /* this can't happen ;-) lets be sane if it doesn though */
00754             break;
00755         }
00756 
00757         t->ignoreProblem = f->ignoreProblem;
00758         t++, f++;
00759     }
00760 
00761     if ((t - target->probs) < target->numProblems)
00762         gotProblems = 1;
00763 
00764     return gotProblems;
00765 }
00766 
00767 static int sharedCmp(const void * one, const void * two)
00768         /*@*/
00769 {
00770     const struct sharedFileInfo * a = one;
00771     const struct sharedFileInfo * b = two;
00772 
00773     if (a->otherPkg < b->otherPkg)
00774         return -1;
00775     else if (a->otherPkg > b->otherPkg)
00776         return 1;
00777 
00778     return 0;
00779 }
00780 
00781 static fileAction decideFileFate(const char * dirName,
00782                         const char * baseName, short dbMode,
00783                         const char * dbMd5, const char * dbLink, short newMode,
00784                         const char * newMd5, const char * newLink, int newFlags,
00785                         int brokenMd5, rpmtransFlags transFlags)
00786         /*@*/
00787 {
00788     char buffer[1024];
00789     const char * dbAttr, * newAttr;
00790     fileTypes dbWhat, newWhat, diskWhat;
00791     struct stat sb;
00792     int i, rc;
00793     int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
00794     char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
00795 
00796     (void) stpcpy( stpcpy(filespec, dirName), baseName);
00797 
00798     if (lstat(filespec, &sb)) {
00799         /*
00800          * The file doesn't exist on the disk. Create it unless the new
00801          * package has marked it as missingok, or allfiles is requested.
00802          */
00803         if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
00804            (newFlags & RPMFILE_MISSINGOK)) {
00805             rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
00806                         filespec);
00807             return FA_SKIP;
00808         } else {
00809             return FA_CREATE;
00810         }
00811     }
00812 
00813     diskWhat = whatis(sb.st_mode);
00814     dbWhat = whatis(dbMode);
00815     newWhat = whatis(newMode);
00816 
00817     /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
00818        them in older packages as well */
00819     if (newWhat == XDIR) {
00820         return FA_CREATE;
00821     }
00822 
00823     if (diskWhat != newWhat) {
00824         return save;
00825     } else if (newWhat != dbWhat && diskWhat != dbWhat) {
00826         return save;
00827     } else if (dbWhat != newWhat) {
00828         return FA_CREATE;
00829     } else if (dbWhat != LINK && dbWhat != REG) {
00830         return FA_CREATE;
00831     }
00832 
00833     if (dbWhat == REG) {
00834         if (brokenMd5)
00835             rc = mdfileBroken(filespec, buffer);
00836         else
00837             rc = mdfile(filespec, buffer);
00838 
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                         !headerIsEntry(h, RPMTAG_RPMVERSION),
00975                         transFlags);
00976         }
00977 
00978         fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
00979     }
00980 
00981     otherMd5s = hfd(otherMd5s, omtype);
00982     otherLinks = hfd(otherLinks, oltype);
00983     mi = rpmdbFreeIterator(mi);
00984 
00985     fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
00986                            sizeof(*fi->replaced) * (numReplaced + 1));
00987     fi->replaced[numReplaced].otherPkg = 0;
00988 
00989     return 0;
00990 }
00991 
00992 static int handleRmvdInstalledFiles(TFI_t fi, /*@null@*/ rpmdb db,
00993                                     struct sharedFileInfo * shared,
00994                                     int sharedCount)
00995         /*@modifies fi, db @*/
00996 {
00997     HGE_t hge = fi->hge;
00998     Header h;
00999     const char * otherStates;
01000     int i;
01001    
01002     rpmdbMatchIterator mi;
01003 
01004     mi = rpmdbInitIterator(db, RPMDBI_PACKAGES,
01005                         &shared->otherPkg, sizeof(shared->otherPkg));
01006     h = rpmdbNextIterator(mi);
01007     if (h == NULL) {
01008         mi = rpmdbFreeIterator(mi);
01009         return 1;
01010     }
01011 
01012     (void) hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
01013 
01014     for (i = 0; i < sharedCount; i++, shared++) {
01015         int otherFileNum, fileNum;
01016         otherFileNum = shared->otherFileNum;
01017         fileNum = shared->pkgFileNum;
01018 
01019         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
01020             continue;
01021 
01022         fi->actions[fileNum] = FA_SKIP;
01023     }
01024 
01025     mi = rpmdbFreeIterator(mi);
01026 
01027     return 0;
01028 }
01029 
01033 static void handleOverlappedFiles(TFI_t fi, hashTable ht,
01034                            rpmProblemSet probs, struct diskspaceInfo * dsl)
01035         /*@modifies fi, probs, dsl @*/
01036 {
01037     int i, j;
01038     struct diskspaceInfo * ds = NULL;
01039     uint_32 fixupSize = 0;
01040     char * filespec = NULL;
01041     int fileSpecAlloced = 0;
01042   
01043     for (i = 0; i < fi->fc; i++) {
01044         int otherPkgNum, otherFileNum;
01045         const TFI_t * recs;
01046         int numRecs;
01047 
01048         if (XFA_SKIPPING(fi->actions[i]))
01049             continue;
01050 
01051         j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
01052         if (j > fileSpecAlloced) {
01053             fileSpecAlloced = j * 2;
01054             filespec = xrealloc(filespec, fileSpecAlloced);
01055         }
01056 
01057         (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
01058 
01059         if (dsl) {
01060             ds = dsl;
01061             while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
01062             if (!ds->bsize) ds = NULL;
01063             fixupSize = 0;
01064         }
01065 
01066         /*
01067          * Retrieve all records that apply to this file. Note that the
01068          * file info records were built in the same order as the packages
01069          * will be installed and removed so the records for an overlapped
01070          * files will be sorted in exactly the same order.
01071          */
01072         (void) htGetEntry(ht, &fi->fps[i], (const void ***) &recs, &numRecs, NULL);
01073 
01074         /*
01075          * If this package is being added, look only at other packages
01076          * being added -- removed packages dance to a different tune.
01077          * If both this and the other package are being added, overlapped
01078          * files must be identical (or marked as a conflict). The
01079          * disposition of already installed config files leads to
01080          * a small amount of extra complexity.
01081          *
01082          * If this package is being removed, then there are two cases that
01083          * need to be worried about:
01084          * If the other package is being added, then skip any overlapped files
01085          * so that this package removal doesn't nuke the overlapped files
01086          * that were just installed.
01087          * If both this and the other package are being removed, then each
01088          * file removal from preceding packages needs to be skipped so that
01089          * the file removal occurs only on the last occurence of an overlapped
01090          * file in the transaction set.
01091          *
01092          */
01093 
01094         /* Locate this overlapped file in the set of added/removed packages. */
01095         for (j = 0; j < numRecs && recs[j] != fi; j++)
01096             {};
01097 
01098         /* Find what the previous disposition of this file was. */
01099         otherFileNum = -1;                      /* keep gcc quiet */
01100         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
01101             /* Added packages need only look at other added packages. */
01102             if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
01103                 continue;
01104 
01105             /* TESTME: there are more efficient searches in the world... */
01106             for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
01107                  otherFileNum++) {
01108 
01109                 /* If the addresses are the same, so are the values. */
01110                 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
01111                     /*@innerbreak@*/ break;
01112 
01113                 /* Otherwise, compare fingerprints by value. */
01114                 /*@-nullpass@*/ /* LCL: looks good to me */
01115                 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
01116                     /*@innerbreak@*/ break;
01117                 /*@=nullpass@*/
01118 
01119             }
01120             /* XXX is this test still necessary? */
01121             if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
01122                 /*@innerbreak@*/ break;
01123         }
01124 
01125         switch (fi->type) {
01126         struct stat sb;
01127         case TR_ADDED:
01128             if (otherPkgNum < 0) {
01129                 /* XXX is this test still necessary? */
01130                 if (fi->actions[i] != FA_UNKNOWN)
01131                     break;
01132                 if ((fi->fflags[i] & RPMFILE_CONFIG) && 
01133                         !lstat(filespec, &sb)) {
01134                     /* Here is a non-overlapped pre-existing config file. */
01135                     fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
01136                         ? FA_ALTNAME : FA_BACKUP;
01137                 } else {
01138                     fi->actions[i] = FA_CREATE;
01139                 }
01140                 break;
01141             }
01142 
01143             /* Mark added overlapped non-identical files as a conflict. */
01144             if (probs && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
01145                         recs[otherPkgNum]->fmd5s[otherFileNum],
01146                         recs[otherPkgNum]->flinks[otherFileNum],
01147                         fi->fmodes[i],
01148                         fi->fmd5s[i],
01149                         fi->flinks[i])) {
01150                 psAppend(probs, RPMPROB_NEW_FILE_CONFLICT, fi->ap,
01151                                 filespec, NULL, recs[otherPkgNum]->ap->h, 0);
01152             }
01153 
01154             /* Try to get the disk accounting correct even if a conflict. */
01155             fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
01156 
01157             if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
01158                 /* Here is an overlapped  pre-existing config file. */
01159                 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
01160                         ? FA_ALTNAME : FA_SKIP;
01161             } else {
01162                 fi->actions[i] = FA_CREATE;
01163             }
01164             break;
01165         case TR_REMOVED:
01166             if (otherPkgNum >= 0) {
01167                 /* Here is an overlapped added file we don't want to nuke. */
01168                 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
01169                     /* On updates, don't remove files. */
01170                     fi->actions[i] = FA_SKIP;
01171                     break;
01172                 }
01173                 /* Here is an overlapped removed file: skip in previous. */
01174                 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
01175             }
01176             if (XFA_SKIPPING(fi->actions[i]))
01177                 break;
01178             if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
01179                 break;
01180             if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
01181                 fi->actions[i] = FA_ERASE;
01182                 break;
01183             }
01184                 
01185             /* Here is a pre-existing modified config file that needs saving. */
01186             {   char mdsum[50];
01187                 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
01188                     fi->actions[i] = FA_BACKUP;
01189                     break;
01190                 }
01191             }
01192             fi->actions[i] = FA_ERASE;
01193             break;
01194         }
01195 
01196         if (ds) {
01197             uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
01198 
01199             switch (fi->actions[i]) {
01200               case FA_BACKUP:
01201               case FA_SAVE:
01202               case FA_ALTNAME:
01203                 ds->ineeded++;
01204                 ds->bneeded += s;
01205                 break;
01206 
01207             /*
01208              * FIXME: If two packages share a file (same md5sum), and
01209              * that file is being replaced on disk, will ds->bneeded get
01210              * decremented twice? Quite probably!
01211              */
01212               case FA_CREATE:
01213                 ds->bneeded += s;
01214                 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
01215                 break;
01216 
01217               case FA_ERASE:
01218                 ds->ineeded--;
01219                 ds->bneeded -= s;
01220                 break;
01221 
01222               default:
01223                 break;
01224             }
01225 
01226             ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
01227         }
01228     }
01229     if (filespec) free(filespec);
01230 }
01231 
01232 static int ensureOlder(struct availablePackage * alp, Header old,
01233                 rpmProblemSet probs)
01234         /*@modifies alp, probs @*/
01235 {
01236     int result, rc = 0;
01237 
01238     if (old == NULL) return 1;
01239 
01240     result = rpmVersionCompare(old, alp->h);
01241     if (result <= 0)
01242         rc = 0;
01243     else if (result > 0) {
01244         rc = 1;
01245         psAppend(probs, RPMPROB_OLDPACKAGE, alp, NULL, NULL, old, 0);
01246     }
01247 
01248     return rc;
01249 }
01250 
01251 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
01252         /*@modifies fi @*/
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 #ifdef  DYING
01525     Header * hdrs;
01526 #endif
01527     int totalFileCount = 0;
01528     hashTable ht;
01529     TFI_t fi;
01530     struct diskspaceInfo * dip;
01531     struct sharedFileInfo * shared, * sharedList;
01532     int numShared;
01533     int nexti;
01534     int lastFailed;
01535     int oc;
01536     fingerPrintCache fpc;
01537     struct psm_s psmbuf;
01538     PSM_t psm = &psmbuf;
01539     void * tsi;
01540 
01541     /* FIXME: what if the same package is included in ts twice? */
01542 
01543     ts->transFlags = transFlags;
01544     if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
01545         ts->transFlags |= (_noTransScripts | _noTransTriggers);
01546     if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
01547         ts->transFlags |= _noTransTriggers;
01548 
01549     /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
01550     if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
01551         ts->transFlags |= (_noTransScripts | _noTransTriggers);
01552 
01553     ts->notify = notify;
01554     ts->notifyData = notifyData;
01555     /*@-assignexpose@*/
01556     ts->probs = *newProbs = psCreate();
01557     /*@=assignexpose@*/
01558     ts->ignoreSet = ignoreSet;
01559     ts->currDir = _free(ts->currDir);
01560     ts->currDir = currentDirectory();
01561     ts->chrootDone = 0;
01562     if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
01563     ts->id = (int_32) time(NULL);
01564 
01565     memset(psm, 0, sizeof(*psm));
01566     /*@-assignexpose@*/
01567     psm->ts = ts;
01568     /*@=assignexpose@*/
01569 
01570     /* Get available space on mounted file systems. */
01571     if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
01572                 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
01573         struct stat sb;
01574 
01575         ts->di = _free(ts->di);
01576         dip = ts->di = xcalloc(sizeof(*ts->di), ts->filesystemCount + 1);
01577 
01578         for (i = 0; (i < ts->filesystemCount) && dip; i++) {
01579 #if STATFS_IN_SYS_STATVFS
01580             struct statvfs sfb;
01581             memset(&sfb, 0, sizeof(sfb));
01582             if (statvfs(ts->filesystems[i], &sfb))
01583 #else
01584             struct statfs sfb;
01585 #  if STAT_STATFS4
01586 /* This platform has the 4-argument version of the statfs call.  The last two
01587  * should be the size of struct statfs and 0, respectively.  The 0 is the
01588  * filesystem type, and is always 0 when statfs is called on a mounted
01589  * filesystem, as we're doing.
01590  */
01591             memset(&sfb, 0, sizeof(sfb));
01592             if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
01593 #  else
01594             memset(&sfb, 0, sizeof(sfb));
01595             if (statfs(ts->filesystems[i], &sfb))
01596 #  endif
01597 #endif
01598             {
01599                 dip = NULL;
01600             } else {
01601                 ts->di[i].bsize = sfb.f_bsize;
01602                 ts->di[i].bneeded = 0;
01603                 ts->di[i].ineeded = 0;
01604 #ifdef STATFS_HAS_F_BAVAIL
01605                 ts->di[i].bavail = sfb.f_bavail;
01606 #else
01607 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
01608  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
01609  * it's about all we can do.
01610  */
01611                 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
01612 #endif
01613                 /* XXX Avoid FAT and other file systems that have not inodes. */
01614                 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
01615                                 ? sfb.f_ffree : -1;
01616 
01617                 (void) stat(ts->filesystems[i], &sb);
01618                 ts->di[i].dev = sb.st_dev;
01619             }
01620         }
01621 
01622         if (dip) ts->di[i].bsize = 0;
01623     }
01624 
01625 #ifdef  DYING
01626     hdrs = alloca(sizeof(*hdrs) * ts->addedPackages.size);
01627 #endif
01628 
01629     /* ===============================================
01630      * For packages being installed:
01631      * - verify package arch/os.
01632      * - verify package epoch:version-release is newer.
01633      * - count files.
01634      * For packages being removed:
01635      * - count files.
01636      */
01637     /* The ordering doesn't matter here */
01638     if (ts->addedPackages.list != NULL)
01639     for (alp = ts->addedPackages.list;
01640         (alp - ts->addedPackages.list) < ts->addedPackages.size;
01641         alp++)
01642     {
01643         if (!archOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
01644             psAppend(ts->probs, RPMPROB_BADARCH, alp, NULL, NULL, NULL, 0);
01645 
01646         if (!osOkay(alp->h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
01647             psAppend(ts->probs, RPMPROB_BADOS, alp, NULL, NULL, NULL, 0);
01648 
01649         if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
01650             rpmdbMatchIterator mi;
01651             Header oldH;
01652             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
01653             while ((oldH = rpmdbNextIterator(mi)) != NULL)
01654                 (void) ensureOlder(alp, oldH, ts->probs);
01655             mi = rpmdbFreeIterator(mi);
01656         }
01657 
01658         /* XXX multilib should not display "already installed" problems */
01659         if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG) && !alp->multiLib) {
01660             rpmdbMatchIterator mi;
01661             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, alp->name, 0);
01662             (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
01663                         RPMMIRE_DEFAULT, alp->version);
01664             (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
01665                         RPMMIRE_DEFAULT, alp->release);
01666 
01667             while (rpmdbNextIterator(mi) != NULL) {
01668                 psAppend(ts->probs, RPMPROB_PKG_INSTALLED, alp,
01669                         NULL, NULL, NULL, 0);
01670                 /*@innerbreak@*/ break;
01671             }
01672             mi = rpmdbFreeIterator(mi);
01673         }
01674 
01675         totalFileCount += alp->filesCount;
01676 
01677     }
01678 
01679     /* FIXME: it seems a bit silly to read in all of these headers twice */
01680     /* The ordering doesn't matter here */
01681     if (ts->numRemovedPackages > 0) {
01682         rpmdbMatchIterator mi;
01683         Header h;
01684         int fileCount;
01685 
01686         mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
01687         (void) rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
01688         while ((h = rpmdbNextIterator(mi)) != NULL) {
01689             if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
01690                 totalFileCount += fileCount;
01691         }
01692         mi = rpmdbFreeIterator(mi);
01693     }
01694 
01695     /* ===============================================
01696      * Initialize file list:
01697      */
01698     ts->flEntries = ts->addedPackages.size + ts->numRemovedPackages;
01699     ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
01700 
01701     /*
01702      * FIXME?: we'd be better off assembling one very large file list and
01703      * calling fpLookupList only once. I'm not sure that the speedup is
01704      * worth the trouble though.
01705      */
01706     tsi = tsInitIterator(ts);
01707     while ((fi = tsNextIterator(tsi)) != NULL) {
01708         oc = tsGetOc(tsi);
01709         fi->magic = TFIMAGIC;
01710 
01711         /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
01712         fi->type = ts->order[oc].type;
01713         switch (fi->type) {
01714         case TR_ADDED:
01715             i = ts->order[oc].u.addedIndex;
01716             /* XXX watchout: fi->type must be set for tsGetAlp() to "work" */
01717             fi->ap = tsGetAlp(tsi);
01718             fi->record = 0;
01719             loadFi(fi->ap->h, fi);
01720             if (fi->fc == 0) {
01721 #ifdef  DYING
01722                 hdrs[i] = headerLink(fi->h);
01723 #endif
01724                 continue;
01725             }
01726 
01727 #ifdef  DYING
01728             /* Allocate file actions (and initialize to FA_UNKNOWN) */
01729             fi->actions = xcalloc(fi->fc, sizeof(*fi->actions));
01730             hdrs[i] = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
01731 #else
01732             {   Header foo = relocateFileList(ts, fi, fi->ap, fi->h, fi->actions);
01733                 foo = headerFree(foo);
01734             }
01735 #endif
01736 
01737             /* Skip netshared paths, not our i18n files, and excluded docs */
01738             skipFiles(ts, fi);
01739             break;
01740         case TR_REMOVED:
01741             fi->ap = NULL;
01742             fi->record = ts->order[oc].u.removed.dboffset;
01743             {   rpmdbMatchIterator mi;
01744 
01745                 mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES,
01746                                 &fi->record, sizeof(fi->record));
01747                 if ((fi->h = rpmdbNextIterator(mi)) != NULL)
01748                     fi->h = headerLink(fi->h);
01749                 mi = rpmdbFreeIterator(mi);
01750             }
01751             if (fi->h == NULL) {
01752                 /* ACK! */
01753                 continue;
01754             }
01755             /* XXX header arg unused. */
01756             loadFi(fi->h, fi);
01757             break;
01758         }
01759 
01760         if (fi->fc)
01761             fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
01762     }
01763     tsi = tsFreeIterator(tsi);
01764 
01765 #ifdef  DYING
01766     /* Open all database indices before installing. */
01767     (void) rpmdbOpenAll(ts->rpmdb);
01768 #endif
01769 
01770     if (!ts->chrootDone) {
01771         (void) chdir("/");
01772         /*@-unrecog@*/ chroot(ts->rootDir); /*@=unrecog@*/
01773         ts->chrootDone = 1;
01774         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
01775         /*@-onlytrans@*/
01776         chroot_prefix = ts->rootDir;
01777         /*@=onlytrans@*/
01778     }
01779 
01780     ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
01781     fpc = fpCacheCreate(totalFileCount);
01782 
01783     /* ===============================================
01784      * Add fingerprint for each file not skipped.
01785      */
01786     tsi = tsInitIterator(ts);
01787     while ((fi = tsNextIterator(tsi)) != NULL) {
01788         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
01789         for (i = 0; i < fi->fc; i++) {
01790             if (XFA_SKIPPING(fi->actions[i]))
01791                 continue;
01792             /*@-dependenttrans@*/
01793             htAddEntry(ht, fi->fps + i, fi);
01794             /*@=dependenttrans@*/
01795         }
01796     }
01797     tsi = tsFreeIterator(tsi);
01798 
01799     /*@-moduncon@*/
01800     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
01801         NULL, ts->notifyData));
01802     /*@=moduncon@*/
01803 
01804     /* ===============================================
01805      * Compute file disposition for each package in transaction set.
01806      */
01807     tsi = tsInitIterator(ts);
01808     while ((fi = tsNextIterator(tsi)) != NULL) {
01809         dbiIndexSet * matches;
01810         int knownBad;
01811 
01812         /*@-moduncon@*/
01813         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
01814                         ts->flEntries, NULL, ts->notifyData));
01815         /*@=moduncon@*/
01816 
01817         if (fi->fc == 0) continue;
01818 
01819         /* Extract file info for all files in this package from the database. */
01820         matches = xcalloc(sizeof(*matches), fi->fc);
01821         if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc))
01822             return 1;   /* XXX WTFO? */
01823 
01824         numShared = 0;
01825         for (i = 0; i < fi->fc; i++)
01826             numShared += dbiIndexSetCount(matches[i]);
01827 
01828         /* Build sorted file info list for this package. */
01829         shared = sharedList = xmalloc((numShared + 1) * sizeof(*sharedList));
01830         for (i = 0; i < fi->fc; i++) {
01831             /*
01832              * Take care not to mark files as replaced in packages that will
01833              * have been removed before we will get here.
01834              */
01835             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
01836                 int k, ro;
01837                 ro = dbiIndexRecordOffset(matches[i], j);
01838                 knownBad = 0;
01839                 for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
01840                     switch (ts->order[k].type) {
01841                     case TR_REMOVED:
01842                         if (ts->order[k].u.removed.dboffset == ro)
01843                             knownBad = ro;
01844                         break;
01845                     case TR_ADDED:
01846                         break;
01847                     }
01848                 }
01849 
01850                 shared->pkgFileNum = i;
01851                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
01852                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
01853                 shared->isRemoved = (knownBad == ro);
01854                 shared++;
01855             }
01856             matches[i] = dbiFreeIndexSet(matches[i]);
01857         }
01858         numShared = shared - sharedList;
01859         shared->otherPkg = -1;
01860         matches = _free(matches);
01861 
01862         /* Sort file info by other package index (otherPkg) */
01863         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
01864 
01865         /* For all files from this package that are in the database ... */
01866         for (i = 0; i < numShared; i = nexti) {
01867             int beingRemoved;
01868 
01869             shared = sharedList + i;
01870 
01871             /* Find the end of the files in the other package. */
01872             for (nexti = i + 1; nexti < numShared; nexti++) {
01873                 if (sharedList[nexti].otherPkg != shared->otherPkg)
01874                     /*@innerbreak@*/ break;
01875             }
01876 
01877             /* Is this file from a package being removed? */
01878             beingRemoved = 0;
01879             for (j = 0; j < ts->numRemovedPackages; j++) {
01880                 if (ts->removedPackages[j] != shared->otherPkg)
01881                     continue;
01882                 beingRemoved = 1;
01883                 /*@innerbreak@*/ break;
01884             }
01885 
01886             /* Determine the fate of each file. */
01887             switch (fi->type) {
01888             case TR_ADDED:
01889                 (void) handleInstInstalledFiles(fi, ts->rpmdb, shared, nexti - i,
01890                 !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)),
01891                          ts->probs, ts->transFlags);
01892                 break;
01893             case TR_REMOVED:
01894                 if (!beingRemoved)
01895                     (void) handleRmvdInstalledFiles(fi, ts->rpmdb, shared, nexti - i);
01896                 break;
01897             }
01898         }
01899 
01900         free(sharedList);
01901 
01902         /* Update disk space needs on each partition for this package. */
01903         handleOverlappedFiles(fi, ht,
01904                ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
01905                     ? NULL : ts->probs), ts->di);
01906 
01907         /* Check added package has sufficient space on each partition used. */
01908         switch (fi->type) {
01909         case TR_ADDED:
01910             if (!(ts->di && fi->fc))
01911                 break;
01912             for (i = 0; i < ts->filesystemCount; i++) {
01913 
01914                 dip = ts->di + i;
01915 
01916                 /* XXX Avoid FAT and other file systems that have not inodes. */
01917                 if (dip->iavail <= 0)
01918                     continue;
01919 
01920                 if (adj_fs_blocks(dip->bneeded) > dip->bavail)
01921                     psAppend(ts->probs, RPMPROB_DISKSPACE, fi->ap,
01922                                 ts->filesystems[i], NULL, NULL,
01923                    (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
01924 
01925                 if (adj_fs_blocks(dip->ineeded) > dip->iavail)
01926                     psAppend(ts->probs, RPMPROB_DISKNODES, fi->ap,
01927                                 ts->filesystems[i], NULL, NULL,
01928                     (adj_fs_blocks(dip->ineeded) - dip->iavail));
01929             }
01930             break;
01931         case TR_REMOVED:
01932             break;
01933         }
01934     }
01935     tsi = tsFreeIterator(tsi);
01936 
01937     if (ts->chrootDone) {
01938         /*@-unrecog@*/ chroot("."); /*@-unrecog@*/
01939         ts->chrootDone = 0;
01940         if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
01941         chroot_prefix = NULL;
01942         (void) chdir(ts->currDir);
01943     }
01944 
01945     /*@-moduncon@*/
01946     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
01947         NULL, ts->notifyData));
01948     /*@=moduncon@*/
01949 
01950     /* ===============================================
01951      * Free unused memory as soon as possible.
01952      */
01953 
01954     tsi = tsInitIterator(ts);
01955     while ((fi = tsNextIterator(tsi)) != NULL) {
01956         psm->fi = fi;
01957         if (fi->fc == 0)
01958             continue;
01959         fi->fps = _free(fi->fps);
01960     }
01961     tsi = tsFreeIterator(tsi);
01962 
01963     fpCacheFree(fpc);
01964     htFree(ht);
01965 
01966     /* ===============================================
01967      * If unfiltered problems exist, free memory and return.
01968      */
01969     if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS) ||
01970            (ts->probs->numProblems && (!okProbs || psTrim(okProbs, ts->probs))))
01971     {
01972         *newProbs = ts->probs;
01973 
01974 #ifdef  DYING
01975         for (alp = ts->addedPackages.list, fi = ts->flList;
01976                 (alp - ts->addedPackages.list) < ts->addedPackages.size;
01977                 alp++, fi++)
01978         {
01979             hdrs[alp - ts->addedPackages.list] =
01980                 headerFree(hdrs[alp - ts->addedPackages.list]);
01981         }
01982 #endif
01983 
01984         ts->flList = freeFl(ts, ts->flList);
01985         ts->flEntries = 0;
01986         /*@-nullstate@*/
01987         return ts->orderCount;
01988         /*@=nullstate@*/
01989     }
01990 
01991     /* ===============================================
01992      * Save removed files before erasing.
01993      */
01994     if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
01995         tsi = tsInitIterator(ts);
01996         while ((fi = tsNextIterator(tsi)) != NULL) {
01997             psm->fi = fi;
01998             switch (fi->type) {
01999             case TR_ADDED:
02000                 break;
02001             case TR_REMOVED:
02002                 if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE)
02003                     (void) psmStage(psm, PSM_PKGSAVE);
02004                 break;
02005             }
02006         }
02007         tsi = tsFreeIterator(tsi);
02008     }
02009 
02010     /* ===============================================
02011      * Install and remove packages.
02012      */
02013 
02014     lastFailed = -2;    /* erased packages have -1 */
02015     tsi = tsInitIterator(ts);
02016     while ((fi = tsNextIterator(tsi)) != NULL) {
02017         Header h;
02018         int gotfd;
02019 
02020         gotfd = 0;
02021         psm->fi = fi;
02022         switch (fi->type)
02023         {
02024         case TR_ADDED:
02025             alp = tsGetAlp(tsi);
02026 assert(alp == fi->ap);
02027             i = alp - ts->addedPackages.list;
02028 
02029             h = headerLink(fi->h);
02030             if (alp->fd == NULL) {
02031                 alp->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
02032                             alp->key, ts->notifyData);
02033                 if (alp->fd) {
02034                     rpmRC rpmrc;
02035 
02036 #ifdef  DYING
02037                     hdrs[i] = headerFree(hdrs[i]);
02038 #else
02039                     h = headerFree(h);
02040 #endif
02041                     /*@-mustmod@*/      /* LCL: segfault */
02042                     rpmrc = rpmReadPackageHeader(alp->fd, &h, NULL, NULL, NULL);
02043                     /*@=mustmod@*/
02044                     if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
02045                         (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
02046                                         0, 0, alp->key, ts->notifyData);
02047                         alp->fd = NULL;
02048                         ourrc++;
02049                     } else {
02050 #ifdef  DYING
02051                         hdrs[i] = relocateFileList(ts, fi, alp, h, NULL);
02052                         h = headerFree(h);
02053 #else
02054                         Header foo = relocateFileList(ts, fi, alp, h, NULL);
02055                         h = headerFree(h);
02056                         h = headerLink(foo);
02057                         foo = headerFree(foo);
02058 #endif
02059                     }
02060                     if (alp->fd) gotfd = 1;
02061                 }
02062             }
02063 
02064             if (alp->fd) {
02065                 Header hsave = NULL;
02066 
02067                 if (fi->h) {
02068                     hsave = headerLink(fi->h);
02069                     fi->h = headerFree(fi->h);
02070                 }
02071 #ifdef  DYING
02072                 fi->h = headerLink(hdrs[i]);
02073 #else
02074                 fi->h = headerLink(h);
02075 #endif
02076                 if (alp->multiLib)
02077                     ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
02078 
02079 assert(alp == fi->ap);
02080                 if (psmStage(psm, PSM_PKGINSTALL)) {
02081                     ourrc++;
02082                     lastFailed = i;
02083                 }
02084                 fi->h = headerFree(fi->h);
02085                 if (hsave) {
02086                     fi->h = headerLink(hsave);
02087                     hsave = headerFree(hsave);
02088                 }
02089             } else {
02090                 ourrc++;
02091                 lastFailed = i;
02092             }
02093 
02094 #ifdef  DYING
02095             hdrs[i] = headerFree(hdrs[i]);
02096 #else
02097             h = headerFree(h);
02098 #endif
02099 
02100             if (gotfd) {
02101                 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
02102                         alp->key, ts->notifyData);
02103                 alp->fd = NULL;
02104             }
02105             break;
02106         case TR_REMOVED:
02107             oc = tsGetOc(tsi);
02108             /* If install failed, then we shouldn't erase. */
02109             if (ts->order[oc].u.removed.dependsOnIndex == lastFailed)
02110                 break;
02111 
02112             if (psmStage(psm, PSM_PKGERASE))
02113                 ourrc++;
02114 
02115             break;
02116         }
02117         (void) rpmdbSync(ts->rpmdb);
02118     }
02119     tsi = tsFreeIterator(tsi);
02120 
02121     ts->flList = freeFl(ts, ts->flList);
02122     ts->flEntries = 0;
02123 
02124     /*@-nullstate@*/
02125     if (ourrc)
02126         return -1;
02127     else
02128         return 0;
02129     /*@=nullstate@*/
02130 }

Generated at Mon Sep 24 10:37:23 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001