This is needed to allow changing autoinstalled header tag without actually 
reinstalling package from file.
This may be useful in case you need to modify autoinstalled flag of package 
which is updated in repository or removed from it
without actually updating or otherwise changing package.

Signed-off-by: Aleksei Nikiforov <darktemp...@altlinux.org>
---
 lib/depends.c        | 26 ++++++++++++++++++++------
 lib/order.c          | 23 ++++++++++++++++++++---
 lib/psm.c            | 40 +++++++++++++++++++++++++++-------------
 lib/rpmte.c          | 11 +++++++++++
 lib/rpmte.h          |  1 +
 lib/rpmte_internal.h |  3 ++-
 lib/rpmts.c          |  1 +
 lib/rpmts.h          | 15 ++++++++++++++-
 lib/transaction.c    | 18 ++++++++++++++++++
 plugins/syslog.c     | 18 +++++++++++++++++-
 python/rpmmodule.c   |  1 +
 11 files changed, 132 insertions(+), 25 deletions(-)

diff --git a/lib/depends.c b/lib/depends.c
index 9f4db8f..2f95657 100644
--- a/lib/depends.c
+++ b/lib/depends.c
@@ -70,6 +70,7 @@ enum addOp_e {
     RPMTE_INSTALL      = 0,
     RPMTE_UPGRADE      = 1,
     RPMTE_REINSTALL    = 2,
+    RPMTE_CHANGE       = 3,
 };
 
 /**
@@ -422,13 +423,13 @@ static int addPackage(rpmts ts, Header h,
     int oc = tsmem->orderCount;
 
     /* Check for supported payload format if it's a package */
