Splint fiddles.
authorjbj <devnull@localhost>
Fri, 26 Mar 2004 17:27:57 +0000 (17:27 +0000)
committerjbj <devnull@localhost>
Fri, 26 Mar 2004 17:27:57 +0000 (17:27 +0000)
CVS patchset: 7195
CVS date: 2004/03/26 17:27:57

13 files changed:
.splintrc
lib/fsm.c
lib/psm.c
lib/rpmlock.c
lib/rpmte.h
lib/rpmts.c
lib/rpmts.h
lib/transaction.c
python/dscmp
rpmdb/rpmdb.c
rpmio/macro.c
rpmio/rpmlua.c
rpmio/rpmlua.h

index ce52bc0..ede7c79 100644 (file)
--- a/.splintrc
+++ b/.splintrc
@@ -1,4 +1,4 @@
--I. -I./build -I./lib -I./rpmdb -I./rpmio -I./beecrypt -I./file -I./popt -I./elfutils/libelf -I./zlib -I/usr/lib/gcc-lib/i386-redhat-linux/3.1/include -DHAVE_CONFIG_H -D_GNU_SOURCE -D_REENTRANT -DHAVE_DEV_DSP -DHAVE_SYS_SOUNDCARD
+-I. -I./build -I./lib -I./rpmdb -I./rpmio -I./beecrypt -I./lua/include -I./lua/local -I./file -I./popt -I./elfutils/libelf -I./zlib -I/usr/lib/gcc-lib/i386-redhat-linux/3.1/include -DHAVE_CONFIG_H -D_GNU_SOURCE -D_REENTRANT -DHAVE_DEV_DSP -DHAVE_SYS_SOUNDCARD
 
 #+partial
 +forcehints
index 776dac6..65825d8 100644 (file)
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -2182,7 +2182,7 @@ if (!(fsm->mapFlags & CPIO_ALL_HARDLINKS)) break;
            rpmMessage(RPMMESS_DEBUG, " %8s (%s, %s) %s\n", cur,
                fsm->path, fsm->fcontext,
                (rc < 0 ? strerror(errno) : ""));
-       if (rc < 0) rc = (errno == ENOTSUP ? 0 : CPIOERR_LSETFCON_FAILED);
+       if (rc < 0) rc = (errno == EOPNOTSUPP ? 0 : CPIOERR_LSETFCON_FAILED);
        break;
     case FSM_CHOWN:
        rc = chown(fsm->path, st->st_uid, st->st_gid);
index d8ea213..c521d11 100644 (file)
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -42,7 +42,10 @@ int _psm_threads = 0;
 /* Give access to the rpmte global tracking the last instance added
  * to the database.
  */
+/*@-exportheadervar@*/
+/*@unchecked@*/
 extern unsigned int myinstall_instance;
+/*@=exportheadervar@*/
 
 /*@access FD_t @*/             /* XXX void ptr args */
 /*@access rpmpsm @*/
@@ -51,6 +54,10 @@ extern unsigned int myinstall_instance;
 /*@access rpmte @*/    /* XXX rpmInstallSourcePackage */
 /*@access rpmts @*/    /* XXX ts->notify */
 
