Detect attempts to replace directory symlink to directory in package
authorPanu Matilainen <pmatilai@redhat.com>
Fri, 24 Aug 2012 10:36:52 +0000 (13:36 +0300)
committerPanu Matilainen <pmatilai@redhat.com>
Fri, 24 Aug 2012 10:36:52 +0000 (13:36 +0300)
- Rpm cannot currently *correctly* deal with directory symlink changing
  to a directory through updates, detect early and abort with conflicts
  instead of proceeding with known-broken results: previously these
  would seemingly succeed but without actually doing the requested
  changes, and leaving orphans on the disk. Far less evil than the
  directory replacement failure but incorrect anyway.
- Same %pretrans wackiness as with directory replacements applies here.
- Adjust test-suite to match the new behavior.
- It's possible there are packages that have been relying on the former
  broken "success" results, so this might need further fine-tuning...

lib/transaction.c
tests/rpmconflict.at
tests/rpmreplace.at

index b1b7642..5e5a970 100644 (file)
@@ -287,11 +287,19 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx)
     rpmFileTypes ft = rpmfiWhatis(rpmfiFModeIndex(fi, fx));
     rpmFileTypes oft = rpmfiWhatis(rpmfiFModeIndex(ofi, ofx));
     struct stat sb;
+    char *fn = NULL;
 
     if (oft == XDIR) {
        /* We can't handle directory changing to anything else */
        if (ft != XDIR)
            rConflicts = 1;
+    } else if (oft == LINK) {
+       /* We can't correctly handle directory symlink changing to directory */
+       if (ft == XDIR) {
+           fn = rpmfiFNIndex(fi, fx);
+           if (stat(fn, &sb) == 0 && S_ISDIR(sb.st_mode))
+               rConflicts = 1;
+       }
     }
 
     /*
@@ -299,12 +307,13 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx)
      * already been changed to the new type, we should be ok afterall.
      */
     if (rConflicts) {
-       char *fn = rpmfiFNIndex(fi, fx);
+       if (fn == NULL)
+           fn = rpmfiFNIndex(fi, fx);
        if (lstat(fn, &sb) || rpmfiWhatis(sb.st_mode) == ft)
            rConflicts = 0;
-       free(fn);
     }
 
+    free(fn);
     return rConflicts;
 }
 
index 5058c58..692e294 100644 (file)
@@ -259,9 +259,7 @@ runroot rpm -U "${TOPDIR}"/RPMS/noarch/symlinktest-1.0-2.noarch.rpm
 AT_CLEANUP
 
 # ------------------------------
-# Replace symlink with a directory - the upgrade succeeds but leaves an
-# orphan directory that the symlink now points to. Should verify the
-# result more carefully...
+# Replace symlink with a directory
 AT_SETUP([rpm -U replacing symlink with directory])
 AT_KEYWORDS([install])
 AT_CHECK([
@@ -278,7 +276,8 @@ runroot rpmbuild --quiet -bb \
 runroot rpm -U "${TOPDIR}"/RPMS/noarch/symlinktest-1.0-1.noarch.rpm
 runroot rpm -U "${TOPDIR}"/RPMS/noarch/symlinktest-1.0-2.noarch.rpm
 ],
-[0],
+[2],
 [],
-[])
+[      file /usr/share/symlinktest from install of symlinktest-1.0-2.noarch conflicts with file from package symlinktest-1.0-1.noarch
+])
 AT_CLEANUP
index 97707a6..cdc8d03 100644 (file)
@@ -301,7 +301,6 @@ test -d "${tf}"
 [])
 AT_CLEANUP
 
-# XXX: this "succeeds" but with bogus results
 AT_SETUP([upgrade directory link to directory])
 AT_KEYWORDS([install])
 AT_CHECK([
@@ -325,12 +324,12 @@ runroot rpmbuild --quiet -bb \
 runroot rpm -U "${TOPDIR}"/RPMS/noarch/replacetest-1.0-1.noarch.rpm
 readlink "${tf}"
 runroot rpm -U "${TOPDIR}"/RPMS/noarch/replacetest-2.0-1.noarch.rpm
-test -d "${tf}"
 ],
-[0],
+[2],
 [zoo
 ],
-[])
+[      file /opt/foo from install of replacetest-2.0-1.noarch conflicts with file from package replacetest-1.0-1.noarch
+])
 AT_CLEANUP
 
 AT_SETUP([upgrade empty directory to empty directory])