-    if (key && headerCheckPayloadFormat(h) != RPMRC_OK) {
+    if ((op != RPMTE_CHANGE) && key && headerCheckPayloadFormat(h) != 
RPMRC_OK) {
        ec = 1;
        goto exit;
     }
 
     /* Source packages are never "upgraded" */
-    if (isSource)
+    if ((op != RPMTE_CHANGE) && isSource)
        op = RPMTE_INSTALL;
 
     /* Do lazy (readonly?) open of rpm database for upgrades. */
@@ -437,14 +438,14 @@ static int addPackage(rpmts ts, Header h,
            goto exit;
     }
 
-    p = rpmteNew(ts, h, TR_ADDED, key, relocs);
+    p = rpmteNew(ts, h, (op != RPMTE_CHANGE) ? TR_ADDED : TR_CHANGED, key, 
relocs);
     if (p == NULL) {
        ec = 1;
        goto exit;
     }
 
     /* Check binary packages for redundancies in the set */
-    if (!isSource) {
+    if ((op == RPMTE_CHANGE) || (!isSource)) {
        oc = findPos(ts, tscolor, p, (op == RPMTE_UPGRADE));
        /* If we're replacing a previously added element, free the old one */
        if (oc >= 0 && oc < tsmem->orderCount) {
@@ -477,8 +478,11 @@ static int addPackage(rpmts ts, Header h,
 
     /* Add erasure elements for old versions and obsoletions on upgrades */
     /* XXX TODO: If either of these fails, we'd need to undo all additions */
-    if (op != RPMTE_INSTALL)
-       addSelfErasures(ts, tscolor, op, p, rpmteColor(p), h);
+    if ((op != RPMTE_INSTALL) && (op != RPMTE_CHANGE))
+    {
+        addSelfErasures(ts, tscolor, op, p, rpmteColor(p), h);
+    }
+
     if (op == RPMTE_UPGRADE)
        addObsoleteErasures(ts, tscolor, p);
 
@@ -504,6 +508,16 @@ int rpmtsAddReinstallElement(rpmts ts, Header h, fnpyKey 
key)
     return addPackage(ts, h, key, RPMTE_REINSTALL, NULL);
 }
 
+int rpmtsAddChangeElement(rpmts ts, Header h)
+{
+    if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
+    {
+        return 1;
+    }
+
+    return addPackage(ts, h, NULL, RPMTE_CHANGE, NULL);
+}
+
 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
 {
     if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
diff --git a/lib/order.c b/lib/order.c
index 7a1dd10..4610794 100644
--- a/lib/order.c
+++ b/lib/order.c
@@ -633,9 +633,26 @@ int rpmtsOrder(rpmts ts)
 
     rpmlog(RPMLOG_DEBUG, "========== tsorting packages (order, #predecessors, 
#succesors, depth)\n");
 
-    for (int i = 0; i < 2; i++) {
-       /* Do two separate runs: installs first - then erases */
-       int oType = !i ? TR_ADDED : TR_REMOVED;
+    for (int i = 0; i < 3; i++) {
+       /* Do three separate runs: installs first - then erases, and changes 
after that */
+       int oType;
+
+       switch (i)
+       {
+       case 0:
+               oType = TR_ADDED;
+               break;
+       case 1:
+               oType = TR_REMOVED;
+               break;
+       case 2:
+               oType = TR_CHANGED;
+               break;
+       default:
+               return -1;
+               break;
+       }
+
        q = r = NULL;
        /* Scan for zeroes and add them to the queue */
        for (int e = 0; e < nelem; e++) {
diff --git a/lib/psm.c b/lib/psm.c
index f3a7ce4..c2d6be2 100644
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -531,7 +531,7 @@ static void markReplacedInstance(rpmts ts, rpmte te)
     rpmdbFreeIterator(mi);
 }
 
-static rpmRC dbAdd(rpmts ts, rpmte te)
+static rpmRC dbAdd(rpmts ts, rpmte te, unsigned int oldDBInstance)
 {
     Header h = rpmteHeader(te);
     rpm_time_t installTime = (rpm_time_t) time(NULL);
@@ -542,13 +542,21 @@ static rpmRC dbAdd(rpmts ts, rpmte te)
     rpm_tid_t tid = rpmtsGetTid(ts);
     rpmRC rc;
 
-    if (fileStates != NULL && fc > 0) {
-       headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc);
-    }
+       /*
+        * if oldDBInstance is not zero, then it's a header that already was in 
DB,
+        * and thus it already contains following headers, and they must not be 
added again.
+        */
+       if (oldDBInstance == 0)
+       {
+               if (fileStates != NULL && fc > 0)
+               {
+                       headerPutChar(h, RPMTAG_FILESTATES, fileStates, fc);
+               }
 
-    headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
-    headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1);
-    headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1);
+               headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
+               headerPutUint32(h, RPMTAG_INSTALLTIME, &installTime, 1);
+               headerPutUint32(h, RPMTAG_INSTALLCOLOR, &tscolor, 1);
+       }
 
     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_DBADD), 0);
     rc = (rpmdbAdd(rpmtsGetRdb(ts), h) == 0) ? RPMRC_OK : RPMRC_FAIL;
@@ -643,12 +651,13 @@ static rpmRC rpmpsmRemove(rpmpsm psm)
     return (fsmrc == 0) ? RPMRC_OK : RPMRC_FAIL;
 }
 
-static rpmRC rpmPackageInstall(rpmts ts, rpmpsm psm)
+static rpmRC rpmPackageInstall(rpmts ts, rpmpsm psm, unsigned int change)
 {
     rpmRC rc = RPMRC_OK;
     int once = 1;
+    unsigned int oldDBInstance = 0; /* if this value is not zero, then this 
header is already present in DB and should be processed a bit differently: some 
header tags should not be modified */
 
-    rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_INSTALL), 0);
+    rpmswEnter(rpmtsOp(psm->ts, (!change) ? RPMTS_OP_INSTALL : 
RPMTS_OP_CHANGE), 0);
     while (once--) {
        /* HACK: replacepkgs abuses te instance to remove old header */
        if (rpmtsFilterFlags(psm->ts) & RPMPROB_FILTER_REPLACEPKG)
@@ -677,12 +686,13 @@ static rpmRC rpmPackageInstall(rpmts ts, rpmpsm psm)
         * If this package has already been installed, remove it from
         * the database before adding the new one.
         */
-       if (rpmteDBInstance(psm->te)) {
+       oldDBInstance = rpmteDBInstance(psm->te);
+       if (oldDBInstance != 0) {
            rc = dbRemove(ts, psm->te);
            if (rc) break;
        }
 
-       rc = dbAdd(ts, psm->te);
+       rc = dbAdd(ts, psm->te, change ? oldDBInstance : 0);
        if (rc) break;
 
        if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERIN)) {
@@ -727,7 +737,7 @@ static rpmRC rpmPackageInstall(rpmts ts, rpmpsm psm)
        rc = markReplacedFiles(psm);
     }
 
-    rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_INSTALL), 0);
+    rpmswExit(rpmtsOp(psm->ts, (!change) ? RPMTS_OP_INSTALL : 
RPMTS_OP_CHANGE), 0);
 
     return rc;
 }