+/*@access rpmluav @*/
+/*@access rpmtsScore @*/
+/*@access rpmtsScoreEntry @*/
+
 int rpmVersionCompare(Header first, Header second)
 {
     const char * one, * two;
@@ -563,9 +570,11 @@ exit:
 /**
  * Run internal Lua script.
  */
-rpmRC runLuaScript(rpmpsm psm, Header h, const char *sln,
+static rpmRC runLuaScript(rpmpsm psm, Header h, const char *sln,
                   int progArgc, const char **progArgv,
                   const char *script, int arg1, int arg2)
+       /*@globals fileSystem, internalState @*/
+       /*@modifies psm, fileSystem, internalState @*/
 {
     const rpmts ts = psm->ts;
     int rootFd = -1;
@@ -575,17 +584,21 @@ rpmRC runLuaScript(rpmpsm psm, Header h, const char *sln,
     int xx;
     rpmlua lua = NULL; /* Global state. */
     rpmluav var;
-    
+
     xx = headerNVR(h, &n, &v, &r);
 
     if (!rpmtsChrootDone(ts)) {
        const char *rootDir = rpmtsRootDir(ts);
        if (rootDir != NULL && !(rootDir[0] == '/' && rootDir[1] == '\0')) {
-           chdir("/");
+           xx = chdir("/");
+/*@-nullpass@*/
            rootFd = open(".", O_RDONLY, 0);
+/*@=nullpass@*/
            if (rootFd >= 0) {
-               chroot(rootDir);
-               rpmtsSetChrootDone(ts, 1);
+               /*@-superuser -noeffect @*/
+               xx = chroot(rootDir);
+               /*@=superuser =noeffect @*/
+               xx = rpmtsSetChrootDone(ts, 1);
            }
        }
     }
@@ -594,6 +607,7 @@ rpmRC runLuaScript(rpmpsm psm, Header h, const char *sln,
     rpmluaPushTable(lua, "arg");
     var = rpmluavNew();
     rpmluavSetListMode(var, 1);
+/*@+relaxtypes@*/
     if (progArgv) {
        for (i = 0; i < progArgc && progArgv[i]; i++) {
            rpmluavSetValue(var, RPMLUAV_STRING, progArgv[i]);
@@ -608,12 +622,15 @@ rpmRC runLuaScript(rpmpsm psm, Header h, const char *sln,
        rpmluavSetValueNum(var, arg2);
        rpmluaSetVar(lua, var);
     }
+/*@=relaxtypes@*/
+/*@-moduncon@*/
     var = rpmluavFree(var);
+/*@=moduncon@*/
     rpmluaPop(lua);
 
     {
        char buf[BUFSIZ];
-       snprintf(buf, BUFSIZ, "%s(%s-%s-%s)", sln, n, v, r);
+       xx = snprintf(buf, BUFSIZ, "%s(%s-%s-%s)", sln, n, v, r);
        if (rpmluaRunScript(lua, script, buf) == -1)
            rc = RPMRC_FAIL;
     }
@@ -621,10 +638,12 @@ rpmRC runLuaScript(rpmpsm psm, Header h, const char *sln,
     rpmluaDelVar(lua, "arg");
 
     if (rootFd >= 0) {
-       fchdir(rootFd);
-       close(rootFd);
-       chroot(".");
-       rpmtsSetChrootDone(ts, 0);
+       xx = fchdir(rootFd);
+       xx = close(rootFd);
+       /*@-superuser -noeffect @*/
+       xx = chroot(".");
+       /*@=superuser =noeffect @*/
+       xx = rpmtsSetChrootDone(ts, 0);
     }
 
 exit:
@@ -646,7 +665,7 @@ static const char * ldconfig_path = "/sbin/ldconfig";
  * Run a script with an interpreter. If the interpreter is not specified,
  * /bin/sh will be used. If the interpreter is /bin/sh, then the args from
  * the header will be ignored, passing instead arg1 and arg2.
- * 
+ *
  * @param psm          package state machine data
  * @param h            header
  * @param sln          name of scriptlet section
@@ -659,7 +678,7 @@ static const char * ldconfig_path = "/sbin/ldconfig";
  * @return             0 on success
  */
 static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
-               int progArgc, const char ** progArgv, 
+               int progArgc, const char ** progArgv,
                const char * script, int arg1, int arg2)
        /*@globals ldconfig_done, rpmGlobalMacroContext, h_errno,
                fileSystem, internalState@*/
@@ -708,7 +727,7 @@ static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
     /*
      * If a successor node, and ldconfig was just run, don't bother.
      */
-    if (ldconfig_path && progArgv && psm->unorderedSuccessor) {
+    if (ldconfig_path && progArgv != NULL && psm->unorderedSuccessor) {
        if (ldconfig_done && !strcmp(progArgv[0], ldconfig_path)) {
            rpmMessage(RPMMESS_DEBUG,
                _("%s: %s(%s-%s-%s) skipping redundant \"%s\".\n"),
@@ -814,7 +833,7 @@ static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
        out = fdDup(STDOUT_FILENO);
     }
     if (out == NULL) return RPMRC_FAIL;        /* XXX can't happen */
-    
+
     /*@-branchstate@*/
     xx = rpmsqFork(&psm->sq);
     if (psm->sq.child == 0) {
@@ -945,7 +964,7 @@ static rpmRC runScript(rpmpsm psm, Header h, const char * sln,
     if (freePrefixes) prefixes = hfd(prefixes, ipt);
 
     xx = Fclose(out);  /* XXX dup'd STDOUT_FILENO */
-    
+
     /*@-branchstate@*/
     if (script) {
        if (!rpmIsDebug())
@@ -1088,7 +1107,7 @@ static rpmRC handleOneTrigger(const rpmpsm psm,
                    triggersAlreadyRun[index] == 0)
                {
                    rc = runScript(psm, triggeredH, "%trigger", 1,
-                           triggerProgs + index, triggerScripts[index], 
+                           triggerProgs + index, triggerScripts[index],
                            arg1, arg2);
                    if (triggersAlreadyRun != NULL)
                        triggersAlreadyRun[index] = 1;
@@ -1200,7 +1219,7 @@ static rpmRC runImmedTriggers(rpmpsm psm)
            mi = rpmtsInitIterator(ts, RPMTAG_NAME, triggerNames[i], 0);
 
            while((sourceH = rpmdbNextIterator(mi)) != NULL) {
-               rc |= handleOneTrigger(psm, sourceH, fi->h, 
+               rc |= handleOneTrigger(psm, sourceH, fi->h,
                                rpmdbGetIteratorCount(mi),
                                triggersRun);
            }
@@ -1374,7 +1393,7 @@ rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
                rpmfiFC(fi), (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST));
 
        /*
-        * When we run scripts, we pass an argument which is the number of 
+        * When we run scripts, we pass an argument which is the number of
         * versions of this package that will be installed when we are
         * finished.
         */
@@ -1385,41 +1404,41 @@ rpmRC rpmpsmStage(rpmpsm psm, pkgStage stage)
        }
 
        /* If we have a score then autorollback is enabled.  If autorollback is
-        * enabled, and this is an autorollback transaction, then we may need to 
+        * enabled, and this is an autorollback transaction, then we may need to
         * adjust the pkgs installed count.
-        * 
+        *
         * If all this is true, this adjustment should only be made if the PSM goal
-        * is an install.  No need to make this adjustment on the erase 
-        * component of the upgrade, or even more absurd to do this when doing a 
+        * is an install.  No need to make this adjustment on the erase
+        * component of the upgrade, or even more absurd to do this when doing a
         * PKGSAVE.
         */
-       if(rpmtsGetScore(ts) != NULL &&
+       if (rpmtsGetScore(ts) != NULL &&
            rpmtsGetType(ts) == RPMTRANS_TYPE_AUTOROLLBACK &&
            (psm->goal & ~(PSM_PKGSAVE|PSM_PKGERASE))) {
-           /* Get the score, if its not NULL, get the appropriate 
+           /* Get the score, if its not NULL, get the appropriate
             * score entry.
             */
            rpmtsScore score = rpmtsGetScore(ts);
-           if(score != NULL) {
+           if (score != NULL) {
                /* OK, we got a real score so lets get the appropriate
                 * score entry.
                 */
                rpmtsScoreEntry se;
                se = rpmtsScoreGetEntry(score, rpmteN(psm->te));
 
-               /* IF the header for the install element has been installed, 
+               /* IF the header for the install element has been installed,
                 * but the header for the erase element has not been erased,
-                * then decrement the instance count.  This is because in an 
+                * then decrement the instance count.  This is because in an
                 * autorollback, if the header was added in the initial transaction
-                * then in the case of an upgrade the instance count will be 
+                * then in the case of an upgrade the instance count will be
                 * 2 instead of one when re-installing the old package, and 3 when
                 * erasing the new package.
-                * 
+                *
                 * Another wrinkle is we only want to make this adjustement
                 * if the thing we are rollback was an upgrade of package.  A pure
                 * install or erase does not need the adjustment
                 */
-               if(se && se->installed && 
+               if (se && se->installed &&
                    !se->erased &&
                    (se->te_types & (TR_ADDED|TR_REMOVED)))
                    psm->npkgs_installed--;
@@ -1470,7 +1489,7 @@ assert(psm->mi == NULL);
             */
            {   const char * p;
                xx = hge(fi->h, RPMTAG_DEFAULTPREFIX, NULL, (void **) &p, NULL);
-               fi->striplen = (xx ? strlen(p) + 1 : 1); 
+               fi->striplen = (xx ? strlen(p) + 1 : 1);
            }
            fi->mapflags =
                CPIO_MAP_PATH | CPIO_MAP_MODE | CPIO_MAP_UID | CPIO_MAP_GID;
@@ -2092,26 +2111,26 @@ assert(psm->mi == NULL);
         * If the score exists and this is not a rollback or autorollback
         * then lets check off installed for this package.
         */
-       if(rpmtsGetScore(ts) != NULL &&
-            rpmtsGetType(ts) != RPMTRANS_TYPE_ROLLBACK &&
-            rpmtsGetType(ts) != RPMTRANS_TYPE_AUTOROLLBACK) {
-            /* Get the score, if its not NULL, get the appropriate
-             * score entry.
-             */
-            rpmtsScore score = rpmtsGetScore(ts);
-            if(score != NULL) {
+       if (rpmtsGetScore(ts) != NULL &&
+           rpmtsGetType(ts) != RPMTRANS_TYPE_ROLLBACK &&
+           rpmtsGetType(ts) != RPMTRANS_TYPE_AUTOROLLBACK)
+       {
+           /* Get the score, if its not NULL, get the appropriate
+            * score entry.
+            */
+           rpmtsScore score = rpmtsGetScore(ts);
+           if (score != NULL) {
+               rpmtsScoreEntry se;
                /* OK, we got a real score so lets get the appropriate
                 * score entry.
                 */
                rpmMessage(RPMMESS_DEBUG,
-                   _("Attempting to mark %s as installed in score board(0x%x).\n"),
+                   _("Attempting to mark %s as installed in score board(%p).\n"),
                    rpmteN(psm->te), score);
-               rpmtsScoreEntry se;
                se = rpmtsScoreGetEntry(score, rpmteN(psm->te));
-               if(se) se->installed = 1;
+               if (se != NULL) se->installed = 1;
            }
        }
-
        (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
        break;
     case PSM_RPMDB_REMOVE:
@@ -2124,23 +2143,25 @@ assert(psm->mi == NULL);
         * If the score exists and this is not a rollback or autorollback
         * then lets check off erased for this package.
         */
-       if(rpmtsGetScore(ts) != NULL &&
-           rpmtsGetType(ts) != RPMTRANS_TYPE_ROLLBACK &&
-           rpmtsGetType(ts) != RPMTRANS_TYPE_AUTOROLLBACK) {
+       if (rpmtsGetScore(ts) != NULL &&
+          rpmtsGetType(ts) != RPMTRANS_TYPE_ROLLBACK &&
+          rpmtsGetType(ts) != RPMTRANS_TYPE_AUTOROLLBACK)
+       {
            /* Get the score, if its not NULL, get the appropriate
             * score entry.
             */
            rpmtsScore score = rpmtsGetScore(ts);
-           if(score != NULL) { /* XXX: Can't happen */
+
+           if (score != NULL) { /* XXX: Can't happen */
+               rpmtsScoreEntry se;
                /* OK, we got a real score so lets get the appropriate
                 * score entry.
                 */
                rpmMessage(RPMMESS_DEBUG,
                    _("Attempting to mark %s as erased in score board(0x%x).\n"),
-                   rpmteN(psm->te), score);
-               rpmtsScoreEntry se;
+                   rpmteN(psm->te), (unsigned) score);
                se = rpmtsScoreGetEntry(score, rpmteN(psm->te));
-               if(se) se->erased = 1;
+               if (se != NULL) se->erased = 1;
            }
        }
 
index 467d2f5..4045a0b 100644 (file)
@@ -32,7 +32,7 @@ typedef struct {
 } * rpmlock;
 
 /*@null@*/
-static rpmlock rpmlock_new(const char *rootdir)
+static rpmlock rpmlock_new(/*@unused@*/ const char *rootdir)
        /*@globals fileSystem @*/
        /*@modifies fileSystem @*/
 {
@@ -49,10 +49,14 @@ static rpmlock rpmlock_new(const char *rootdir)
                                free(lock);
                                lock = NULL;
                        } else {
+/*@-nullderef@*/       /* XXX splint on crack */
                                lock->openmode = RPMLOCK_READ;
+/*@=nullderef@*/
                        }
                } else {
+/*@-nullderef@*/       /* XXX splint on crack */
                        lock->openmode = RPMLOCK_WRITE | RPMLOCK_READ;
+/*@=nullderef@*/
                }
 /*@=branchstate@*/
        }
index f91bf6a..530d651 100644 (file)
@@ -115,7 +115,7 @@ struct rpmte_s {
     FD_t fd;                   /*!< (TR_ADDED) Payload file descriptor. */
 
 /*@-fielduse@*/        /* LCL: confused by union? */
-    union { 
+    union {
 /*@exposed@*/ /*@dependent@*/ /*@null@*/
        alKey addedKey;
        struct {
@@ -259,7 +259,8 @@ uint_32 rpmteSetColor(rpmte te, uint_32 color)
  * @param te           transaction element
  * @return             last install instance.
  */
-unsigned int rpmteDBInstance(rpmte te);
+unsigned int rpmteDBInstance(rpmte te)
+       /*@*/;
 
 /**
  * Set last instance installed to the database.
@@ -267,7 +268,8 @@ unsigned int rpmteDBInstance(rpmte te);
  * @param instance     Database instance of last install element.
  * @return             last install instance.
  */
-void rpmteSetDBInstance(rpmte te, unsigned int instance);
+void rpmteSetDBInstance(rpmte te, unsigned int instance)
+       /*@modifies te @*/;
 
 /**
  * Retrieve size in bytes of package file.
index 6b38cc7..f121f4c 100644 (file)
@@ -834,7 +834,9 @@ rpmts rpmtsFree(rpmts ts)
        rpmtsPrintStats(ts);
 
     /* Free up the memory used by the rpmtsScore */
-    rpmtsScoreFree(ts->score);
+/*@-kepttrans -onlytrans @*/
+    ts->score = rpmtsScoreFree(ts->score);
+/*@=kepttrans =onlytrans @*/
 
     (void) rpmtsUnlink(ts, "tsCreate");
 
@@ -879,7 +881,7 @@ rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
  */
 void rpmtsSetType(rpmts ts, rpmtsType type)
 {
-    if(ts != NULL) {
+    if (ts != NULL) {
        ts->type = type;
     }   
 }
@@ -887,7 +889,7 @@ void rpmtsSetType(rpmts ts, rpmtsType type)
 /* Let them know what type of transaction we are */
 rpmtsType rpmtsGetType(rpmts ts) 
 {
-    if(ts != NULL) 
+    if (ts != NULL) 
        return ts->type;
     else
        return 0;
@@ -1530,12 +1532,12 @@ rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
     rpmRC      rc = RPMRC_OK; /* Assume success */
     rpmtsScoreEntry se;
 
-    rpmMessage(RPMMESS_DEBUG, _("Creating transaction score board(0x%x, 0x%x)\n"),
+    rpmMessage(RPMMESS_DEBUG, _("Creating transaction score board(%p, %p)\n"),
        runningTS, rollbackTS); 
 
     /* Allocate space for score board */
     score = xcalloc(1, sizeof(*score));
-    rpmMessage(RPMMESS_DEBUG, _("\tScore board address:  0x%x\n"), score);
+    rpmMessage(RPMMESS_DEBUG, _("\tScore board address:  %p\n"), score);
 
     /* 
      * Determine the maximum size needed for the entry list.
@@ -1563,18 +1565,20 @@ rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
        /* Try to find the entry in the score list */
        for(i = 0; i < score->entries; i++) {
            se = score->scores[i]; 
-           if(strcmp(rpmteN(p), se->N) == 0) {
+           if (strcmp(rpmteN(p), se->N) == 0) {
                found = 1;
-               break;
+               /*@innerbreak@*/ break;
            }
        }
 
        /* If we did not find the entry then allocate space for it */
-       if(!found) {
+       if (!found) {
+/*@-compdef -usereleased@*/ /* XXX p->fi->te undefined. */
            rpmMessage(RPMMESS_DEBUG, _("\tAdding entry for %s to score board.\n"),
                rpmteN(p));
+/*@=compdef =usereleased@*/
            se = xcalloc(1, sizeof(*(*(score->scores))));
-           rpmMessage(RPMMESS_DEBUG, _("\t\tEntry address:  0x%x\n"), se);
+           rpmMessage(RPMMESS_DEBUG, _("\t\tEntry address:  %p\n"), se);
            se->N         = xstrdup(rpmteN(p));
            se->te_types  = rpmteType(p); 
            se->installed = 0;
@@ -1605,17 +1609,17 @@ rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
     return rc;
 }
 
-rpmRC rpmtsScoreFree(rpmtsScore score) 
+rpmtsScore rpmtsScoreFree(rpmtsScore score) 
 {
-    int i;
     rpmtsScoreEntry se = NULL;
+    int i;
 
-    rpmMessage(RPMMESS_DEBUG, _("May free Score board(0x%x)\n"), score);
+    rpmMessage(RPMMESS_DEBUG, _("May free Score board(%p)\n"), score);
 
     /* If score is not initialized, then just return.
      * This is likely the case if autorollbacks are not enabled.
      */
-    if(score == NULL) return RPMRC_OK;
+    if (score == NULL) return NULL;
 
     /* Decrement the reference count */
     score->nrefs--;
@@ -1623,29 +1627,31 @@ rpmRC rpmtsScoreFree(rpmtsScore score)
     /* Do we have any more references?  If so
      * just return.
      */
-    if(score->nrefs > 0) return RPMRC_OK;
+    if (score->nrefs > 0) return NULL;
 
-    rpmMessage(RPMMESS_DEBUG, _("\tRefcount is zero...will free\n"), score);
+    rpmMessage(RPMMESS_DEBUG, _("\tRefcount is zero...will free\n"));
     /* No more references, lets clean up  */
     /* First deallocate the score entries */
+/*@-branchstate@*/
     for(i = 0; i < score->entries; i++) {
        /* Get the score for the ith entry */
        se = score->scores[i]; 
        
        /* Deallocate the score entries name */
-       _free(se->N);
+       se->N = _free(se->N);
 
        /* Deallocate the score entry itself */
-       _free(se);
+       se = _free(se);
     }
+/*@=branchstate@*/
 
     /* Next deallocate the score entry table */
-    _free(score->scores);
+    score->scores = _free(score->scores);
 
     /* Finally deallocate the score itself */
-    _free(score);
+    score = _free(score);
 
-    return RPMRC_OK;
+    return NULL;
 }
 
 /* 
@@ -1655,7 +1661,7 @@ rpmRC rpmtsScoreFree(rpmtsScore score)
  */
 rpmtsScore rpmtsGetScore(rpmts ts) 
 {
-    if(ts == NULL) return NULL;
+    if (ts == NULL) return NULL;
     return ts->score;
 }
 
@@ -1673,17 +1679,19 @@ rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N)
     rpmtsScoreEntry se;
     rpmtsScoreEntry ret = NULL; /* Assume we don't find it */
 
-    rpmMessage(RPMMESS_DEBUG, _("Looking in score board(0x%x) for %s\n"), score, N);
+    rpmMessage(RPMMESS_DEBUG, _("Looking in score board(%p) for %s\n"), score, N);
 
     /* Try to find the entry in the score list */
     for(i = 0; i < score->entries; i++) {
        se = score->scores[i]; 
-       if(strcmp(N, se->N) == 0) {
-           rpmMessage(RPMMESS_DEBUG, _("\tFound entry at address:  0x%x\n"), se);
+       if (strcmp(N, se->N) == 0) {
+           rpmMessage(RPMMESS_DEBUG, _("\tFound entry at address:  %p\n"), se);
            ret = se;
            break;
        }
     }
        
+/*@-compdef@*/ /* XXX score->scores undefined. */
     return ret;        
+/*@=compdef@*/
 }
index 7281473..31cea53 100644 (file)
@@ -100,7 +100,7 @@ typedef     enum rpmtsOpX_e {
 /**********************
  * Transaction Scores *
  **********************
- * 
+ *
  * In order to allow instance counts to be adjusted properly when an
  * autorollback transaction is ran, we keep a list that is indexed
  * by rpm name of whether the rpm has been installed or erased.  This listed
@@ -115,17 +115,17 @@ typedef   enum rpmtsOpX_e {
  * at the point the running transaction failed, and thus on a per package
  * basis make adjustments to the instance counts.
  *
- * XXX: Jeff, I am not convinced that this does not need to be in its own file 
- *      (i.e. rpmtsScore.{h,c}), but I first wanted to get it working.  
+ * XXX: Jeff, I am not convinced that this does not need to be in its own file
+ *      (i.e. rpmtsScore.{h,c}), but I first wanted to get it working.
  */
 struct rpmtsScoreEntry_s {
-       char *         N;               /*!<Name of package                */
-       rpmElementType te_types;        /*!<te types this entry represents */
-       int            installed;       /*!<Was the new header installed   */
-       int            erased;          /*!<Was the old header removed     */
+    char *         N;                  /*!<Name of package                */
+    rpmElementType te_types;           /*!<te types this entry represents */
+    int            installed;          /*!<Was the new header installed   */
+    int            erased;             /*!<Was the old header removed     */
 };
 
-typedef struct rpmtsScoreEntry_s * rpmtsScoreEntry;
+typedef /*@abstract@*/ struct rpmtsScoreEntry_s * rpmtsScoreEntry;
 
 struct rpmtsScore_s {
        int entries;                    /*!< Number of scores       */
@@ -133,38 +133,48 @@ struct rpmtsScore_s {
        int nrefs;                      /*!< Reference count.       */
 };
 
-typedef struct rpmtsScore_s * rpmtsScore;
+typedef /*@abstract@*/ struct rpmtsScore_s * rpmtsScore;
 
 
 /** \ingroup rpmts
- * initialize rpmtsScore for running transaction and autorollback 
+ * initialize rpmtsScore for running transaction and autorollback
  * transaction.
  * @param runningTS    Running Transaction.
  * @param rollbackTS   Rollback Transaction.
  * @return             RPMRC_OK
  */
-rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS); 
+rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
+       /*@globals fileSystem @*/
+       /*@modifies runningTS, rollbackTS, fileSystem @*/;
 
 /** \ingroup rpmts
  * Free rpmtsScore provided no more references exist against it.
  * @param score                rpmtsScore to free
- * @return             RPMRC_OK
+ * @return             NULL always
  */
-rpmRC rpmtsScoreFree(rpmtsScore score);
+/*@-exportlocal@*/
+/*@null@*/
+rpmtsScore rpmtsScoreFree(/*@only@*/ /*@null@*/ rpmtsScore score)
+       /*@modifies score @*/;
+/*@=exportlocal@*/
 
 /** \ingroup rpmts
  * Get rpmtsScore from transaction.
  * @param ts   RPM Transaction.
  * @return     rpmtsScore or NULL.
  */
-rpmtsScore rpmtsGetScore(rpmts ts);
+/*@exposed@*/ /*@null@*/
+rpmtsScore rpmtsGetScore(rpmts ts)
+       /*@*/;
 
 /** \ingroup rpmts
  * Get rpmtsScoreEntry from rpmtsScore.
  * @param score   RPM Transaction Score.
  * @return       rpmtsScoreEntry or NULL.
  */
-rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N);
+/*@null@*/
+rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N)
+       /*@*/;
 
 /** \ingroup rpmts
  * \file lib/rpmts.h
@@ -317,6 +327,7 @@ struct rpmts_s {
 /*@null@*/
     Spec spec;                 /*!< Spec file control structure. */
 
+/*@kept@*/ /*@null@*/
     rpmtsScore score;          /*!< Transaction Score (autorollback). */
 
 /*@refs@*/
@@ -537,24 +548,26 @@ int rpmtsSetSolveCallback(rpmts ts,
        /*@modifies ts @*/;
 
 /**
+ * Return the type of a transaction.
+ * @param ts           transaction set
+ * @return             0 it is not, 1 it is.
+ */
+rpmtsType rpmtsGetType(rpmts ts)
+       /*@*/;
+
+/**
  * Set transaction type.   Allowed types are:
- * 
+ *
  *     RPMTRANS_TYPE_NORMAL
  *     RPMTRANS_TYPE_ROLLBACK
  *     RPMTRANS_TYPE_AUTOROLLBACK
- * 
+ *
  * @param ts           transaction set
  * @param rollback     rpmtsType
  * @return             void
  */
-void rpmtsSetType(rpmts ts, rpmtsType type);
-
-/**
- * Return the type of a transaction.
- * @param ts           transaction set
- * @return             0 it is not, 1 it is.
- */
-rpmtsType rpmtsGetType(rpmts ts);
+void rpmtsSetType(rpmts ts, rpmtsType type)
+       /*@modifies ts @*/;
 
 /**
  * Return current transaction set problems.
index a035cc6..a078615 100644 (file)
 /*@access rpmtsi @*/
 /*@access rpmts @*/
 
-/* Internal function to rollback a transaction
- * This is not declared in the header because we not
- * want others calling this directly (or at all).
- */
-rpmRC _rpmtsRollback(rpmts rollbackTransaction);
-
-/* Internal function to add an element to a rollback transaction
- * This is not declared in the header because we not want others 
- * calling this directly (or at all).
- */
-rpmRC _rpmtsAddRollbackElement(rpmts rollbackTransaction, rpmts runningTransaction, rpmte te);
+/*@access IDT @*/
+/*@access IDTX @*/
+/*@access FD_t @*/
 
-/* You might want to move this into the header Jeff (or even 
- * to a different file altogether (i.e. the prototype and the 
- * the function).
- */
-rpmRC getRepackageHeaderFromTE(rpmte te, rpmts ts, Header *hdrp, char **fn); 
 /* XXX: This is a hack.  I needed a to setup a notify callback
  * for the rollback transaction, but I did not want to create
  * a header for rpminstall.c.
@@ -81,7 +67,8 @@ extern void * rpmShowProgress(/*@null@*/ const void * arg,
                         const unsigned long amount,
                         const unsigned long total,
                         /*@null@*/ fnpyKey key,
-                        /*@null@*/ void * data);
+                        /*@null@*/ void * data)
+       /*@*/;
 
 /**
  */
@@ -266,7 +253,7 @@ static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
     Header h;
     const char * otherStates;
     int i, xx;
-   
+
     rpmdbMatchIterator mi;
 
     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
@@ -459,7 +446,7 @@ static void handleOverlappedFiles(const rpmts ts,
     rpmps ps;
     const char * fn;
     int i, j;
-  
+
     ps = rpmtsProblems(ts);
     fi = rpmfiInit(fi, 0);
     if (fi != NULL)
@@ -693,7 +680,7 @@ static int ensureOlder(rpmts ts,
     *t++ = '-';
     if (rpmteR(p) != NULL)     t = stpcpy(t, rpmteR(p));
 /*@=boundswrite@*/
-    
+
     req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
     rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
     req = rpmdsFree(req);
@@ -969,1292 +956,1326 @@ rpmfi rpmtsiFi(const rpmtsi tsi)
     /*@=compdef =refcounttrans =usereleased @*/
 }
 
-#define        NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
-
-int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
+/**
+ * This is not a generalized function to be called from outside
+ * librpm.  It is called internally by rpmtsRun() to rollback
+ * a failed transaction.
+ * @param rollbackTransaction          rollback transaction
+ * @return                             RPMRC_OK, or RPMRC_FAIL
+ */
+static rpmRC _rpmtsRollback(rpmts rollbackTransaction)
+       /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
+       /*@modifies rollbackTransaction,
+               rpmGlobalMacroContext, fileSystem, internalState @*/
 {
-    uint_32 tscolor = rpmtsColor(ts);
-    int i, j;
-    int ourrc = 0;
-    int totalFileCount = 0;
-    rpmfi fi;
-    sharedFileInfo shared, sharedList;
-    int numShared;
-    int nexti;
-    alKey lastFailKey;
-    fingerPrintCache fpc;
-    rpmps ps;
-    rpmpsm psm;
-    rpmtsi pi; rpmte p;
-    rpmtsi qi; rpmte q;
-    int numAdded;
-    int numRemoved;
-    rpmts rollbackTransaction = NULL;
-    int rollbackOnFailure = 0;
-    void * lock;
-    int xx;
-
-
-    /* XXX programmer error segfault avoidance. */
-    if (rpmtsNElements(ts) <= 0)
-       return -1;
+    int    rc         = 0;
+    int    numAdded   = 0;
+    int    numRemoved = 0;
+    int_32 tid;
+    rpmtsi tsi;
+    rpmte  te;
+    rpmps  ps;
 
-    /* See if we need to rollback on failure */
-    rollbackOnFailure = rpmExpandNumeric(
-       "%{?_rollback_transaction_on_failure}");
-    if(rpmtsGetType(ts) & (RPMTRANS_TYPE_ROLLBACK 
-       | RPMTRANS_TYPE_AUTOROLLBACK)) {
-       rollbackOnFailure = 0;
-    }
-    /* If we are in test mode, there is no need to rollback on 
-     * failure (-;
+    /*
+     * Gather information about this rollback transaction for reporting.
+     *    1) Get tid
      */
-    if(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) rollbackOnFailure = 0;
-
-    lock = rpmtsAcquireLock(ts);
-    if (lock == NULL)
-       return -1;      /* XXX W2DO? */
-
-    if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
-       (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
-    if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
-       (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
-
-    if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
-       (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
+    tid = rpmtsGetTid(rollbackTransaction);
 
-    ts->probs = rpmpsFree(ts->probs);
-    ts->probs = rpmpsCreate();
+    /*
+     *    2) Get number of install elments and erase elements
+     */
+    tsi = rpmtsiInit(rollbackTransaction);
+    while((te = rpmtsiNext(tsi, 0)) != NULL) {
+       switch (rpmteType(te)) {
+       case TR_ADDED:
+          numAdded++;
+          /*@switchbreak@*/ break;
+       case TR_REMOVED:
+          numRemoved++;
+          /*@switchbreak@*/ break;
+       default:
+          /*@switchbreak@*/ break;
+       }       
+    }
+    tsi = rpmtsiFree(tsi);
 
-    /* XXX Make sure the database is open RDWR for package install/erase. */
-    {  int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
-               ? O_RDONLY : (O_RDWR|O_CREAT);
+    rpmMessage(RPMMESS_NORMAL, _("Transaction failed...rolling back\n"));
+    rpmMessage(RPMMESS_NORMAL,
+       _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
+                        numAdded, numRemoved, ctime(&tid), tid);
 
-       /* Open database RDWR for installing packages. */
-       if (rpmtsOpenDB(ts, dbmode)) {
-           rpmtsFreeLock(lock);
-           return -1;  /* XXX W2DO? */
-       }
+    /* Check the transaction to see if it is doable */
+    rc = rpmtsCheck(rollbackTransaction);
+    ps = rpmtsProblems(rollbackTransaction);
+    if (rc != 0 && rpmpsNumProblems(ps) > 0) {
+       rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
+       rpmpsPrint(NULL, ps);
+       ps = rpmpsFree(ps);
+       return -1;
     }
+    ps = rpmpsFree(ps);
 
-    ts->ignoreSet = ignoreSet;
-    {  const char * currDir = currentDirectory();
-       rpmtsSetCurrDir(ts, currDir);
-       currDir = _free(currDir);
+    /* Order the transaction */
+    rc = rpmtsOrder(rollbackTransaction);
+    if (rc != 0) {
+       rpmMessage(RPMMESS_ERROR,
+           _("Could not order auto-rollback transaction!\n"));
+       return -1;
     }
 
-    (void) rpmtsSetChrootDone(ts, 0);
-
-    {  int_32 tid = (int_32) time(NULL);
-       (void) rpmtsSetTid(ts, tid);
-    }
 
-    /* Get available space on mounted file systems. */
-    xx = rpmtsInitDSI(ts);
 
-    /* ===============================================
-     * For packages being installed:
-     * - verify package arch/os.
-     * - verify package epoch:version-release is newer.
-     * - count files.
-     * For packages being removed:
-     * - count files.
+    /* Run the transaction and print any problems
+     * We want to stay with the original transactions flags except
+     * that we want to add what is essentially a force.
+     * This handles two things in particular:
+     * 
+     * 1.  We we want to upgrade over a newer package.
+     *         2.  If a header for the old package is there we
+     *      we want to replace it.  No questions asked.
      */
+    rc = rpmtsRun(rollbackTransaction, NULL,
+         RPMPROB_FILTER_REPLACEPKG
+       | RPMPROB_FILTER_REPLACEOLDFILES
+       | RPMPROB_FILTER_REPLACENEWFILES
+       | RPMPROB_FILTER_OLDPACKAGE
+    );
+    ps = rpmtsProblems(rollbackTransaction);
+    if (rc > 0 && rpmpsNumProblems(ps) > 0)
+       rpmpsPrint(stderr, ps);
+    ps = rpmpsFree(ps);
+    rollbackTransaction = rpmtsFree(rollbackTransaction);
 
-rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
-    ps = rpmtsProblems(ts);
-    /* The ordering doesn't matter here */
-    pi = rpmtsiInit(ts);
-    while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
-       rpmdbMatchIterator mi;
-       int fc;
-
-       if ((fi = rpmtsiFi(pi)) == NULL)
-           continue;   /* XXX can't happen */
-       fc = rpmfiFC(fi);
-
-       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
-           if (!archOkay(rpmteA(p)))
-               rpmpsAppend(ps, RPMPROB_BADARCH,
-                       rpmteNEVR(p), rpmteKey(p),
-                       rpmteA(p), NULL,
-                       NULL, 0);
+    return rc;
+}
 
-       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
-           if (!osOkay(rpmteO(p)))
-               rpmpsAppend(ps, RPMPROB_BADOS,
-                       rpmteNEVR(p), rpmteKey(p),
-                       rpmteO(p), NULL,
-                       NULL, 0);
+/**
+ * Get the repackaged header and filename from the repackage directory.
+ * @todo Find a suitable home for this function.
+ * @todo This function creates an IDTX everytime it is called.  Needs to
+ *       be made more efficient (only create on per running transaction).
+ * @param ts           rpm transaction
+ * @param te           transaction element
+ * @return hdrp                Repackaged header
+ * @return fn          Repackaged package's path (transaction key)
+ * @return             RPMRC_NOTFOUND or RPMRC_OK
+ */
+static rpmRC getRepackageHeaderFromTE(rpmts ts, rpmte te,
+               /*@out@*/ /*@null@*/ Header *hdrp,
+               /*@out@*/ /*@null@*/ const char **fn)
+       /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
+       /*@modifies ts, *hdrp, *fn,
+               rpmGlobalMacroContext, fileSystem, internalState @*/
+{
+    int_32 tid;
+    const char * name;
+    const char * rpname = NULL;
+    const char * _repackage_dir = NULL;
+    const char * globStr = "-*.rpm";
+    char * rp = NULL;          /* Rollback package name */
+    IDTX rtids = NULL;
+    IDT rpIDT;
+    int nrids = 0;
+    int nb;                    /* Number of bytes */
+    Header h = NULL;
+    int rc   = RPMRC_NOTFOUND; /* Assume we do not find it*/
+    int xx;
 
-       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
-           Header h;
-           mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
-           while ((h = rpmdbNextIterator(mi)) != NULL)
-               xx = ensureOlder(ts, p, h);
-           mi = rpmdbFreeIterator(mi);
-       }
+    rpmMessage(RPMMESS_DEBUG,
+       _("Getting repackaged header from transaction element\n"));
 
-       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
-           mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
-           xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
-                               rpmteE(p));
-           xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
-                               rpmteV(p));
-           xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
-                               rpmteR(p));
-           if (tscolor) {
-               xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP,
-                               rpmteA(p));
-               xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP,
-                               rpmteO(p));
-           }
+    /* Set header pointer to null if its not already */
+    if (hdrp)
+       *hdrp = NULL;
+    if (fn)
+       *fn = NULL;
 
-           while (rpmdbNextIterator(mi) != NULL) {
-               rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
-                       rpmteNEVR(p), rpmteKey(p),
-                       NULL, NULL,
-                       NULL, 0);
-               /*@innerbreak@*/ break;
-           }
-           mi = rpmdbFreeIterator(mi);
-       }
+    /* Get the TID of the current transaction */
+    tid = rpmtsGetTid(ts);
+    /* Need the repackage dir if the user want to
+     * rollback on a failure.
+     */
+    _repackage_dir = rpmExpand("%{?_repackage_dir}", NULL);
+    if (_repackage_dir == NULL) goto exit;
 
-       /* Count no. of files (if any). */
-       totalFileCount += fc;
+    /* Build the glob string to find the possible repackaged
+     * packages for this package.
+     */
+    name = rpmteN(te); 
+    nb = strlen(_repackage_dir) + strlen(name) + strlen(globStr) + 2;
+    rp = memset((char *) malloc(nb), 0, nb);
+    xx = snprintf(rp, nb, "%s/%s%s.rpm", _repackage_dir, name, globStr);
 
+    /* Get the index of possible repackaged packages */
+    rpmMessage(RPMMESS_DEBUG, _("\tLooking for %s...\n"), rp);
+    rtids = IDTXglob(ts, rp, RPMTAG_REMOVETID);
+    rp = _free(rp);
+    if (rtids != NULL) {
+       rpmMessage(RPMMESS_DEBUG, _("\tMatches found.\n"));
+       rpIDT = rtids->idt;
+       nrids = rtids->nidt;
+    } else {
+       rpmMessage(RPMMESS_DEBUG, _("\tNo matches found.\n"));
+       goto exit;
     }
-    pi = rpmtsiFree(pi);
-    ps = rpmpsFree(ps);
 
-    /* The ordering doesn't matter here */
-    pi = rpmtsiInit(ts);
-    while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
-       int fc;
+    /* Now walk through index until we find the package (or we have
+     * exhausted the index.
+     */
+/*@-branchstate@*/
+    do {
+       /* If index is null we have exhausted the list and need to
+        * get out of here...the repackaged package was not found.
+        */
+       if (rpIDT == NULL) {
+           rpmMessage(RPMMESS_DEBUG, _("\tRepackaged package not found!.\n"));
+           break;
+       }
 
-       if ((fi = rpmtsiFi(pi)) == NULL)
-           continue;   /* XXX can't happen */
-       fc = rpmfiFC(fi);
+       /* Is this the same tid.  If not decrement the list and continue */
+       if (rpIDT->val.u32 != tid) {
+           nrids--;
+           if (nrids > 0)
+               rpIDT++;
+           else
+               rpIDT = NULL;
+           continue;
+       }
 
-       totalFileCount += fc;
+       /* OK, the tid matches.  Now lets see if the name is the same.
+        * If I could not get the name from the package, I will go onto
+        * the next one.  Perhaps I should return an error at this
+        * point, but if this was not the correct one, at least the correct one
+        * would be found.
+        * XXX:  Should I be matching name and arch?
+        */
+       rpmMessage(RPMMESS_DEBUG, _("\tREMOVETID matched INSTALLTID.\n"));
+       if (headerGetEntry(rpIDT->h, RPMTAG_NAME, NULL, (void **) &rpname, NULL)) {
+           rpmMessage(RPMMESS_DEBUG, _("\t\tName:  %s.\n"), rpname);
+           if (!strcmp(name,rpname)) {
+               /* It matched we have a canidate */
+               h  = headerLink(rpIDT->h);
+               nb = strlen(rpIDT->key) + 1;
+               rp = memset((char *) malloc(nb), 0, nb);
+               rp = strncat(rp, rpIDT->key, nb);
+               rc = RPMRC_OK;
+               break;
+           }
+       }
+
+       /* Decrement list */    
+       nrids--;
+       if (nrids > 0)
+           rpIDT++;
+       else
+           rpIDT = NULL;
+    } while (1);
+/*@=branchstate@*/
+
+exit:
+    if (rc != RPMRC_NOTFOUND && h != NULL && hdrp != NULL) {
+       rpmMessage(RPMMESS_DEBUG, _("\tRepackaged Package was %s...\n"), rp);
+       if (hdrp != NULL)
+           *hdrp = headerLink(h);
+/*@-branchstate@*/
+       if (fn != NULL)
+           *fn = rp;
+       else
+           rp = _free(rp);
+/*@=branchstate@*/
     }
-    pi = rpmtsiFree(pi);
+    if (h != NULL)
+       h = headerFree(h);
+    rtids = IDTXfree(rtids);
+    return rc; 
+}
 
+/**
+ * This is not a generalized function to be called from outside
+ * librpm.  It is called internally by rpmtsRun() to add elements
+ * to its rollback transaction.
+ * @param rollbackTransaction          rollback transaction
+ * @param runningTransaction           running transaction (the one you want to rollback)
+ * @param te                           Transaction element.
+ * @return                             RPMRC_OK, or RPMRC_FAIL
+ */
+static rpmRC _rpmtsAddRollbackElement(rpmts rollbackTransaction,
+               rpmts runningTransaction, rpmte te)
+       /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
+       /*@modifies rollbackTransaction, runningTransaction,
+               rpmGlobalMacroContext, fileSystem, internalState @*/
+{
+    Header h   = NULL;
+    Header rph = NULL;
+    char * rpn;        
+    unsigned int db_instance = 0;
+    rpmtsi pi;         
+    rpmte p;
+    int rc  = RPMRC_FAIL;      /* Assume Failure */
 
-    /* Run pre-transaction scripts, but only if there are no known
-     * problems up to this point. */
-    if (!((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
-         || (ts->probs->numProblems &&
-               (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) {
-       rpmMessage(RPMMESS_DEBUG, _("running pre-transaction scripts\n"));
-       pi = rpmtsiInit(ts);
-       while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
-           if ((fi = rpmtsiFi(pi)) == NULL)
-               continue;       /* XXX can't happen */
+    switch(rpmteType(te)) {
+    case TR_ADDED:
+    {   rpmdbMatchIterator mi;
 
-           p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
-                           rpmteKey(p), ts->notifyData);
-           p->h = NULL;
-           if (rpmteFd(p) != NULL) {
-               rpmVSFlags ovsflags = rpmtsVSFlags(ts);
-               rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
-               rpmRC rpmrc;
-               ovsflags = rpmtsSetVSFlags(ts, vsflags);
-               rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
-                           rpmteNEVR(p), &p->h);
-               vsflags = rpmtsSetVSFlags(ts, ovsflags);
-               switch (rpmrc) {
-               default:
-                   /*@-noeffectuncon@*/ /* FIX: notify annotations */
-                   p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
-                                   0, 0,
-                                   rpmteKey(p), ts->notifyData);
-                   /*@=noeffectuncon@*/
-                   p->fd = NULL;
-                   /*@innerbreak@*/ break;
-               case RPMRC_NOTTRUSTED:
-               case RPMRC_NOKEY:
-               case RPMRC_OK:
-                   /*@innerbreak@*/ break;
-               }
-           }
+       rpmMessage(RPMMESS_DEBUG,
+           _("Adding install element to auto-rollback transaction.\n"));
 
-           if (rpmteFd(p) != NULL) {
-               fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
-               if (fi != NULL) {       /* XXX can't happen */
-                   fi->te = p;
-                   p->fi = fi;
-               }
-               psm = rpmpsmNew(ts, p, p->fi);
-               psm->scriptTag = RPMTAG_PRETRANS;
-               psm->progTag = RPMTAG_PRETRANSPROG;
-               xx = rpmpsmStage(psm, PSM_SCRIPT);
-               psm = rpmpsmFree(psm);
+       /* Get the header for this package from the database
+        * First get the database instance (the key).
+        */
+       db_instance = rpmteDBInstance(te);
+       if (db_instance == 0) {
+           /* Could not get the db instance: WTD! */
+           rpmMessage(RPMMESS_FATALERROR,
+               _("Could not get install element database instance!\n"));
+           break;
+       }
 
-               (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
-                                 rpmteKey(p), ts->notifyData);
-               p->fd = NULL;
-               p->h = headerFree(p->h);
+       /* Now suck the header out of the database */
+       mi = rpmtsInitIterator(rollbackTransaction,
+           RPMDBI_PACKAGES, &db_instance, sizeof(db_instance));
+       h = rpmdbNextIterator(mi);
+       if (h != NULL) h = headerLink(h);
+       mi = rpmdbFreeIterator(mi);
+       if (h == NULL) {
+           /* Header was not there??? */
+           rpmMessage(RPMMESS_FATALERROR,
+               _("Could not get header for auto-rollback transaction!\n"));
+           break;
+       }
+
+       /* Now see if there is a repackaged package for this */
+       rc = getRepackageHeaderFromTE(runningTransaction, te, &rph, &rpn);
+       switch(rc) {
+       case RPMRC_OK:
+           /* Add the install element, as we had a repackaged package */
+           rpmMessage(RPMMESS_DEBUG,
+               _("\tAdded repackaged package header: %s.\n"), rpn);
+           rc = rpmtsAddInstallElement(rollbackTransaction, headerLink(rph),
+               (fnpyKey) rpn, 1, te->relocs);
+           /*@innerbreak@*/ break;
+
+       case RPMRC_NOTFOUND:
+           /* Add the header as an erase element, we did not
+            * have a repackaged package
+            */
+           rpmMessage(RPMMESS_DEBUG, _("\tAdded erase element.\n"));
+           rc = rpmtsAddEraseElement(rollbackTransaction, h, db_instance);
+           /*@innerbreak@*/ break;
+                       
+       default:
+           /* Not sure what to do on failure...just give up */
+           rpmMessage(RPMMESS_FATALERROR,
+               _("Could not get repackaged header for auto-rollback transaction!\n"));
+           /*@innerbreak@*/ break;
+       }
+    }  break;
+
+   case TR_REMOVED:
+       rpmMessage(RPMMESS_DEBUG,
+           _("Add erase element to auto-rollback transaction.\n"));
+
+       /* See if this element has already been added as an upgrade.
+        * If so we want to do nothing.
+        */
+       pi = rpmtsiInit(rollbackTransaction);
+       while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
+           if (rpmteType(p) == TR_ADDED) continue;
+           if (!strcmp(rpmteN(p), rpmteN(te))) {
+               rpmMessage(RPMMESS_DEBUG, _("\tFound existing upgrade element.\n"));
+               rpmMessage(RPMMESS_DEBUG, _("\tNot adding erase element for %s.\n"),
+                       rpmteN(te));
+               rc = RPMRC_OK;  
+               pi = rpmtsiFree(pi);
+               /*@loopbreak@*/ break;
            }
        }
        pi = rpmtsiFree(pi);
-    }
-
-    /* ===============================================
-     * Initialize transaction element file info for package:
-     */
 
-    /*
-     * FIXME?: we'd be better off assembling one very large file list and
-     * calling fpLookupList only once. I'm not sure that the speedup is
-     * worth the trouble though.
-     */
-rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
 
-    numAdded = numRemoved = 0;
-    pi = rpmtsiInit(ts);
-    while ((p = rpmtsiNext(pi, 0)) != NULL) {
-       int fc;
+       /* Get the repackage header from the current transaction
+       * element.
+       */
+       rc = getRepackageHeaderFromTE(runningTransaction, te, &rph, &rpn);
+       switch(rc) {
+       case RPMRC_OK:
+           /* Add the install element */
+           rpmMessage(RPMMESS_DEBUG,
+               _("\tAdded repackaged package %s.\n"), rpn);
+           rc = rpmtsAddInstallElement(rollbackTransaction, rph,
+               (fnpyKey) rpn, 1, te->relocs);
+           if (rc != RPMRC_OK)
+               rpmMessage(RPMMESS_FATALERROR,
+                   _("Could not add erase element to auto-rollback transaction.\n"));
+           /*@innerbreak@*/ break;
 
-       if ((fi = rpmtsiFi(pi)) == NULL)
-           continue;   /* XXX can't happen */
-       fc = rpmfiFC(fi);
+       case RPMRC_NOTFOUND:
+           /* Just did not have a repackaged package */
+           rpmMessage(RPMMESS_DEBUG,
+               _("\tNo repackaged package...nothing to do.\n"));
+           rc = RPMRC_OK;
+           /*@innerbreak@*/ break;
 
-       /*@-branchstate@*/
-       switch (rpmteType(p)) {
-       case TR_ADDED:
-           numAdded++;
-           fi->record = 0;
-           /* Skip netshared paths, not our i18n files, and excluded docs */
-           if (fc > 0)
-               skipFiles(ts, fi);
-           /*@switchbreak@*/ break;
-       case TR_REMOVED:
-           numRemoved++;
-           fi->record = rpmteDBOffset(p);
-           /*@switchbreak@*/ break;
+       default:
+           rpmMessage(RPMMESS_FATALERROR,
+               _("Failure reading repackaged package!\n"));
+           /*@innerbreak@*/ break;
        }
-       /*@=branchstate@*/
+       break;
 
-       fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
+    default:
+       break;
     }
-    pi = rpmtsiFree(pi);
 
-    if (!rpmtsChrootDone(ts)) {
-       const char * rootDir = rpmtsRootDir(ts);
-       xx = chdir("/");
-       /*@-superuser -noeffect @*/
-       if (rootDir != NULL)
-           xx = chroot(rootDir);
-       /*@=superuser =noeffect @*/
-       (void) rpmtsSetChrootDone(ts, 1);
-    }
+/* XXX:  I want to free this, but if I do then the consumers of
+ *       are hosed.  Just leaving you a little note Jeff, so you
+ *       know that this does introduce a memory leak.  I wanted
+ *       keep the patch as simple as possible so I am not fixxing
+ *       the leak.
+ *   if (rpn != NULL)
+ *     free(rpn);
+ */
 
-    ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
-    fpc = fpCacheCreate(totalFileCount);
+    /* Clean up */
+    if (h != NULL)
+       h = headerFree(h);
+    if (rph != NULL)
+       rph = headerFree(rph);
+    return rc;
+}
+#define        NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
 
-    /* ===============================================
-     * Add fingerprint for each file not skipped.
-     */
-    pi = rpmtsiInit(ts);
-    while ((p = rpmtsiNext(pi, 0)) != NULL) {
-       int fc;
+int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
+{
+    uint_32 tscolor = rpmtsColor(ts);
+    int i, j;
+    int ourrc = 0;
+    int totalFileCount = 0;
+    rpmfi fi;
+    sharedFileInfo shared, sharedList;
+    int numShared;
+    int nexti;
+    alKey lastFailKey;
+    fingerPrintCache fpc;
+    rpmps ps;
+    rpmpsm psm;
+    rpmtsi pi; rpmte p;
+    rpmtsi qi; rpmte q;
+    int numAdded;
+    int numRemoved;
+    rpmts rollbackTransaction = NULL;
+    int rollbackOnFailure = 0;
+    void * lock;
+    int xx;
 
-       (void) rpmdbCheckSignals();
 
-       if ((fi = rpmtsiFi(pi)) == NULL)
-           continue;   /* XXX can't happen */
-       fc = rpmfiFC(fi);
+    /* XXX programmer error segfault avoidance. */
+    if (rpmtsNElements(ts) <= 0)
+       return -1;
 
-       (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
-       fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
-       /*@-branchstate@*/
-       fi = rpmfiInit(fi, 0);
-       if (fi != NULL)         /* XXX lclint */
-       while ((i = rpmfiNext(fi)) >= 0) {
-           if (XFA_SKIPPING(fi->actions[i]))
-               /*@innercontinue@*/ continue;
-           /*@-dependenttrans@*/
-           htAddEntry(ts->ht, fi->fps + i, (void *) fi);
-           /*@=dependenttrans@*/
+    /* See if we need to rollback on failure */
+    rollbackOnFailure = rpmExpandNumeric(
+       "%{?_rollback_transaction_on_failure}");
+    if (rpmtsGetType(ts) & (RPMTRANS_TYPE_ROLLBACK
+       | RPMTRANS_TYPE_AUTOROLLBACK)) {
+       rollbackOnFailure = 0;
+    }
+    /* If we are in test mode, there is no need to rollback on
+     * failure (-;
+     */
+    if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) rollbackOnFailure = 0;
+
+    lock = rpmtsAcquireLock(ts);
+    if (lock == NULL)
+       return -1;      /* XXX W2DO? */
+
+    if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
+       (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
+    if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
+       (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
+
+    if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
+       (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
+
+    ts->probs = rpmpsFree(ts->probs);
+    ts->probs = rpmpsCreate();
+
+    /* XXX Make sure the database is open RDWR for package install/erase. */
+    {  int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
+               ? O_RDONLY : (O_RDWR|O_CREAT);
+
+       /* Open database RDWR for installing packages. */
+       if (rpmtsOpenDB(ts, dbmode)) {
+           rpmtsFreeLock(lock);
+           return -1;  /* XXX W2DO? */
        }
-       /*@=branchstate@*/
-       (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
+    }
+
+    ts->ignoreSet = ignoreSet;
+    {  const char * currDir = currentDirectory();
+       rpmtsSetCurrDir(ts, currDir);
+       currDir = _free(currDir);
+    }
+
+    (void) rpmtsSetChrootDone(ts, 0);
 
+    {  int_32 tid = (int_32) time(NULL);
+       (void) rpmtsSetTid(ts, tid);
     }
-    pi = rpmtsiFree(pi);
 
-    NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
-       NULL, ts->notifyData));
+    /* Get available space on mounted file systems. */
+    xx = rpmtsInitDSI(ts);
 
     /* ===============================================
-     * Compute file disposition for each package in transaction set.
+     * For packages being installed:
+     * - verify package arch/os.
+     * - verify package epoch:version-release is newer.
+     * - count files.
+     * For packages being removed:
+     * - count files.
      */
-rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
+
+rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
     ps = rpmtsProblems(ts);
+    /* The ordering doesn't matter here */
     pi = rpmtsiInit(ts);
-    while ((p = rpmtsiNext(pi, 0)) != NULL) {
-       dbiIndexSet * matches;
-       int knownBad;
+    while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
+       rpmdbMatchIterator mi;
        int fc;
 
-       (void) rpmdbCheckSignals();
-
        if ((fi = rpmtsiFi(pi)) == NULL)
            continue;   /* XXX can't happen */
        fc = rpmfiFC(fi);
 
-       NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
-                       ts->orderCount, NULL, ts->notifyData));
-
-       if (fc == 0) continue;
-
-       (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
-       /* Extract file info for all files in this package from the database. */
-       matches = xcalloc(fc, sizeof(*matches));
-       if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
-           ps = rpmpsFree(ps);
-           rpmtsFreeLock(lock);
-           return 1;   /* XXX WTFO? */
-       }
-
-       numShared = 0;
-       fi = rpmfiInit(fi, 0);
-       while ((i = rpmfiNext(fi)) >= 0)
-           numShared += dbiIndexSetCount(matches[i]);
-
-       /* Build sorted file info list for this package. */
-       shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
+       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
+           if (!archOkay(rpmteA(p)))
+               rpmpsAppend(ps, RPMPROB_BADARCH,
+                       rpmteNEVR(p), rpmteKey(p),
+                       rpmteA(p), NULL,
+                       NULL, 0);
 
-       fi = rpmfiInit(fi, 0);
-       while ((i = rpmfiNext(fi)) >= 0) {
-           /*
-            * Take care not to mark files as replaced in packages that will
-            * have been removed before we will get here.
-            */
-           for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
-               int ro;
-               ro = dbiIndexRecordOffset(matches[i], j);
-               knownBad = 0;
-               qi = rpmtsiInit(ts);
-               while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
-                   if (ro == knownBad)
-                       /*@innerbreak@*/ break;
-                   if (rpmteDBOffset(q) == ro)
-                       knownBad = ro;
-               }
-               qi = rpmtsiFree(qi);
+       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
+           if (!osOkay(rpmteO(p)))
+               rpmpsAppend(ps, RPMPROB_BADOS,
+                       rpmteNEVR(p), rpmteKey(p),
+                       rpmteO(p), NULL,
+                       NULL, 0);
 
-               shared->pkgFileNum = i;
-               shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
-               shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
-               shared->isRemoved = (knownBad == ro);
-               shared++;
-           }
-           matches[i] = dbiFreeIndexSet(matches[i]);
+       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
+           Header h;
+           mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
+           while ((h = rpmdbNextIterator(mi)) != NULL)
+               xx = ensureOlder(ts, p, h);
+           mi = rpmdbFreeIterator(mi);
        }
-       numShared = shared - sharedList;
-       shared->otherPkg = -1;
-       matches = _free(matches);
-
-       /* Sort file info by other package index (otherPkg) */
-       qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
-
-       /* For all files from this package that are in the database ... */
-       /*@-branchstate@*/
-       for (i = 0; i < numShared; i = nexti) {
-           int beingRemoved;
-
-           shared = sharedList + i;
 
-           /* Find the end of the files in the other package. */
-           for (nexti = i + 1; nexti < numShared; nexti++) {
-               if (sharedList[nexti].otherPkg != shared->otherPkg)
-                   /*@innerbreak@*/ break;
+       if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
+           mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
+           xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
+                               rpmteE(p));
+           xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
+                               rpmteV(p));
+           xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
+                               rpmteR(p));
+           if (tscolor) {
+               xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP,
+                               rpmteA(p));
+               xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP,
+                               rpmteO(p));
            }
 
-           /* Is this file from a package being removed? */
-           beingRemoved = 0;
-           if (ts->removedPackages != NULL)
-           for (j = 0; j < ts->numRemovedPackages; j++) {
-               if (ts->removedPackages[j] != shared->otherPkg)
-                   /*@innercontinue@*/ continue;
-               beingRemoved = 1;
+           while (rpmdbNextIterator(mi) != NULL) {
+               rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
+                       rpmteNEVR(p), rpmteKey(p),
+                       NULL, NULL,
+                       NULL, 0);
                /*@innerbreak@*/ break;
            }
-
-           /* Determine the fate of each file. */
-           switch (rpmteType(p)) {
-           case TR_ADDED:
-               xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
-       !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
-               /*@switchbreak@*/ break;
-           case TR_REMOVED:
-               if (!beingRemoved)
-                   xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
-               /*@switchbreak@*/ break;
-           }
+           mi = rpmdbFreeIterator(mi);
        }
-       /*@=branchstate@*/
-
-       free(sharedList);
 
-       /* Update disk space needs on each partition for this package. */
-       handleOverlappedFiles(ts, p, fi);
+       /* Count no. of files (if any). */
+       totalFileCount += fc;
 
-       /* Check added package has sufficient space on each partition used. */
-       switch (rpmteType(p)) {
-       case TR_ADDED:
-           rpmtsCheckDSIProblems(ts, p);
-           /*@switchbreak@*/ break;
-       case TR_REMOVED:
-           /*@switchbreak@*/ break;
-       }
-       (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
     }
     pi = rpmtsiFree(pi);
     ps = rpmpsFree(ps);
 
-    if (rpmtsChrootDone(ts)) {
-       const char * currDir = rpmtsCurrDir(ts);
-       /*@-superuser -noeffect @*/
-       xx = chroot(".");
-       /*@=superuser =noeffect @*/
-       (void) rpmtsSetChrootDone(ts, 0);
-       if (currDir != NULL)
-           xx = chdir(currDir);
-    }
-
-    NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
-       NULL, ts->notifyData));
-
-    /* ===============================================
-     * Free unused memory as soon as possible.
-     */
+    /* The ordering doesn't matter here */
     pi = rpmtsiInit(ts);
-    while ((p = rpmtsiNext(pi, 0)) != NULL) {
+    while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
+       int fc;
+
        if ((fi = rpmtsiFi(pi)) == NULL)
            continue;   /* XXX can't happen */
-       if (rpmfiFC(fi) == 0)
-           continue;
-       fi->fps = _free(fi->fps);
+       fc = rpmfiFC(fi);
+
+       totalFileCount += fc;
     }
     pi = rpmtsiFree(pi);
 
-    fpc = fpCacheFree(fpc);
-    ts->ht = htFree(ts->ht);
 
-    /* ===============================================
-     * If unfiltered problems exist, free memory and return.
-     */
-    if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
-     || (ts->probs->numProblems &&
-               (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))
-       )
-    {
-       rpmtsFreeLock(lock);
-       return ts->orderCount;
+    /* Run pre-transaction scripts, but only if there are no known
+     * problems up to this point. */
+    if (!((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
+         || (ts->probs->numProblems &&
+               (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) {
+       rpmMessage(RPMMESS_DEBUG, _("running pre-transaction scripts\n"));
+       pi = rpmtsiInit(ts);
+       while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
+           if ((fi = rpmtsiFi(pi)) == NULL)
+               continue;       /* XXX can't happen */
+
+           p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
+                           rpmteKey(p), ts->notifyData);
+           p->h = NULL;
+           if (rpmteFd(p) != NULL) {
+               rpmVSFlags ovsflags = rpmtsVSFlags(ts);
+               rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
+               rpmRC rpmrc;
+               ovsflags = rpmtsSetVSFlags(ts, vsflags);
+               rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
+                           rpmteNEVR(p), &p->h);
+               vsflags = rpmtsSetVSFlags(ts, ovsflags);
+               switch (rpmrc) {
+               default:
+                   /*@-noeffectuncon@*/ /* FIX: notify annotations */
+                   p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
+                                   0, 0,
+                                   rpmteKey(p), ts->notifyData);
+                   /*@=noeffectuncon@*/
+                   p->fd = NULL;
+                   /*@switchbreak@*/ break;
+               case RPMRC_NOTTRUSTED:
+               case RPMRC_NOKEY:
+               case RPMRC_OK:
+                   /*@switchbreak@*/ break;
+               }
+           }
+
+/*@-branchstate@*/
+           if (rpmteFd(p) != NULL) {
+               fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
+               if (fi != NULL) {       /* XXX can't happen */
+                   fi->te = p;
+                   p->fi = fi;
+               }
+/*@-compdef -usereleased@*/    /* p->fi->te undefined */
+               psm = rpmpsmNew(ts, p, p->fi);
+/*@=compdef =usereleased@*/
+assert(psm != NULL);
+               psm->scriptTag = RPMTAG_PRETRANS;
+               psm->progTag = RPMTAG_PRETRANSPROG;
+               xx = rpmpsmStage(psm, PSM_SCRIPT);
+               psm = rpmpsmFree(psm);
+
+/*@-noeffectuncon -compdef -usereleased @*/
+               (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
+                                 rpmteKey(p), ts->notifyData);
+/*@=noeffectuncon =compdef =usereleased @*/
+               p->fd = NULL;
+               p->h = headerFree(p->h);
+           }
+/*@=branchstate@*/
+       }
+       pi = rpmtsiFree(pi);
     }
 
     /* ===============================================
-     * If we were requested to rollback this transaction
-     * if an error occurs, then we need to create a 
-     * a rollback transaction.
+     * Initialize transaction element file info for package:
      */
-     if(rollbackOnFailure) {
-       rpmtransFlags xx;
-       rpmVSFlags ovsflags;
-       rpmVSFlags vsflags;
 
-       rpmMessage(RPMMESS_DEBUG, 
-           _("Creating auto-rollback transaction\n"));
+    /*
+     * FIXME?: we'd be better off assembling one very large file list and
+     * calling fpLookupList only once. I'm not sure that the speedup is
+     * worth the trouble though.
+     */
+rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
 
-       rollbackTransaction = rpmtsCreate();
+    numAdded = numRemoved = 0;
+    pi = rpmtsiInit(ts);
+    while ((p = rpmtsiNext(pi, 0)) != NULL) {
+       int fc;
 
-       /* Set the verify signature flags:
-        *      - can't verify digests on repackaged packages.  Other than 
-        *        they are wrong, this will cause segfaults down stream.
-        *      - signatures are out too.
-        *      - header check are out.
-        */     
-       vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
-       vsflags |= _RPMVSF_NODIGESTS;       
-       vsflags |= _RPMVSF_NOSIGNATURES;
-       vsflags |= RPMVSF_NOHDRCHK;
-       vsflags |= RPMVSF_NEEDPAYLOAD;      /* XXX no legacy signatures */
-       ovsflags = rpmtsSetVSFlags(ts, vsflags);
+       if ((fi = rpmtsiFi(pi)) == NULL)
+           continue;   /* XXX can't happen */
+       fc = rpmfiFC(fi);
 
-       /* 
-        *  If we run this thing its imperitive that it be known that it
-        *  is an autorollback transaction.  This will affect the instance
-        *  counts passed to the scriptlets in the psm.
-        */
-       rpmtsSetType(rollbackTransaction, RPMTRANS_TYPE_AUTOROLLBACK);
+       /*@-branchstate@*/
+       switch (rpmteType(p)) {
+       case TR_ADDED:
+           numAdded++;
+           fi->record = 0;
+           /* Skip netshared paths, not our i18n files, and excluded docs */
+           if (fc > 0)
+               skipFiles(ts, fi);
+           /*@switchbreak@*/ break;
+       case TR_REMOVED:
+           numRemoved++;
+           fi->record = rpmteDBOffset(p);
+           /*@switchbreak@*/ break;
+       }
+       /*@=branchstate@*/
 
-       /* Set transaction flags to be the same as the running transaction */
-       xx = rpmtsSetFlags(rollbackTransaction, rpmtsFlags(ts)); 
+       fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
+    }
+    pi = rpmtsiFree(pi);
 
-       /* Set root dir to be the same as the running transaction */
-       rpmtsSetRootDir(rollbackTransaction, rpmtsRootDir(ts));
-    
-       /* Setup the notify of the call back to be the same as the running
-        * transaction 
-        */ 
-       xx = rpmtsSetNotifyCallback(rollbackTransaction, ts->notify, ts->notifyData);
+    if (!rpmtsChrootDone(ts)) {
+       const char * rootDir = rpmtsRootDir(ts);
+       xx = chdir("/");
+       /*@-superuser -noeffect @*/
+       if (rootDir != NULL)
+           xx = chroot(rootDir);
+       /*@=superuser =noeffect @*/
+       (void) rpmtsSetChrootDone(ts, 1);
+    }
 
-       /* Create rpmtsScore for running transaction and rollback transaction */
-       xx = rpmtsScoreInit(ts, rollbackTransaction);
-     }
+    ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
+    fpc = fpCacheCreate(totalFileCount);
 
     /* ===============================================
-     * Save removed files before erasing.
+     * Add fingerprint for each file not skipped.
      */
-    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
-       int progress;
-
-       progress = 0;
-       pi = rpmtsiInit(ts);
-       while ((p = rpmtsiNext(pi, 0)) != NULL) {
-
-           (void) rpmdbCheckSignals();
-
-           if ((fi = rpmtsiFi(pi)) == NULL)
-               continue;       /* XXX can't happen */
-           switch (rpmteType(p)) {
-           case TR_ADDED:
-               /*@switchbreak@*/ break;
-           case TR_REMOVED:
-               if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
-                   /*@switchbreak@*/ break;
-               if (!progress)
-                   NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
-                               7, numRemoved, NULL, ts->notifyData));
-
-               NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
-                       numRemoved, NULL, ts->notifyData));
-               progress++;
-
-               (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
+    pi = rpmtsiInit(ts);
+    while ((p = rpmtsiNext(pi, 0)) != NULL) {
+       int fc;
 
-       /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
-               fi->mapflags |= CPIO_MAP_ABSOLUTE;
-               fi->mapflags |= CPIO_MAP_ADDDOT;
-               fi->mapflags |= CPIO_ALL_HARDLINKS;
-               psm = rpmpsmNew(ts, p, fi);
-               xx = rpmpsmStage(psm, PSM_PKGSAVE);
-               psm = rpmpsmFree(psm);
-               fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
-               fi->mapflags &= ~CPIO_MAP_ADDDOT;
-               fi->mapflags &= ~CPIO_ALL_HARDLINKS;
+       (void) rpmdbCheckSignals();
 
-               (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
+       if ((fi = rpmtsiFi(pi)) == NULL)
+           continue;   /* XXX can't happen */
+       fc = rpmfiFC(fi);
 
-               /*@switchbreak@*/ break;
-           }
-       }
-       pi = rpmtsiFree(pi);
-       if (progress) {
-           NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
-                       NULL, ts->notifyData));
+       (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
+       fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
+       /*@-branchstate@*/
+       fi = rpmfiInit(fi, 0);
+       if (fi != NULL)         /* XXX lclint */
+       while ((i = rpmfiNext(fi)) >= 0) {
+           if (XFA_SKIPPING(fi->actions[i]))
+               /*@innercontinue@*/ continue;
+           /*@-dependenttrans@*/
+           htAddEntry(ts->ht, fi->fps + i, (void *) fi);
+           /*@=dependenttrans@*/
        }
+       /*@=branchstate@*/
+       (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
+
     }
+    pi = rpmtsiFree(pi);
+
+    NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
+       NULL, ts->notifyData));
 
     /* ===============================================
-     * Install and remove packages.
+     * Compute file disposition for each package in transaction set.
      */
-    lastFailKey = (alKey)-2;   /* erased packages have -1 */
+rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
+    ps = rpmtsProblems(ts);
     pi = rpmtsiInit(ts);
-    /*@-branchstate@*/ /* FIX: fi reload needs work */
     while ((p = rpmtsiNext(pi, 0)) != NULL) {
-       alKey pkgKey;
-       int gotfd;
+       dbiIndexSet * matches;
+       int knownBad;
+       int fc;
 
        (void) rpmdbCheckSignals();
 
-       gotfd = 0;
        if ((fi = rpmtsiFi(pi)) == NULL)
            continue;   /* XXX can't happen */
-       
-       psm = rpmpsmNew(ts, p, fi);
-assert(psm != NULL);
-       psm->unorderedSuccessor =
-               (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
+       fc = rpmfiFC(fi);
 
-       switch (rpmteType(p)) {
-       case TR_ADDED:
-           (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
+       NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
+                       ts->orderCount, NULL, ts->notifyData));
 
-           pkgKey = rpmteAddedKey(p);
+       if (fc == 0) continue;
 
-           rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s-%s 0x%x\n",
-               rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
-
-           p->h = NULL;
-           /*@-type@*/ /* FIX: rpmte not opaque */
-           {
-               /*@-noeffectuncon@*/ /* FIX: notify annotations */
-               p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
-                               rpmteKey(p), ts->notifyData);
-               /*@=noeffectuncon@*/
-               if (rpmteFd(p) != NULL) {
-                   rpmVSFlags ovsflags = rpmtsVSFlags(ts);
-                   rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
-                   rpmRC rpmrc;
-
-                   ovsflags = rpmtsSetVSFlags(ts, vsflags);
-                   rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
-                               rpmteNEVR(p), &p->h);
-                   vsflags = rpmtsSetVSFlags(ts, ovsflags);
+       (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
+       /* Extract file info for all files in this package from the database. */
+       matches = xcalloc(fc, sizeof(*matches));
+       if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
+           ps = rpmpsFree(ps);
+           rpmtsFreeLock(lock);
+           return 1;   /* XXX WTFO? */
+       }
 
-                   switch (rpmrc) {
-                   default:
-                       /*@-noeffectuncon@*/ /* FIX: notify annotations */
-                       p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
-                                       0, 0,
-                                       rpmteKey(p), ts->notifyData);
-                       /*@=noeffectuncon@*/
-                       p->fd = NULL;
-                       ourrc++;
+       numShared = 0;
+       fi = rpmfiInit(fi, 0);
+       while ((i = rpmfiNext(fi)) >= 0)
+           numShared += dbiIndexSetCount(matches[i]);
 
-                       /* If we should rollback this transaction 
-                          on failure, lets do it.                 */
-                       if(rollbackOnFailure) {
-                           rpmMessage(RPMMESS_ERROR, 
-                               _("Add failed.  Could not read package header.\n"));
-                           /* Clean up the current transaction */
-                           p->h = headerFree(p->h);
-                           xx = rpmdbSync(rpmtsGetRdb(ts));
-                           psm = rpmpsmFree(psm);
-                           p->fi = rpmfiFree(p->fi);
-                           pi = rpmtsiFree(pi);
+       /* Build sorted file info list for this package. */
+       shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
 
-                           /* Run the rollback transaction */
-                           xx = _rpmtsRollback(rollbackTransaction);
-                           return -1;
-                       }
-                       /*@innerbreak@*/ break;
-                   case RPMRC_NOTTRUSTED:
-                   case RPMRC_NOKEY:
-                   case RPMRC_OK:
+       fi = rpmfiInit(fi, 0);
+       while ((i = rpmfiNext(fi)) >= 0) {
+           /*
+            * Take care not to mark files as replaced in packages that will
+            * have been removed before we will get here.
+            */
+           for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
+               int ro;
+               ro = dbiIndexRecordOffset(matches[i], j);
+               knownBad = 0;
+               qi = rpmtsiInit(ts);
+               while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
+                   if (ro == knownBad)
                        /*@innerbreak@*/ break;
-                   }
-                   if (rpmteFd(p) != NULL) gotfd = 1;
+                   if (rpmteDBOffset(q) == ro)
+                       knownBad = ro;
                }
-           }
-           /*@=type@*/
-
-           if (rpmteFd(p) != NULL) {
-               /*
-                * XXX Sludge necessary to tranfer existing fstates/actions
-                * XXX around a recreated file info set.
-                */
-               psm->fi = rpmfiFree(psm->fi);
-               {
-                   char * fstates = fi->fstates;
-                   fileAction * actions = fi->actions;
-                   rpmte savep;
+               qi = rpmtsiFree(qi);
 
-                   fi->fstates = NULL;
-                   fi->actions = NULL;
-/*@-nullstate@*/ /* FIX: fi->actions is NULL */
-                   fi = rpmfiFree(fi);
-/*@=nullstate@*/
+               shared->pkgFileNum = i;
+               shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
+               shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
+               shared->isRemoved = (knownBad == ro);
+               shared++;
+           }
+           matches[i] = dbiFreeIndexSet(matches[i]);
+       }
+       numShared = shared - sharedList;
+       shared->otherPkg = -1;
+       matches = _free(matches);
 
-                   savep = rpmtsSetRelocateElement(ts, p);
-                   fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
-                   (void) rpmtsSetRelocateElement(ts, savep);
+       /* Sort file info by other package index (otherPkg) */
+       qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
 
-                   if (fi != NULL) {   /* XXX can't happen */
-                       fi->te = p;
-                       fi->fstates = _free(fi->fstates);
-                       fi->fstates = fstates;
-                       fi->actions = _free(fi->actions);
-                       fi->actions = actions;
-                       p->fi = fi;
-                   }
-               }
-               psm->fi = rpmfiLink(p->fi, NULL);
+       /* For all files from this package that are in the database ... */
+       /*@-branchstate@*/
+       for (i = 0; i < numShared; i = nexti) {
+           int beingRemoved;
 
-/*@-nullstate@*/ /* FIX: psm->fi may be NULL */
-               if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
-                   ourrc++;
-                   lastFailKey = pkgKey;
-                   
-                   /* If we should rollback this transaction 
-                      on failure, lets do it.                 */
-                   if(rollbackOnFailure) {
-                       rpmMessage(RPMMESS_ERROR, 
-                           _("Add failed in rpmpsmStage().\n"));
-                       /* Clean up the current transaction */
-                       p->h = headerFree(p->h);
-                       xx = rpmdbSync(rpmtsGetRdb(ts));
-                       psm = rpmpsmFree(psm);
-                       p->fi = rpmfiFree(p->fi);
-                       pi = rpmtsiFree(pi);
+           shared = sharedList + i;
 
-                       /* Run the rollback transaction */
-                       xx = _rpmtsRollback(rollbackTransaction);
-                       return -1;
-                   }
-               }
-               
-               /* If we should rollback on failure lets add
-                * this element to the rollback transaction
-                * as an erase element as it has installed succesfully.
-                */
-               if(rollbackOnFailure) {
-                   int rc;
-                   rc = _rpmtsAddRollbackElement(rollbackTransaction, ts, p);
-                   if(rc != RPMRC_OK) {
-                       /* Clean up the current transaction */
-                       p->h = headerFree(p->h);
-                       xx = rpmdbSync(rpmtsGetRdb(ts));
-                       psm = rpmpsmFree(psm);
-                       p->fi = rpmfiFree(p->fi);
-                       pi = rpmtsiFree(pi);
-                       
-                       /* Clean up rollback transaction */
-                       rpmtsFree(rollbackTransaction);
-                       return -1;
-                   }
-               }
-/*@=nullstate@*/
-           } else {
-               ourrc++;
-               lastFailKey = pkgKey;
-               
-               /* If we should rollback this transaction 
-                * on failure, lets do it.                 
-                */
-               if(rollbackOnFailure) {
-                   rpmMessage(RPMMESS_ERROR, _("Add failed.  Could not get file list.\n"));
-                   /* Clean up the current transaction */
-                   p->h = headerFree(p->h);
-                   xx = rpmdbSync(rpmtsGetRdb(ts));
-                   psm = rpmpsmFree(psm);
-                   p->fi = rpmfiFree(p->fi);
-                   pi = rpmtsiFree(pi);
+           /* Find the end of the files in the other package. */
+           for (nexti = i + 1; nexti < numShared; nexti++) {
+               if (sharedList[nexti].otherPkg != shared->otherPkg)
+                   /*@innerbreak@*/ break;
+           }
 
-                   /* Run the rollback transaction */
-                   xx = _rpmtsRollback(rollbackTransaction);
-                   return -1;
-               }
+           /* Is this file from a package being removed? */
+           beingRemoved = 0;
+           if (ts->removedPackages != NULL)
+           for (j = 0; j < ts->numRemovedPackages; j++) {
+               if (ts->removedPackages[j] != shared->otherPkg)
+                   /*@innercontinue@*/ continue;
+               beingRemoved = 1;
+               /*@innerbreak@*/ break;
            }
 
-           if (gotfd) {
-               /*@-noeffectuncon @*/ /* FIX: check rc */
-               (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
-                       rpmteKey(p), ts->notifyData);
-               /*@=noeffectuncon @*/
-               /*@-type@*/
-               p->fd = NULL;
-               /*@=type@*/
+           /* Determine the fate of each file. */
+           switch (rpmteType(p)) {
+           case TR_ADDED:
+               xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
+       !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
+               /*@switchbreak@*/ break;
+           case TR_REMOVED:
+               if (!beingRemoved)
+                   xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
+               /*@switchbreak@*/ break;
            }
+       }
+       /*@=branchstate@*/
 
-           p->h = headerFree(p->h);
+       free(sharedList);
 
-           (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
+       /* Update disk space needs on each partition for this package. */
+       handleOverlappedFiles(ts, p, fi);
 
+       /* Check added package has sufficient space on each partition used. */
+       switch (rpmteType(p)) {
+       case TR_ADDED:
+           rpmtsCheckDSIProblems(ts, p);
            /*@switchbreak@*/ break;
-
        case TR_REMOVED:
-           (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
+           /*@switchbreak@*/ break;
+       }
+       (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
+    }
+    pi = rpmtsiFree(pi);
+    ps = rpmpsFree(ps);
 
-           rpmMessage(RPMMESS_DEBUG, "========== --- %s %s-%s 0x%x\n",
-               rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
+    if (rpmtsChrootDone(ts)) {
+       const char * currDir = rpmtsCurrDir(ts);
+       /*@-superuser -noeffect @*/
+       xx = chroot(".");
+       /*@=superuser =noeffect @*/
+       (void) rpmtsSetChrootDone(ts, 0);
+       if (currDir != NULL)
+           xx = chdir(currDir);
+    }
 
-           /*
-            * XXX This has always been a hack, now mostly broken.
-            * If install failed, then we shouldn't erase.
-            */
-           if (rpmteDependsOnKey(p) != lastFailKey) {
-               if (rpmpsmStage(psm, PSM_PKGERASE)) {
-                   ourrc++;
-                   
-                   /* If we should rollback this transaction 
-                    * on failure, lets do it.                
-                    */ 
-                   if(rollbackOnFailure) {
-                       rpmMessage(RPMMESS_ERROR, 
-                           _("Erase failed failed in rpmpsmStage().\n"));
-                       /* Clean up the current transaction */
-                       xx = rpmdbSync(rpmtsGetRdb(ts));
-                       psm = rpmpsmFree(psm);
-                       p->fi = rpmfiFree(p->fi);
-                       pi = rpmtsiFree(pi);
+    NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
+       NULL, ts->notifyData));
 
-                       /* Run the rollback transaction */
-                       xx = _rpmtsRollback(rollbackTransaction);
-                       return -1;
-                   }
-               }
+    /* ===============================================
+     * Free unused memory as soon as possible.
+     */
+    pi = rpmtsiInit(ts);
+    while ((p = rpmtsiNext(pi, 0)) != NULL) {
+       if ((fi = rpmtsiFi(pi)) == NULL)
+           continue;   /* XXX can't happen */
+       if (rpmfiFC(fi) == 0)
+           continue;
+       fi->fps = _free(fi->fps);
+    }
+    pi = rpmtsiFree(pi);
 
-               /* If we should rollback on failure lets add
-                * this element to the rollback transaction
-                * as an install element as it has erased succesfully.
-                */
-               if(rollbackOnFailure) {
-                   int rc;
+    fpc = fpCacheFree(fpc);
+    ts->ht = htFree(ts->ht);
 
-                   rc = _rpmtsAddRollbackElement(rollbackTransaction, ts, p);
+    /* ===============================================
+     * If unfiltered problems exist, free memory and return.
+     */
+    if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
+     || (ts->probs->numProblems &&
+               (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))
+       )
+    {
+       rpmtsFreeLock(lock);
+       return ts->orderCount;
+    }
 
-                   if(rc != RPMRC_OK) {
-                       /* Clean up the current transaction */
-                       xx = rpmdbSync(rpmtsGetRdb(ts));
-                       psm = rpmpsmFree(psm);
-                       p->fi = rpmfiFree(p->fi);
-                       pi = rpmtsiFree(pi);
-               
-                       /* Clean up rollback transaction */
-                       rpmtsFree(rollbackTransaction);
-                       return -1;
-                   }
-               }
-           }
+    /* ===============================================
+     * If we were requested to rollback this transaction
+     * if an error occurs, then we need to create a
+     * a rollback transaction.
+     */
+     if (rollbackOnFailure) {
+       rpmtransFlags tsFlags;
+       rpmVSFlags ovsflags;
+       rpmVSFlags vsflags;
 
-           (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
+       rpmMessage(RPMMESS_DEBUG,
+           _("Creating auto-rollback transaction\n"));
 
-           /*@switchbreak@*/ break;
-       }
-       xx = rpmdbSync(rpmtsGetRdb(ts));
+       rollbackTransaction = rpmtsCreate();
 
-/*@-nullstate@*/ /* FIX: psm->fi may be NULL */
-       psm = rpmpsmFree(psm);
-/*@=nullstate@*/
+       /* Set the verify signature flags:
+        *      - can't verify digests on repackaged packages.  Other than
+        *        they are wrong, this will cause segfaults down stream.
+        *      - signatures are out too.
+        *      - header check are out.
+        */     
+       vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
+       vsflags |= _RPMVSF_NODIGESTS;
+       vsflags |= _RPMVSF_NOSIGNATURES;
+       vsflags |= RPMVSF_NOHDRCHK;
+       vsflags |= RPMVSF_NEEDPAYLOAD;      /* XXX no legacy signatures */
+       ovsflags = rpmtsSetVSFlags(ts, vsflags);
 
-/*@-type@*/ /* FIX: p is almost opaque */
-       p->fi = rpmfiFree(p->fi);
-/*@=type@*/
+       /*
+        *  If we run this thing its imperitive that it be known that it
+        *  is an autorollback transaction.  This will affect the instance
+        *  counts passed to the scriptlets in the psm.
+        */
+       rpmtsSetType(rollbackTransaction, RPMTRANS_TYPE_AUTOROLLBACK);
 
-    }
-    /*@=branchstate@*/
-    pi = rpmtsiFree(pi);
+       /* Set transaction flags to be the same as the running transaction */
+       tsFlags = rpmtsSetFlags(rollbackTransaction, rpmtsFlags(ts));
 
-    /* If we created a rollback transaction lets get rid of it */
-    if(rollbackOnFailure && rollbackTransaction != NULL) {
-       rpmtsFree(rollbackTransaction);
-    }
+       /* Set root dir to be the same as the running transaction */
+       rpmtsSetRootDir(rollbackTransaction, rpmtsRootDir(ts));
 
-    rpmMessage(RPMMESS_DEBUG, _("running post-transaction scripts\n"));
-    pi = rpmtsiInit(ts);
-    while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
-       p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
-                       rpmteKey(p), ts->notifyData);
-       p->h = NULL;
-       if (rpmteFd(p) != NULL) {
-           rpmVSFlags ovsflags = rpmtsVSFlags(ts);
-           rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
-           rpmRC rpmrc;
-           ovsflags = rpmtsSetVSFlags(ts, vsflags);
-           rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
-                       rpmteNEVR(p), &p->h);
-           vsflags = rpmtsSetVSFlags(ts, ovsflags);
-           switch (rpmrc) {
-           default:
-               p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
-                               0, 0, rpmteKey(p), ts->notifyData);
-               p->fd = NULL;
-               break;
-           case RPMRC_NOTTRUSTED:
-           case RPMRC_NOKEY:
-           case RPMRC_OK:
-               break;
-           }
-       }
+       /* Setup the notify of the call back to be the same as the running
+        * transaction
+        */
+       xx = rpmtsSetNotifyCallback(rollbackTransaction, ts->notify, ts->notifyData);
 
-       if (rpmteFd(p) != NULL) {
-           fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
-           if (fi != NULL) {   /* XXX can't happen */
-               fi->te = p;
-               p->fi = fi;
-           }
-           psm = rpmpsmNew(ts, p, p->fi);
-           psm->scriptTag = RPMTAG_POSTTRANS;
-           psm->progTag = RPMTAG_POSTTRANSPROG;
-           xx = rpmpsmStage(psm, PSM_SCRIPT);
-           psm = rpmpsmFree(psm);
+       /* Create rpmtsScore for running transaction and rollback transaction */
+       xx = rpmtsScoreInit(ts, rollbackTransaction);
+     }
 
-           (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
-                             rpmteKey(p), ts->notifyData);
-           p->fd = NULL;
-           p->h = headerFree(p->h);
-       }
-    }
-    pi = rpmtsiFree(pi);
+    /* ===============================================
+     * Save removed files before erasing.
+     */
+    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
+       int progress;
 
-    rpmtsFreeLock(lock);
+       progress = 0;
+       pi = rpmtsiInit(ts);
+       while ((p = rpmtsiNext(pi, 0)) != NULL) {
 
-    /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
-    if (ourrc)
-       return -1;
-    else
-       return 0;
-    /*@=nullstate@*/
-}
+           (void) rpmdbCheckSignals();
 
-/**
- * Get the repackaged header and filename from the repackage directory.
- * @todo Find a suitable home for this function.
- * @todo This function creates an IDTX everytime it is called.  Needs to 
- *       be made more efficient (only create on per running transaction).
- * @param te           transaction element
- * @param rpmts                rpm transaction
- * @return hdrp                Repackaged header
- * @return fn          Repackaged package's path (transaction key)
- * @return             RPMRC_NOTFOUND or RPMRC_OK
- */
-rpmRC getRepackageHeaderFromTE(rpmte te, rpmts ts, Header *hdrp, char **fn) 
-{
-    int_32 tid;
-    const char * name; 
-    const char * rpname = NULL;
-    const char * _repackage_dir = NULL;
-    const char * globStr = "-*.rpm";
-    char * rp = NULL;          /* Rollback package name */
-    IDTX rtids = NULL;
-    IDT rpIDT;
-    int nrids = 0;
-    int nb;                    /* Number of bytes */
-    Header h = NULL;
-    int rc   = RPMRC_NOTFOUND; /* Assume we do not find it*/
-  
-    rpmMessage(RPMMESS_DEBUG, 
-       _("Getting repackaged header from transaction element\n"));
+           if ((fi = rpmtsiFi(pi)) == NULL)
+               continue;       /* XXX can't happen */
+           switch (rpmteType(p)) {
+           case TR_ADDED:
+               /*@switchbreak@*/ break;
+           case TR_REMOVED:
+               if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
+                   /*@switchbreak@*/ break;
+               if (!progress)
+                   NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
+                               7, numRemoved, NULL, ts->notifyData));
 
-    /* Set header pointer to null if its not already */
-    if(hdrp)
-       *hdrp = NULL;
-    if(fn)
-       *fn = NULL;
+               NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
+                       numRemoved, NULL, ts->notifyData));
+               progress++;
 
-    /* Get the TID of the current transaction */
-    tid = rpmtsGetTid(ts);
-    /* Need the repackage dir if the user want to
-     * rollback on a failure.
-     */
-    _repackage_dir = rpmExpand("%{?_repackage_dir}", NULL);
-    if(_repackage_dir == NULL) goto exit;
+               (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
 
-    /* Build the glob string to find the possible repackaged 
-     * packages for this package.
-     */
-    name = rpmteN(te); 
-    nb = strlen(_repackage_dir) + strlen(name) + strlen(globStr) + 2;
-    rp = memset((char *) malloc(nb), 0, nb);
-    snprintf(rp, nb, "%s/%s%s.rpm", _repackage_dir, name, globStr);
+       /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
+               fi->mapflags |= CPIO_MAP_ABSOLUTE;
+               fi->mapflags |= CPIO_MAP_ADDDOT;
+               fi->mapflags |= CPIO_ALL_HARDLINKS;
+               psm = rpmpsmNew(ts, p, fi);
+assert(psm != NULL);
+               xx = rpmpsmStage(psm, PSM_PKGSAVE);
+               psm = rpmpsmFree(psm);
+               fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
+               fi->mapflags &= ~CPIO_MAP_ADDDOT;
+               fi->mapflags &= ~CPIO_ALL_HARDLINKS;
 
-    /* Get the index of possible repackaged packages */
-    rpmMessage(RPMMESS_DEBUG, _("\tLooking for %s...\n"), rp);
-    rtids = IDTXglob(ts, rp, RPMTAG_REMOVETID);
-    rp = _free(rp);
-    if (rtids != NULL) {
-       rpmMessage(RPMMESS_DEBUG, _("\tMatches found.\n"));
-       rpIDT = rtids->idt;
-       nrids = rtids->nidt;
-    } else {
-       rpmMessage(RPMMESS_DEBUG, _("\tNo matches found.\n"));
-       goto exit;
-    }
+               (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
 
-    /* Now walk through index until we find the package (or we have
-     * exhausted the index.
-     */
-    do {
-       /* If index is null we have exhausted the list and need to 
-        * get out of here...the repackaged package was not found.
-        */
-       if(rpIDT == NULL) {
-           rpmMessage(RPMMESS_DEBUG, _("\tRepackaged package not found!.\n"));
-           break;
+               /*@switchbreak@*/ break;
+           }
        }
-
-       /* Is this the same tid.  If not decrement the list and continue */
-       if(rpIDT->val.u32 != tid) {
-           nrids--;
-           if(nrids > 0)
-               rpIDT++;
-           else
-               rpIDT = NULL;
-           continue;
+       pi = rpmtsiFree(pi);
+       if (progress) {
+           NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
+                       NULL, ts->notifyData));
        }
+    }
 
-       /* OK, the tid matches.  Now lets see if the name is the same.
-        * If I could not get the name from the package, I will go onto
-        * the next one.  Perhaps I should return an error at this
-        * point, but if this was not the correct one, at least the correct one
-        * would be found.
-        * XXX:  Should I be matching name and arch?
-        */
-       rpmMessage(RPMMESS_DEBUG, _("\tREMOVETID matched INSTALLTID.\n"));
-       if(headerGetEntry(rpIDT->h, RPMTAG_NAME, NULL, (void **) &rpname, NULL)) {
-           rpmMessage(RPMMESS_DEBUG, _("\t\tName:  %s.\n"), rpname);
-           if(!strcmp(name,rpname)) {
-               /* It matched we have a canidate */
-               h  = headerLink(rpIDT->h);
-               nb = strlen(rpIDT->key) + 1;
-               rp = memset((char *) malloc(nb), 0, nb);
-               rp = strncat(rp, rpIDT->key, nb);
-               rc = RPMRC_OK;
-               break;
+    /* ===============================================
+     * Install and remove packages.
+     */
+    lastFailKey = (alKey)-2;   /* erased packages have -1 */
+    pi = rpmtsiInit(ts);
+    /*@-branchstate@*/ /* FIX: fi reload needs work */
+    while ((p = rpmtsiNext(pi, 0)) != NULL) {
+       alKey pkgKey;
+       int gotfd;
+
+       (void) rpmdbCheckSignals();
+
+       gotfd = 0;
+       if ((fi = rpmtsiFi(pi)) == NULL)
+           continue;   /* XXX can't happen */
+       
+       psm = rpmpsmNew(ts, p, fi);
+assert(psm != NULL);
+       psm->unorderedSuccessor =
+               (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
+
+       switch (rpmteType(p)) {
+       case TR_ADDED:
+           (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
+
+           pkgKey = rpmteAddedKey(p);
+
+           rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s-%s 0x%x\n",
+               rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
+
+           p->h = NULL;
+           /*@-type@*/ /* FIX: rpmte not opaque */
+           {
+               /*@-noeffectuncon@*/ /* FIX: notify annotations */
+               p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
+                               rpmteKey(p), ts->notifyData);
+               /*@=noeffectuncon@*/
+               if (rpmteFd(p) != NULL) {
+                   rpmVSFlags ovsflags = rpmtsVSFlags(ts);
+                   rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
+                   rpmRC rpmrc;
+
+                   ovsflags = rpmtsSetVSFlags(ts, vsflags);
+                   rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
+                               rpmteNEVR(p), &p->h);
+                   vsflags = rpmtsSetVSFlags(ts, ovsflags);
+
+                   switch (rpmrc) {
+                   default:
+                       /*@-noeffectuncon@*/ /* FIX: notify annotations */
+                       p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
+                                       0, 0,
+                                       rpmteKey(p), ts->notifyData);
+                       /*@=noeffectuncon@*/
+                       p->fd = NULL;
+                       ourrc++;
+
+                       /* If we should rollback this transaction
+                          on failure, lets do it.                 */
+                       if (rollbackOnFailure) {
+                           rpmMessage(RPMMESS_ERROR,
+                               _("Add failed.  Could not read package header.\n"));
+                           /* Clean up the current transaction */
+                           p->h = headerFree(p->h);
+                           xx = rpmdbSync(rpmtsGetRdb(ts));
+                           psm = rpmpsmFree(psm);
+                           p->fi = rpmfiFree(p->fi);
+                           pi = rpmtsiFree(pi);
+
+                           /* Run the rollback transaction */
+                           xx = _rpmtsRollback(rollbackTransaction);
+                           return -1;
+                       }
+                       /*@innerbreak@*/ break;
+                   case RPMRC_NOTTRUSTED:
+                   case RPMRC_NOKEY:
+                   case RPMRC_OK:
+                       /*@innerbreak@*/ break;
+                   }
+                   if (rpmteFd(p) != NULL) gotfd = 1;
+               }
            }
-       }
+           /*@=type@*/
 
-       /* Decrement list */    
-       nrids--;
-       if(nrids > 0)
-           rpIDT++;
-       else
-           rpIDT = NULL;
-    } while(1);
-exit:
-    if(rc != RPMRC_NOTFOUND && h != NULL && hdrp != NULL) {
-       rpmMessage(RPMMESS_DEBUG, _("\tRepackaged Package was %s...\n"), rp); 
-       *hdrp = headerLink(h);
-       *fn   = rp;
-    }
-    if(h != NULL) {
-       h = headerFree(h);
-    }
-    rtids = IDTXfree(rtids); 
-    return rc; 
-}
+           if (rpmteFd(p) != NULL) {
+               /*
+                * XXX Sludge necessary to tranfer existing fstates/actions
+                * XXX around a recreated file info set.
+                */
+               psm->fi = rpmfiFree(psm->fi);
+               {
+                   char * fstates = fi->fstates;
+                   fileAction * actions = fi->actions;
+                   rpmte savep;
 
-/**
- * This is not a generalized function to be called from outside 
- * librpm.  It is called internally by rpmtsRun() to add elements
- * to its rollback transaction.
- * @param rollbackTransaction          rollback transaction
- * @param runningTransaction           running transaction (the one you want to rollback)
- * @param te                           Transaction element.
- * @return                             RPMRC_OK, or RPMRC_FAIL
- */
-rpmRC _rpmtsAddRollbackElement(rpmts rollbackTransaction, rpmts runningTransaction, rpmte te)
-{
-    Header h   = NULL;
-    Header rph = NULL;
-    char * rpn;        
-    unsigned int db_instance = 0;
-    rpmtsi pi;         
-    rpmte p;
-    int rc  = RPMRC_FAIL;      /* Assume Failure */
-    switch(rpmteType(te)) {
-    case TR_ADDED:
-       rpmMessage(RPMMESS_DEBUG, 
-           _("Adding install element to auto-rollback transaction.\n"));
-    
-       /* Get the header for this package from the database 
-        * First get the database instance (the key).
-        */
-       db_instance = rpmteDBInstance(te);
-       if(db_instance <= 0) {
-           /* Could not get the db instance: WTD! */
-           rpmMessage(RPMMESS_FATALERROR, 
-               _("Could not get install element database instance!\n"));
-           break;
-       }
+                   fi->fstates = NULL;
+                   fi->actions = NULL;
+/*@-nullstate@*/ /* FIX: fi->actions is NULL */
+                   fi = rpmfiFree(fi);
+/*@=nullstate@*/
 
-       /* Now suck the header out of the database */
-       rpmdbMatchIterator mi = rpmtsInitIterator(rollbackTransaction, 
-           RPMDBI_PACKAGES, &db_instance, sizeof(db_instance));
-       h = rpmdbNextIterator(mi);
-       if(h != NULL) h = headerLink(h); 
-       mi = rpmdbFreeIterator(mi);
-       if(h == NULL) {
-           /* Header was not there??? */
-           rpmMessage(RPMMESS_FATALERROR, 
-               _("Could not get header for auto-rollback transaction!\n"));
-           break;
-       }
-                  
-       /* Now see if there is a repackaged package for this */
-       rc = getRepackageHeaderFromTE(te, runningTransaction, &rph, &rpn);
-       switch(rc) {
-       case RPMRC_OK:
-           /* Add the install element, as we had a repackaged package */
-           rpmMessage(RPMMESS_DEBUG, 
-               _("\tAdded repackaged package header: %s.\n"), rpn);
-           rc = rpmtsAddInstallElement(rollbackTransaction, headerLink(rph), 
-               (fnpyKey) rpn, 1, te->relocs);
-           break;
+                   savep = rpmtsSetRelocateElement(ts, p);
+                   fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
+                   (void) rpmtsSetRelocateElement(ts, savep);
 
-       case RPMRC_NOTFOUND:
-           /* Add the header as an erase element, we did not
-            * have a repackaged package
-            */
-           rpmMessage(RPMMESS_DEBUG, _("\tAdded erase element.\n"));
-           rc = rpmtsAddEraseElement(rollbackTransaction, h, db_instance);    
-           break;
+                   if (fi != NULL) {   /* XXX can't happen */
+                       fi->te = p;
+                       fi->fstates = _free(fi->fstates);
+                       fi->fstates = fstates;
+                       fi->actions = _free(fi->actions);
+                       fi->actions = actions;
+                       p->fi = fi;
+                   }
+               }
+               psm->fi = rpmfiLink(p->fi, NULL);
+
+/*@-nullstate@*/ /* FIX: psm->fi may be NULL */
+               if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
+                   ourrc++;
+                   lastFailKey = pkgKey;
+
+                   /* If we should rollback this transaction
+                      on failure, lets do it.                 */
+                   if (rollbackOnFailure) {
+                       rpmMessage(RPMMESS_ERROR,
+                           _("Add failed in rpmpsmStage().\n"));
+                       /* Clean up the current transaction */
+                       p->h = headerFree(p->h);
+                       xx = rpmdbSync(rpmtsGetRdb(ts));
+                       psm = rpmpsmFree(psm);
+                       p->fi = rpmfiFree(p->fi);
+                       pi = rpmtsiFree(pi);
+
+                       /* Run the rollback transaction */
+                       xx = _rpmtsRollback(rollbackTransaction);
+                       return -1;
+                   }
+               }
+               
+               /* If we should rollback on failure lets add
+                * this element to the rollback transaction
+                * as an erase element as it has installed succesfully.
+                */
+               if (rollbackOnFailure) {
+                   int rc;
+
+                   rc = _rpmtsAddRollbackElement(rollbackTransaction, ts, p);
+                   if (rc != RPMRC_OK) {
+                       /* Clean up the current transaction */
+                       p->h = headerFree(p->h);
+                       xx = rpmdbSync(rpmtsGetRdb(ts));
+                       psm = rpmpsmFree(psm);
+                       p->fi = rpmfiFree(p->fi);
+                       pi = rpmtsiFree(pi);
                        
-       default:
-           /* Not sure what to do on failure...just give up */ 
-           rpmMessage(RPMMESS_FATALERROR, 
-               _("Could not get repackaged header for auto-rollback transaction!\n"));
-           break;
-       }
-       break;
+                       /* Clean up rollback transaction */
+                       rollbackTransaction = rpmtsFree(rollbackTransaction);
+                       return -1;
+                   }
+               }
+/*@=nullstate@*/
+           } else {
+               ourrc++;
+               lastFailKey = pkgKey;
+               
+               /* If we should rollback this transaction
+                * on failure, lets do it.
+                */
+               if (rollbackOnFailure) {
+                   rpmMessage(RPMMESS_ERROR, _("Add failed.  Could not get file list.\n"));
+                   /* Clean up the current transaction */
+                   p->h = headerFree(p->h);
+                   xx = rpmdbSync(rpmtsGetRdb(ts));
+                   psm = rpmpsmFree(psm);
+                   p->fi = rpmfiFree(p->fi);
+                   pi = rpmtsiFree(pi);
 
-   case TR_REMOVED:
-       rpmMessage(RPMMESS_DEBUG, 
-           _("Add erase element to auto-rollback transaction.\n"));
+                   /* Run the rollback transaction */
+                   xx = _rpmtsRollback(rollbackTransaction);
+                   return -1;
+               }
+           }
 
-       /* See if this element has already been added as an upgrade.
-        * If so we want to do nothing.
-        */
-       pi = rpmtsiInit(rollbackTransaction);
-       while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
-           if(rpmteType(p) == TR_ADDED) continue;
-           if(!strcmp(rpmteN(p), rpmteN(te))) {
-               rpmMessage(RPMMESS_DEBUG, _("\tFound existing upgrade element.\n"));
-               rpmMessage(RPMMESS_DEBUG, _("\tNot adding erase element for %s.\n"),
-                       rpmteN(te));
-               rc = RPMRC_OK;  
-               pi = rpmtsiFree(pi);
-               break;
+           if (gotfd) {
+               /*@-noeffectuncon @*/ /* FIX: check rc */
+               (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
+                       rpmteKey(p), ts->notifyData);
+               /*@=noeffectuncon @*/
+               /*@-type@*/
+               p->fd = NULL;
+               /*@=type@*/
            }
-       }
-       pi = rpmtsiFree(pi);
 
+           p->h = headerFree(p->h);
 
-       /* Get the repackage header from the current transaction
-       * element.
-       */
-       rc = getRepackageHeaderFromTE(te, runningTransaction, &rph, &rpn); 
-       switch(rc) {
-       case RPMRC_OK:
-           /* Add the install element */
-           rpmMessage(RPMMESS_DEBUG, 
-               _("\tAdded repackaged package %s.\n"), rpn);
-           rc = rpmtsAddInstallElement(rollbackTransaction, rph, 
-               (fnpyKey) rpn, 1, te->relocs);    
-           if(rc != RPMRC_OK) 
-               rpmMessage(RPMMESS_FATALERROR, 
-                   _("Could not add erase element to auto-rollback transaction.\n"));
-           break;
+           (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
 
-       case RPMRC_NOTFOUND:
-           /* Just did not have a repackaged package */
-           rpmMessage(RPMMESS_DEBUG, 
-               _("\tNo repackaged package...nothing to do.\n"));
-           rc = RPMRC_OK;
-           break;
+           /*@switchbreak@*/ break;
 
-       default:
-           rpmMessage(RPMMESS_FATALERROR, 
-               _("Failure reading repackaged package!\n"));
-           break;
-       }
-       break;
+       case TR_REMOVED:
+           (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
 
-    default:
-       break;
-    }
+           rpmMessage(RPMMESS_DEBUG, "========== --- %s %s-%s 0x%x\n",
+               rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
 
-/* XXX:  I want to free this, but if I do then the consumers of
- *       are hosed.  Just leaving you a little note Jeff, so you
- *       know that this does introduce a memory leak.  I wanted
- *       keep the patch as simple as possible so I am not fixxing
- *       the leak.
- *   if(rpn != NULL) 
- *     free(rpn); 
- */
+           /*
+            * XXX This has always been a hack, now mostly broken.
+            * If install failed, then we shouldn't erase.
+            */
+           if (rpmteDependsOnKey(p) != lastFailKey) {
+               if (rpmpsmStage(psm, PSM_PKGERASE)) {
+                   ourrc++;
 
-    /* Clean up */
-    if(h != NULL)   
-       h = headerFree(h);
-    if(rph != NULL) 
-       rph = headerFree(rph);
-    return rc;
-}
+                   /* If we should rollback this transaction
+                    * on failure, lets do it.
+                    */
+                   if (rollbackOnFailure) {
+                       rpmMessage(RPMMESS_ERROR,
+                           _("Erase failed failed in rpmpsmStage().\n"));
+                       /* Clean up the current transaction */
+                       xx = rpmdbSync(rpmtsGetRdb(ts));
+                       psm = rpmpsmFree(psm);
+                       p->fi = rpmfiFree(p->fi);
+                       pi = rpmtsiFree(pi);
 
-/**
- * This is not a generalized function to be called from outside 
- * librpm.  It is called internally by rpmtsRun() to rollback
- * a failed transaction.
- * @param rollbackTransaction          rollback transaction
- * @return                             RPMRC_OK, or RPMRC_FAIL
- */
-rpmRC _rpmtsRollback(rpmts rollbackTransaction)
-{
-    int    rc         = 0;
-    int    numAdded   = 0;
-    int    numRemoved = 0;
-    int_32 tid;
-    rpmtsi tsi;
-    rpmte  te;
-    rpmps  ps;
+                       /* Run the rollback transaction */
+                       xx = _rpmtsRollback(rollbackTransaction);
+                       return -1;
+                   }
+               }
 
-    /* 
-     * Gather information about this rollback transaction for reporting.
-     *    1) Get tid
-     */
-    tid = rpmtsGetTid(rollbackTransaction);
-    /*    
-     *    2) Get number of install elments and erase elements 
-     */
-    tsi = rpmtsiInit(rollbackTransaction);
-    while((te = rpmtsiNext(tsi, 0)) != NULL) {
-       switch (rpmteType(te)) {
-       case TR_ADDED:
-          numAdded++;
-          break;
-       case TR_REMOVED:
-          numRemoved++;
-          break;
-       default:
-          break;
-       }       
-    }
-    tsi = rpmtsiFree(tsi);
+               /* If we should rollback on failure lets add
+                * this element to the rollback transaction
+                * as an install element as it has erased succesfully.
+                */
+               if (rollbackOnFailure) {
+                   int rc;
 
-    rpmMessage(RPMMESS_NORMAL, _("Transaction failed...rolling back\n"));
-    rpmMessage(RPMMESS_NORMAL, 
-       _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
-                        numAdded, numRemoved, ctime(&tid), tid);
+                   rc = _rpmtsAddRollbackElement(rollbackTransaction, ts, p);
 
-    /* Check the transaction to see if it is doable */
-    rc = rpmtsCheck(rollbackTransaction);
-    ps = rpmtsProblems(rollbackTransaction);
-    if (rc != 0 && rpmpsNumProblems(ps) > 0) {
-       rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
-       rpmpsPrint(NULL, ps);
-       ps = rpmpsFree(ps);
-       return -1;
-    }
-    ps = rpmpsFree(ps);
+                   if (rc != RPMRC_OK) {
+                       /* Clean up the current transaction */
+                       xx = rpmdbSync(rpmtsGetRdb(ts));
+                       psm = rpmpsmFree(psm);
+                       p->fi = rpmfiFree(p->fi);
+                       pi = rpmtsiFree(pi);
+               
+                       /* Clean up rollback transaction */
+                       rollbackTransaction = rpmtsFree(rollbackTransaction);
+                       return -1;
+                   }
+               }
+           }
+
+           (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
+
+           /*@switchbreak@*/ break;
+       }
+       xx = rpmdbSync(rpmtsGetRdb(ts));
+
+/*@-nullstate@*/ /* FIX: psm->fi may be NULL */
+       psm = rpmpsmFree(psm);
+/*@=nullstate@*/
+
+/*@-type@*/ /* FIX: p is almost opaque */
+       p->fi = rpmfiFree(p->fi);
+/*@=type@*/
 
-    /* Order the transaction */
-    rc = rpmtsOrder(rollbackTransaction);
-    if (rc != 0) {
-       rpmMessage(RPMMESS_ERROR, 
-           _("Could not order auto-rollback transaction!\n"));
-       return -1;
     }
+    /*@=branchstate@*/
+    pi = rpmtsiFree(pi);
 
-                  
+    /* If we created a rollback transaction lets get rid of it */
+    if (rollbackOnFailure && rollbackTransaction != NULL)
+       rollbackTransaction = rpmtsFree(rollbackTransaction);
 
-    /* Run the transaction and print any problems 
-     * We want to stay with the original transactions flags except
-     * that we want to add what is essentially a force.
-     * This handles two things in particular:
-     * 
-     * 1.  We we want to upgrade over a newer package.
-     *         2.  If a header for the old package is there we
-     *      we want to replace it.  No questions asked.
-     */
-    rc = rpmtsRun(rollbackTransaction, NULL, 
-         RPMPROB_FILTER_REPLACEPKG
-       | RPMPROB_FILTER_REPLACEOLDFILES
-       | RPMPROB_FILTER_REPLACENEWFILES
-       | RPMPROB_FILTER_OLDPACKAGE 
-    );
-    ps = rpmtsProblems(rollbackTransaction);
-    if (rc > 0 && rpmpsNumProblems(ps) > 0)
-       rpmpsPrint(stderr, ps);
-    ps = rpmpsFree(ps);
-    rollbackTransaction = rpmtsFree(rollbackTransaction);
+    rpmMessage(RPMMESS_DEBUG, _("running post-transaction scripts\n"));
+    pi = rpmtsiInit(ts);
+    while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
+       p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
+                       rpmteKey(p), ts->notifyData);
+       p->h = NULL;
+       if (rpmteFd(p) != NULL) {
+           rpmVSFlags ovsflags = rpmtsVSFlags(ts);
+           rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
+           rpmRC rpmrc;
+           ovsflags = rpmtsSetVSFlags(ts, vsflags);
+           rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
+                       rpmteNEVR(p), &p->h);
+           vsflags = rpmtsSetVSFlags(ts, ovsflags);
+           switch (rpmrc) {
+           default:
+               p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
+                               0, 0, rpmteKey(p), ts->notifyData);
+               p->fd = NULL;
+               /*@switchbreak@*/ break;
+           case RPMRC_NOTTRUSTED:
+           case RPMRC_NOKEY:
+           case RPMRC_OK:
+               /*@switchbreak@*/ break;
+           }
+       }
 
-    return rc;
+       if (rpmteFd(p) != NULL) {
+           fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
+           if (fi != NULL) {   /* XXX can't happen */
+               fi->te = p;
+               p->fi = fi;
+           }
+/*@-compdef -usereleased@*/    /* p->fi->te undefined */
+           psm = rpmpsmNew(ts, p, p->fi);
+/*@=compdef =usereleased@*/
+assert(psm != NULL);
+           psm->scriptTag = RPMTAG_POSTTRANS;
+           psm->progTag = RPMTAG_POSTTRANSPROG;
+           xx = rpmpsmStage(psm, PSM_SCRIPT);
+           psm = rpmpsmFree(psm);
+
+/*@-noeffectuncon -compdef -usereleased @*/
+           (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
+                             rpmteKey(p), ts->notifyData);
+/*@=noeffectuncon =compdef =usereleased @*/
+           p->fd = NULL;
+           p->h = headerFree(p->h);
+       }
+    }
+    pi = rpmtsiFree(pi);
+
+    rpmtsFreeLock(lock);
+
+    /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
+    if (ourrc)
+       return -1;
+    else
+       return 0;
+    /*@=nullstate@*/
 }
index 4e77586..d261178 100755 (executable)
@@ -13,6 +13,13 @@ print cmp(ds2,ds2)
 print ds1 == ds2
 print ds2 == ds1
 print ds2 == ds2
+
 print ds1 != ds2
 print ds2 != ds1
 print ds2 != ds2
+
+print ds1 > ds2
+print ds2 < ds1
+print ds1 >= ds2
+print ds2 <= ds1
+
index a01bcd2..2e467bd 100644 (file)
@@ -2866,7 +2866,9 @@ DBT * data = alloca(sizeof(*data));
      * we won't have bogus information (i.e. the last succesful
      * add).
      */
+/*@-mods@*/
     myinstall_instance = 0;
+/*@=mods@*/
 
     if (db == NULL)
        return 0;
@@ -2976,13 +2978,13 @@ memset(data, 0, sizeof(*data));
 
     if (hdrNum)
     {  
-       /* Need to save the header number for the current 
-        * transaction.
-        */
-       myinstall_instance = hdrNum;
-       
        dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
 
+       /* Save the header number for the current transaction. */
+/*@-mods@*/
+       myinstall_instance = hdrNum;
+/*@=mods@*/
+       
        if (dbiTags != NULL)
        for (dbix = 0; dbix < dbiTagsMax; dbix++) {
            const char *av[1];
@@ -3018,7 +3020,9 @@ memset(data, 0, sizeof(*data));
 mi_offset.ui = hdrNum;
 if (dbiByteSwapped(dbi) == 1)
     _DBSWAP(mi_offset);
+/*@-immediatetrans@*/
 key->data = (void *) &mi_offset;
+/*@=immediatetrans@*/
 key->size = sizeof(mi_offset.ui);
 data->data = headerUnload(h);
 data->size = headerSizeof(h, HEADER_MAGIC_NO);
index 13172b1..562870c 100644 (file)
@@ -1516,7 +1516,7 @@ expandMacro(MacroBuf mb)
 #define POPT_ARGV_ARRAY_GROW_DELTA 5
 
 /*@-boundswrite@*/
-static int poptDupArgv(int argc, const char **argv,
+static int XpoptDupArgv(int argc, const char **argv,
                int * argcPtr, const char *** argvPtr)
        /*@modifies *argcPtr, *argvPtr @*/
 {
@@ -1560,7 +1560,7 @@ static int poptDupArgv(int argc, const char **argv,
 /*@=boundswrite@*/
 
 /*@-bounds@*/
-static int poptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
+static int XpoptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
        /*@modifies *argcPtr, *argvPtr @*/
 {
     const char * src;
@@ -1620,7 +1620,7 @@ static int poptParseArgvString(const char * s, int * argcPtr, const char *** arg
        argc++, buf++;
     }
 
-    rc = poptDupArgv(argc, argv, argcPtr, argvPtr);
+    rc = XpoptDupArgv(argc, argv, argcPtr, argvPtr);
 
 exit:
     if (argv) free(argv);
@@ -1642,7 +1642,7 @@ int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
     int i, j;
     int rc;
 
-    rc = poptParseArgvString(patterns, &ac, &av);
+    rc = XpoptParseArgvString(patterns, &ac, &av);
     if (rc)
        return rc;
 
index 0fce710..e77b418 100644 (file)
@@ -69,7 +69,9 @@ rpmlua rpmluaNew()
 
     lua->L = L;
     for (; lib->name; lib++) {
+/*@-noeffectuncon@*/
        (void) lib->func(L);
+/*@=noeffectuncon@*/
        lua_settop(L, 0);
     }
     lua_pushliteral(L, "LUA_PATH");
index bdff3e1..7f6f376 100644 (file)
@@ -42,10 +42,12 @@ struct rpmluav_s {
 typedef /*@abstract@*/ struct rpmlua_s * rpmlua;
 typedef /*@abstract@*/ struct rpmluav_s * rpmluav;
 
+/*@-exportlocal@*/
 /*@only@*/
 rpmlua rpmluaNew(void)
        /*@globals fileSystem @*/
        /*@modifies fileSystem @*/;
+/*@=exportlocal@*/
 void *rpmluaFree(/*@only@*/ rpmlua lua)
        /*@modifies lua @*/;
 
@@ -105,7 +107,7 @@ void rpmluaPop(/*@null@*/ rpmlua lua)
 /*@only@*/
 rpmluav rpmluavNew(void)
        /*@*/;
-void *rpmluavFree(/*@only@*/ rpmluav var)
+void * rpmluavFree(/*@only@*/ rpmluav var)
        /*@modifes var @*/;
 void rpmluavSetListMode(rpmluav var, int flag)
        /*@modifies var @*/;