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

Generated at Thu Apr 19 15:29:44 2001 for rpm by doxygen1.2.6-20010408 written by Dimitri van Heesch, © 1997-2001