@@ -820,6 +830,7 @@ static const char * pkgGoalString(pkgGoal goal)
     switch (goal) {
     case PKG_INSTALL:  return "  install";
     case PKG_ERASE:    return "    erase";
+    case PKG_CHANGE:   return "   change";
     case PKG_VERIFY:   return "   verify";
     case PKG_PRETRANS: return " pretrans";
     case PKG_POSTTRANS:        return "posttrans";
@@ -844,8 +855,11 @@ rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal)
        if (!rc) {
            switch (goal) {
            case PKG_INSTALL:
-               rc = rpmPackageInstall(ts, psm);
+               rc = rpmPackageInstall(ts, psm, 0);
                break;
+               case PKG_CHANGE:
+                       rc = rpmPackageInstall(ts, psm, 1);
+                       break;
            case PKG_ERASE:
                rc = rpmPackageErase(ts, psm);
                break;
diff --git a/lib/rpmte.c b/lib/rpmte.c
index 238c8b6..906756f 100644
--- a/lib/rpmte.c
+++ b/lib/rpmte.c
@@ -556,6 +556,7 @@ static int rpmteOpen(rpmte te, int reload_fi)
 {
     int rc = 0; /* assume failure */
     Header h = NULL;
+    Header tmp_h = NULL;
     if (te == NULL || te->ts == NULL || rpmteFailed(te))
        goto exit;
 
@@ -565,6 +566,11 @@ static int rpmteOpen(rpmte te, int reload_fi)
     case TR_ADDED:
        h = rpmteDBInstance(te) ? rpmteDBHeader(te) : rpmteFDHeader(te);
        break;
+       case TR_CHANGED:
+               tmp_h = rpmteDBHeader(te);
+               h = headerCopy(tmp_h);
+               headerFree(tmp_h);
+               break;
     case TR_REMOVED:
     case TR_RPMDB:
        h = rpmteDBHeader(te);
@@ -581,6 +587,8 @@ static int rpmteOpen(rpmte te, int reload_fi)
        
        if (rc)
        {
+               /* remove previos copy of flags if there was any and insert new 
value */
+               headerDel(h, RPMTAG_AUTOINSTALLED);
                rc = (headerPutUint32(h, RPMTAG_AUTOINSTALLED, 
&(te->autoinstalled), 1) == 1);
        }
 
@@ -604,6 +612,8 @@ static int rpmteClose(rpmte te, int reset_fi)
            te->fd = NULL;
        }
        break;
+       case TR_CHANGED:
+       break;
     case TR_REMOVED:
     case TR_RPMDB:
        /* eventually we'll want notifications for erase open too */
@@ -740,6 +750,7 @@ const char * rpmteTypeString(rpmte te)
     case TR_ADDED:     return _("install");
     case TR_REMOVED:   return _("erase");
     case TR_RPMDB:     return _("rpmdb");
+    case TR_CHANGED:   return _("change");
     default:           return "???";
     }
 }
diff --git a/lib/rpmte.h b/lib/rpmte.h
index 5b8d6dd..6160fdd 100644
--- a/lib/rpmte.h
+++ b/lib/rpmte.h
@@ -20,6 +20,7 @@ typedef enum rpmElementType_e {
     TR_ADDED           = (1 << 0),     /*!< Package will be installed. */
     TR_REMOVED         = (1 << 1),     /*!< Package will be removed. */
     TR_RPMDB           = (1 << 2),     /*!< Package from the rpmdb. */
+    TR_CHANGED         = (1 << 3),     /*!< Package will be changed. */
 } rpmElementType;
 
 typedef rpmFlags rpmElementTypes;
diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h
index e76b932..05ae370 100644
--- a/lib/rpmte_internal.h
+++ b/lib/rpmte_internal.h
@@ -10,6 +10,7 @@ typedef enum pkgGoal_e {
     /* permit using rpmteType() for install + erase goals */
     PKG_INSTALL                = TR_ADDED,
     PKG_ERASE          = TR_REMOVED,
+    PKG_CHANGE         = TR_CHANGED,
     /* permit using scriptname for these for now... */
     PKG_VERIFY         = RPMTAG_VERIFYSCRIPT,
     PKG_PRETRANS       = RPMTAG_PRETRANS,
@@ -31,7 +32,7 @@ extern "C" {
  * Create a transaction element.
  * @param ts           transaction set
  * @param h            header
- * @param type         TR_ADDED/TR_REMOVED/TR_RPMDB
+ * @param type         TR_ADDED/TR_REMOVED/TR_RPMDB/TR_CHANGED
  * @param key          (TR_ADDED) package retrieval key (e.g. file name)
  * @param relocs       (TR_ADDED) package file relocations
  * @return             new transaction element
diff --git a/lib/rpmts.c b/lib/rpmts.c
index 1f8b7bd..5a8b122 100644
--- a/lib/rpmts.c
+++ b/lib/rpmts.c
@@ -731,6 +731,7 @@ static void rpmtsPrintStats(rpmts ts)
     rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
     rpmtsPrintStat("install:     ", rpmtsOp(ts, RPMTS_OP_INSTALL));
     rpmtsPrintStat("erase:       ", rpmtsOp(ts, RPMTS_OP_ERASE));
+       rpmtsPrintStat("change:      ", rpmtsOp(ts, RPMTS_OP_CHANGE));
     rpmtsPrintStat("scriptlets:  ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
     rpmtsPrintStat("compress:    ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
     rpmtsPrintStat("uncompress:  ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
diff --git a/lib/rpmts.h b/lib/rpmts.h
index e357247..3c655cd 100644
--- a/lib/rpmts.h
+++ b/lib/rpmts.h
@@ -154,7 +154,8 @@ typedef     enum rpmtsOpX_e {
     RPMTS_OP_DBGET             = 14,
     RPMTS_OP_DBPUT             = 15,
     RPMTS_OP_DBDEL             = 16,
-    RPMTS_OP_MAX               = 17
+       RPMTS_OP_CHANGE         = 17,
+    RPMTS_OP_MAX               = 18
 } rpmtsOpX;
 
 enum rpmtxnFlags_e {
@@ -582,6 +583,18 @@ int rpmtsAddReinstallElement(rpmts ts, Header h, const 
fnpyKey key);
 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset);
 
 /** \ingroup rpmts
+ * Add package to be changed to transaction set.
+ * If at least one such element is added to transaction,
+ * it should use transaction flags NOSCRIPTS, NOTRIGGERS, JUSTDB,
+ * or transaction will fail.
+ *
+ * @param ts           transaction set
+ * @param h            header
+ * @return             0 on success
+ */
+int rpmtsAddChangeElement(rpmts ts, Header h);
+
+/** \ingroup rpmts
  * Create a transaction (lock) handle
  * @param ts           transaction set
  * @param flags                flags
diff --git a/lib/transaction.c b/lib/transaction.c
index 1edc202..a0e1221 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -1550,6 +1550,8 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags 
ignoreSet)
     int nelem = rpmtsNElements(ts);
     /* Ignore SIGPIPE for the duration of transaction */
     rpmsqAction_t oact = rpmsqSetAction(SIGPIPE, RPMSQ_IGN);
+    rpmtsi pi;
+    rpmte p;
     
     /* Force default 022 umask during transaction for consistent results */
     mode_t oldmask = umask(022);
@@ -1560,6 +1562,22 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags 
ignoreSet)
        goto exit;
     }
 
+       /* Check if there are any 'changed' elements. If there are, and some 
transaction flags are missing, return error */
+       pi = rpmtsiInit(ts);
+       while ((p = rpmtsiNext(pi, 0)) != NULL)
+       {
+               if ((rpmteType(p) == TR_CHANGED)
+                       && ((rpmtsFlags(ts) & (RPMTRANS_FLAG_JUSTDB | 
RPMTRANS_FLAG_NOSCRIPTS | RPMTRANS_FLAG_NOTRIGGERS))
+                               != (RPMTRANS_FLAG_JUSTDB | 
RPMTRANS_FLAG_NOSCRIPTS | RPMTRANS_FLAG_NOTRIGGERS)))
+               {
+                       rpmtsiFree(pi);
+                       rc = -1;
+                       goto exit;
+               }
+       }
+
+       rpmtsiFree(pi);
+
     /* If we are in test mode, then there's no need for transaction lock. */
     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
        if (!(txn = rpmtxnBegin(ts, RPMTXN_WRITE))) {
diff --git a/plugins/syslog.c b/plugins/syslog.c
index 5f22f98..697b640 100644
--- a/plugins/syslog.c
+++ b/plugins/syslog.c
@@ -78,11 +78,27 @@ static rpmRC syslog_psm_post(rpmPlugin plugin, rpmte te, 
int res)
 
     if (state->logging) {
        int lvl = LOG_NOTICE;
-       const char *op = (rpmteType(te) == TR_ADDED) ? "install" : "erase";
+       const char *op = NULL;
        const char *outcome = "success";
        /* XXX: Permit configurable header queryformat? */
        const char *pkg = rpmteNEVRA(te);
 
+       switch (rpmteType(te))
+       {
+       case TR_ADDED:
+               op = "install";
+               break;
+       case TR_REMOVED:
+               op = "erase";
+               break;
+       case TR_CHANGED:
+               op = "change";
+               break;
+       default:
+               op = "unknown";
+               break;
+       }
+
        if (res != RPMRC_OK) {
            lvl = LOG_WARNING;
            outcome = "failure";
diff --git a/python/rpmmodule.c b/python/rpmmodule.c
index f0d40cc..3529b6b 100644
--- a/python/rpmmodule.c
+++ b/python/rpmmodule.c
@@ -558,6 +558,7 @@ static int initModule(PyObject *m)
     REGISTER_ENUM(TR_ADDED);
     REGISTER_ENUM(TR_REMOVED);
     REGISTER_ENUM(TR_RPMDB);
+    REGISTER_ENUM(TR_CHANGED);
 
     REGISTER_ENUM(RPMDBI_PACKAGES);
     REGISTER_ENUM(RPMDBI_LABEL);
-- 
2.10.4

_______________________________________________
Rpm-maint mailing list
Rpm-maint@lists.rpm.org
http://lists.rpm.org/mailman/listinfo/rpm-maint

Reply via email to