Avoid unnecessary .rpmnew and .rpmsave files (rhbz#128622)
authorPanu Matilainen <pmatilai@redhat.com>
Thu, 9 Aug 2007 12:15:24 +0000 (15:15 +0300)
committerPanu Matilainen <pmatilai@redhat.com>
Thu, 9 Aug 2007 12:15:24 +0000 (15:15 +0300)
Don't create .rpmnew and .rpmsave files when file/symlink on disk differs
just by timestamp. Patch by Tomas Mraz.
(transplanted from 0d4b8cfd8dc9e99d030b0d7d81611b5580468f2f)

lib/rpmfi.c
lib/rpmfi.h
lib/transaction.c

index 3825f90..6c4e10e 100644 (file)
@@ -22,6 +22,7 @@
 #include "rpmte.h"
 #include "rpmts.h"
 
+#include "legacy.h"     /* XXX domd5 */
 #include "misc.h"      /* XXX stripTrailingChar */
 #include "rpmmacro.h"  /* XXX rpmCleanPath */
 
@@ -627,6 +628,49 @@ fileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
 }
 /*@=boundsread@*/
 
+/*@-boundsread@*/
+int rpmfiConfigConflict(const rpmfi fi)
+{
+    const char * fn = rpmfiFN(fi);
+    int flags = rpmfiFFlags(fi);
+    char buffer[1024];
+    fileTypes newWhat, diskWhat;
+    struct stat sb;
+
+    if (!(flags & RPMFILE_CONFIG) || lstat(fn, &sb)) {
+       return 0;
+    }
+
+    diskWhat = whatis((int_16)sb.st_mode);
+    newWhat = whatis(rpmfiFMode(fi));
+
+    if (newWhat != LINK && newWhat != REG)
+       return 1;
+
+    if (diskWhat != newWhat)
+       return 1;
+    
+    memset(buffer, 0, sizeof(buffer));
+    if (newWhat == REG) {
+       const unsigned char * nmd5;
+       if (domd5(fn, (unsigned char *)buffer, 0, NULL))
+           return 0;   /* assume file has been removed */
+       nmd5 = rpmfiMD5(fi);
+       if (nmd5 && !memcmp(nmd5, buffer, 16))
+           return 0;   /* unmodified config file */
+    } else /* newWhat == LINK */ {
+       const char * nFLink;
+       if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
+           return 0;   /* assume file has been removed */
+       nFLink = rpmfiFLink(fi);
+       if (nFLink && !strcmp(nFLink, buffer))
+           return 0;   /* unmodified config file */
+    }
+
+    return 1;
+}
+/*@=boundsread@*/
+
 /*@observer@*/
 const char *const rpmfiTypeString(rpmfi fi)
 {
index 1c9bdfa..9ffd367 100644 (file)
@@ -620,6 +620,14 @@ fileAction rpmfiDecideFate(const rpmfi ofi, rpmfi nfi, int skipMissing)
        /*@modifies nfi, fileSystem, internalState @*/;
 
 /**
+ * Return whether file is conflicting config
+ * @param fi           file info
+ * @return             1 if config file and file on disk conflicts
+ */
+int rpmfiConfigConflict(const rpmfi fi)
+       /*@*/;
+
+/**
  * Return formatted string representation of package disposition.
  * @param fi           file info set
  * @return             formatted string
index f92fa68..13a036a 100644 (file)
@@ -547,7 +547,7 @@ static void handleOverlappedFiles(const rpmts ts,
 /*@-boundswrite@*/
        switch (rpmteType(p)) {
        case TR_ADDED:
-         { struct stat sb;
+         {
            int reportConflicts =
                !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES);
            int done = 0;
@@ -556,7 +556,7 @@ static void handleOverlappedFiles(const rpmts ts,
                /* XXX is this test still necessary? */
                if (fi->actions[i] != FA_UNKNOWN)
                    /*@switchbreak@*/ break;
-               if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
+               if (rpmfiConfigConflict(fi)) {
                    /* Here is a non-overlapped pre-existing config file. */
                    fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
                        ? FA_ALTNAME : FA_BACKUP;
@@ -613,7 +613,7 @@ assert(otherFi != NULL);
            /* Try to get the disk accounting correct even if a conflict. */
            fixupSize = rpmfiFSize(otherFi);
 
-           if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
+           if (rpmfiConfigConflict(fi)) {
                /* Here is an overlapped  pre-existing config file. */
                fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
                        ? FA_ALTNAME : FA_SKIP;