From 886c24cfc6c0fec90d8db1406a0e32c0e09e92c9 Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Thu, 27 Aug 2020 10:31:07 +0300
Subject: [PATCH] Upgrade FA_TOUCH to FA_CREATE if the file went away
 (RhBug:1872141)

Conflict:delete testcode
Reference:https://github.com/rpm-software-management/rpm/commit/886c24cfc6c0fec90d8db1406a0e32c0e09e92c9

When %_minimize_writes is enabled, we determine unchanged files during
fingerprinting and only update their metadata (FA_TOUCH) instead of
always recreating from scratch (FA_CREATE) during install. However
package scriptlets (and administrators) can and will do arbitrary stuff
in the meanwhile, such as rm -f their own files in %pre, hoping to
get a fresh copy of contents no matter what. Or something.
Now, if the file was determined to not need changing by rpm, this will
just fail with chown & friends trying to touch non-existent file.
One can consider this a case of package shooting itself in the foot, but
when a package update fails or succeeds depending on %_minimize_writes this
to me suggests the feature is at fault as much as the package.

Do fsmVerify() on all files to be FA_TOUCH'ed to detect files whose
type changed or were removed since fingerprinting. This still doesn't
ensure correctness if something tampers with the contents in the meanwhile,
(for that we'd need to run the file through the whole machinery again,
checksumming and all) but covers the most glaring cases.
---
 lib/fsm.c                      | 15 +++++++++----
 1 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/lib/fsm.c b/lib/fsm.c
index 5fb507993..08980d49b 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -902,10 +902,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
         if (!skip) {
 	    int setmeta = 1;
 
-	    /* When touching we don't need any of this... */
-	    if (action == FA_TOUCH)
-		goto touch;
-
 	    /* Directories replacing something need early backup */
 	    if (!suffix) {
 		rc = fsmBackup(fi, action);
@@ -917,6 +913,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
 		rc = RPMERR_ENOENT;
 	    }
 
+	    /* See if the file was removed while our attention was elsewhere */
+	    if (rc == RPMERR_ENOENT && action == FA_TOUCH) {
+		rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n", fpath);
+		action = FA_CREATE;
+		fsmDebug(fpath, action, &sb);
+	    }
+
+	    /* When touching we don't need any of this... */
+	    if (action == FA_TOUCH)
+		goto touch;
+
             if (S_ISREG(sb.st_mode)) {
 		if (rc == RPMERR_ENOENT) {
 		    rc = fsmMkfile(fi, fpath, files, psm, nodigest,
-- 
2.27.0

