From dce44771b2a3325b3dc1ebfe41027df9910a39fd Mon Sep 17 00:00:00 2001
From: Panu Matilainen <pmatilai@redhat.com>
Date: Fri, 11 Feb 2022 13:18:11 +0200
Subject: [PATCH] Fix + sanitize the hardlink metadata setting logic

Fix the initial setmeta value to something meaningful: we will never
set metadata on skipped files, and hardlinks are handled with a special
logic during install. They'd need different kind of special logic on
FA_TOUCH so just play it safe and always apply metadata on those.

Harlink metadata setting on install should happen on the *last* entry
of hardlinked set that gets installed (wrt various skip scenarios)
as otherwise creating those additional links affects the timestamp.
Note in particular the "last file of..." case in fsmMkfile() where we
the comment said just that, but set the metadata on the *first* file
which would then be NULL'ed away.

This all gets current masked by the fact that we do the metadata setting on
a separate round, but that is about to change plus this makes the overall
logic clearer anyhow.
---
 lib/fsm.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/fsm.c b/lib/fsm.c
index 82610c7..d9cfe6f 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -193,7 +193,6 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
 	/* Create hard links for others and avoid redundant metadata setting */
 	if (*firstlink != fp) {
 	    rc = fsmLink((*firstlink)->fpath, fp->fpath);
-	    fp->setmeta = 0;
 	}
 	fd = *firstlinkfile;
     }
@@ -204,7 +203,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
 	    rc = fsmUnpack(fi, fd, psm, nodigest);
 	/* Last file of hardlink set, ensure metadata gets set */
 	if (*firstlink) {
-	    (*firstlink)->setmeta = 1;
+	    fp->setmeta = 1;
 	    *firstlink = NULL;
 	    *firstlinkfile = NULL;
 	}
@@ -797,7 +796,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
 	else
 	    fp->action = rpmfsGetAction(fs, fx);
 	fp->skip = XFA_SKIPPING(fp->action);
-	fp->setmeta = 1;
 	if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi)))
 	    fp->suffix = tid;
 	fp->fpath = fsmFsPath(fi, fp->suffix);
@@ -805,6 +803,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
 	/* Remap file perms, owner, and group. */
 	rc = rpmfiStat(fi, 1, &fp->sb);
 
+	/* Hardlinks are tricky and handled elsewhere for install */
+	fp->setmeta = (fp->skip == 0) &&
+		      (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);
+
 	setFileState(fs, fx);
 	fsmDebug(fp->fpath, fp->action, &fp->sb);
 
-- 
1.8.3.1

