diff --git a/0001-Add-SourceLicense-tag-to-spec-syntax.patch b/0001-Add-SourceLicense-tag-to-spec-syntax.patch
new file mode 100644
index 0000000..0f48138
--- /dev/null
+++ b/0001-Add-SourceLicense-tag-to-spec-syntax.patch
@@ -0,0 +1,124 @@
+From 1dc9372821487ccace23ff1ae9cba6b30f02c91c Mon Sep 17 00:00:00 2001
+From: Florian Festi <ffesti@redhat.com>
+Date: Tue, 5 Jul 2022 16:34:08 +0200
+Subject: [PATCH] Add SourceLicense tag to spec syntax
+
+to set a separate license to the source RPM. This can be useful if the
+sources have code under additional licenses that do not end up in the
+binary packeges.
+
+Resolves: #2079
+
+Note on the backport:  The spec document on this branch is ancient and
+doesn't even contain the License tag's description so this backport
+leaves the documentation part out.
+
+(backported from commit 9ed9d3fce34bc3c8121989e0cf263528e7e68756)
+---
+ build/parsePreamble.c       |  6 ++++++
+ lib/rpmtag.h                |  3 +++
+ tests/data/SPECS/foo.spec   |  1 +
+ tests/data/SPECS/hello.spec |  1 +
+ tests/rpmbuild.at           | 11 +++++++++++
+ tests/rpmspec.at            |  1 +
+ 6 files changed, 23 insertions(+)
+
+diff --git a/build/parsePreamble.c b/build/parsePreamble.c
+index e7d6d8752..bd07ecdf0 100644
+--- a/build/parsePreamble.c
++++ b/build/parsePreamble.c
+@@ -831,6 +831,11 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
+ 	if (addLangTag(spec, pkg->header, tag, field, lang))
+ 	    goto exit;
+ 	break;
++    case RPMTAG_SOURCELICENSE:
++	if (addLangTag(spec, spec->sourcePackage->header,
++		       RPMTAG_LICENSE, field, lang))
++	    goto exit;
++	break;
+     case RPMTAG_BUILDROOT:
+ 	/* just silently ignore BuildRoot */
+ 	break;
+@@ -1012,6 +1017,7 @@ static struct PreambleRec_s const preambleList[] = {
+     {RPMTAG_EPOCH,		0, 0, 1, LEN_AND_STR("epoch")},
+     {RPMTAG_SUMMARY,		1, 0, 1, LEN_AND_STR("summary")},
+     {RPMTAG_LICENSE,		0, 0, 1, LEN_AND_STR("license")},
++    {RPMTAG_SOURCELICENSE,	0, 0, 1, LEN_AND_STR("sourcelicense")},
+     {RPMTAG_DISTRIBUTION,	0, 0, 1, LEN_AND_STR("distribution")},
+     {RPMTAG_DISTURL,		0, 0, 1, LEN_AND_STR("disturl")},
+     {RPMTAG_VENDOR,		0, 0, 1, LEN_AND_STR("vendor")},
+diff --git a/lib/rpmtag.h b/lib/rpmtag.h
+index 7d1943835..1fd829118 100644
+--- a/lib/rpmtag.h
++++ b/lib/rpmtag.h
+@@ -375,6 +375,9 @@ typedef enum rpmTag_e {
+     RPMTAG_MODULARITYLABEL	= 5096, /* s */
+     RPMTAG_PAYLOADDIGESTALT	= 5097, /* s[] */
+ 
++    /* Backports */
++    RPMTAG_SOURCELICENSE	= 5102, /* internal */
++
+     RPMTAG_FIRSTFREE_TAG	/*!< internal */
+ } rpmTag;
+ 
+diff --git a/tests/data/SPECS/foo.spec b/tests/data/SPECS/foo.spec
+index 859e98142..9b1087094 100644
+--- a/tests/data/SPECS/foo.spec
++++ b/tests/data/SPECS/foo.spec
+@@ -8,6 +8,7 @@ Source: hello-2.0.tar.gz
+ Patch1: hello-1.0-modernize.patch
+ Group: Testing
+ License: GPLv2+
++SourceLicense: GPL, ASL 1.0
+ BuildArch: noarch
+ 
+ %description
+diff --git a/tests/data/SPECS/hello.spec b/tests/data/SPECS/hello.spec
+index 5bc9cfaf7..4b9053aca 100644
+--- a/tests/data/SPECS/hello.spec
++++ b/tests/data/SPECS/hello.spec
+@@ -4,6 +4,7 @@ Version: 1.0
+ Release: 1
+ Group: Utilities
+ License: GPL
++SourceLicense: GPL, ASL 1.0
+ Distribution: RPM test suite.
+ Vendor: Red Hat Software
+ Packager: Red Hat Software <bugs@redhat.com>
+diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at
+index bff65303b..7680f1502 100644
+--- a/tests/rpmbuild.at
++++ b/tests/rpmbuild.at
+@@ -31,6 +31,17 @@ run rpmbuild \
+ [0],
+ [ignore],
+ [ignore])
++
++AT_CHECK([
++
++runroot rpm -qp --qf "%{license}\n" /build/SRPMS/hello-1.0-1.src.rpm
++runroot rpm -qp --qf "%{license}\n" /build/RPMS/*/hello-1.0-1.*.rpm
++],
++[0],
++[GPL, ASL 1.0
++GPL
++],
++[])
+ AT_CLEANUP
+ 
+ AT_SETUP([rpmbuild -ba autosetup])
+diff --git a/tests/rpmspec.at b/tests/rpmspec.at
+index 2b11201db..c898ee654 100644
+--- a/tests/rpmspec.at
++++ b/tests/rpmspec.at
+@@ -243,6 +243,7 @@ Source: hello-2.0.tar.gz
+ Patch1: hello-1.0-modernize.patch
+ Group: Testing
+ License: GPLv2+
++SourceLicense: GPL, ASL 1.0
+ BuildArch: noarch
+ 
+ %description
+-- 
+2.45.2
+
diff --git a/0001-Add-optional-callback-on-directory-changes-during-rp.patch b/0001-Add-optional-callback-on-directory-changes-during-rp.patch
new file mode 100644
index 0000000..bda7110
--- /dev/null
+++ b/0001-Add-optional-callback-on-directory-changes-during-rp.patch
@@ -0,0 +1,107 @@
+From 186e0ab025b9ad92d900697f611633a6f6162f3b Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Wed, 9 Feb 2022 14:47:14 +0200
+Subject: [PATCH] Add optional callback on directory changes during rpmfi
+ iteration
+
+Internal only for now in case we need to fiddle with the API some more,
+but no reason this couldn't be made public later.
+---
+ lib/rpmfi.c          | 24 ++++++++++++++++++++----
+ lib/rpmfi_internal.h | 17 +++++++++++++++++
+ 2 files changed, 37 insertions(+), 4 deletions(-)
+
+diff --git a/lib/rpmfi.c b/lib/rpmfi.c
+index aec8220a3..6c631fdb5 100644
+--- a/lib/rpmfi.c
++++ b/lib/rpmfi.c
+@@ -53,6 +53,9 @@ struct rpmfi_s {
+     int intervalStart;		/*!< Start of iterating interval. */
+     int intervalEnd;		/*!< End of iterating interval. */
+ 
++    rpmfiChdirCb onChdir;	/*!< Callback for directory changes */
++    void *onChdirData;		/*!< Caller private callback data */
++
+     rpmfiles files;		/*!< File info set */
+     rpmcpio_t archive;		/*!< Archive with payload */
+     unsigned char * found;	/*!< Bit field of files found in the archive */
+@@ -298,11 +301,16 @@ rpm_count_t rpmfiDC(rpmfi fi)
+     return (fi != NULL ? rpmfilesDC(fi->files) : 0);
+ }
+ 
+-#ifdef	NOTYET
+-int rpmfiDI(rpmfi fi)
++int rpmfiSetOnChdir(rpmfi fi, rpmfiChdirCb cb, void *data)
+ {
++    int rc = -1;
++    if (fi != NULL) {
++	fi->onChdir = cb;
++	fi->onChdirData = data;
++	rc = 0;
++    }
++    return rc;
+ }
+-#endif
+ 
+ int rpmfiFX(rpmfi fi)
+ {
+@@ -314,9 +322,17 @@ int rpmfiSetFX(rpmfi fi, int fx)
+     int i = -1;
+ 
+     if (fi != NULL && fx >= 0 && fx < rpmfilesFC(fi->files)) {
++	int dx = fi->j;
+ 	i = fi->i;
+ 	fi->i = fx;
+ 	fi->j = rpmfilesDI(fi->files, fi->i);
++	i = fi->i;
++
++	if (fi->j != dx && fi->onChdir) {
++	    int chrc = fi->onChdir(fi, fi->onChdirData);
++	    if (chrc < 0)
++		i = chrc;
++	}
+     }
+     return i;
+ }
+@@ -1682,9 +1698,9 @@ static rpmfi initIter(rpmfiles files, int itype, int link)
+     if (files && itype>=0 && itype<=RPMFILEITERMAX) {
+ 	fi = xcalloc(1, sizeof(*fi)); 
+ 	fi->i = -1;
++	fi->j = -1;
+ 	fi->files = link ? rpmfilesLink(files) : files;
+ 	fi->next = nextfuncs[itype];
+-	fi->i = -1;
+ 	if (itype == RPMFI_ITER_BACK) {
+ 	    fi->i = rpmfilesFC(fi->files);
+ 	} else if (itype >=RPMFI_ITER_READ_ARCHIVE
+diff --git a/lib/rpmfi_internal.h b/lib/rpmfi_internal.h
+index dccc6ccbe..37f1d45f5 100644
+--- a/lib/rpmfi_internal.h
++++ b/lib/rpmfi_internal.h
+@@ -13,6 +13,23 @@
+ extern "C" {
+ #endif
+ 
++/** \ingroup rpmfi
++ * Callback on file iterator directory changes
++ * @param fi		file info
++ * @param data		caller private callback data
++ * @return		0 on success, < 0 on error (to stop iteration)
++ */
++typedef int (*rpmfiChdirCb)(rpmfi fi, void *data);
++
++/** \ingroup rpmfi
++ * Set a callback for directory changes during iteration.
++ * @param fi		file info
++ * @param cb		callback function
++ * @param data		caller private callback data
++ * @return		string pool handle (weak reference)
++ */
++int rpmfiSetOnChdir(rpmfi fi, rpmfiChdirCb cb, void *data);
++
+ /** \ingroup rpmfi
+  * Return file info set string pool handle
+  * @param fi		file info
+-- 
+2.41.0
+
diff --git a/0001-Don-t-segfault-on-missing-priority-tag.patch b/0001-Don-t-segfault-on-missing-priority-tag.patch
new file mode 100644
index 0000000..32a72dc
--- /dev/null
+++ b/0001-Don-t-segfault-on-missing-priority-tag.patch
@@ -0,0 +1,39 @@
+From fd57fc716231c8296d340fdb4c0f6eac176f7f7c Mon Sep 17 00:00:00 2001
+From: Florian Festi <ffesti@redhat.com>
+Date: Fri, 20 Aug 2021 15:14:16 +0200
+Subject: [PATCH] Don't segfault on missing priority tag
+
+Resolves: #1636
+Related: #1638
+---
+ lib/rpmtriggers.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c
+index fc809a65e..d541974e8 100644
+--- a/lib/rpmtriggers.c
++++ b/lib/rpmtriggers.c
+@@ -517,7 +517,8 @@ rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ 	if (matchFunc(ts, te, pfx, sense)) {
+ 	    for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++) {
+ 		struct rpmtd_s priorities;
+-		unsigned int priority;
++		unsigned int priority = 0;
++		unsigned int *priority_ptr;
+ 		unsigned int offset = rpmdbIndexIteratorPkgOffset(ii, i);
+ 		unsigned int tix = rpmdbIndexIteratorTagNum(ii, i);
+ 
+@@ -535,7 +536,9 @@ rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ 		trigH = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offset);
+ 		headerGet(trigH, priorityTag, &priorities, HEADERGET_MINMEM);
+ 		rpmtdSetIndex(&priorities, tix);
+-		priority = *rpmtdGetUint32(&priorities);
++		priority_ptr = rpmtdGetUint32(&priorities);
++		if (priority_ptr)
++		    priority = *priority_ptr;
+ 		headerFree(trigH);
+ 
+ 		/* Store file trigger in array */
+-- 
+2.45.1
+
diff --git a/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch
new file mode 100644
index 0000000..f910f38
--- /dev/null
+++ b/0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch
@@ -0,0 +1,30 @@
+From 6c66abd34cccbb5b3c063f8f613e0c2faffc415f Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Wed, 13 Dec 2023 11:57:50 +0200
+Subject: [PATCH] Don't warn about missing user/group on skipped files
+
+There's no reason to complain about missing user/group for entities
+we don't create at all. It's cosmetical only, but "regressed" in the
+4.17 fsm robustness rewrite.
+
+Reported in https://issues.redhat.com/browse/RHEL-18037
+---
+ lib/fsm.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/fsm.c b/lib/fsm.c
+index 2189bd84c..a54e43bae 100644
+--- a/lib/fsm.c
++++ b/lib/fsm.c
+@@ -903,7 +903,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 	fp->fpath = fsmFsPath(fi, fp->suffix);
+ 
+ 	/* Remap file perms, owner, and group. */
+-	rc = rpmfiStat(fi, 1, &fp->sb);
++	rc = rpmfiStat(fi, (fp->skip == 0), &fp->sb);
+ 
+ 	/* Hardlinks are tricky and handled elsewhere for install */
+ 	fp->setmeta = (fp->skip == 0) &&
+-- 
+2.43.0
+
diff --git a/0001-Eliminate-code-duplication-from-rpmfiNext.patch b/0001-Eliminate-code-duplication-from-rpmfiNext.patch
new file mode 100644
index 0000000..a5e0463
--- /dev/null
+++ b/0001-Eliminate-code-duplication-from-rpmfiNext.patch
@@ -0,0 +1,35 @@
+From 0bc13d75b5883ccf4d6579f7a60fb1badd104649 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Thu, 10 Feb 2022 10:23:22 +0200
+Subject: [PATCH] Eliminate code duplication from rpmfiNext()
+
+Now that we can, let rpmfiSetFX() take care of the details.
+---
+ lib/rpmfi.c | 11 ++---------
+ 1 file changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/lib/rpmfi.c b/lib/rpmfi.c
+index 689ead2c5..aec8220a3 100644
+--- a/lib/rpmfi.c
++++ b/lib/rpmfi.c
+@@ -856,15 +856,8 @@ int rpmfiNext(rpmfi fi)
+ 	    next = fi->next(fi);
+ 	} while (next == RPMERR_ITER_SKIP);
+ 
+-	if (next >= 0 && next < rpmfilesFC(fi->files)) {
+-	    fi->i = next;
+-	    fi->j = rpmfilesDI(fi->files, fi->i);
+-	} else {
+-	    fi->i = -1;
+-	    if (next >= 0) {
+-		next = -1;
+-	    }
+-	}
++	if (next >= 0)
++	    next = rpmfiSetFX(fi, next);
+     }
+     return next;
+ }
+-- 
+2.41.0
+
diff --git a/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch
new file mode 100644
index 0000000..29fb473
--- /dev/null
+++ b/0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch
@@ -0,0 +1,66 @@
+From c140768202e271b60910644c1e4bf848a50218d3 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Mon, 27 Nov 2023 11:52:34 +0200
+Subject: [PATCH] Emit full paths for file disposition diagnostics on
+ --fsmdebug
+
+The full path is visible in the actual file operations later, but the
+pre-flight disposition diagnostics is unreadable without the full path.
+This regressed in the switch to relative paths for the *at() API family
+for the symlink CVE fixes.
+---
+ lib/fsm.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/lib/fsm.c b/lib/fsm.c
+index 091e90554..fcd764648 100644
+--- a/lib/fsm.c
++++ b/lib/fsm.c
+@@ -482,14 +482,14 @@ static void removeSBITS(int dirfd, const char *path)
+     }
+ }
+ 
+-static void fsmDebug(const char *fpath, rpmFileAction action,
++static void fsmDebug(const char *dn, const char *fpath, rpmFileAction action,
+ 		     const struct stat *st)
+ {
+-    rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s\n",
++    rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s%s\n",
+ 	   fileActionString(action), (int)st->st_mode,
+ 	   (int)st->st_nlink, (int)st->st_uid,
+ 	   (int)st->st_gid, (int)st->st_size,
+-	    (fpath ? fpath : ""));
++	    (dn ? dn : ""), (fpath ? fpath : ""));
+ }
+ 
+ static int fsmSymlink(const char *opath, int dirfd, const char *path)
+@@ -910,7 +910,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 		      (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);
+ 
+ 	setFileState(fs, fx);
+-	fsmDebug(fp->fpath, fp->action, &fp->sb);
++	fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
+ 
+ 	fp->stage = FILE_PRE;
+     }
+@@ -975,7 +975,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 		rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n",
+ 			fp->fpath);
+ 		fp->action = FA_CREATE;
+-		fsmDebug(fp->fpath, fp->action, &fp->sb);
++		fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
+ 	    }
+ 
+ 	    /* When touching we don't need any of this... */
+@@ -1138,7 +1138,7 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
+ 
+ 	rc = fsmStat(di.dirfd, fp->fpath, 1, &fp->sb);
+ 
+-	fsmDebug(fp->fpath, fp->action, &fp->sb);
++	fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
+ 
+ 	/* Run fsm file pre hook for all plugins */
+ 	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
+-- 
+2.43.0
+
diff --git a/0001-Expose-and-document-rpmdb-verifydb-operation.patch b/0001-Expose-and-document-rpmdb-verifydb-operation.patch
new file mode 100644
index 0000000..23b444a
--- /dev/null
+++ b/0001-Expose-and-document-rpmdb-verifydb-operation.patch
@@ -0,0 +1,148 @@
+From 173b737f40e7da85f79544e3f4ea4ad7b8f7d5c2 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Mon, 6 Nov 2023 15:58:54 +0200
+Subject: [PATCH] Expose and document rpmdb --verifydb operation
+
+After years of BDB, sometimes folks just want some assurance that their db
+is still fine. Properly exposing an operation to do so hopefully makes
+less likely to poke at the db directly (with eg sqlite3 command).
+---
+ docs/man/rpmdb.8.md | 4 ++++
+ tools/rpmdb.c       | 4 ++--
+ 2 files changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/rpmdb.c b/rpmdb.c
+index 22b0b3e5d..36efff8af 100644
+--- a/rpmdb.c
++++ b/rpmdb.c
+@@ -23,8 +23,8 @@ static struct poptOption dbOptsTable[] = {
+     { "rebuilddb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_REBUILDDB,
+ 	N_("rebuild database inverted lists from installed package headers"),
+ 	NULL},
+-    { "verifydb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN),
+-	&mode, MODE_VERIFYDB, N_("verify database files"), NULL},
++    { "verifydb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
++	&mode, MODE_VERIFYDB, N_("verify database"), NULL},
+     { "salvagedb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN),
+ 	&mode, MODE_SALVAGEDB, N_("salvage database"), NULL},
+     { "exportdb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_EXPORTDB,
+-- 
+2.41.0
+
+--- a/doc/rpmdb.8	2020-05-28 12:04:25.024136615 +0200
++++ b/doc/rpmdb.8	2023-12-13 11:57:30.646202901 +0100
+@@ -1,48 +1,70 @@
+-.TH "RPMDB" "8" "29 June 2010" "Red Hat, Inc"
++.\" Automatically generated by Pandoc 3.1.3
++.\"
++.\" Define V font for inline verbatim, using C font in formats
++.\" that render this, and otherwise B font.
++.ie "\f[CB]x\f[]"x" \{\
++. ftr V B
++. ftr VI BI
++. ftr VB B
++. ftr VBI BI
++.\}
++.el \{\
++. ftr V CR
++. ftr VI CI
++. ftr VB CB
++. ftr VBI CBI
++.\}
++.TH "RPMDB" "8" "29 June 2010" "" ""
++.hy
+ .SH NAME
+-rpmdb \- RPM Database Tool
++.PP
++rpmdb - RPM Database Tool
+ .SH SYNOPSIS
+-
+-\fBrpm\fR {\fB--initdb|--rebuilddb\fR}
+-
+-.SH "DESCRIPTION"
+-The general form of an rpm rebuild database command is 
+-.PP
+-
+-\fBrpm\fR {\fB--initdb|--rebuilddb\fR} [\fB-v\fR] [\fB--dbpath \fIDIRECTORY\fB\fR] [\fB--root \fIDIRECTORY\fB\fR]
+-
+-.PP
+-Use \fB--initdb\fR to create a new database if one doesn't already exist
+-(existing database is not overwritten), use
+-\fB--rebuilddb\fR to rebuild the database indices from
+-the installed package headers.
+-.PP
+-
+-.SH "SEE ALSO"
+-
+-.nf
+-\fBpopt\fR(3),
+-\fBrpm\fR(8),
+-\fBrpmkeys\fR(8),
+-\fBrpmsign\fR(8),
+-\fBrpm2cpio\fR(8),
+-\fBrpmbuild\fR(8),
+-\fBrpmspec\fR(8),
+-.fi
+-
+-\fBrpm --help\fR - as rpm supports customizing the options via popt aliases 
+-it's impossible to guarantee that what's described in the manual matches 
+-what's available.
+-
+-
+-\fBhttp://www.rpm.org/ <URL:http://www.rpm.org/>
+-\fR
+-.SH "AUTHORS"
+-
++.PP
++\f[B]rpmdb\f[R] {\f[B]--initdb|--rebuilddb\f[R]}
++.PP
++\f[B]rpmdb\f[R] {\f[B]--verifydb\f[R]}
++.PP
++\f[B]rpmdb\f[R] {\f[B]--exportdb|--importdb\f[R]}
++.SH DESCRIPTION
++.PP
++The general form of an rpmdb command is
++.PP
++\f[B]rpm\f[R] {\f[B]--initdb|--rebuilddb\f[R]} [\f[B]-v\f[R]]
++[\f[B]--dbpath \f[R]\f[I]DIRECTORY\f[R]] [\f[B]--root
++\f[R]\f[I]DIRECTORY\f[R]]
++.PP
++Use \f[B]--initdb\f[R] to create a new database if one doesn\[aq]t
++already exist (existing database is not overwritten), use
++\f[B]--rebuilddb\f[R] to rebuild the database indices from the installed
++package headers.
++.PP
++\f[B]--verifydb\f[R] performs a low-level integrity check on the
++database.
++.PP
++\f[B]--exportdb\f[R] exports the database in header-list format,
++suitable for transfporting to another host or database type.
++.PP
++\f[B]--importdb\f[R] imports a database from a header-list format as
++created by \f[B]--exportdb\f[R].
++.SH SEE ALSO
++.PP
++\f[B]popt\f[R](3), \f[B]rpm\f[R](8), \f[B]rpmkeys\f[R](8),
++\f[B]rpmsign\f[R](8), \f[B]rpm2cpio\f[R](8), \f[B]rpmbuild\f[R](8),
++\f[B]rpmspec\f[R](8)
++.PP
++\f[B]rpm --help\f[R] - as rpm supports customizing the options via popt
++aliases it\[aq]s impossible to guarantee that what\[aq]s described in
++the manual matches what\[aq]s available.
++.PP
++\f[B]http://www.rpm.org/ <URL:http://www.rpm.org/>\f[R]
++.SH AUTHORS
++.IP
+ .nf
+-Marc Ewing <marc@redhat.com>
+-Jeff Johnson <jbj@redhat.com>
+-Erik Troan <ewt@redhat.com>
+-Panu Matilainen <pmatilai@redhat.com>
++\f[C]
++Marc Ewing <marc\[at]redhat.com>
++Jeff Johnson <jbj\[at]redhat.com>
++Erik Troan <ewt\[at]redhat.com>
++Panu Matilainen <pmatilai\[at]redhat.com>
++\f[R]
+ .fi
+-
diff --git a/0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch b/0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch
new file mode 100644
index 0000000..63cc183
--- /dev/null
+++ b/0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch
@@ -0,0 +1,26 @@
+From 03525592c944957f3b7b200b7daeb9f615cdcde7 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 23 May 2023 12:46:22 +0300
+Subject: [PATCH] Fix a copy-paste --help description of --whatconflicts
+ (RhBug:2208661)
+
+---
+ lib/poptQV.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/poptQV.c b/lib/poptQV.c
+index ac8e8975d..8bd91c652 100644
+--- a/lib/poptQV.c
++++ b/lib/poptQV.c
+@@ -108,7 +108,7 @@ struct poptOption rpmQVSourcePoptTable[] = {
+  { "verify", 'V', POPT_ARGFLAG_DOC_HIDDEN, NULL, 'V',
+ 	N_("rpm verify mode"), NULL },
+  { "whatconflicts", '\0', 0, 0, POPT_WHATCONFLICTS, 
+-	N_("query/verify the package(s) which require a dependency"), "CAPABILITY" },
++	N_("query/verify the package(s) which conflict with a dependency"), "CAPABILITY" },
+  { "whatrequires", '\0', 0, 0, POPT_WHATREQUIRES, 
+ 	N_("query/verify the package(s) which require a dependency"), "CAPABILITY" },
+  { "whatobsoletes", '\0', 0, 0, POPT_WHATOBSOLETES,
+-- 
+2.41.0
+
diff --git a/0001-Fix-potential-use-of-uninitialized-pgp-struct.patch b/0001-Fix-potential-use-of-uninitialized-pgp-struct.patch
new file mode 100644
index 0000000..3d4557c
--- /dev/null
+++ b/0001-Fix-potential-use-of-uninitialized-pgp-struct.patch
@@ -0,0 +1,12 @@
+diff -up rpm-4.16.1.3/lib/rpmts.c.orig rpm-4.16.1.3/lib/rpmts.c
+--- rpm-4.16.1.3/lib/rpmts.c.orig	2024-07-11 13:55:35.430198126 +0200
++++ rpm-4.16.1.3/lib/rpmts.c	2024-07-11 13:55:59.243061182 +0200
+@@ -482,6 +482,8 @@ static int makePubkeyHeader(rpmts ts, rp
+     int rc = -1;
+     int i;
+ 
++    memset(&kd, 0, sizeof(kd));
++
+     if ((enc = rpmPubkeyBase64(key)) == NULL)
+ 	goto exit;
+     if ((dig = rpmPubkeyDig(key)) == NULL)
diff --git a/0001-Fix-potential-use-of-uninitialized-pipe-array.patch b/0001-Fix-potential-use-of-uninitialized-pipe-array.patch
new file mode 100644
index 0000000..dcabc59
--- /dev/null
+++ b/0001-Fix-potential-use-of-uninitialized-pipe-array.patch
@@ -0,0 +1,32 @@
+From bff65aad8af719542c7b0c6429e09223c014a909 Mon Sep 17 00:00:00 2001
+From: Michal Domonkos <mdomonko@redhat.com>
+Date: Thu, 6 Jun 2024 09:15:02 +0200
+Subject: [PATCH] Fix potential use of uninitialized pipe array
+
+We only call pipe(2) after the script is written to disk so if the
+latter fails, the array will be left uninitialized and subsequently read
+after skipping to the exit label.  Fix by initializing it.
+
+Found by Coverity.
+
+Fixes: RHEL-22604
+---
+ lib/rpmscript.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/rpmscript.c b/lib/rpmscript.c
+index 281c55c53..1de4acf8e 100644
+--- a/lib/rpmscript.c
++++ b/lib/rpmscript.c
+@@ -316,7 +316,7 @@ static rpmRC runExtScript(rpmPlugins plugins, ARGV_const_t prefixes,
+     char * fn = NULL;
+     pid_t pid, reaped;
+     int status;
+-    int inpipe[2];
++    int inpipe[2] = { -1, -1 };
+     FILE *in = NULL;
+     const char *line;
+     char *mline = NULL;
+-- 
+2.45.2
+
diff --git a/0001-Fix-root-relocation-regression.patch b/0001-Fix-root-relocation-regression.patch
new file mode 100644
index 0000000..e4ce8b6
--- /dev/null
+++ b/0001-Fix-root-relocation-regression.patch
@@ -0,0 +1,91 @@
+From bce17e42f2301a88574d757740627480a38d86aa Mon Sep 17 00:00:00 2001
+From: Michal Domonkos <mdomonko@redhat.com>
+Date: Fri, 26 Jul 2024 10:44:04 +0200
+Subject: [PATCH] Fix root relocation regression
+
+When relocating the root directory, make sure we insert the new path's
+dirname to dirNames[] even if the root itself is owned by the package.
+
+This appears to have been the intention from the first version (largely
+untouched since) of this code as we allow the root to pass through the
+first checks (by setting len to 0 in that case) as well as the second
+for loop where we do the relocations.
+
+This allows fsm to properly create and remove the relocated directory
+since we're now using fd-based calls (#1919) and the parent directory
+needs to be opened first.
+
+No need to do string comparison here, the empty basename signals that
+we're processing the root directory, so just use that.
+
+Building a relocatable package that owns the root directory seems to be
+a handy way to create user-installable packages (see RHEL-28967) and it
+happened to work before with the path-based calls so this technically
+was a regression.  Add a test that emulates this use case.
+
+Backported from commits:
+31c14ba6610568c2d634647fed1fb57221178da9
+308ac60677732e9979b9ce11e5a3085906da1901
+
+Fixes: RHEL-28967
+---
+ lib/relocation.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/lib/relocation.c b/lib/relocation.c
+index 3ba4cfeab..8c35bc1a7 100644
+--- a/lib/relocation.c
++++ b/lib/relocation.c
+@@ -123,7 +123,7 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations,
+     char ** baseNames;
+     char ** dirNames;
+     uint32_t * dirIndexes;
+-    rpm_count_t fileCount, dirCount;
++    rpm_count_t fileCount, dirCount, dirCountOrig;
+     int nrelocated = 0;
+     int fileAlloced = 0;
+     char * fn = NULL;
+@@ -162,7 +162,7 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations,
+     baseNames = bnames.data;
+     dirIndexes = dindexes.data;
+     fileCount = rpmtdCount(&bnames);
+-    dirCount = rpmtdCount(&dnames);
++    dirCount = dirCountOrig = rpmtdCount(&dnames);
+     /* XXX TODO: use rpmtdDup() instead */
+     dirNames = dnames.data = duparray(dnames.data, dirCount);
+     dnames.flags |= RPMTD_PTR_ALLOCED;
+@@ -179,8 +179,9 @@ void rpmRelocateFileList(rpmRelocation *relocations, int numRelocations,
+ 	rpmFileTypes ft;
+ 	int fnlen;
+ 
++	size_t baselen = strlen(baseNames[i]);
+ 	size_t len = maxlen +
+-		strlen(dirNames[dirIndexes[i]]) + strlen(baseNames[i]) + 1;
++		strlen(dirNames[dirIndexes[i]]) + baselen + 1;
+ 	if (len >= fileAlloced) {
+ 	    fileAlloced = len * 2;
+ 	    fn = xrealloc(fn, fileAlloced);
+@@ -242,8 +243,9 @@ assert(fn != NULL);		/* XXX can't happen */
+ 	    continue;
+ 	}
+ 
+-	/* Relocation on full paths only, please. */
+-	if (fnlen != len) continue;
++	/* Relocation on '/' and full paths only, please. */
++	if (baselen && fnlen != len)
++	    continue;
+ 
+ 	rpmlog(RPMLOG_DEBUG, "relocating %s to %s\n",
+ 	       fn, relocations[j].newPath);
+@@ -294,7 +296,7 @@ assert(fn != NULL);		/* XXX can't happen */
+     }
+ 
+     /* Finish off by relocating directories. */
+-    for (i = dirCount - 1; i >= 0; i--) {
++    for (i = dirCountOrig - 1; i >= 0; i--) {
+ 	for (j = numRelocations - 1; j >= 0; j--) {
+ 
+ 	    if (relocations[j].oldPath == NULL) /* XXX can't happen */
+-- 
+2.45.2
+
diff --git a/0001-Fix-short-circuiting-of-version-strings-in-expressio.patch b/0001-Fix-short-circuiting-of-version-strings-in-expressio.patch
new file mode 100644
index 0000000..e06709a
--- /dev/null
+++ b/0001-Fix-short-circuiting-of-version-strings-in-expressio.patch
@@ -0,0 +1,50 @@
+From 321933f060896f721e361a1c8a8d3731bdcee827 Mon Sep 17 00:00:00 2001
+From: Michael Schroeder <mls@suse.de>
+Date: Wed, 22 Jun 2022 14:07:01 +0200
+Subject: [PATCH] Fix short circuiting of version strings in expressions
+
+We use an empty string when discarding a value due to short circuiting, but
+an empty string is not allowed for versions. So use "0" in that case.
+
+Fixes: #1883
+---
+ rpmio/expression.c | 2 +-
+ tests/rpmmacro.at  | 2 ++
+ 2 files changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/rpmio/expression.c b/rpmio/expression.c
+index a389a04d5..98a44bbdb 100644
+--- a/rpmio/expression.c
++++ b/rpmio/expression.c
+@@ -477,7 +477,7 @@ static int rdToken(ParseState state)
+       if (qtok == TOK_STRING) {
+ 	v = valueMakeString(temp);
+       } else {
+-	v = valueMakeVersion(temp);
++	v = valueMakeVersion(state->flags & RPMEXPR_DISCARD ? "0" : temp);
+         free(temp); /* version doesn't take ownership of the string */
+         if (v == 0) {
+ 	  exprErr(state, _("invalid version"), p+1);
+diff --git a/tests/rpmmacro.at b/tests/rpmmacro.at
+index d1490b4d9..c4376d49e 100644
+--- a/tests/rpmmacro.at
++++ b/tests/rpmmacro.at
+@@ -533,6 +533,7 @@ runroot rpm \
+     --eval '%["%{aaa}"]' \
+     --eval '%[%{?ccc}]' \
+     --eval '%[v"1:2.3-4"]' \
++    --eval '%[v"0" && v"0"]' \
+ ]],
+ [0],
+ [4096
+@@ -542,6 +543,7 @@ runroot rpm \
+ 5
+ 0
+ 1:2.3-4
++0
+ ],
+ [])
+ AT_CLEANUP
+-- 
+2.41.0
+
diff --git a/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch
new file mode 100644
index 0000000..1d73765
--- /dev/null
+++ b/0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch
@@ -0,0 +1,46 @@
+From 89ce4e7ca592f5abafc3f25aeaa07d36a7b43a61 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 14 Nov 2023 11:37:48 +0200
+Subject: [PATCH] Fix wrong return code on O_DIRECTORY open of invalid symlink
+
+The dir argument to fsmOpenpath() is supposed to be a rough O_DIRECTORY
+equivalent, and if the path is actually a misowned symlink it should
+return ENOTDIR instead of ELOOP. Makes the resulting error messages
+at least a little more comprehensible.
+---
+ lib/fsm.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/lib/fsm.c b/lib/fsm.c
+index 51f439ef3..091e90554 100644
+--- a/lib/fsm.c
++++ b/lib/fsm.c
+@@ -304,6 +304,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)
+     struct stat lsb, sb;
+     int sflags = flags | O_NOFOLLOW;
+     int fd = openat(dirfd, path, sflags);
++    int ffd = fd;
+ 
+     /*
+      * Only ever follow symlinks by root or target owner. Since we can't
+@@ -312,7 +313,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)
+      * it could've only been the link owner or root.
+      */
+     if (fd < 0 && errno == ELOOP && flags != sflags) {
+-	int ffd = openat(dirfd, path, flags);
++	ffd = openat(dirfd, path, flags);
+ 	if (ffd >= 0) {
+ 	    if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) {
+ 		if (fstat(ffd, &sb) == 0) {
+@@ -327,7 +328,7 @@ static int fsmOpenat(int dirfd, const char *path, int flags, int dir)
+     }
+ 
+     /* O_DIRECTORY equivalent */
+-    if (dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
++    if (dir && ((fd != ffd) || (fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)))) {
+ 	errno = ENOTDIR;
+ 	fsmClose(&fd);
+     }
+-- 
+2.43.0
+
diff --git a/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch
new file mode 100644
index 0000000..177aa0f
--- /dev/null
+++ b/0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch
@@ -0,0 +1,158 @@
+From ac7b0dbd5a18d2c57a942ca14ac856b8047425ff Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 15 Feb 2022 10:43:13 +0200
+Subject: [PATCH] Pass file descriptor to file prepare plugin hook, use when
+ possible
+
+Sadly the thing that allegedly makes things better mostly just makes
+things more complicated as symlinks can't be opened, so we'll now have
+to deal with both cases in plugins too. To make matters worse, most
+APIs out there support either an fd or a path, but very few support
+the *at() style dirfd + basename approach so plugins are stuck with
+absolute paths for now.
+
+This is of course a plugin API/ABI change too.
+---
+ lib/rpmplugin.h   |  2 +-
+ lib/rpmplugins.c  |  4 ++--
+ lib/rpmplugins.h  |  3 ++-
+ plugins/ima.c     |  9 +++++++--
+ plugins/selinux.c | 13 ++++++++-----
+ 5 files changed, 20 insertions(+), 11 deletions(-)
+
+diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h
+index fd81aec8d..fab4b3e83 100644
+--- a/lib/rpmplugin.h
++++ b/lib/rpmplugin.h
+@@ -57,7 +57,7 @@ typedef rpmRC (*plugin_fsm_file_post_func)(rpmPlugin plugin, rpmfi fi,
+ 					   const char* path, mode_t file_mode,
+ 					   rpmFsmOp op, int res);
+ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,
+-					      const char* path,
++					      int fd, const char* path,
+ 					      const char *dest,
+ 					      mode_t file_mode, rpmFsmOp op);
+ 
+diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
+index 65e684e84..923084b78 100644
+--- a/lib/rpmplugins.c
++++ b/lib/rpmplugins.c
+@@ -384,7 +384,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,
+ }
+ 
+ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+-				   const char *path, const char *dest,
++				   int fd, const char *path, const char *dest,
+ 				   mode_t file_mode, rpmFsmOp op)
+ {
+     plugin_fsm_file_prepare_func hookFunc;
+@@ -394,7 +394,7 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+     for (i = 0; i < plugins->count; i++) {
+ 	rpmPlugin plugin = plugins->plugins[i];
+ 	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_prepare);
+-	if (hookFunc && hookFunc(plugin, fi, path, dest, file_mode, op) == RPMRC_FAIL) {
++	if (hookFunc && hookFunc(plugin, fi, fd, path, dest, file_mode, op) == RPMRC_FAIL) {
+ 	    rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_prepare failed\n", plugin->name);
+ 	    rc = RPMRC_FAIL;
+ 	}
+diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
+index 39762c376..ddf5d7048 100644
+--- a/lib/rpmplugins.h
++++ b/lib/rpmplugins.h
+@@ -156,6 +156,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,
+  * permissions etc, but before committing file to destination path.
+  * @param plugins	plugins structure
+  * @param fi		file info iterator (or NULL)
++ * @param fd		file descriptor (or -1 if not available)
+  * @param path		file object current path
+  * @param dest		file object destination path
+  * @param mode		file object mode
+@@ -164,7 +165,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,
+  */
+ RPM_GNUC_INTERNAL
+ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+-                                   const char *path, const char *dest,
++                                   int fd, const char *path, const char *dest,
+                                    mode_t mode, rpmFsmOp op);
+ 
+ #ifdef __cplusplus
+diff --git a/plugins/ima.c b/plugins/ima.c
+index fe6d3ad7f..9c28a41a3 100644
+--- a/plugins/ima.c
++++ b/plugins/ima.c
+@@ -39,7 +39,7 @@ static int check_zero_hdr(const unsigned char *fsig, size_t siglen)
+ 	return (memcmp(fsig, &zero_hdr, sizeof(zero_hdr)) == 0);
+ }
+ 
+-static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
++static rpmRC ima_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, int fd,
+                                   const char *path,
+                                   const char *dest,
+                                   mode_t file_mode, rpmFsmOp op)
+@@ -68,8 +68,13 @@
+ 
+ 	fsig = rpmfiFSignature(fi, &len);
+ 	if (fsig && (check_zero_hdr(fsig, len) == 0)) {
+-	    if (lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0) < 0) {
+-		int is_err = errno != EOPNOTSUPP; 
++	    int xx;
++	    if (fd >= 0)
++		xx = fsetxattr(fd, XATTR_NAME_IMA, fsig, len, 0);
++	    else
++		xx = lsetxattr(path, XATTR_NAME_IMA, fsig, len, 0);
++	    if (xx < 0) {
++		int is_err = errno != EOPNOTSUPP;
+ 	        rpmlog(is_err?RPMLOG_ERR:RPMLOG_DEBUG,
+ 			"ima: could not apply signature on '%s': %s\n",
+ 			path, strerror(errno));
+diff --git a/plugins/fapolicyd.c b/plugins/fapolicyd.c
+index 7ac44f0d0..1ff50c30f 100644
+--- a/plugins/fapolicyd.c
++++ b/plugins/fapolicyd.c
+@@ -145,7 +145,8 @@ static rpmRC fapolicyd_scriptlet_pre(rpmPlugin plugin, const char *s_name,
+ }
+ 
+ static rpmRC fapolicyd_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
+-                                        const char *path, const char *dest,
++                                        int fd, const char *path,
++					const char *dest,
+                                         mode_t file_mode, rpmFsmOp op)
+ {
+     /* not ready  */
+diff --git a/plugins/selinux.c b/plugins/selinux.c
+index 32c3b7529..a7f20aeca 100644
+--- a/plugins/selinux.c
++++ b/plugins/selinux.c
+@@ -149,7 +149,7 @@ static rpmRC selinux_scriptlet_fork_post(rpmPlugin plugin,
+     return rc;
+ }
+ 
+-static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
++static rpmRC selinux_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, int fd,
+ 					const char *path, const char *dest,
+ 				        mode_t file_mode, rpmFsmOp op)
+ {
+@@ -194,13 +194,17 @@
+     if (sehandle && !XFA_SKIPPING(action)) {
+ 	char *scon = NULL;
+ 	if (selabel_lookup_raw(sehandle, &scon, dest, file_mode) == 0) {
+-	    int conrc = lsetfilecon(path, scon);
++	    int conrc;
++	    if (fd >= 0)
++		conrc = fsetfilecon(fd, scon);
++	    else
++		conrc = lsetfilecon(path, scon);
+ 
+ 	    if (conrc == 0 || (conrc < 0 && errno == EOPNOTSUPP))
+ 		rc = RPMRC_OK;
+ 
+-	    rpmlog(loglvl(rc != RPMRC_OK), "lsetfilecon: (%s, %s) %s\n",
+-		       path, scon, (conrc < 0 ? strerror(errno) : ""));
++	    rpmlog(loglvl(rc != RPMRC_OK), "lsetfilecon: (%d %s, %s) %s\n",
++		   fd, path, scon, (conrc < 0 ? strerror(errno) : ""));
+ 
+ 	    freecon(scon);
+ 	} else {
+-- 
+2.41.0
+
diff --git a/0001-Print-full-path-if-file-removal-fails.patch b/0001-Print-full-path-if-file-removal-fails.patch
new file mode 100644
index 0000000..266bd69
--- /dev/null
+++ b/0001-Print-full-path-if-file-removal-fails.patch
@@ -0,0 +1,32 @@
+From f1503ab6e898430b80017c0f8347860f3a74d5bb Mon Sep 17 00:00:00 2001
+From: Florian Festi <ffesti@redhat.com>
+Date: Mon, 11 Dec 2023 15:50:15 +0100
+Subject: [PATCH] Print full path if file removal fails
+
+For normal debug output the basename of the files are sufficient as when
+debugging is enabled the directories are also printed. But here the
+warning is given without a debug flag so we need the full context right
+there.
+---
+ lib/fsm.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/lib/fsm.c b/lib/fsm.c
+index fcd764648..2189bd84c 100644
+--- a/lib/fsm.c
++++ b/lib/fsm.c
+@@ -1174,9 +1174,9 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
+ 
+ 	    if (rc) {
+ 		int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;
+-		rpmlog(lvl, _("%s %s: remove failed: %s\n"),
++		rpmlog(lvl, _("%s %s%s: remove failed: %s\n"),
+ 			S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"),
+-			fp->fpath, strerror(errno));
++			rpmfiDN(fi), fp->fpath, strerror(errno));
+             }
+         }
+ 
+-- 
+2.43.0
+
diff --git a/0001-RPM-with-Copy-on-Write.patch b/0001-RPM-with-Copy-on-Write.patch
index 151d2d8..49a0f32 100644
--- a/0001-RPM-with-Copy-on-Write.patch
+++ b/0001-RPM-with-Copy-on-Write.patch
@@ -85,9 +85,10 @@ and other non file types.
 Nothing has been removed, and none of the changes are intended to be
 used externally, so I don't think a soname bump is warranted here.
 ---
+ .gitignore          |   1 +
  Makefile.am         |   6 +-
  lib/depends.c       |   2 +
- lib/fsm.c           |  45 +++-
+ lib/fsm.c           |  61 +++++-
  lib/package.c       |  40 ++++
  lib/rpmlib.h        |   9 +
  lib/rpmplugins.c    |  21 +-
@@ -100,7 +101,7 @@ used externally, so I don't think a soname bump is warranted here.
  rpm2extents.c       | 519 ++++++++++++++++++++++++++++++++++++++++++++
  rpmio/rpmpgp.c      |  10 +
  rpmio/rpmpgp.h      |   9 +
- 15 files changed, 1004 insertions(+), 12 deletions(-)
+ 16 files changed, 1020 insertions(+), 13 deletions(-)
  create mode 100644 plugins/reflink.c
  create mode 100644 rpm2extents.c
 
@@ -108,7 +109,7 @@ diff --git a/Makefile.am b/Makefile.am
 index e5c75d7b4..288668819 100644
 --- a/Makefile.am
 +++ b/Makefile.am
-@@ -99,7 +99,7 @@ pkginclude_HEADERS += build/rpmfc.h
+@@ -106,7 +106,7 @@ pkginclude_HEADERS += build/rpmfc.h
  pkginclude_HEADERS += build/rpmspec.h
  
  
@@ -117,7 +118,7 @@ index e5c75d7b4..288668819 100644
  if WITH_ARCHIVE
  bin_PROGRAMS += 	rpm2archive 
  endif
-@@ -154,6 +154,10 @@ rpm2cpio_SOURCES =	rpm2cpio.c debug.h system.h
+@@ -160,6 +160,10 @@ rpm2cpio_SOURCES =	rpm2cpio.c debug.h system.h
  rpm2cpio_LDADD =	lib/librpm.la rpmio/librpmio.la
  rpm2cpio_LDADD +=	@WITH_POPT_LIB@
  
@@ -132,7 +133,7 @@ diff --git a/lib/depends.c b/lib/depends.c
 index 30234df3d..8998afcd3 100644
 --- a/lib/depends.c
 +++ b/lib/depends.c
-@@ -81,6 +81,8 @@ static rpmRC headerCheckPayloadFormat(Header h) {
+@@ -80,6 +80,8 @@ static rpmRC headerCheckPayloadFormat(Header h) {
       */
      if (!payloadfmt) return rc;
  
@@ -146,33 +147,33 @@ index 935a0a5c6..90193c749 100644
 --- a/lib/fsm.c
 +++ b/lib/fsm.c
 @@ -8,6 +8,7 @@
- 
+ #include <inttypes.h>
  #include <utime.h>
  #include <errno.h>
 +#include <stdbool.h>
- #if WITH_CAP
+ #include <fcntl.h>
+ #ifdef WITH_CAP
  #include <sys/capability.h>
- #endif
-@@ -19,6 +20,7 @@
+@@ -17,6 +18,7 @@
+ #include <rpm/rpmts.h>
+ #include <rpm/rpmlog.h>
+ #include <rpm/rpmmacro.h>
++#include <rpm/rpmlib.h>
  
  #include "rpmio/rpmio_internal.h"	/* fdInit/FiniDigest */
- #include "lib/fsm.h"
-+#include "lib/rpmlib.h"
- #include "lib/rpmte_internal.h"	/* XXX rpmfs */
- #include "lib/rpmplugins.h"	/* rpm plugins hooks */
- #include "lib/rpmug.h"
-@@ -52,6 +54,7 @@ struct filedata_s {
+ #include "fsm.h"
+@@ -54,6 +56,7 @@ struct filedata_s {
      int stage;
      int setmeta;
      int skip;
-+    int plugin_contents;
++    bool plugin_contents;
      rpmFileAction action;
      const char *suffix;
      char *fpath;
-@@ -891,6 +894,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+@@ -885,6 +888,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
      struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
      struct filedata_s *firstlink = NULL;
- 
+     struct diriter_s di = { -1, -1 };
 +    Header h = rpmteHeader(te);
 +    const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
 +    bool cpio = true;
@@ -180,21 +181,14 @@ index 935a0a5c6..90193c749 100644
 +    if (payloadfmt && rstreq(payloadfmt, "clon")) {
 +	cpio = false;
 +    }
-+
+ 
      /* transaction id used for temporary path suffix while installing */
      rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
- 
-@@ -911,12 +922,23 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	/* Remap file perms, owner, and group. */
- 	rc = rpmfiStat(fi, 1, &fp->sb);
+@@ -909,7 +919,20 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 	fp->setmeta = (fp->skip == 0) &&
+ 		      (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);
  
 -	setFileState(fs, fx);
- 	fsmDebug(fp->fpath, fp->action, &fp->sb);
- 
- 	/* Run fsm file pre hook for all plugins */
- 	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
- 				      fp->sb.st_mode, fp->action);
-+	fp->plugin_contents = false;
 +	switch (rc) {
 +	case RPMRC_OK:
 +	    setFileState(fs, fx);
@@ -205,57 +199,95 @@ index 935a0a5c6..90193c749 100644
 +	    // this is from a hard link.
 +	    rc = RPMRC_OK;
 +	    break;
++	default:
++	    fp->action = FA_SKIP;
++	    fp->skip = XFA_SKIPPING(fp->action);
 +	}
+ 	fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
+ 
  	fp->stage = FILE_PRE;
-     }
-     fi = rpmfiFree(fi);
-@@ -924,10 +946,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+@@ -919,8 +942,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
      if (rc)
  	goto exit;
  
--    fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
--    if (fi == NULL) {
--        rc = RPMERR_BAD_MAGIC;
--        goto exit;
+-    fi = fsmIter(payload, files,
+-		 payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di);
 +    if (cpio) {
-+	fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
-+	if (fi == NULL) {
-+	    rc = RPMERR_BAD_MAGIC;
-+	    goto exit;
-+	}
++	fi = fsmIter(payload, files,
++		     payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di);
 +    } else {
 +	fi = rpmfilesIter(files, RPMFI_ITER_FWD);
-     }
++    }
+ 
+     if (fi == NULL) {
+         rc = RPMERR_BAD_MAGIC;
+@@ -943,6 +970,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+         if (!fp->skip) {
+ 	    int mayopen = 0;
+ 	    int fd = -1;
++
++	    if (!cpio && di.dirfd >= 0)
++		fsmClose(&di.dirfd);
+ 	    rc = ensureDir(plugins, rpmfiDN(fi), 0,
+ 			    (fp->action == FA_CREATE), 0, &di.dirfd);
  
-     /* Detect and create directories not explicitly in package. */
-@@ -969,8 +995,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+@@ -952,9 +982,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 	    }
+ 
+ 	    /* Run fsm file pre hook for all plugins */
+-	    if (!rc)
++	    if (!rc) {
+ 		rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
+ 					      fp->sb.st_mode, fp->action);
++		if (rc == RPMRC_PLUGIN_CONTENTS) {
++		    fp->plugin_contents = true;
++		    rc = RPMRC_OK;
++		}
++	    }
+ 	    if (rc)
+ 		goto setmeta; /* for error notification */
+ 
+@@ -984,9 +1019,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
  
              if (S_ISREG(fp->sb.st_mode)) {
  		if (rc == RPMERR_ENOENT) {
--		    rc = fsmMkfile(fi, fp, files, psm, nodigest,
--				   &firstlink, &firstlinkfile);
-+		    if(fp->plugin_contents) {
+-		    rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
+-				   &firstlink, &firstlinkfile, &di.firstdir,
+-				   &fd);
++		    if (fp->plugin_contents) {
 +			rc = RPMRC_OK;
-+		    }else {
-+			rc = fsmMkfile(fi, fp, files, psm, nodigest,
-+			    &firstlink, &firstlinkfile);
++		    } else {
++			rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
++				       &firstlink, &firstlinkfile,
++				       &di.firstdir, &fd);
 +		    }
  		}
              } else if (S_ISDIR(fp->sb.st_mode)) {
                  if (rc == RPMERR_ENOENT) {
-@@ -1078,6 +1108,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
+@@ -1054,11 +1093,17 @@ setmeta:
+ 	rc = fx;
+ 
+     /* If all went well, commit files to final destination */
+-    fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di);
++    if (cpio) {
++	fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di);
++    } else {
++	fi = rpmfilesIter(files, RPMFI_ITER_FWD);
++    }
+     while (!rc && (fx = rpmfiNext(fi)) >= 0) {
+ 	struct filedata_s *fp = &fdata[fx];
+ 
+ 	if (!fp->skip) {
++	    if (!cpio && di.dirfd >= 0)
++		fsmClose(&di.dirfd);
+ 	    if (!rc)
+ 		rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd);
  
- exit:
-+    h = headerFree(h);
-     fi = rpmfiFree(fi);
-     Fclose(payload);
-     free(tid);
 diff --git a/lib/package.c b/lib/package.c
 index 281275029..90bd0d8a7 100644
 --- a/lib/package.c
 +++ b/lib/package.c
-@@ -404,5 +404,45 @@ exit:
+@@ -402,5 +402,45 @@ exit:
      return rc;
  }
  
@@ -305,7 +337,7 @@ diff --git a/lib/rpmlib.h b/lib/rpmlib.h
 index 0879d04e5..a09ba0daf 100644
 --- a/lib/rpmlib.h
 +++ b/lib/rpmlib.h
-@@ -155,6 +155,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg);
+@@ -156,6 +156,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg);
  rpmRC rpmReadPackageFile(rpmts ts, FD_t fd,
  		const char * fn, Header * hdrp);
  
@@ -325,16 +357,17 @@ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
 index 62d75c4cf..c5084d398 100644
 --- a/lib/rpmplugins.c
 +++ b/lib/rpmplugins.c
-@@ -356,13 +356,28 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
+@@ -364,14 +364,29 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
      plugin_fsm_file_pre_func hookFunc;
      int i;
      rpmRC rc = RPMRC_OK;
 +    rpmRC hook_rc;
+     char *apath = abspath(fi, path);
  
      for (i = 0; i < plugins->count; i++) {
  	rpmPlugin plugin = plugins->plugins[i];
  	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);
--	if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) {
+-	if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op) == RPMRC_FAIL) {
 -	    rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
 -	    rc = RPMRC_FAIL;
 +	if (hookFunc) {
@@ -344,9 +377,9 @@ index 62d75c4cf..c5084d398 100644
 +		rc = RPMRC_FAIL;
 +	    } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
 +		if (rc == RPMRC_PLUGIN_CONTENTS) {
-+		    /*
-+		    Another plugin already said it'd handle contents. It's undefined how
-+		    these would combine, so treat this as a failure condition.
++		    /* Another plugin already said it'd handle contents. It's
++		     * undefined how these would combine, so treat this as a
++		     * failure condition.
 +		    */
 +		    rc = RPMRC_FAIL;
 +		} else {
@@ -356,12 +389,12 @@ index 62d75c4cf..c5084d398 100644
 +	    }
  	}
      }
- 
+     free(apath);
 diff --git a/lib/rpmte.c b/lib/rpmte.c
 index 3663604e7..d43dc41ad 100644
 --- a/lib/rpmte.c
 +++ b/lib/rpmte.c
-@@ -423,6 +423,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd)
+@@ -421,6 +421,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd)
      return NULL;
  }
  
@@ -404,7 +437,7 @@ diff --git a/macros.in b/macros.in
 index e90cefa9a..363252b0f 100644
 --- a/macros.in
 +++ b/macros.in
-@@ -1143,6 +1143,7 @@ package or when debugging this package.\
+@@ -1189,6 +1189,7 @@ package or when debugging this package.\
  
  # Transaction plugin macros
  %__plugindir		%{_libdir}/rpm-plugins
@@ -416,7 +449,7 @@ diff --git a/plugins/Makefile.am b/plugins/Makefile.am
 index 3a929d0ce..ad0d3bce7 100644
 --- a/plugins/Makefile.am
 +++ b/plugins/Makefile.am
-@@ -42,6 +42,10 @@ prioreset_la_SOURCES = prioreset.c
+@@ -33,6 +33,10 @@ prioreset_la_SOURCES = prioreset.c
  prioreset_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
  plugins_LTLIBRARIES += prioreset.la
  
@@ -1302,7 +1335,7 @@ diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
 index 015c15a5c..7b972b4a6 100644
 --- a/rpmio/rpmpgp.c
 +++ b/rpmio/rpmpgp.c
-@@ -283,6 +283,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se)
+@@ -298,6 +298,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se)
      return vs->val;
  }
  
diff --git a/0001-Skip-to-hashed-subpacket-data-directly.patch b/0001-Skip-to-hashed-subpacket-data-directly.patch
new file mode 100644
index 0000000..f0eaf1f
--- /dev/null
+++ b/0001-Skip-to-hashed-subpacket-data-directly.patch
@@ -0,0 +1,35 @@
+From 331afbf2b6b32582b29ceadcd37b43a4f905b7f4 Mon Sep 17 00:00:00 2001
+From: Michal Domonkos <mdomonko@redhat.com>
+Date: Mon, 5 Aug 2024 14:40:57 +0200
+Subject: [PATCH] Skip to hashed subpacket data directly
+
+Make OpenScanHub grok the bigger picture here, instead of producing a
+spurious overrun warning for v->hashlen when we're dereferencing p
+later.
+
+No functional change.
+
+Resolves: RHEL-22607
+---
+ rpmio/rpmpgp.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
+index d0688ebe9..6a7049954 100644
+--- a/rpmio/rpmpgp.c
++++ b/rpmio/rpmpgp.c
+@@ -618,10 +618,9 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
+ 	pgpPrtVal(" ", pgpSigTypeTbl, v->sigtype);
+ 	pgpPrtNL();
+ 
+-	p = &v->hashlen[0];
+ 	if (pgpGet(v->hashlen, sizeof(v->hashlen), h + hlen, &plen))
+ 	    return 1;
+-	p += sizeof(v->hashlen);
++	p = h + sizeof(*v);
+ 
+ 	if ((p + plen) > (h + hlen))
+ 	    return 1;
+-- 
+2.45.2
+
diff --git a/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch
new file mode 100644
index 0000000..3210c07
--- /dev/null
+++ b/0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch
@@ -0,0 +1,90 @@
+From 6dd62720fe84f7e2ad902c915b952fc0b29e3dcd Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 15 Feb 2022 11:34:37 +0200
+Subject: [PATCH] Swap over to dirfd+basename based operation within the fsm
+
+Within fsm this is just a matter of adjusting error messages to include
+the directory... if it only wasn't for the plugins requiring absolute
+paths for outside users. For the plugins, we need to assemble absolute
+paths as needed, both in ensureDir() and plugin file slots.
+---
+ lib/rpmplugins.c | 20 +++++++++++++++++---
+ 2 files changed, 36 insertions(+), 14 deletions(-)
+
+diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
+index 703368c0d..f06fd7895 100644
+--- a/lib/rpmplugins.c
++++ b/lib/rpmplugins.c
+@@ -350,21 +350,31 @@ rpmRC rpmpluginsCallScriptletPost(rpmPlugins plugins, const char *s_name, int ty
+     return rc;
+ }
+ 
++static char *abspath(rpmfi fi, const char *path)
++{
++    if (*path == '/')
++	return xstrdup(path);
++    else
++	return rstrscat(NULL, rpmfiDN(fi), path, NULL);
++}
++
+ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
+ 			       mode_t file_mode, rpmFsmOp op)
+ {
+     plugin_fsm_file_pre_func hookFunc;
+     int i;
+     rpmRC rc = RPMRC_OK;
++    char *apath = abspath(fi, path);
+ 
+     for (i = 0; i < plugins->count; i++) {
+ 	rpmPlugin plugin = plugins->plugins[i];
+ 	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);
+-	if (hookFunc && hookFunc(plugin, fi, path, file_mode, op) == RPMRC_FAIL) {
++	if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op) == RPMRC_FAIL) {
+ 	    rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);
+ 	    rc = RPMRC_FAIL;
+ 	}
+     }
++    free(apath);
+ 
+     return rc;
+ }
+@@ -375,14 +385,16 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,
+     plugin_fsm_file_post_func hookFunc;
+     int i;
+     rpmRC rc = RPMRC_OK;
++    char *apath = abspath(fi, path);
+ 
+     for (i = 0; i < plugins->count; i++) {
+ 	rpmPlugin plugin = plugins->plugins[i];
+ 	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_post);
+-	if (hookFunc && hookFunc(plugin, fi, path, file_mode, op, res) == RPMRC_FAIL) {
++	if (hookFunc && hookFunc(plugin, fi, apath, file_mode, op, res) == RPMRC_FAIL) {
+ 	    rpmlog(RPMLOG_WARNING, "Plugin %s: hook fsm_file_post failed\n", plugin->name);
+ 	}
+     }
++    free(apath);
+ 
+     return rc;
+ }
+@@ -394,15 +406,17 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+     plugin_fsm_file_prepare_func hookFunc;
+     int i;
+     rpmRC rc = RPMRC_OK;
++    char *apath = abspath(fi, path);
+ 
+     for (i = 0; i < plugins->count; i++) {
+ 	rpmPlugin plugin = plugins->plugins[i];
+ 	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_prepare);
+-	if (hookFunc && hookFunc(plugin, fi, fd, path, dest, file_mode, op) == RPMRC_FAIL) {
++	if (hookFunc && hookFunc(plugin, fi, fd, apath, dest, file_mode, op) == RPMRC_FAIL) {
+ 	    rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_prepare failed\n", plugin->name);
+ 	    rc = RPMRC_FAIL;
+ 	}
+     }
++    free(apath);
+ 
+     return rc;
+ }
+-- 
+2.41.0
+
diff --git a/0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch b/0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch
new file mode 100644
index 0000000..e198993
--- /dev/null
+++ b/0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch
@@ -0,0 +1,57 @@
+From d29651be364ef72c7c0f468157602e4ed5cab4ff Mon Sep 17 00:00:00 2001
+From: Florian Festi <ffesti@redhat.com>
+Date: Wed, 12 Jun 2024 15:46:12 +0200
+Subject: [PATCH] Talk about rpmsign in the rpmsign man page
+
+In the past handling signatures was done by the rpm / rpmbuild binaries
+directly. When this functionality was split into rpmsign the man page
+was not adjusted accoringly. This is the long overdue update.
+
+Resolves: # 3125
+
+(backported from commit 8e1f55c7004e8c1a7d9140ab2dd9456a7ace3e77)
+---
+ doc/rpmsign.8 | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
+index f7ceae89b..6c5bcc8ef 100644
+--- a/doc/rpmsign.8
++++ b/doc/rpmsign.8
+@@ -5,9 +5,9 @@ rpmsign \- RPM Package Signing
+ .SS "SIGNING PACKAGES:"
+ .PP
+ 
+-\fBrpm\fR \fB--addsign|--resign\fR [\fBrpmsign-options\fR] \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
++\fBrpmsign\fR \fB--addsign|--resign\fR [\fBrpmsign-options\fR] \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
+ 
+-\fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
++\fBrpmsign\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
+ 
+ .SS "rpmsign-options"
+ .PP
+@@ -22,10 +22,10 @@ options generate and insert new signatures for each package
+ existing signatures. There are two options for historical reasons,
+ there is no difference in behavior currently.
+ 
+-To create a signature rpm needs to verify the package's checksum. As a result
++To create a signature rpmsign needs to verify the package's checksum. As a result
+ packages with a MD5/SHA1 checksums cannot be signed in FIPS mode.
+ 
+-\fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
++\fBrpmsign\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
+ 
+ .PP
+ Delete all signatures from each package \fIPACKAGE_FILE\fR given.
+@@ -36,7 +36,7 @@ Delete all signatures from each package \fIPACKAGE_FILE\fR given.
+ \fB--rpmv3\fR
+ Force RPM V3 header+payload signature addition.
+ These are expensive and redundant baggage on packages where a separate
+-payload digest exists (packages built with rpm >= 4.14).  Rpm will
++payload digest exists (packages built with rpm >= 4.14).  Rpmsign will
+ automatically detect the need for V3 signatures, but this option can be
+ used to force their creation if the packages must be fully 
+ signature verifiable with rpm < 4.14 or other interoperability reasons.
+-- 
+2.45.2
+
diff --git a/0001-Use-file-state-machine-from-rpm-4.19.patch b/0001-Use-file-state-machine-from-rpm-4.19.patch
new file mode 100644
index 0000000..2bb5dd9
--- /dev/null
+++ b/0001-Use-file-state-machine-from-rpm-4.19.patch
@@ -0,0 +1,1631 @@
+From 36ee14a07630668629a0d461fba8b5b2248d7d71 Mon Sep 17 00:00:00 2001
+From: Florian Festi <ffesti@redhat.com>
+Date: Tue, 10 Oct 2023 16:46:17 +0200
+Subject: [PATCH] Use file state machine from rpm-4.19
+
+This new implementation fixes several race conditions when placing down
+files on disc
+---
+ lib/fsm.c        | 1164 +++++++++++++++++++++++++---------------------
+ lib/rpmarchive.h |    3 +
+ lib/rpmfiles.h   |    3 +
+
+diff --git a/lib/rpmarchive.h b/lib/rpmarchive.h
+index c864e5b56..e5cda4f97 100644
+--- a/lib/rpmarchive.h
++++ b/lib/rpmarchive.h
+@@ -26,6 +26,8 @@ enum rpmfilesErrorCodes {
+ 	RPMERR_FILE_SIZE	= -12,
+ 	RPMERR_ITER_SKIP	= -13,
+ 	RPMERR_EXIST_AS_DIR	= -14,
++	RPMERR_INVALID_SYMLINK  = -15,
++	RPMERR_ENOTDIR          = -16,
+ 
+ 	RPMERR_OPEN_FAILED	= -32768,
+ 	RPMERR_CHMOD_FAILED	= -32769,
+@@ -47,6 +49,7 @@ enum rpmfilesErrorCodes {
+ 	RPMERR_COPY_FAILED	= -32785,
+ 	RPMERR_LSETFCON_FAILED	= -32786,
+ 	RPMERR_SETCAP_FAILED	= -32787,
++	RPMERR_CLOSE_FAILED     = -32788,
+ };
+ 
+ #ifdef __cplusplus
+diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
+index daf572cf4..e74bb2201 100644
+--- a/lib/rpmfiles.h
++++ b/lib/rpmfiles.h
+@@ -90,6 +90,9 @@ typedef enum rpmFileAction_e {
+ #define XFA_SKIPPING(_a)	\
+     ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR)
+ 
++#define XFA_CREATING(_a)	\
++    ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME)
++
+ /**
+  * We pass these around as an array with a sentinel.
+  */
+--- rpm-4.16.1.3/lib/fsm.c.orig	2023-11-11 10:05:19.208206675 +0100
++++ rpm-4.16.1.3/lib/fsm.c	2023-11-11 10:05:43.559432708 +0100
+@@ -5,9 +5,11 @@
+ 
+ #include "system.h"
+ 
++#include <inttypes.h>
+ #include <utime.h>
+ #include <errno.h>
+-#if WITH_CAP
++#include <fcntl.h>
++#ifdef WITH_CAP
+ #include <sys/capability.h>
+ #endif
+ 
+@@ -17,10 +19,11 @@
+ #include <rpm/rpmmacro.h>
+ 
+ #include "rpmio/rpmio_internal.h"	/* fdInit/FiniDigest */
+-#include "lib/fsm.h"
+-#include "lib/rpmte_internal.h"	/* XXX rpmfs */
+-#include "lib/rpmplugins.h"	/* rpm plugins hooks */
+-#include "lib/rpmug.h"
++#include "fsm.h"
++#include "rpmte_internal.h"	/* XXX rpmfs */
++#include "rpmfi_internal.h" /* rpmfiSetOnChdir */
++#include "rpmplugins.h"	/* rpm plugins hooks */
++#include "rpmug.h"
+ 
+ #include "debug.h"
+ 
+@@ -38,172 +41,92 @@
+ #define _dirPerms 0755
+ #define _filePerms 0644
+ 
++enum filestage_e {
++    FILE_COMMIT = -1,
++    FILE_NONE   = 0,
++    FILE_PRE    = 1,
++    FILE_UNPACK = 2,
++    FILE_PREP   = 3,
++    FILE_POST   = 4,
++};
++
++struct filedata_s {
++    int stage;
++    int setmeta;
++    int skip;
++    rpmFileAction action;
++    const char *suffix;
++    char *fpath;
++    struct stat sb;
++};
++
+ /* 
+  * XXX Forward declarations for previously exported functions to avoid moving 
+  * things around needlessly 
+  */ 
+ static const char * fileActionString(rpmFileAction a);
++static int fsmOpenat(int dirfd, const char *path, int flags, int dir);
++static int fsmClose(int *wfdp);
+ 
+ /** \ingroup payload
+  * Build path to file from file info, optionally ornamented with suffix.
++ * "/" needs special handling to avoid appearing as empty path.
+  * @param fi		file info iterator
+  * @param suffix	suffix to use (NULL disables)
+- * @retval		path to file (malloced)
++ * @param[out]		path to file (malloced)
+  */
+ static char * fsmFsPath(rpmfi fi, const char * suffix)
+ {
+-    return rstrscat(NULL, rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL);
+-}
+-
+-/** \ingroup payload
+- * Directory name iterator.
+- */
+-typedef struct dnli_s {
+-    rpmfiles fi;
+-    char * active;
+-    int reverse;
+-    int isave;
+-    int i;
+-} * DNLI_t;
+-
+-/** \ingroup payload
+- * Destroy directory name iterator.
+- * @param dnli		directory name iterator
+- * @retval		NULL always
+- */
+-static DNLI_t dnlFreeIterator(DNLI_t dnli)
+-{
+-    if (dnli) {
+-	if (dnli->active) free(dnli->active);
+-	free(dnli);
+-    }
+-    return NULL;
++    const char *bn = rpmfiBN(fi);
++    return rstrscat(NULL, *bn ? bn : "/", suffix ? suffix : "", NULL);
+ }
+ 
+-/** \ingroup payload
+- * Create directory name iterator.
+- * @param fi		file info set
+- * @param fs		file state set
+- * @param reverse	traverse directory names in reverse order?
+- * @return		directory name iterator
+- */
+-static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse)
++static int fsmLink(int odirfd, const char *opath, int dirfd, const char *path)
+ {
+-    DNLI_t dnli;
+-    int i, j;
+-    int dc;
+-
+-    if (fi == NULL)
+-	return NULL;
+-    dc = rpmfilesDC(fi);
+-    dnli = xcalloc(1, sizeof(*dnli));
+-    dnli->fi = fi;
+-    dnli->reverse = reverse;
+-    dnli->i = (reverse ? dc : 0);
+-
+-    if (dc) {
+-	dnli->active = xcalloc(dc, sizeof(*dnli->active));
+-	int fc = rpmfilesFC(fi);
+-
+-	/* Identify parent directories not skipped. */
+-	for (i = 0; i < fc; i++)
+-            if (!XFA_SKIPPING(rpmfsGetAction(fs, i)))
+-		dnli->active[rpmfilesDI(fi, i)] = 1;
+-
+-	/* Exclude parent directories that are explicitly included. */
+-	for (i = 0; i < fc; i++) {
+-	    int dil;
+-	    size_t dnlen, bnlen;
++    int rc = linkat(odirfd, opath, dirfd, path, 0);
+ 
+-	    if (!S_ISDIR(rpmfilesFMode(fi, i)))
+-		continue;
+-
+-	    dil = rpmfilesDI(fi, i);
+-	    dnlen = strlen(rpmfilesDN(fi, dil));
+-	    bnlen = strlen(rpmfilesBN(fi, i));
+-
+-	    for (j = 0; j < dc; j++) {
+-		const char * dnl;
+-		size_t jlen;
+-
+-		if (!dnli->active[j] || j == dil)
+-		    continue;
+-		dnl = rpmfilesDN(fi, j);
+-		jlen = strlen(dnl);
+-		if (jlen != (dnlen+bnlen+1))
+-		    continue;
+-		if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen))
+-		    continue;
+-		if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen))
+-		    continue;
+-		if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
+-		    continue;
+-		/* This directory is included in the package. */
+-		dnli->active[j] = 0;
+-		break;
+-	    }
+-	}
+-
+-	/* Print only once per package. */
+-	if (!reverse) {
+-	    j = 0;
+-	    for (i = 0; i < dc; i++) {
+-		if (!dnli->active[i]) continue;
+-		if (j == 0) {
+-		    j = 1;
+-		    rpmlog(RPMLOG_DEBUG,
+-	"========== Directories not explicitly included in package:\n");
+-		}
+-		rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i));
+-	    }
+-	    if (j)
+-		rpmlog(RPMLOG_DEBUG, "==========\n");
+-	}
++    if (_fsm_debug) {
++	rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__,
++	       odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : ""));
+     }
+-    return dnli;
++
++    if (rc < 0)
++	rc = RPMERR_LINK_FAILED;
++    return rc;
+ }
+ 
+-/** \ingroup payload
+- * Return next directory name (from file info).
+- * @param dnli		directory name iterator
+- * @return		next directory name
+- */
+-static
+-const char * dnlNextIterator(DNLI_t dnli)
++#ifdef WITH_CAP
++static int cap_set_fileat(int dirfd, const char *path, cap_t fcaps)
+ {
+-    const char * dn = NULL;
+-
+-    if (dnli) {
+-	rpmfiles fi = dnli->fi;
+-	int dc = rpmfilesDC(fi);
+-	int i = -1;
+-
+-	if (dnli->active)
+-	do {
+-	    i = (!dnli->reverse ? dnli->i++ : --dnli->i);
+-	} while (i >= 0 && i < dc && !dnli->active[i]);
+-
+-	if (i >= 0 && i < dc)
+-	    dn = rpmfilesDN(fi, i);
+-	else
+-	    i = -1;
+-	dnli->isave = i;
++    int rc = -1;
++    int fd = fsmOpenat(dirfd, path, O_RDONLY|O_NOFOLLOW, 0);
++    if (fd >= 0) {
++	rc = cap_set_fd(fd, fcaps);
++	fsmClose(&fd);
+     }
+-    return dn;
++    return rc;
+ }
++#endif
+ 
+-static int fsmSetFCaps(const char *path, const char *captxt)
++static int fsmSetFCaps(int fd, int dirfd, const char *path, const char *captxt)
+ {
+     int rc = 0;
+-#if WITH_CAP
++
++#ifdef WITH_CAP
+     if (captxt && *captxt != '\0') {
+ 	cap_t fcaps = cap_from_text(captxt);
+-	if (fcaps == NULL || cap_set_file(path, fcaps) != 0) {
+-	    rc = RPMERR_SETCAP_FAILED;
++
++	if (fd >= 0) {
++	    if (fcaps == NULL || cap_set_fd(fd, fcaps))
++		rc = RPMERR_SETCAP_FAILED;
++	} else {
++	    if (fcaps == NULL || cap_set_fileat(dirfd, path, fcaps))
++		rc = RPMERR_SETCAP_FAILED;
+ 	}
++
+ 	if (_fsm_debug) {
+-	    rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
+-		   path, captxt, (rc < 0 ? strerror(errno) : ""));
++	    rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %s) %s\n", __func__,
++		   fd, dirfd, path, captxt, (rc < 0 ? strerror(errno) : ""));
+ 	}
+ 	cap_free(fcaps);
+     } 
+@@ -211,101 +134,104 @@
+     return rc;
+ }
+ 
+-static void wfd_close(FD_t *wfdp)
++static int fsmClose(int *wfdp)
+ {
+-    if (wfdp && *wfdp) {
++    int rc = 0;
++    if (wfdp && *wfdp >= 0) {
+ 	int myerrno = errno;
+ 	static int oneshot = 0;
+ 	static int flush_io = 0;
++	int fdno = *wfdp;
++
+ 	if (!oneshot) {
+ 	    flush_io = (rpmExpandNumeric("%{?_flush_io}") > 0);
+ 	    oneshot = 1;
+ 	}
+ 	if (flush_io) {
+-	    int fdno = Fileno(*wfdp);
+ 	    fsync(fdno);
+ 	}
+-	Fclose(*wfdp);
+-	*wfdp = NULL;
++	if (close(fdno))
++	    rc = RPMERR_CLOSE_FAILED;
++
++	if (_fsm_debug) {
++	    rpmlog(RPMLOG_DEBUG, " %8s ([%d]) %s\n", __func__,
++		   fdno, (rc < 0 ? strerror(errno) : ""));
++	}
++	*wfdp = -1;
+ 	errno = myerrno;
+     }
++    return rc;
+ }
+ 
+-static int wfd_open(FD_t *wfdp, const char *dest)
++static int fsmOpen(int *wfdp, int dirfd, const char *dest)
+ {
+     int rc = 0;
+     /* Create the file with 0200 permissions (write by owner). */
+-    {
+-	mode_t old_umask = umask(0577);
+-	*wfdp = Fopen(dest, "wx.ufdio");
+-	umask(old_umask);
+-    }
+-    if (Ferror(*wfdp)) {
++    int fd = openat(dirfd, dest, O_WRONLY|O_EXCL|O_CREAT, 0200);
++
++    if (fd < 0)
+ 	rc = RPMERR_OPEN_FAILED;
+-	goto exit;
+-    }
+ 
+-    return 0;
++    if (_fsm_debug) {
++	rpmlog(RPMLOG_DEBUG, " %8s (%s [%d]) %s\n", __func__,
++	       dest, fd, (rc < 0 ? strerror(errno) : ""));
++    }
++    *wfdp = fd;
+ 
+-exit:
+-    wfd_close(wfdp);
+     return rc;
+ }
+ 
+-/** \ingroup payload
+- * Create file from payload stream.
+- * @return		0 on success
+- */
+-static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest)
++static int fsmUnpack(rpmfi fi, int fdno, rpmpsm psm, int nodigest)
+ {
+-    FD_t wfd = NULL;
+-    int rc;
+-
+-    rc = wfd_open(&wfd, dest);
+-    if (rc != 0)
+-        goto exit;
+-
+-    rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm);
+-    wfd_close(&wfd);
+-exit:
++    FD_t fd = fdDup(fdno);
++    int rc = rpmfiArchiveReadToFilePsm(fi, fd, nodigest, psm);
++    if (_fsm_debug) {
++	rpmlog(RPMLOG_DEBUG, " %8s (%s %" PRIu64 " bytes [%d]) %s\n", __func__,
++	       rpmfiFN(fi), rpmfiFSize(fi), Fileno(fd),
++	       (rc < 0 ? strerror(errno) : ""));
++    }
++    Fclose(fd);
+     return rc;
+ }
+ 
+-static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
+-		     rpmpsm psm, int nodigest, int *setmeta,
+-		     int * firsthardlink, FD_t *firstlinkfile)
++static int fsmMkfile(int dirfd, rpmfi fi, struct filedata_s *fp, rpmfiles files,
++		     rpmpsm psm, int nodigest,
++		     struct filedata_s ** firstlink, int *firstlinkfile,
++		     int *firstdir, int *fdp)
+ {
+     int rc = 0;
+-    int numHardlinks = rpmfiFNlink(fi);
++    int fd = -1;
+ 
+-    if (numHardlinks > 1) {
+-	/* Create first hardlinked file empty */
+-	if (*firsthardlink < 0) {
+-	    *firsthardlink = rpmfiFX(fi);
+-	    rc = wfd_open(firstlinkfile, dest);
+-	} else {
+-	    /* Create hard links for others */
+-	    char *fn = rpmfilesFN(files, *firsthardlink);
+-	    rc = link(fn, dest);
+-	    if (rc < 0) {
+-		rc = RPMERR_LINK_FAILED;
+-	    }
+-	    free(fn);
++    if (*firstlink == NULL) {
++	/* First encounter, open file for writing */
++	rc = fsmOpen(&fd, dirfd, fp->fpath);
++	/* If it's a part of a hardlinked set, the content may come later */
++	if (fp->sb.st_nlink > 1) {
++	    *firstlink = fp;
++	    *firstlinkfile = fd;
++	    *firstdir = dup(dirfd);
++	}
++    } else {
++	/* Create hard links for others and avoid redundant metadata setting */
++	if (*firstlink != fp) {
++	    rc = fsmLink(*firstdir, (*firstlink)->fpath, dirfd, fp->fpath);
+ 	}
++	fd = *firstlinkfile;
+     }
+-    /* Write normal files or fill the last hardlinked (already
+-       existing) file with content */
+-    if (numHardlinks<=1) {
+-	if (!rc)
+-	    rc = expandRegular(fi, dest, psm, nodigest);
+-    } else if (rpmfiArchiveHasContent(fi)) {
++
++    /* If the file has content, unpack it */
++    if (rpmfiArchiveHasContent(fi)) {
+ 	if (!rc)
+-	    rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
+-	wfd_close(firstlinkfile);
+-	*firsthardlink = -1;
+-    } else {
+-	*setmeta = 0;
++	    rc = fsmUnpack(fi, fd, psm, nodigest);
++	/* Last file of hardlink set, ensure metadata gets set */
++	if (*firstlink) {
++	    fp->setmeta = 1;
++	    *firstlink = NULL;
++	    *firstlinkfile = -1;
++	    fsmClose(firstdir);
++	}
+     }
++    *fdp = fd;
+ 
+     return rc;
+ }
+@@ -330,18 +256,15 @@
+     return rc;
+ }
+ 
+-static int fsmStat(const char *path, int dolstat, struct stat *sb)
++static int fsmStat(int dirfd, const char *path, int dolstat, struct stat *sb)
+ {
+-    int rc;
+-    if (dolstat){
+-	rc = lstat(path, sb);
+-    } else {
+-        rc = stat(path, sb);
+-    }
++    int flags = dolstat ? AT_SYMLINK_NOFOLLOW : 0;
++    int rc = fstatat(dirfd, path, sb, flags);
++
+     if (_fsm_debug && rc && errno != ENOENT)
+-        rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n",
++        rpmlog(RPMLOG_DEBUG, " %8s (%d %s, ost) %s\n",
+                __func__,
+-               path, (rc < 0 ? strerror(errno) : ""));
++               dirfd, path, (rc < 0 ? strerror(errno) : ""));
+     if (rc < 0) {
+         rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_LSTAT_FAILED);
+ 	/* Ensure consistent struct content on failure */
+@@ -350,12 +273,12 @@
+     return rc;
+ }
+ 
+-static int fsmRmdir(const char *path)
++static int fsmRmdir(int dirfd, const char *path)
+ {
+-    int rc = rmdir(path);
++    int rc = unlinkat(dirfd, path, AT_REMOVEDIR);
+     if (_fsm_debug)
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__,
+-	       path, (rc < 0 ? strerror(errno) : ""));
++	rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__,
++	       dirfd, path, (rc < 0 ? strerror(errno) : ""));
+     if (rc < 0)
+ 	switch (errno) {
+ 	case ENOENT:        rc = RPMERR_ENOENT;    break;
+@@ -365,148 +288,194 @@
+     return rc;
+ }
+ 
+-static int fsmMkdir(const char *path, mode_t mode)
++static int fsmMkdir(int dirfd, const char *path, mode_t mode)
+ {
+-    int rc = mkdir(path, (mode & 07777));
++    int rc = mkdirat(dirfd, path, (mode & 07777));
+     if (_fsm_debug)
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
+-	       path, (unsigned)(mode & 07777),
++	rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n", __func__,
++	       dirfd, path, (unsigned)(mode & 07777),
+ 	       (rc < 0 ? strerror(errno) : ""));
+     if (rc < 0)	rc = RPMERR_MKDIR_FAILED;
+     return rc;
+ }
+ 
+-static int fsmMkfifo(const char *path, mode_t mode)
++static int fsmOpenat(int dirfd, const char *path, int flags, int dir)
+ {
+-    int rc = mkfifo(path, (mode & 07777));
+-
+-    if (_fsm_debug) {
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n",
+-	       __func__, path, (unsigned)(mode & 07777),
+-	       (rc < 0 ? strerror(errno) : ""));
++    struct stat lsb, sb;
++    int sflags = flags | O_NOFOLLOW;
++    int fd = openat(dirfd, path, sflags);
++
++    /*
++     * Only ever follow symlinks by root or target owner. Since we can't
++     * open the symlink itself, the order matters: we stat the link *after*
++     * opening the target, and if the link ownership changed between the calls
++     * it could've only been the link owner or root.
++     */
++    if (fd < 0 && errno == ELOOP && flags != sflags) {
++	int ffd = openat(dirfd, path, flags);
++	if (ffd >= 0) {
++	    if (fstatat(dirfd, path, &lsb, AT_SYMLINK_NOFOLLOW) == 0) {
++		if (fstat(ffd, &sb) == 0) {
++		    if (lsb.st_uid == 0 || lsb.st_uid == sb.st_uid) {
++			fd = ffd;
++		    }
++		}
++	    }
++	    if (ffd != fd)
++		close(ffd);
++	}
+     }
+ 
+-    if (rc < 0)
+-	rc = RPMERR_MKFIFO_FAILED;
+-
+-    return rc;
++    /* O_DIRECTORY equivalent */
++    if (dir && fd >= 0 && fstat(fd, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
++	errno = ENOTDIR;
++	fsmClose(&fd);
++    }
++    return fd;
+ }
+ 
+-static int fsmMknod(const char *path, mode_t mode, dev_t dev)
++static int fsmDoMkDir(rpmPlugins plugins, int dirfd, const char *dn,
++			const char *apath,
++			int owned, mode_t mode, int *fdp)
+ {
+-    /* FIX: check S_IFIFO or dev != 0 */
+-    int rc = mknod(path, (mode & ~07777), dev);
++    int rc;
++    rpmFsmOp op = (FA_CREATE);
++    if (!owned)
++	op |= FAF_UNOWNED;
+ 
+-    if (_fsm_debug) {
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n",
+-	       __func__, path, (unsigned)(mode & ~07777),
+-	       (unsigned)dev, (rc < 0 ? strerror(errno) : ""));
++    /* Run fsm file pre hook for all plugins */
++    rc = rpmpluginsCallFsmFilePre(plugins, NULL, apath, mode, op);
++
++    if (!rc)
++	rc = fsmMkdir(dirfd, dn, mode);
++
++    if (!rc) {
++	*fdp = fsmOpenat(dirfd, dn, O_RDONLY|O_NOFOLLOW, 1);
++	if (*fdp == -1)
++	    rc = RPMERR_ENOTDIR;
+     }
+ 
+-    if (rc < 0)
+-	rc = RPMERR_MKNOD_FAILED;
++    if (!rc) {
++	rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, *fdp, apath, apath, mode, op);
++    }
++
++    /* Run fsm file post hook for all plugins */
++    rpmpluginsCallFsmFilePost(plugins, NULL, apath, mode, op, rc);
++
++    if (!rc) {
++	rpmlog(RPMLOG_DEBUG,
++		"%s directory created with perms %04o\n",
++		apath, (unsigned)(mode & 07777));
++    }
+ 
+     return rc;
+ }
+ 
+-/**
+- * Create (if necessary) directories not explicitly included in package.
+- * @param files		file data
+- * @param fs		file states
+- * @param plugins	rpm plugins handle
+- * @return		0 on success
+- */
+-static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins)
++static int ensureDir(rpmPlugins plugins, const char *p, int owned, int create,
++		    int quiet, int *dirfdp)
+ {
+-    DNLI_t dnli = dnlInitIterator(files, fs, 0);
+-    struct stat sb;
+-    const char *dpath;
++    char *sp = NULL, *bn;
++    char *apath = NULL;
++    int oflags = O_RDONLY;
+     int rc = 0;
+-    int i;
+-    size_t ldnlen = 0;
+-    const char * ldn = NULL;
+-
+-    while ((dpath = dnlNextIterator(dnli)) != NULL) {
+-	size_t dnlen = strlen(dpath);
+-	char * te, dn[dnlen+1];
+ 
+-	if (dnlen <= 1)
+-	    continue;
++    if (*dirfdp >= 0)
++	return rc;
+ 
+-	if (dnlen == ldnlen && rstreq(dpath, ldn))
+-	    continue;
++    int dirfd = fsmOpenat(-1, "/", oflags, 1);
++    int fd = dirfd; /* special case of "/" */
+ 
+-	/* Copy as we need to modify the string */
+-	(void) stpcpy(dn, dpath);
++    char *path = xstrdup(p);
++    char *dp = path;
+ 
+-	/* Assume '/' directory exists, "mkdir -p" for others if non-existent */
+-	for (i = 1, te = dn + 1; *te != '\0'; te++, i++) {
+-	    if (*te != '/')
+-		continue;
++    while ((bn = strtok_r(dp, "/", &sp)) != NULL) {
++	fd = fsmOpenat(dirfd, bn, oflags, 1);
++	/* assemble absolute path for plugins benefit, sigh */
++	apath = rstrscat(&apath, "/", bn, NULL);
++
++	if (fd < 0 && errno == ENOENT && create) {
++	    mode_t mode = S_IFDIR | (_dirPerms & 07777);
++	    rc = fsmDoMkDir(plugins, dirfd, bn, apath, owned, mode, &fd);
++	}
+ 
+-	    /* Already validated? */
+-	    if (i < ldnlen &&
+-		(ldn[i] == '/' || ldn[i] == '\0') && rstreqn(dn, ldn, i))
+-		continue;
++	fsmClose(&dirfd);
++	if (fd >= 0) {
++	    dirfd = fd;
++	} else {
++	    if (!quiet) {
++		rpmlog(RPMLOG_ERR, _("failed to open dir %s of %s: %s\n"),
++			bn, p, strerror(errno));
++	    }
++	    rc = RPMERR_OPEN_FAILED;
++	    break;
++	}
+ 
+-	    /* Validate next component of path. */
+-	    *te = '\0';
+-	    rc = fsmStat(dn, 1, &sb); /* lstat */
+-	    *te = '/';
++	dp = NULL;
++    }
+ 
+-	    /* Directory already exists? */
+-	    if (rc == 0 && S_ISDIR(sb.st_mode)) {
+-		continue;
+-	    } else if (rc == RPMERR_ENOENT) {
+-		*te = '\0';
+-		mode_t mode = S_IFDIR | (_dirPerms & 07777);
+-		rpmFsmOp op = (FA_CREATE|FAF_UNOWNED);
+-
+-		/* Run fsm file pre hook for all plugins */
+-		rc = rpmpluginsCallFsmFilePre(plugins, NULL, dn, mode, op);
+-
+-		if (!rc)
+-		    rc = fsmMkdir(dn, mode);
+-
+-		if (!rc) {
+-		    rc = rpmpluginsCallFsmFilePrepare(plugins, NULL, dn, dn,
+-						      mode, op);
+-		}
++    if (rc) {
++	fsmClose(&fd);
++	fsmClose(&dirfd);
++    } else {
++	rc = 0;
++    }
++    *dirfdp = dirfd;
+ 
+-		/* Run fsm file post hook for all plugins */
+-		rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc);
++    if (_fsm_debug) {
++	rpmlog(RPMLOG_DEBUG, " %8s (%s: %d) %s\n", __func__,
++		p, dirfd, (rc < 0 ? strerror(errno) : ""));
++    }
+ 
+-		if (!rc) {
+-		    rpmlog(RPMLOG_DEBUG,
+-			    "%s directory created with perms %04o\n",
+-			    dn, (unsigned)(mode & 07777));
+-		}
+-		*te = '/';
+-	    }
+-	    if (rc)
+-		break;
+-	}
+-	if (rc) break;
++    free(path);
++    free(apath);
++    return rc;
++}
+ 
+-	/* Save last validated path. */
+-	ldn = dpath;
+-	ldnlen = dnlen;
++static int fsmMkfifo(int dirfd, const char *path, mode_t mode)
++{
++    int rc = mkfifoat(dirfd, path, (mode & 07777));
++
++    if (_fsm_debug) {
++	rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%04o) %s\n",
++	       __func__, dirfd, path, (unsigned)(mode & 07777),
++	       (rc < 0 ? strerror(errno) : ""));
+     }
+-    dnlFreeIterator(dnli);
++
++    if (rc < 0)
++	rc = RPMERR_MKFIFO_FAILED;
+ 
+     return rc;
+ }
+ 
+-static void removeSBITS(const char *path)
++static int fsmMknod(int dirfd, const char *path, mode_t mode, dev_t dev)
++{
++    /* FIX: check S_IFIFO or dev != 0 */
++    int rc = mknodat(dirfd, path, (mode & ~07777), dev);
++
++    if (_fsm_debug) {
++	rpmlog(RPMLOG_DEBUG, " %8s (%d %s, 0%o, 0x%x) %s\n",
++	       __func__, dirfd, path, (unsigned)(mode & ~07777),
++	       (unsigned)dev, (rc < 0 ? strerror(errno) : ""));
++    }
++
++    if (rc < 0)
++	rc = RPMERR_MKNOD_FAILED;
++
++    return rc;
++}
++
++static void removeSBITS(int dirfd, const char *path)
+ {
+     struct stat stb;
+-    if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)) {
++    int flags = AT_SYMLINK_NOFOLLOW;
++    if (fstatat(dirfd, path, &stb, flags) == 0 && S_ISREG(stb.st_mode)) {
++    	/* We now know it's not a link so no need to worry about following */
+ 	if ((stb.st_mode & 06000) != 0) {
+-	    (void) chmod(path, stb.st_mode & 0777);
++	    (void) fchmodat(dirfd, path, stb.st_mode & 0777, 0);
+ 	}
+-#if WITH_CAP
++#ifdef WITH_CAP
+ 	if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
+-	    (void) cap_set_file(path, NULL);
++	    (void) cap_set_fileat(dirfd, path, NULL);
+ 	}
+ #endif
+     }
+@@ -522,13 +491,13 @@
+ 	    (fpath ? fpath : ""));
+ }
+ 
+-static int fsmSymlink(const char *opath, const char *path)
++static int fsmSymlink(const char *opath, int dirfd, const char *path)
+ {
+-    int rc = symlink(opath, path);
++    int rc = symlinkat(opath, dirfd, path);
+ 
+     if (_fsm_debug) {
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
+-	       opath, path, (rc < 0 ? strerror(errno) : ""));
++	rpmlog(RPMLOG_DEBUG, " %8s (%s, %d %s) %s\n", __func__,
++	       opath, dirfd, path, (rc < 0 ? strerror(errno) : ""));
+     }
+ 
+     if (rc < 0)
+@@ -536,96 +505,125 @@
+     return rc;
+ }
+ 
+-static int fsmUnlink(const char *path)
++static int fsmUnlink(int dirfd, const char *path)
+ {
+     int rc = 0;
+-    removeSBITS(path);
+-    rc = unlink(path);
++    removeSBITS(dirfd, path);
++    rc = unlinkat(dirfd, path, 0);
+     if (_fsm_debug)
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__,
+-	       path, (rc < 0 ? strerror(errno) : ""));
++	rpmlog(RPMLOG_DEBUG, " %8s (%d %s) %s\n", __func__,
++	       dirfd, path, (rc < 0 ? strerror(errno) : ""));
+     if (rc < 0)
+ 	rc = (errno == ENOENT ? RPMERR_ENOENT : RPMERR_UNLINK_FAILED);
+     return rc;
+ }
+ 
+-static int fsmRename(const char *opath, const char *path)
++static int fsmRename(int odirfd, const char *opath, int dirfd, const char *path)
+ {
+-    removeSBITS(path);
+-    int rc = rename(opath, path);
++    removeSBITS(dirfd, path);
++    int rc = renameat(odirfd, opath, dirfd, path);
+ #if defined(ETXTBSY) && defined(__HPUX__)
+     /* XXX HP-UX (and other os'es) don't permit rename to busy files. */
+     if (rc && errno == ETXTBSY) {
+ 	char *rmpath = NULL;
+ 	rstrscat(&rmpath, path, "-RPMDELETE", NULL);
+-	rc = rename(path, rmpath);
+-	if (!rc) rc = rename(opath, path);
++	/* Rename within the original directory */
++	rc = renameat(odirfd, path, odirfd, rmpath);
++	if (!rc) rc = renameat(odirfd, opath, dirfd, path);
+ 	free(rmpath);
+     }
+ #endif
+     if (_fsm_debug)
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
+-	       opath, path, (rc < 0 ? strerror(errno) : ""));
++	rpmlog(RPMLOG_DEBUG, " %8s (%d %s, %d %s) %s\n", __func__,
++	       odirfd, opath, dirfd, path, (rc < 0 ? strerror(errno) : ""));
+     if (rc < 0)
+ 	rc = (errno == EISDIR ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED);
+     return rc;
+ }
+ 
+-static int fsmRemove(const char *path, mode_t mode)
++static int fsmRemove(int dirfd, const char *path, mode_t mode)
+ {
+-    return S_ISDIR(mode) ? fsmRmdir(path) : fsmUnlink(path);
++    return S_ISDIR(mode) ? fsmRmdir(dirfd, path) : fsmUnlink(dirfd, path);
+ }
+ 
+-static int fsmChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
++static int fsmChown(int fd, int dirfd, const char *path, mode_t mode, uid_t uid, gid_t gid)
+ {
+-    int rc = S_ISLNK(mode) ? lchown(path, uid, gid) : chown(path, uid, gid);
+-    if (rc < 0) {
+-	struct stat st;
+-	if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
+-	    rc = 0;
++    int rc;
++    struct stat st;
++
++    if (fd >= 0) {
++	rc = fchown(fd, uid, gid);
++	if (rc < 0) {
++	    if (fstat(fd, &st) == 0 && (st.st_uid == uid && st.st_gid == gid)) {
++		rc = 0;
++	    }
++	}
++    } else {
++	int flags = AT_SYMLINK_NOFOLLOW;
++	rc = fchownat(dirfd, path, uid, gid, flags);
++	if (rc < 0) {
++	    struct stat st;
++	    if (fstatat(dirfd, path, &st, flags) == 0 &&
++		    (st.st_uid == uid && st.st_gid == gid)) {
++		rc = 0;
++	    }
++	}
+     }
+-    if (_fsm_debug)
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__,
+-	       path, (int)uid, (int)gid,
++    if (_fsm_debug) {
++	rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, %d, %d) %s\n", __func__,
++	       fd, dirfd, path, (int)uid, (int)gid,
+ 	       (rc < 0 ? strerror(errno) : ""));
++    }
+     if (rc < 0)	rc = RPMERR_CHOWN_FAILED;
+     return rc;
+ }
+ 
+-static int fsmChmod(const char *path, mode_t mode)
++static int fsmChmod(int fd, int dirfd, const char *path, mode_t mode)
+ {
+-    int rc = chmod(path, (mode & 07777));
+-    if (rc < 0) {
+-	struct stat st;
+-	if (lstat(path, &st) == 0 && (st.st_mode & 07777) == (mode & 07777))
+-	    rc = 0;
++    mode_t fmode = (mode & 07777);
++    int rc;
++    if (fd >= 0) {
++	rc = fchmod(fd, fmode);
++	if (rc < 0) {
++	    struct stat st;
++	    if (fstat(fd, &st) == 0 && (st.st_mode & 07777) == fmode) {
++		rc = 0;
++	    }
++	}
++    } else {
++	rc = fchmodat(dirfd, path, fmode, 0);
++	if (rc < 0) {
++	    struct stat st;
++	    if (fstatat(dirfd, path, &st, AT_SYMLINK_NOFOLLOW) == 0 &&
++		    (st.st_mode & 07777) == fmode) {
++		rc = 0;
++	    }
++	}
+     }
+     if (_fsm_debug)
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
+-	       path, (unsigned)(mode & 07777),
++	rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0%04o) %s\n", __func__,
++	       fd, dirfd, path, (unsigned)(mode & 07777),
+ 	       (rc < 0 ? strerror(errno) : ""));
+     if (rc < 0)	rc = RPMERR_CHMOD_FAILED;
+     return rc;
+ }
+ 
+-static int fsmUtime(const char *path, mode_t mode, time_t mtime)
++static int fsmUtime(int fd, int dirfd, const char *path, mode_t mode, time_t mtime)
+ {
+     int rc = 0;
+-    struct timeval stamps[2] = {
+-	{ .tv_sec = mtime, .tv_usec = 0 },
+-	{ .tv_sec = mtime, .tv_usec = 0 },
++    struct timespec stamps[2] = {
++	{ .tv_sec = mtime, .tv_nsec = 0 },
++	{ .tv_sec = mtime, .tv_nsec = 0 },
+     };
+ 
+-#if HAVE_LUTIMES
+-    rc = lutimes(path, stamps);
+-#else
+-    if (!S_ISLNK(mode))
+-	rc = utimes(path, stamps);
+-#endif
++    if (fd >= 0)
++	rc = futimens(fd, stamps);
++    else
++	rc = utimensat(dirfd, path, stamps, AT_SYMLINK_NOFOLLOW);
+     
+     if (_fsm_debug)
+-	rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__,
+-	       path, (unsigned)mtime, (rc < 0 ? strerror(errno) : ""));
++	rpmlog(RPMLOG_DEBUG, " %8s (%d - %d %s, 0x%x) %s\n", __func__,
++	       fd, dirfd, path, (unsigned)mtime, (rc < 0 ? strerror(errno) : ""));
+     if (rc < 0)	rc = RPMERR_UTIME_FAILED;
+     /* ...but utime error is not critical for directories */
+     if (rc && S_ISDIR(mode))
+@@ -633,24 +631,24 @@
+     return rc;
+ }
+ 
+-static int fsmVerify(const char *path, rpmfi fi)
++static int fsmVerify(int dirfd, const char *path, rpmfi fi)
+ {
+     int rc;
+     int saveerrno = errno;
+     struct stat dsb;
+     mode_t mode = rpmfiFMode(fi);
+ 
+-    rc = fsmStat(path, 1, &dsb);
++    rc = fsmStat(dirfd, path, 1, &dsb);
+     if (rc)
+ 	return rc;
+ 
+     if (S_ISREG(mode)) {
+ 	/* HP-UX (and other os'es) don't permit unlink on busy files. */
+ 	char *rmpath = rstrscat(NULL, path, "-RPMDELETE", NULL);
+-	rc = fsmRename(path, rmpath);
++	rc = fsmRename(dirfd, path, dirfd, rmpath);
+ 	/* XXX shouldn't we take unlink return code here? */
+ 	if (!rc)
+-	    (void) fsmUnlink(rmpath);
++	    (void) fsmUnlink(dirfd, rmpath);
+ 	else
+ 	    rc = RPMERR_UNLINK_FAILED;
+ 	free(rmpath);
+@@ -659,7 +657,7 @@
+         if (S_ISDIR(dsb.st_mode)) return 0;
+         if (S_ISLNK(dsb.st_mode)) {
+ 	    uid_t luid = dsb.st_uid;
+-            rc = fsmStat(path, 0, &dsb);
++            rc = fsmStat(dirfd, path, 0, &dsb);
+             if (rc == RPMERR_ENOENT) rc = 0;
+             if (rc) return rc;
+             errno = saveerrno;
+@@ -685,7 +683,7 @@
+         if (S_ISSOCK(dsb.st_mode)) return 0;
+     }
+     /* XXX shouldn't do this with commit/undo. */
+-    rc = fsmUnlink(path);
++    rc = fsmUnlink(dirfd, path);
+     if (rc == 0)	rc = RPMERR_ENOENT;
+     return (rc ? rc : RPMERR_ENOENT);	/* XXX HACK */
+ }
+@@ -699,7 +697,7 @@
+ 
+ 
+ /* Rename pre-existing modified or unmanaged file. */
+-static int fsmBackup(rpmfi fi, rpmFileAction action)
++static int fsmBackup(int dirfd, rpmfi fi, rpmFileAction action)
+ {
+     int rc = 0;
+     const char *suffix = NULL;
+@@ -720,9 +718,10 @@
+     if (suffix) {
+ 	char * opath = fsmFsPath(fi, NULL);
+ 	char * path = fsmFsPath(fi, suffix);
+-	rc = fsmRename(opath, path);
++	rc = fsmRename(dirfd, opath, dirfd, path);
+ 	if (!rc) {
+-	    rpmlog(RPMLOG_WARNING, _("%s saved as %s\n"), opath, path);
++	    rpmlog(RPMLOG_WARNING, _("%s%s saved as %s%s\n"),
++		   rpmfiDN(fi), opath, rpmfiDN(fi), path);
+ 	}
+ 	free(path);
+ 	free(opath);
+@@ -730,7 +729,8 @@
+     return rc;
+ }
+ 
+-static int fsmSetmeta(const char *path, rpmfi fi, rpmPlugins plugins,
++static int fsmSetmeta(int fd, int dirfd, const char *path,
++		      rpmfi fi, rpmPlugins plugins,
+ 		      rpmFileAction action, const struct stat * st,
+ 		      int nofcaps)
+ {
+@@ -738,27 +738,28 @@
+     const char *dest = rpmfiFN(fi);
+ 
+     if (!rc && !getuid()) {
+-	rc = fsmChown(path, st->st_mode, st->st_uid, st->st_gid);
++	rc = fsmChown(fd, dirfd, path, st->st_mode, st->st_uid, st->st_gid);
+     }
+     if (!rc && !S_ISLNK(st->st_mode)) {
+-	rc = fsmChmod(path, st->st_mode);
++	rc = fsmChmod(fd, dirfd, path, st->st_mode);
+     }
+     /* Set file capabilities (if enabled) */
+     if (!rc && !nofcaps && S_ISREG(st->st_mode) && !getuid()) {
+-	rc = fsmSetFCaps(path, rpmfiFCaps(fi));
++	rc = fsmSetFCaps(fd, dirfd, path, rpmfiFCaps(fi));
+     }
+     if (!rc) {
+-	rc = fsmUtime(path, st->st_mode, rpmfiFMtime(fi));
++	rc = fsmUtime(fd, dirfd, path, st->st_mode, rpmfiFMtime(fi));
+     }
+     if (!rc) {
+ 	rc = rpmpluginsCallFsmFilePrepare(plugins, fi,
+-					  path, dest, st->st_mode, action);
++					  fd, path, dest,
++					  st->st_mode, action);
+     }
+ 
+     return rc;
+ }
+ 
+-static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *suffix)
++static int fsmCommit(int dirfd, char **path, rpmfi fi, rpmFileAction action, const char *suffix)
+ {
+     int rc = 0;
+ 
+@@ -772,15 +773,18 @@
+ 
+ 	/* Rename temporary to final file name if needed. */
+ 	if (dest != *path) {
+-	    rc = fsmRename(*path, dest);
+-	    if (!rc && nsuffix) {
+-		char * opath = fsmFsPath(fi, NULL);
+-		rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
+-		       opath, dest);
+-		free(opath);
+-	    }
+-	    free(*path);
+-	    *path = dest;
++	    rc = fsmRename(dirfd, *path, dirfd, dest);
++	    if (!rc) {
++		if (nsuffix) {
++		    char * opath = fsmFsPath(fi, NULL);
++		    rpmlog(RPMLOG_WARNING, _("%s%s created as %s%s\n"),
++			   rpmfiDN(fi), opath, rpmfiDN(fi), dest);
++		    free(opath);
++		}
++		free(*path);
++		*path = dest;
++	    } else
++		free(dest);
+ 	}
+     }
+ 
+@@ -831,191 +835,277 @@
+     }
+ }
+ 
++struct diriter_s {
++    int dirfd;
++    int firstdir;
++};
++
++static int onChdir(rpmfi fi, void *data)
++{
++    struct diriter_s *di = data;
++
++    fsmClose(&(di->dirfd));
++    return 0;
++}
++
++static rpmfi fsmIter(FD_t payload, rpmfiles files, rpmFileIter iter, void *data)
++{
++    rpmfi fi;
++    if (payload)
++	fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
++    else
++	fi = rpmfilesIter(files, iter);
++    if (fi && data)
++	rpmfiSetOnChdir(fi, onChdir, data);
++    return fi;
++}
++
++static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di)
++{
++    fsmClose(&(di->dirfd));
++    fsmClose(&(di->firstdir));
++    return rpmfiFree(fi);
++}
++
+ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+               rpmpsm psm, char ** failedFile)
+ {
+     FD_t payload = rpmtePayload(te);
+-    rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
++    rpmfi fi = NULL;
+     rpmfs fs = rpmteGetFileStates(te);
+     rpmPlugins plugins = rpmtsPlugins(ts);
+-    struct stat sb;
+-    int saveerrno = errno;
+     int rc = 0;
++    int fx = -1;
++    int fc = rpmfilesFC(files);
+     int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
+     int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
+-    int firsthardlink = -1;
+-    FD_t firstlinkfile = NULL;
+-    int skip;
+-    rpmFileAction action;
++    int firstlinkfile = -1;
+     char *tid = NULL;
+-    const char *suffix;
+-    char *fpath = NULL;
+-
+-    if (fi == NULL) {
+-	rc = RPMERR_BAD_MAGIC;
+-	goto exit;
+-    }
++    struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
++    struct filedata_s *firstlink = NULL;
++    struct diriter_s di = { -1, -1 };
+ 
+     /* transaction id used for temporary path suffix while installing */
+     rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
+ 
+-    /* Detect and create directories not explicitly in package. */
+-    rc = fsmMkdirs(files, fs, plugins);
++    /* Collect state data for the whole operation */
++    fi = rpmfilesIter(files, RPMFI_ITER_FWD);
++    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
++	struct filedata_s *fp = &fdata[fx];
++	if (rpmfiFFlags(fi) & RPMFILE_GHOST)
++            fp->action = FA_SKIP;
++	else
++	    fp->action = rpmfsGetAction(fs, fx);
++	fp->skip = XFA_SKIPPING(fp->action);
++	if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi)))
++	    fp->suffix = tid;
++	fp->fpath = fsmFsPath(fi, fp->suffix);
+ 
+-    while (!rc) {
+-	/* Read next payload header. */
+-	rc = rpmfiNext(fi);
++	/* Remap file perms, owner, and group. */
++	rc = rpmfiStat(fi, 1, &fp->sb);
+ 
+-	if (rc < 0) {
+-	    if (rc == RPMERR_ITER_END)
+-		rc = 0;
+-	    break;
+-	}
++	/* Hardlinks are tricky and handled elsewhere for install */
++	fp->setmeta = (fp->skip == 0) &&
++		      (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);
+ 
+-	action = rpmfsGetAction(fs, rpmfiFX(fi));
+-	skip = XFA_SKIPPING(action);
+-	if (action != FA_TOUCH) {
+-	    suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
+-	} else {
+-	    suffix = NULL;
+-	}
+-	fpath = fsmFsPath(fi, suffix);
++	setFileState(fs, fx);
++	fsmDebug(fp->fpath, fp->action, &fp->sb);
+ 
+-	/* Remap file perms, owner, and group. */
+-	rc = rpmfiStat(fi, 1, &sb);
++	fp->stage = FILE_PRE;
++    }
++    fi = rpmfiFree(fi);
+ 
+-	fsmDebug(fpath, action, &sb);
++    if (rc)
++	goto exit;
+ 
+-        /* Exit on error. */
+-        if (rc)
+-            break;
++    fi = fsmIter(payload, files,
++		 payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di);
+ 
+-	/* Run fsm file pre hook for all plugins */
+-	rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
+-				      sb.st_mode, action);
+-	if (rc) {
+-	    skip = 1;
+-	} else {
+-	    setFileState(fs, rpmfiFX(fi));
+-	}
++    if (fi == NULL) {
++        rc = RPMERR_BAD_MAGIC;
++        goto exit;
++    }
+ 
+-        if (!skip) {
+-	    int setmeta = 1;
++    /* Process the payload */
++    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
++	struct filedata_s *fp = &fdata[fx];
++
++	/*
++	 * Tricksy case: this file is a being skipped, but it's part of
++	 * a hardlinked set and has the actual content linked with it.
++	 * Write the content to the first non-skipped file of the set
++	 * instead.
++	 */
++	if (fp->skip && firstlink && rpmfiArchiveHasContent(fi))
++	    fp = firstlink;
++
++        if (!fp->skip) {
++	    int mayopen = 0;
++	    int fd = -1;
++	    rc = ensureDir(plugins, rpmfiDN(fi), 0,
++			    (fp->action == FA_CREATE), 0, &di.dirfd);
+ 
+ 	    /* Directories replacing something need early backup */
+-	    if (!suffix) {
+-		rc = fsmBackup(fi, action);
++	    if (!rc && !fp->suffix && fp != firstlink) {
++		rc = fsmBackup(di.dirfd, fi, fp->action);
+ 	    }
++
++	    /* Run fsm file pre hook for all plugins */
++	    if (!rc)
++		rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
++					      fp->sb.st_mode, fp->action);
++	    if (rc)
++		goto setmeta; /* for error notification */
++
+ 	    /* Assume file does't exist when tmp suffix is in use */
+-	    if (!suffix) {
+-		rc = fsmVerify(fpath, fi);
++	    if (!fp->suffix) {
++		if (fp->action == FA_TOUCH) {
++		    struct stat sb;
++		    rc = fsmStat(di.dirfd, fp->fpath, 1, &sb);
++		} else {
++		    rc = fsmVerify(di.dirfd, fp->fpath, fi);
++		}
+ 	    } else {
+ 		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);
++	    if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) {
++		rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n",
++			fp->fpath);
++		fp->action = FA_CREATE;
++		fsmDebug(fp->fpath, fp->action, &fp->sb);
+ 	    }
+ 
+ 	    /* When touching we don't need any of this... */
+-	    if (action == FA_TOUCH)
+-		goto touch;
++	    if (fp->action == FA_TOUCH)
++		goto setmeta;
+ 
+-            if (S_ISREG(sb.st_mode)) {
++            if (S_ISREG(fp->sb.st_mode)) {
+ 		if (rc == RPMERR_ENOENT) {
+-		    rc = fsmMkfile(fi, fpath, files, psm, nodigest,
+-				   &setmeta, &firsthardlink, &firstlinkfile);
++		    rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
++				   &firstlink, &firstlinkfile, &di.firstdir,
++				   &fd);
+ 		}
+-            } else if (S_ISDIR(sb.st_mode)) {
++            } else if (S_ISDIR(fp->sb.st_mode)) {
+                 if (rc == RPMERR_ENOENT) {
+-                    mode_t mode = sb.st_mode;
++                    mode_t mode = fp->sb.st_mode;
+                     mode &= ~07777;
+                     mode |=  00700;
+-                    rc = fsmMkdir(fpath, mode);
++                    rc = fsmMkdir(di.dirfd, fp->fpath, mode);
+                 }
+-            } else if (S_ISLNK(sb.st_mode)) {
++            } else if (S_ISLNK(fp->sb.st_mode)) {
+ 		if (rc == RPMERR_ENOENT) {
+-		    rc = fsmSymlink(rpmfiFLink(fi), fpath);
++		    rc = fsmSymlink(rpmfiFLink(fi), di.dirfd, fp->fpath);
+ 		}
+-            } else if (S_ISFIFO(sb.st_mode)) {
++            } else if (S_ISFIFO(fp->sb.st_mode)) {
+                 /* This mimics cpio S_ISSOCK() behavior but probably isn't right */
+                 if (rc == RPMERR_ENOENT) {
+-                    rc = fsmMkfifo(fpath, 0000);
++                    rc = fsmMkfifo(di.dirfd, fp->fpath, 0000);
+                 }
+-            } else if (S_ISCHR(sb.st_mode) ||
+-                       S_ISBLK(sb.st_mode) ||
+-                       S_ISSOCK(sb.st_mode))
++            } else if (S_ISCHR(fp->sb.st_mode) ||
++                       S_ISBLK(fp->sb.st_mode) ||
++                       S_ISSOCK(fp->sb.st_mode))
+             {
+                 if (rc == RPMERR_ENOENT) {
+-                    rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev);
++                    rc = fsmMknod(di.dirfd, fp->fpath, fp->sb.st_mode, fp->sb.st_rdev);
+                 }
+             } else {
+                 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
+-                if (!IS_DEV_LOG(fpath))
++                if (!IS_DEV_LOG(fp->fpath))
+                     rc = RPMERR_UNKNOWN_FILETYPE;
+             }
+ 
+-touch:
+-	    /* Set permissions, timestamps etc for non-hardlink entries */
+-	    if (!rc && setmeta) {
+-		rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps);
++setmeta:
++	    /* Special files require path-based ops */
++	    mayopen = S_ISREG(fp->sb.st_mode) || S_ISDIR(fp->sb.st_mode);
++	    if (!rc && fd == -1 && mayopen) {
++		int flags = O_RDONLY;
++		/* Only follow safe symlinks, and never on temporary files */
++		if (fp->suffix)
++		    flags |= AT_SYMLINK_NOFOLLOW;
++		fd = fsmOpenat(di.dirfd, fp->fpath, flags,
++				S_ISDIR(fp->sb.st_mode));
++		if (fd < 0)
++		    rc = RPMERR_OPEN_FAILED;
+ 	    }
+-        } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
+-	    /* On FA_TOUCH no hardlinks are created thus this is skipped. */
+-	    /* we skip the hard linked file containing the content */
+-	    /* write the content to the first used instead */
+-	    char *fn = rpmfilesFN(files, firsthardlink);
+-	    rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm);
+-	    wfd_close(&firstlinkfile);
+-	    firsthardlink = -1;
+-	    free(fn);
+-	}
+-
+-        if (rc) {
+-            if (!skip) {
+-                /* XXX only erase if temp fn w suffix is in use */
+-                if (suffix) {
+-		    (void) fsmRemove(fpath, sb.st_mode);
+-                }
+-                errno = saveerrno;
+-            }
+-        } else {
+-	    /* Notify on success. */
+-	    rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
+ 
+-	    if (!skip) {
+-		/* Backup file if needed. Directories are handled earlier */
+-		if (suffix)
+-		    rc = fsmBackup(fi, action);
+-
+-		if (!rc)
+-		    rc = fsmCommit(&fpath, fi, action, suffix);
++	    if (!rc && fp->setmeta) {
++		rc = fsmSetmeta(fd, di.dirfd, fp->fpath,
++				fi, plugins, fp->action,
++				&fp->sb, nofcaps);
+ 	    }
++
++	    if (fd != firstlinkfile)
++		fsmClose(&fd);
+ 	}
+ 
++	/* Notify on success. */
+ 	if (rc)
+-	    *failedFile = xstrdup(fpath);
++	    *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL);
++	else
++	    rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
++	fp->stage = FILE_UNPACK;
++    }
++    fi = fsmIterFini(fi, &di);
+ 
+-	/* Run fsm file post hook for all plugins */
+-	rpmpluginsCallFsmFilePost(plugins, fi, fpath,
+-				  sb.st_mode, action, rc);
+-	fpath = _free(fpath);
++    if (!rc && fx < 0 && fx != RPMERR_ITER_END)
++	rc = fx;
++
++    /* If all went well, commit files to final destination */
++    fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di);
++    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
++	struct filedata_s *fp = &fdata[fx];
++
++	if (!fp->skip) {
++	    if (!rc)
++		rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd);
++
++	    /* Backup file if needed. Directories are handled earlier */
++	    if (!rc && fp->suffix)
++		rc = fsmBackup(di.dirfd, fi, fp->action);
++
++	    if (!rc)
++		rc = fsmCommit(di.dirfd, &fp->fpath, fi, fp->action, fp->suffix);
++
++	    if (!rc)
++		fp->stage = FILE_COMMIT;
++	    else
++		*failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL);
++
++	    /* Run fsm file post hook for all plugins for all processed files */
++	    rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
++				      fp->sb.st_mode, fp->action, rc);
++	}
++    }
++    fi = fsmIterFini(fi, &di);
++
++    /* On failure, walk backwards and erase non-committed files */
++    if (rc) {
++	fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di);
++	while ((fx = rpmfiNext(fi)) >= 0) {
++	    struct filedata_s *fp = &fdata[fx];
++
++	    /* If the directory doesn't exist there's nothing to clean up */
++	    if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd))
++		continue;
++
++	    if (fp->stage > FILE_NONE && !fp->skip) {
++		(void) fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode);
++	    }
++	}
+     }
+ 
+     rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ));
+     rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
+ 
+ exit:
+-
+-    /* No need to bother with close errors on read */
+-    rpmfiArchiveClose(fi);
+-    rpmfiFree(fi);
++    fi = fsmIterFini(fi, &di);
+     Fclose(payload);
+     free(tid);
+-    free(fpath);
++    for (int i = 0; i < fc; i++)
++	free(fdata[i].fpath);
++    free(fdata);
+ 
+     return rc;
+ }
+@@ -1024,32 +1114,42 @@
+ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
+               rpmpsm psm, char ** failedFile)
+ {
+-    rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK);
++    struct diriter_s di = { -1, -1 };
++    rpmfi fi = fsmIter(NULL, files, RPMFI_ITER_BACK, &di);
+     rpmfs fs = rpmteGetFileStates(te);
+     rpmPlugins plugins = rpmtsPlugins(ts);
+-    struct stat sb;
++    int fc = rpmfilesFC(files);
++    int fx = -1;
++    struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
+     int rc = 0;
+-    char *fpath = NULL;
+ 
+-    while (!rc && rpmfiNext(fi) >= 0) {
+-	rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi));
+-	fpath = fsmFsPath(fi, NULL);
+-	rc = fsmStat(fpath, 1, &sb);
++    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
++	struct filedata_s *fp = &fdata[fx];
++	fp->action = rpmfsGetAction(fs, rpmfiFX(fi));
++
++	if (XFA_SKIPPING(fp->action))
++	    continue;
++
++	fp->fpath = fsmFsPath(fi, NULL);
++	/* If the directory doesn't exist there's nothing to clean up */
++	if (ensureDir(NULL, rpmfiDN(fi), 0, 0, 1, &di.dirfd))
++	    continue;
++
++	rc = fsmStat(di.dirfd, fp->fpath, 1, &fp->sb);
+ 
+-	fsmDebug(fpath, action, &sb);
++	fsmDebug(fp->fpath, fp->action, &fp->sb);
+ 
+ 	/* Run fsm file pre hook for all plugins */
+-	rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
+-				      sb.st_mode, action);
++	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
++				      fp->sb.st_mode, fp->action);
+ 
+-	if (!XFA_SKIPPING(action))
+-	    rc = fsmBackup(fi, action);
++	rc = fsmBackup(di.dirfd, fi, fp->action);
+ 
+         /* Remove erased files. */
+-        if (action == FA_ERASE) {
++        if (fp->action == FA_ERASE) {
+ 	    int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST));
+ 
+-	    rc = fsmRemove(fpath, sb.st_mode);
++	    rc = fsmRemove(di.dirfd, fp->fpath, fp->sb.st_mode);
+ 
+ 	    /*
+ 	     * Missing %ghost or %missingok entries are not errors.
+@@ -1074,20 +1174,20 @@
+ 	    if (rc) {
+ 		int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;
+ 		rpmlog(lvl, _("%s %s: remove failed: %s\n"),
+-			S_ISDIR(sb.st_mode) ? _("directory") : _("file"),
+-			fpath, strerror(errno));
++			S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"),
++			fp->fpath, strerror(errno));
+             }
+         }
+ 
+ 	/* Run fsm file post hook for all plugins */
+-	rpmpluginsCallFsmFilePost(plugins, fi, fpath,
+-				  sb.st_mode, action, rc);
++	rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
++				  fp->sb.st_mode, fp->action, rc);
+ 
+         /* XXX Failure to remove is not (yet) cause for failure. */
+         if (!strict_erasures) rc = 0;
+ 
+ 	if (rc)
+-	    *failedFile = xstrdup(fpath);
++	    *failedFile = rstrscat(NULL, rpmfiDN(fi), fp->fpath, NULL);
+ 
+ 	if (rc == 0) {
+ 	    /* Notify on success. */
+@@ -1095,11 +1195,12 @@
+ 	    rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi);
+ 	    rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount);
+ 	}
+-	fpath = _free(fpath);
+     }
+ 
+-    free(fpath);
+-    rpmfiFree(fi);
++    for (int i = 0; i < fc; i++)
++	free(fdata[i].fpath);
++    free(fdata);
++    fsmIterFini(fi, &di);
+ 
+     return rc;
+ }
diff --git a/0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch b/0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch
new file mode 100644
index 0000000..f66545b
--- /dev/null
+++ b/0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch
@@ -0,0 +1,32 @@
+From 97aa64d8281974fb369c66d5aef8650515b89c52 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Wed, 24 Jan 2024 12:03:39 +0200
+Subject: [PATCH] Use unsigned integers for buildtime too for Y2K38 safety
+
+This little patch buys us 68 extra years to move to 64bit time tags
+in rpm. That seems achievable.
+
+Fixes: #1228
+---
+ build/build.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/build/build.c b/build/build.c
+index e4081c673..0ac8bf6c9 100644
+--- a/build/build.c
++++ b/build/build.c
+@@ -36,9 +36,9 @@ static rpm_time_t getBuildTime(void)
+         if (srcdate == endptr || *endptr || errno != 0)
+             rpmlog(RPMLOG_ERR, _("unable to parse SOURCE_DATE_EPOCH\n"));
+         else
+-            buildTime = (int32_t) epoch;
++            buildTime = (uint32_t) epoch;
+     } else
+-        buildTime = (int32_t) time(NULL);
++        buildTime = (uint32_t) time(NULL);
+ 
+     return buildTime;
+ }
+-- 
+2.45.1
+
diff --git a/0002-Remove-use-of-bool-type-for-consistency.patch b/0002-Remove-use-of-bool-type-for-consistency.patch
index 5867127..5b1e7ad 100644
--- a/0002-Remove-use-of-bool-type-for-consistency.patch
+++ b/0002-Remove-use-of-bool-type-for-consistency.patch
@@ -4,23 +4,32 @@ Date: Sun, 31 Jan 2021 12:30:33 -0800
 Subject: [PATCH 02/30] Remove use of bool type for consistency
 
 ---
- lib/fsm.c | 9 ++++-----
- 1 file changed, 4 insertions(+), 5 deletions(-)
+ lib/fsm.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
 
 diff --git a/lib/fsm.c b/lib/fsm.c
 index 90193c749..feda3750c 100644
 --- a/lib/fsm.c
 +++ b/lib/fsm.c
 @@ -8,7 +8,6 @@
- 
+ #include <inttypes.h>
  #include <utime.h>
  #include <errno.h>
 -#include <stdbool.h>
- #if WITH_CAP
+ #include <fcntl.h>
+ #ifdef WITH_CAP
  #include <sys/capability.h>
- #endif
-@@ -896,10 +895,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 
+@@ -56,7 +55,7 @@ struct filedata_s {
+     int stage;
+     int setmeta;
+     int skip;
+-    bool plugin_contents;
++    int plugin_contents;
+     rpmFileAction action;
+     const char *suffix;
+     char *fpath;
+@@ -890,10 +889,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+     struct diriter_s di = { -1, -1 };
      Header h = rpmteHeader(te);
      const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
 -    bool cpio = true;
@@ -32,14 +41,7 @@ index 90193c749..feda3750c 100644
      }
  
      /* transaction id used for temporary path suffix while installing */
-@@ -927,13 +926,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	/* Run fsm file pre hook for all plugins */
- 	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
- 				      fp->sb.st_mode, fp->action);
--	fp->plugin_contents = false;
-+	fp->plugin_contents = 0;
- 	switch (rc) {
- 	case RPMRC_OK:
+@@ -924,7 +923,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
  	    setFileState(fs, fx);
  	    break;
  	case RPMRC_PLUGIN_CONTENTS:
@@ -48,6 +50,15 @@ index 90193c749..feda3750c 100644
  	    // reduce reads on cpio to this value. Could be zero if
  	    // this is from a hard link.
  	    rc = RPMRC_OK;
+@@ -986,7 +985,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 		rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
+ 					      fp->sb.st_mode, fp->action);
+ 		if (rc == RPMRC_PLUGIN_CONTENTS) {
+-		    fp->plugin_contents = true;
++		    fp->plugin_contents = 1;
+ 		    rc = RPMRC_OK;
+ 		}
+ 	    }
 -- 
 2.35.1
 
diff --git a/0003-Match-formatting-style-of-existing-code.patch b/0003-Match-formatting-style-of-existing-code.patch
index aae1035..f827cd0 100644
--- a/0003-Match-formatting-style-of-existing-code.patch
+++ b/0003-Match-formatting-style-of-existing-code.patch
@@ -15,28 +15,10 @@ this reformat here and now, and future changes will be after this.
 I'm keen to fold the patches together, but for now, I'm trying to keep
 the history of #1470 linear so everyone can follow along.
 ---
- lib/rpmplugins.c  |   6 +-
  plugins/reflink.c | 407 ++++++++++++++++++---------------
  rpm2extents.c     | 562 ++++++++++++++++++++--------------------------
- 3 files changed, 462 insertions(+), 513 deletions(-)
+ 2 files changed, 459 insertions(+), 510 deletions(-)
 
-diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
-index c5084d398..3da3097af 100644
---- a/lib/rpmplugins.c
-+++ b/lib/rpmplugins.c
-@@ -368,9 +368,9 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
- 		rc = RPMRC_FAIL;
- 	    } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
- 		if (rc == RPMRC_PLUGIN_CONTENTS) {
--		    /*
--		    Another plugin already said it'd handle contents. It's undefined how
--		    these would combine, so treat this as a failure condition.
-+		    /* Another plugin already said it'd handle contents. It's
-+		     * undefined how these would combine, so treat this as a
-+		     * failure condition.
- 		    */
- 		    rc = RPMRC_FAIL;
- 		} else {
 diff --git a/plugins/reflink.c b/plugins/reflink.c
 index d7f19acd9..9eaa87094 100644
 --- a/plugins/reflink.c
diff --git a/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch b/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch
index ff335d7..d41aeb3 100644
--- a/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch
+++ b/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch
@@ -63,7 +63,7 @@ diff --git a/tests/rpmtests.at b/tests/rpmtests.at
 index a1adab8e0..205fed6a3 100644
 --- a/tests/rpmtests.at
 +++ b/tests/rpmtests.at
-@@ -21,3 +21,4 @@ m4_include([rpmreplace.at])
+@@ -22,3 +22,4 @@ m4_include([rpmreplace.at])
  m4_include([rpmconfig.at])
  m4_include([rpmconfig2.at])
  m4_include([rpmconfig3.at])
diff --git a/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch b/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch
index a0e9757..150ba8a 100644
--- a/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch
+++ b/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch
@@ -15,7 +15,7 @@ diff --git a/Makefile.am b/Makefile.am
 index 288668819..96542c8c8 100644
 --- a/Makefile.am
 +++ b/Makefile.am
-@@ -185,7 +185,7 @@ bin_PROGRAMS +=		rpmgraph
+@@ -203,7 +203,7 @@ bin_PROGRAMS +=		rpmgraph
  rpmgraph_SOURCES =	tools/rpmgraph.c
  rpmgraph_LDADD =	lib/librpm.la rpmio/librpmio.la @WITH_POPT_LIB@
  
diff --git a/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch b/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch
index e7b7804..9d19938 100644
--- a/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch
+++ b/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch
@@ -19,7 +19,7 @@ diff --git a/lib/Makefile.am b/lib/Makefile.am
 index 5a1b6ca9b..2f1b3597f 100644
 --- a/lib/Makefile.am
 +++ b/lib/Makefile.am
-@@ -40,7 +40,8 @@ librpm_la_SOURCES = \
+@@ -41,7 +41,8 @@ librpm_la_SOURCES = \
  	rpmscript.h rpmscript.c \
  	rpmchroot.c rpmchroot.h \
  	rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \
diff --git a/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch b/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch
index 56bb554..392e534 100644
--- a/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch
+++ b/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch
@@ -5,17 +5,122 @@ Subject: [PATCH 13/30] [plugin] add `plugin_fsm_file_install_func` plugin hook
 
 This hook is to be called when installing individual files from the RPM.
 ---
+ lib/Makefile.in  | 51 ++++++++++++++++++++++++++----------------------
  lib/rpmplugin.h  |  5 +++++
- lib/rpmplugins.c | 37 +++++++++++++++++++++++++++++++++++++
- lib/rpmplugins.h | 15 +++++++++++++++
- 3 files changed, 57 insertions(+)
+ lib/rpmplugins.c | 37 +++++++++++++++++++++++++++++++++++
+ lib/rpmplugins.h | 15 ++++++++++++++
+ 4 files changed, 85 insertions(+), 23 deletions(-)
 
+diff --git a/lib/Makefile.in b/lib/Makefile.in
+index e1965d8..c4bba25 100644
+--- a/lib/Makefile.in
++++ b/lib/Makefile.in
+@@ -173,10 +173,11 @@ am__librpm_la_SOURCES_DIST = backend/dbi.c backend/dbi.h \
+ 	rpmlock.c rpmlock.h misc.h relocation.c rpmscript.h \
+ 	rpmscript.c rpmchroot.c rpmchroot.h rpmplugins.c rpmplugins.h \
+ 	rpmplugin.h rpmug.c rpmug.h rpmtriggers.h rpmtriggers.c \
+-	rpmvs.c rpmvs.h backend/db3.c backend/bdb_ro.c \
+-	backend/ndb/glue.c backend/ndb/rpmpkg.c backend/ndb/rpmpkg.h \
+-	backend/ndb/rpmidx.c backend/ndb/rpmidx.h backend/ndb/rpmxdb.c \
+-	backend/ndb/rpmxdb.h backend/sqlite.c
++	rpmvs.c rpmvs.h rpmextents.c rpmextents_internal.h \
++	backend/db3.c backend/bdb_ro.c backend/ndb/glue.c \
++	backend/ndb/rpmpkg.c backend/ndb/rpmpkg.h backend/ndb/rpmidx.c \
++	backend/ndb/rpmidx.h backend/ndb/rpmxdb.c backend/ndb/rpmxdb.h \
++	backend/sqlite.c
+ am__dirstamp = $(am__leading_dot)dirstamp
+ @BDB_TRUE@am__objects_1 = backend/db3.lo
+ @BDB_RO_TRUE@am__objects_2 = backend/bdb_ro.lo
+@@ -192,8 +193,8 @@ am_librpm_la_OBJECTS = backend/dbi.lo backend/dummydb.lo \
+ 	rpmlead.lo rpmps.lo rpmprob.lo rpmrc.lo rpmte.lo rpmts.lo \
+ 	rpmfs.lo signature.lo transaction.lo verify.lo rpmlock.lo \
+ 	relocation.lo rpmscript.lo rpmchroot.lo rpmplugins.lo rpmug.lo \
+-	rpmtriggers.lo rpmvs.lo $(am__objects_1) $(am__objects_2) \
+-	$(am__objects_3) $(am__objects_4)
++	rpmtriggers.lo rpmvs.lo rpmextents.lo $(am__objects_1) \
++	$(am__objects_2) $(am__objects_3) $(am__objects_4)
+ librpm_la_OBJECTS = $(am_librpm_la_OBJECTS)
+ AM_V_lt = $(am__v_lt_@AM_V@)
+ am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+@@ -228,21 +229,21 @@ am__depfiles_remade = ./$(DEPDIR)/cpio.Plo ./$(DEPDIR)/depends.Plo \
+ 	./$(DEPDIR)/relocation.Plo ./$(DEPDIR)/rpmal.Plo \
+ 	./$(DEPDIR)/rpmchecksig.Plo ./$(DEPDIR)/rpmchroot.Plo \
+ 	./$(DEPDIR)/rpmdb.Plo ./$(DEPDIR)/rpmds.Plo \
+-	./$(DEPDIR)/rpmfi.Plo ./$(DEPDIR)/rpmfs.Plo \
+-	./$(DEPDIR)/rpmgi.Plo ./$(DEPDIR)/rpminstall.Plo \
+-	./$(DEPDIR)/rpmlead.Plo ./$(DEPDIR)/rpmlock.Plo \
+-	./$(DEPDIR)/rpmplugins.Plo ./$(DEPDIR)/rpmprob.Plo \
+-	./$(DEPDIR)/rpmps.Plo ./$(DEPDIR)/rpmrc.Plo \
+-	./$(DEPDIR)/rpmscript.Plo ./$(DEPDIR)/rpmtd.Plo \
+-	./$(DEPDIR)/rpmte.Plo ./$(DEPDIR)/rpmtriggers.Plo \
+-	./$(DEPDIR)/rpmts.Plo ./$(DEPDIR)/rpmug.Plo \
+-	./$(DEPDIR)/rpmvs.Plo ./$(DEPDIR)/signature.Plo \
+-	./$(DEPDIR)/tagexts.Plo ./$(DEPDIR)/tagname.Plo \
+-	./$(DEPDIR)/transaction.Plo ./$(DEPDIR)/verify.Plo \
+-	backend/$(DEPDIR)/bdb_ro.Plo backend/$(DEPDIR)/db3.Plo \
+-	backend/$(DEPDIR)/dbi.Plo backend/$(DEPDIR)/dbiset.Plo \
+-	backend/$(DEPDIR)/dummydb.Plo backend/$(DEPDIR)/sqlite.Plo \
+-	backend/ndb/$(DEPDIR)/glue.Plo \
++	./$(DEPDIR)/rpmextents.Plo ./$(DEPDIR)/rpmfi.Plo \
++	./$(DEPDIR)/rpmfs.Plo ./$(DEPDIR)/rpmgi.Plo \
++	./$(DEPDIR)/rpminstall.Plo ./$(DEPDIR)/rpmlead.Plo \
++	./$(DEPDIR)/rpmlock.Plo ./$(DEPDIR)/rpmplugins.Plo \
++	./$(DEPDIR)/rpmprob.Plo ./$(DEPDIR)/rpmps.Plo \
++	./$(DEPDIR)/rpmrc.Plo ./$(DEPDIR)/rpmscript.Plo \
++	./$(DEPDIR)/rpmtd.Plo ./$(DEPDIR)/rpmte.Plo \
++	./$(DEPDIR)/rpmtriggers.Plo ./$(DEPDIR)/rpmts.Plo \
++	./$(DEPDIR)/rpmug.Plo ./$(DEPDIR)/rpmvs.Plo \
++	./$(DEPDIR)/signature.Plo ./$(DEPDIR)/tagexts.Plo \
++	./$(DEPDIR)/tagname.Plo ./$(DEPDIR)/transaction.Plo \
++	./$(DEPDIR)/verify.Plo backend/$(DEPDIR)/bdb_ro.Plo \
++	backend/$(DEPDIR)/db3.Plo backend/$(DEPDIR)/dbi.Plo \
++	backend/$(DEPDIR)/dbiset.Plo backend/$(DEPDIR)/dummydb.Plo \
++	backend/$(DEPDIR)/sqlite.Plo backend/ndb/$(DEPDIR)/glue.Plo \
+ 	backend/ndb/$(DEPDIR)/rpmidx.Plo \
+ 	backend/ndb/$(DEPDIR)/rpmpkg.Plo \
+ 	backend/ndb/$(DEPDIR)/rpmxdb.Plo
+@@ -589,8 +590,9 @@ librpm_la_SOURCES = backend/dbi.c backend/dbi.h backend/dummydb.c \
+ 	signature.h transaction.c verify.c rpmlock.c rpmlock.h misc.h \
+ 	relocation.c rpmscript.h rpmscript.c rpmchroot.c rpmchroot.h \
+ 	rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \
+-	rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h $(am__append_1) \
+-	$(am__append_4) $(am__append_5) $(am__append_8)
++	rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h rpmextents.c \
++	rpmextents_internal.h $(am__append_1) $(am__append_4) \
++	$(am__append_5) $(am__append_8)
+ librpm_la_LDFLAGS = -version-info $(rpm_version_info)
+ librpm_la_LIBADD = $(top_builddir)/rpmio/librpmio.la @WITH_POPT_LIB@ \
+ 	@WITH_CAP_LIB@ @WITH_ACL_LIB@ @LIBINTL@ $(am__append_2) \
+@@ -751,6 +753,7 @@ distclean-compile:
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmchroot.Plo@am__quote@ # am--include-marker
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmdb.Plo@am__quote@ # am--include-marker
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmds.Plo@am__quote@ # am--include-marker
++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmextents.Plo@am__quote@ # am--include-marker
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmfi.Plo@am__quote@ # am--include-marker
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmfs.Plo@am__quote@ # am--include-marker
+ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpmgi.Plo@am__quote@ # am--include-marker
+@@ -981,6 +984,7 @@ distclean: distclean-am
+ 	-rm -f ./$(DEPDIR)/rpmchroot.Plo
+ 	-rm -f ./$(DEPDIR)/rpmdb.Plo
+ 	-rm -f ./$(DEPDIR)/rpmds.Plo
++	-rm -f ./$(DEPDIR)/rpmextents.Plo
+ 	-rm -f ./$(DEPDIR)/rpmfi.Plo
+ 	-rm -f ./$(DEPDIR)/rpmfs.Plo
+ 	-rm -f ./$(DEPDIR)/rpmgi.Plo
+@@ -1080,6 +1084,7 @@ maintainer-clean: maintainer-clean-am
+ 	-rm -f ./$(DEPDIR)/rpmchroot.Plo
+ 	-rm -f ./$(DEPDIR)/rpmdb.Plo
+ 	-rm -f ./$(DEPDIR)/rpmds.Plo
++	-rm -f ./$(DEPDIR)/rpmextents.Plo
+ 	-rm -f ./$(DEPDIR)/rpmfi.Plo
+ 	-rm -f ./$(DEPDIR)/rpmfs.Plo
+ 	-rm -f ./$(DEPDIR)/rpmgi.Plo
 diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h
 index fd81aec8d..877db81f3 100644
 --- a/lib/rpmplugin.h
 +++ b/lib/rpmplugin.h
 @@ -60,6 +60,10 @@ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,
- 					      const char* path,
+ 					      int fd, const char* path,
  					      const char *dest,
  					      mode_t file_mode, rpmFsmOp op);
 +typedef rpmRC (*plugin_fsm_file_install_func)(rpmPlugin plugin, rpmfi fi,
@@ -37,7 +142,7 @@ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
 index 3da3097af..850a025a0 100644
 --- a/lib/rpmplugins.c
 +++ b/lib/rpmplugins.c
-@@ -421,3 +421,40 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+@@ -435,3 +435,40 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
  
      return rc;
  }
@@ -82,8 +187,8 @@ diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
 index 39762c376..5365cf698 100644
 --- a/lib/rpmplugins.h
 +++ b/lib/rpmplugins.h
-@@ -167,6 +167,21 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
-                                    const char *path, const char *dest,
+@@ -168,6 +168,21 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi,
+                                    int fd, const char *path, const char *dest,
                                     mode_t mode, rpmFsmOp op);
  
 +/** \ingroup rpmplugins
diff --git a/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch b/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch
index 737368d..a904670 100644
--- a/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch
+++ b/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch
@@ -11,14 +11,14 @@ been created.
 If this was done in `rpmpluginsCallFsmFilePre`, the directories may be
 missing, which makes file installation fail.
 ---
- lib/fsm.c | 29 +++++++++--------------------
- 1 file changed, 9 insertions(+), 20 deletions(-)
+ lib/fsm.c | 37 ++++++++++---------------------------
+ 1 file changed, 10 insertions(+), 27 deletions(-)
 
 diff --git a/lib/fsm.c b/lib/fsm.c
 index feda3750c..711f553d3 100644
 --- a/lib/fsm.c
 +++ b/lib/fsm.c
-@@ -53,7 +53,6 @@ struct filedata_s {
+@@ -55,7 +55,6 @@ struct filedata_s {
      int stage;
      int setmeta;
      int skip;
@@ -26,17 +26,10 @@ index feda3750c..711f553d3 100644
      rpmFileAction action;
      const char *suffix;
      char *fpath;
-@@ -921,23 +920,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	/* Remap file perms, owner, and group. */
- 	rc = rpmfiStat(fi, 1, &fp->sb);
+@@ -918,20 +917,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 	fp->setmeta = (fp->skip == 0) &&
+ 		      (fp->sb.st_nlink == 1 || fp->action == FA_TOUCH);
  
-+	setFileState(fs, fx);
- 	fsmDebug(fp->fpath, fp->action, &fp->sb);
- 
- 	/* Run fsm file pre hook for all plugins */
- 	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
- 				      fp->sb.st_mode, fp->action);
--	fp->plugin_contents = 0;
 -	switch (rc) {
 -	case RPMRC_OK:
 -	    setFileState(fs, fx);
@@ -47,30 +40,47 @@ index feda3750c..711f553d3 100644
 -	    // this is from a hard link.
 -	    rc = RPMRC_OK;
 -	    break;
+-	default:
+-	    fp->action = FA_SKIP;
+-	    fp->skip = XFA_SKIPPING(fp->action);
 -	}
++	setFileState(fs, fx);
+ 	fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb);
+ 
  	fp->stage = FILE_PRE;
-     }
-     fi = rpmfiFree(fi);
-@@ -992,14 +980,15 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+@@ -984,10 +970,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 	    if (!rc) {
+ 		rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
+ 					      fp->sb.st_mode, fp->action);
+-		if (rc == RPMRC_PLUGIN_CONTENTS) {
+-		    fp->plugin_contents = 1;
+-		    rc = RPMRC_OK;
+-		}
+ 	    }
+ 	    if (rc)
+ 		goto setmeta; /* for error notification */
+@@ -1016,15 +998,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
  	    if (fp->action == FA_TOUCH)
- 		continue;
+ 		goto setmeta;
  
 -            if (S_ISREG(fp->sb.st_mode)) {
 +	    rpmRC plugin_rc = rpmpluginsCallFsmFileInstall(plugins, fi, fp->fpath, fp->sb.st_mode, fp->action);
-+	    if(!(plugin_rc == RPMRC_PLUGIN_CONTENTS || plugin_rc == RPMRC_OK)){
++	    if (!(plugin_rc == RPMRC_PLUGIN_CONTENTS || plugin_rc == RPMRC_OK)){
 +		rc = plugin_rc;
 +	    } else if(plugin_rc == RPMRC_PLUGIN_CONTENTS){
 +		rc = RPMRC_OK;
 +	    } else if (S_ISREG(fp->sb.st_mode)) {
  		if (rc == RPMERR_ENOENT) {
--		    if(fp->plugin_contents) {
+-		    if (fp->plugin_contents) {
 -			rc = RPMRC_OK;
--		    }else {
--			rc = fsmMkfile(fi, fp, files, psm, nodigest,
--			    &firstlink, &firstlinkfile);
+-		    } else {
+-			rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
+-				       &firstlink, &firstlinkfile,
+-				       &di.firstdir, &fd);
 -		    }
-+		    rc = fsmMkfile(fi, fp, files, psm, nodigest,
-+			&firstlink, &firstlinkfile);
++		    rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest,
++				   &firstlink, &firstlinkfile,
++				   &di.firstdir, &fd);
  		}
              } else if (S_ISDIR(fp->sb.st_mode)) {
                  if (rc == RPMERR_ENOENT) {
diff --git a/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch b/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch
deleted file mode 100644
index e6dae81..0000000
--- a/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 7784da14fe57df919df9dfdad30e436ffe6d3e28 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 20 Apr 2020 11:22:15 -0400
-Subject: [PATCH 15/33] rpmsign: RPMSIGN_FLAG_IMA is already set
-
-There is no need to set RPMSIGN_FLAG_IMA since it was already set to
-get here.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- rpmsign.c | 1 -
- 1 file changed, 1 deletion(-)
-
-diff --git a/rpmsign.c b/rpmsign.c
-index a74948ba8..e1d207da5 100644
---- a/rpmsign.c
-+++ b/rpmsign.c
-@@ -130,7 +130,6 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
- 	    free(fileSigningKeyPassword);
- 	}
- 
--	sargs->signflags |= RPMSIGN_FLAG_IMA;
- 	free(key);
-     }
- #endif
--- 
-2.27.0
-
diff --git a/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch b/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch
deleted file mode 100644
index 89845cb..0000000
--- a/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch
+++ /dev/null
@@ -1,136 +0,0 @@
-From f525681b4f66026578bc728b864bfea3d814c29e Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Fri, 27 Mar 2020 18:31:36 -0400
-Subject: [PATCH 16/33] Add basic autoconf and framework for fsverity support
-
-Use the same signing key argument as is used for IMA file signing.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- configure.ac     | 19 +++++++++++++++++++
- rpmsign.c        | 20 ++++++++++++++------
- sign/Makefile.am |  5 +++++
- sign/rpmsign.h   |  1 +
- 4 files changed, 39 insertions(+), 6 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index 3c102d5eb..cc7144440 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -919,6 +919,25 @@ fi
- AM_CONDITIONAL(WITH_IMAEVM,[test "$with_imaevm" = yes])
- AC_SUBST(WITH_IMAEVM_LIB)
- 
-+# fsverity
-+AC_ARG_WITH([fsverity], [AS_HELP_STRING([--with-fsverity],[build with fsverity support])],[],[with_fsverity=no])
-+if test "$with_fsverity" = yes ; then
-+  AC_MSG_CHECKING([libfsverity])
-+  AC_COMPILE_IFELSE(
-+    [AC_LANG_PROGRAM(
-+      [[#include <libfsverity.h>]],
-+      [[return libfsverity_sign_digest(NULL, NULL, NULL, NULL);]]
-+    )],
-+    [AC_MSG_RESULT(yes)
-+      AC_DEFINE(WITH_FSVERITY, 1, [Build with fsverity support?])
-+      WITH_FSVERITY_LIB="-lfsverity"
-+    ],
-+    [AC_MSG_ERROR([--with-fsverity given, libfsverity or libfsverity.h missing])]
-+  )
-+fi
-+AM_CONDITIONAL(WITH_FSVERITY,[test "$with_fsverity" = yes])
-+AC_SUBST(WITH_FSVERITY_LIB)
-+
- # libcap
- WITH_CAP_LIB=
- AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])],
-diff --git a/rpmsign.c b/rpmsign.c
-index e1d207da5..8861c2c59 100644
---- a/rpmsign.c
-+++ b/rpmsign.c
-@@ -18,7 +18,7 @@ enum modes {
- 
- static int mode = MODE_NONE;
- 
--#ifdef WITH_IMAEVM
-+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
- static int fskpass = 0;
- static char * fileSigningKey = NULL;
- #endif
-@@ -39,6 +39,13 @@ static struct poptOption signOptsTable[] = {
-     { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
- 	&sargs.signflags, RPMSIGN_FLAG_IMA,
- 	N_("sign package(s) files"), NULL},
-+#endif
-+#ifdef WITH_FSVERITY
-+    { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
-+	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,
-+	N_("generate fsverity signatures for package(s) files"), NULL},
-+#endif
-+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
-     { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
- 	N_("use file signing key <key>"),
- 	N_("<key>") },
-@@ -59,7 +66,7 @@ static struct poptOption optionsTable[] = {
-     POPT_TABLEEND
- };
- 
--#ifdef WITH_IMAEVM
-+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
- static char *get_fskpass(void)
- {
-     struct termios flags, tmp_flags;
-@@ -106,12 +113,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
- 	goto exit;
-     }
- 
--#ifdef WITH_IMAEVM
-+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
-     if (fileSigningKey) {
- 	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
-     }
- 
--    if (sargs->signflags & RPMSIGN_FLAG_IMA) {
-+    if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) {
- 	char *fileSigningKeyPassword = NULL;
- 	char *key = rpmExpand("%{?_file_signing_key}", NULL);
- 	if (rstreq(key, "")) {
-@@ -165,8 +172,9 @@ int main(int argc, char *argv[])
- 	argerror(_("no arguments given"));
-     }
- 
--#ifdef WITH_IMAEVM
--    if (fileSigningKey && !(sargs.signflags & RPMSIGN_FLAG_IMA)) {
-+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
-+    if (fileSigningKey &&
-+	!(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) {
- 	argerror(_("--fskpath may only be specified when signing files"));
-     }
- #endif
-diff --git a/sign/Makefile.am b/sign/Makefile.am
-index db774de0e..8d372915a 100644
---- a/sign/Makefile.am
-+++ b/sign/Makefile.am
-@@ -24,3 +24,8 @@ if WITH_IMAEVM
- librpmsign_la_SOURCES += rpmsignfiles.c rpmsignfiles.h
- librpmsign_la_LIBADD += @WITH_IMAEVM_LIB@
- endif
-+
-+if WITH_FSVERITY
-+librpmsign_la_SOURCES += rpmsignverity.c rpmsignverity.h
-+librpmsign_la_LIBADD += @WITH_FSVERITY_LIB@
-+endif
-diff --git a/sign/rpmsign.h b/sign/rpmsign.h
-index 7a770d879..2b8a10a1a 100644
---- a/sign/rpmsign.h
-+++ b/sign/rpmsign.h
-@@ -17,6 +17,7 @@ enum rpmSignFlags_e {
-     RPMSIGN_FLAG_NONE		= 0,
-     RPMSIGN_FLAG_IMA		= (1 << 0),
-     RPMSIGN_FLAG_RPMV3		= (1 << 1),
-+    RPMSIGN_FLAG_FSVERITY	= (1 << 2),
- };
- typedef rpmFlags rpmSignFlags;
- 
--- 
-2.27.0
-
diff --git a/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch b/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch
deleted file mode 100644
index ae64146..0000000
--- a/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From dbb4f464d177e2c3bfa13b1b2bb511fa6fde40d9 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Wed, 27 May 2020 16:49:03 -0400
-Subject: [PATCH 17/33] rpmsign: Add helper to indicate file signing enabled
-
-Helper function returning true if either IMA or VERITY signatures are
-to be applied. This simplifies the code and makes it easier to read.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- rpmsign.c | 10 +++++++---
- 1 file changed, 7 insertions(+), 3 deletions(-)
-
-diff --git a/rpmsign.c b/rpmsign.c
-index 8861c2c59..94cbf1d1a 100644
---- a/rpmsign.c
-+++ b/rpmsign.c
-@@ -67,6 +67,11 @@ static struct poptOption optionsTable[] = {
- };
- 
- #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
-+static int flags_sign_files(int flags)
-+{
-+	return (flags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY) ? 1 : 0);
-+}
-+
- static char *get_fskpass(void)
- {
-     struct termios flags, tmp_flags;
-@@ -118,7 +123,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
- 	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
-     }
- 
--    if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) {
-+    if (flags_sign_files(sargs->signflags)) {
- 	char *fileSigningKeyPassword = NULL;
- 	char *key = rpmExpand("%{?_file_signing_key}", NULL);
- 	if (rstreq(key, "")) {
-@@ -173,8 +178,7 @@ int main(int argc, char *argv[])
-     }
- 
- #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
--    if (fileSigningKey &&
--	!(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) {
-+    if (fileSigningKey && !(flags_sign_files(sargs.signflags))) {
- 	argerror(_("--fskpath may only be specified when signing files"));
-     }
- #endif
--- 
-2.27.0
-
diff --git a/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch b/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch
index 7a5c5fd..e5b6ab4 100644
--- a/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch
+++ b/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch
@@ -38,7 +38,7 @@ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
 index 850a025a0..901af1ac5 100644
 --- a/lib/rpmplugins.c
 +++ b/lib/rpmplugins.c
-@@ -457,4 +457,38 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,
+@@ -471,4 +471,38 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,
      return rc;
  }
  
@@ -81,7 +81,7 @@ diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
 index 5365cf698..88807c53c 100644
 --- a/lib/rpmplugins.h
 +++ b/lib/rpmplugins.h
-@@ -181,7 +181,9 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,
+@@ -182,7 +182,9 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi,
  				   const char* path, mode_t file_mode,
  				   rpmFsmOp op);
  
diff --git a/0018-rpmsign-Handle-certpath-for-signing-certificate.patch b/0018-rpmsign-Handle-certpath-for-signing-certificate.patch
deleted file mode 100644
index 77a8b31..0000000
--- a/0018-rpmsign-Handle-certpath-for-signing-certificate.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From 5e74846046e06f5a3401c4d2eb4ccfadacd4ab53 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Fri, 3 Apr 2020 16:26:06 -0400
-Subject: [PATCH 18/33] rpmsign: Handle --certpath for signing certificate
-
-fsverirty needs a certificate for signing, in addition to the signing key.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- rpmsign.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/rpmsign.c b/rpmsign.c
-index 94cbf1d1a..074dd8b13 100644
---- a/rpmsign.c
-+++ b/rpmsign.c
-@@ -22,6 +22,9 @@ static int mode = MODE_NONE;
- static int fskpass = 0;
- static char * fileSigningKey = NULL;
- #endif
-+#ifdef WITH_FSVERITY
-+static char * fileSigningCert = NULL;
-+#endif
- 
- static struct rpmSignArgs sargs = {NULL, 0, 0};
- 
-@@ -44,6 +47,9 @@ static struct poptOption signOptsTable[] = {
-     { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
- 	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,
- 	N_("generate fsverity signatures for package(s) files"), NULL},
-+    { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,
-+	N_("use file signing cert <cert>"),
-+	N_("<cert>") },
- #endif
- #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
-     { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
-@@ -123,6 +129,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
- 	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
-     }
- 
-+#ifdef WITH_FSVERITY
-+    if (fileSigningCert) {
-+	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);
-+    }
-+#endif
-+
-     if (flags_sign_files(sargs->signflags)) {
- 	char *fileSigningKeyPassword = NULL;
- 	char *key = rpmExpand("%{?_file_signing_key}", NULL);
--- 
-2.27.0
-
diff --git a/0019-Implement-rpmSignVerity.patch b/0019-Implement-rpmSignVerity.patch
deleted file mode 100644
index 70e873a..0000000
--- a/0019-Implement-rpmSignVerity.patch
+++ /dev/null
@@ -1,243 +0,0 @@
-From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Fri, 3 Apr 2020 16:38:08 -0400
-Subject: [PATCH 19/33] Implement rpmSignVerity()
-
-This generates the root Merkle tree hash and signs it using the
-specified key and certificate.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- sign/rpmgensig.c     |  36 +++++++++++++
- sign/rpmsignverity.c | 121 +++++++++++++++++++++++++++++++++++++++++++
- sign/rpmsignverity.h |  29 +++++++++++
- 3 files changed, 186 insertions(+)
- create mode 100644 sign/rpmsignverity.c
- create mode 100644 sign/rpmsignverity.h
-
-diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
-index a6e37e71b..8d5c5858f 100644
---- a/sign/rpmgensig.c
-+++ b/sign/rpmgensig.c
-@@ -22,6 +22,7 @@
- #include "lib/signature.h"
- #include "lib/rpmvs.h"
- #include "sign/rpmsignfiles.h"
-+#include "sign/rpmsignverity.h"
- 
- #include "debug.h"
- 
-@@ -446,6 +447,36 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
- #endif
- }
- 
-+static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
-+{
-+#ifdef WITH_FSVERITY
-+    rpmRC rc;
-+    char *key = rpmExpand("%{?_file_signing_key}", NULL);
-+    char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
-+    char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
-+
-+    if (rstreq(keypass, "")) {
-+	free(keypass);
-+	keypass = NULL;
-+    }
-+
-+    if (key && cert) {
-+	rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);
-+    } else {
-+	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));
-+	rc = RPMRC_FAIL;
-+    }
-+
-+    free(keypass);
-+    free(key);
-+    free(cert);
-+    return rc;
-+#else
-+    rpmlog(RPMLOG_ERR, _("fsverity signing support not built in\n"));
-+    return RPMRC_FAIL;
-+#endif
-+}
-+
- static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata)
- {
-     char **msg = cbdata;
-@@ -544,6 +575,11 @@ static int rpmSign(const char *rpm, int deleting, int flags)
- 	    goto exit;
-     }
- 
-+    if (flags & RPMSIGN_FLAG_FSVERITY) {
-+	if (includeVeritySignatures(fd, &sigh, &h))
-+	    goto exit;
-+    }
-+
-     if (deleting) {	/* Nuke all the signature tags. */
- 	deleteSigs(sigh);
-     } else {
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-new file mode 100644
-index 000000000..5346c3bc8
---- /dev/null
-+++ b/sign/rpmsignverity.c
-@@ -0,0 +1,121 @@
-+/**
-+ * Copyright (C) 2020 Facebook
-+ *
-+ * Author: Jes Sorensen <jsorensen@fb.com>
-+ */
-+
-+#include "system.h"
-+
-+#include <rpm/rpmlib.h>		/* RPMSIGTAG & related */
-+#include <rpm/rpmlog.h>		/* rpmlog */
-+#include <rpm/rpmfi.h>
-+#include <rpm/rpmpgp.h>		/* rpmDigestLength */
-+#include "lib/header.h"		/* HEADERGET_MINMEM */
-+#include "lib/header_internal.h"
-+#include "lib/rpmtypes.h"	/* rpmRC */
-+#include <libfsverity.h>
-+#include "rpmio/rpmio_internal.h"
-+#include "lib/rpmvs.h"
-+
-+#include "sign/rpmsignverity.h"
-+
-+#define MAX_SIGNATURE_LENGTH 1024
-+
-+static int rpmVerityRead(void *opaque, void *buf, size_t size)
-+{
-+	int retval;
-+	rpmfi fi = (rpmfi)opaque;
-+
-+	retval = rpmfiArchiveRead(fi, buf, size);
-+
-+	if (retval > 0)
-+		retval = 0;
-+	return retval;
-+}
-+
-+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-+		    char *keypass, char *cert)
-+{
-+    int rc, status;
-+    FD_t gzdi;
-+    rpmfiles files = NULL;
-+    rpmfi fi = NULL;
-+    rpmts ts = rpmtsCreate();
-+    struct libfsverity_digest *digest = NULL;
-+    struct libfsverity_merkle_tree_params params;
-+    struct libfsverity_signature_params sig_params;
-+    rpm_loff_t file_size;
-+    off_t offset = Ftell(fd);
-+    const char *compr;
-+    char *rpmio_flags = NULL;
-+    char *digest_hex;
-+    uint8_t *sig;
-+    size_t sig_size;
-+
-+    Fseek(fd, 0, SEEK_SET);
-+    rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
-+		    RPMVSF_NOHDRCHK);
-+    rc = rpmReadPackageFile(ts, fd, "fsverity", &h);
-+    if (rc != RPMRC_OK) {
-+	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),
-+	       __func__, rc);
-+	goto out;
-+    }
-+
-+    rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key);
-+    rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert);
-+
-+    compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
-+    rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
-+
-+    gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
-+    free(rpmio_flags);
-+
-+    files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
-+    fi = rpmfiNewArchiveReader(gzdi, files,
-+			       RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);
-+
-+    while (rpmfiNext(fi) >= 0) {
-+	if (!S_ISREG(rpmfiFMode(fi)))
-+	    continue;
-+	file_size = rpmfiFSize(fi);
-+	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"),
-+	       rpmfiFN(fi), file_size);
-+
-+	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
-+	params.version = 1;
-+	params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
-+	params.block_size = sysconf(_SC_PAGESIZE);
-+	params.salt_size = 0 /* salt_size */;
-+	params.salt = NULL /* salt */;
-+	params.file_size = file_size;
-+	status = libfsverity_compute_digest(fi, rpmVerityRead,
-+					    &params, &digest);
-+	if (!status) {
-+	    digest_hex = pgpHexStr(digest->digest, digest->digest_size);
-+	    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
-+		   digest->digest_size, digest_hex);
-+	    free(digest_hex);
-+	}
-+	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
-+	sig_params.keyfile = key;
-+	sig_params.certfile = cert;
-+	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {
-+	    rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
-+	    rc = RPMRC_FAIL;
-+	    goto out;
-+	}
-+	rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));
-+
-+	free(digest);
-+	free(sig);
-+    }
-+
-+out:
-+    Fseek(fd, offset, SEEK_SET);
-+
-+    rpmfilesFree(files);
-+    rpmfiFree(fi);
-+    rpmtsFree(ts);
-+    return rc;
-+}
-diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
-new file mode 100644
-index 000000000..f3ad3bb18
---- /dev/null
-+++ b/sign/rpmsignverity.h
-@@ -0,0 +1,29 @@
-+#ifndef H_RPMSIGNVERITY
-+#define H_RPMSIGNVERITY
-+
-+#include <rpm/rpmtypes.h>
-+#include <rpm/rpmutil.h>
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * Sign file digests in header into signature header
-+ * @param fd		file descriptor of RPM
-+ * @param sigh		package signature header
-+ * @param h		package header
-+ * @param key		signing key
-+ * @param keypass	signing key password
-+ * @param cert		signing cert
-+ * @return		RPMRC_OK on success
-+ */
-+RPM_GNUC_INTERNAL
-+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-+		    char *keypass, char *cert);
-+
-+#ifdef _cplusplus
-+}
-+#endif
-+
-+#endif /* H_RPMSIGNVERITY */
--- 
-2.27.0
-
diff --git a/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch b/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch
index 1e98fd1..211772f 100644
--- a/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch
+++ b/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch
@@ -9,15 +9,15 @@ As the plugin can now be responsible to provide an Archive Reader to
 `RPMTAG_PAYLOADFORMAT` header in memory, removing some special-casing.
 ---
  lib/depends.c     |  2 --
- lib/fsm.c         | 38 +++++++++++++++++++-------------------
+ lib/fsm.c         | 48 ++++++++++++++++++++++++++---------------------
  plugins/reflink.c | 18 +++++++++++++-----
- 3 files changed, 32 insertions(+), 26 deletions(-)
+ 3 files changed, 40 insertions(+), 28 deletions(-)
 
 diff --git a/lib/depends.c b/lib/depends.c
 index 8998afcd3..30234df3d 100644
 --- a/lib/depends.c
 +++ b/lib/depends.c
-@@ -81,8 +81,6 @@ static rpmRC headerCheckPayloadFormat(Header h) {
+@@ -80,8 +80,6 @@ static rpmRC headerCheckPayloadFormat(Header h) {
       */
      if (!payloadfmt) return rc;
  
@@ -30,18 +30,43 @@ diff --git a/lib/fsm.c b/lib/fsm.c
 index 711f553d3..6972602e0 100644
 --- a/lib/fsm.c
 +++ b/lib/fsm.c
-@@ -19,7 +19,6 @@
+@@ -17,7 +17,6 @@
+ #include <rpm/rpmts.h>
+ #include <rpm/rpmlog.h>
+ #include <rpm/rpmmacro.h>
+-#include <rpm/rpmlib.h>
  
  #include "rpmio/rpmio_internal.h"	/* fdInit/FiniDigest */
- #include "lib/fsm.h"
--#include "lib/rpmlib.h"
- #include "lib/rpmte_internal.h"	/* XXX rpmfs */
- #include "lib/rpmplugins.h"	/* rpm plugins hooks */
- #include "lib/rpmug.h"
-@@ -892,14 +891,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ #include "fsm.h"
+@@ -869,6 +868,24 @@ static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di)
+     return rpmfiFree(fi);
+ }
+ 
++static int fiIterator(rpmPlugins plugins, FD_t payload, rpmfiles files, rpmfi *fi)
++{
++    rpmRC plugin_rc = rpmpluginsCallFsmFileArchiveReader(plugins, payload, files, fi);
++    switch (plugin_rc) {
++	case RPMRC_PLUGIN_CONTENTS:
++	    if (*fi == NULL)
++                return RPMERR_BAD_MAGIC;
++            return RPMRC_OK;
++	case RPMRC_OK:
++	    *fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
++	    if (*fi == NULL)
++                return RPMERR_BAD_MAGIC;
++            return RPMRC_OK;
++	default:
++            return RPMRC_FAIL;
++    }
++}
++
+ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+               rpmpsm psm, char ** failedFile)
+ {
+@@ -886,13 +903,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
      struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
      struct filedata_s *firstlink = NULL;
- 
+     struct diriter_s di = { -1, -1 };
 -    Header h = rpmteHeader(te);
 -    const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
 -    int cpio = 1;
@@ -49,60 +74,54 @@ index 711f553d3..6972602e0 100644
 -    if (payloadfmt && rstreq(payloadfmt, "clon")) {
 -	cpio = 0;
 -    }
--
+ 
      /* transaction id used for temporary path suffix while installing */
      rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
- 
-@@ -933,14 +924,24 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+@@ -927,12 +937,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
      if (rc)
  	goto exit;
  
 -    if (cpio) {
--	fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
--	if (fi == NULL) {
--	    rc = RPMERR_BAD_MAGIC;
--	    goto exit;
--	}
+-	fi = fsmIter(payload, files,
+-		     payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di);
 -    } else {
 -	fi = rpmfilesIter(files, RPMFI_ITER_FWD);
-+    rpmRC plugin_rc = rpmpluginsCallFsmFileArchiveReader(plugins, payload, files, &fi);
-+    switch(plugin_rc) {
-+	case RPMRC_PLUGIN_CONTENTS:
-+	    if(fi == NULL) {
-+		rc = RPMERR_BAD_MAGIC;
-+		goto exit;
-+	    }
-+	    rc = RPMRC_OK;
-+	    break;
-+	case RPMRC_OK:
-+	    fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
-+	    if (fi == NULL) {
-+		rc = RPMERR_BAD_MAGIC;
-+		goto exit;
-+	    }
-+	    break;
-+	default:
-+	    rc = RPMRC_FAIL;
-     }
+-    }
++    rc = fiIterator(plugins, payload, files, &fi);
++    if (rc)
++        goto exit;
+ 
+     if (fi == NULL) {
+         rc = RPMERR_BAD_MAGIC;
+@@ -956,7 +963,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
+ 	    int mayopen = 0;
+ 	    int fd = -1;
  
-     /* Detect and create directories not explicitly in package. */
-@@ -988,7 +989,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	    } else if (S_ISREG(fp->sb.st_mode)) {
- 		if (rc == RPMERR_ENOENT) {
- 		    rc = fsmMkfile(fi, fp, files, psm, nodigest,
--			&firstlink, &firstlinkfile);
-+				   &firstlink, &firstlinkfile);
- 		}
-             } else if (S_ISDIR(fp->sb.st_mode)) {
-                 if (rc == RPMERR_ENOENT) {
-@@ -1096,7 +1097,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
+-	    if (!cpio && di.dirfd >= 0)
++	    if (di.dirfd >= 0)
+ 		fsmClose(&di.dirfd);
+ 	    rc = ensureDir(plugins, rpmfiDN(fi), 0,
+ 			    (fp->action == FA_CREATE), 0, &di.dirfd);
+@@ -1075,16 +1082,13 @@ setmeta:
+ 	rc = fx;
+ 
+     /* If all went well, commit files to final destination */
+-    if (cpio) {
+-	fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di);
+-    } else {
+-	fi = rpmfilesIter(files, RPMFI_ITER_FWD);
+-    }
++    fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di);
++
+     while (!rc && (fx = rpmfiNext(fi)) >= 0) {
+ 	struct filedata_s *fp = &fdata[fx];
  
- exit:
--    h = headerFree(h);
-     fi = rpmfiFree(fi);
-     Fclose(payload);
-     free(tid);
+ 	if (!fp->skip) {
+-	    if (!cpio && di.dirfd >= 0)
++	    if (di.dirfd >= 0)
+ 		fsmClose(&di.dirfd);
+ 	    if (!rc)
+ 		rc = ensureDir(NULL, rpmfiDN(fi), 0, 0, 0, &di.dirfd);
 diff --git a/plugins/reflink.c b/plugins/reflink.c
 index 7dda06d8e..d5e6db27a 100644
 --- a/plugins/reflink.c
diff --git a/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch b/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch
deleted file mode 100644
index b099eaf..0000000
--- a/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-From a7e81a1b18c9e9d124a4ea917c8015af62584abb Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Thu, 28 May 2020 17:48:23 -0400
-Subject: [PATCH 20/33] Introduce base2bin() - a helper to convert tag array of
- base64 strings
-
-This will convert a tag of base64 strings to a binary array, similar
-to how hex2bin() works. It supports variable sized strings, and will
-determine the maximum string length and build the output array based
-on that.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- lib/rpmfi.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 58 insertions(+)
-
-diff --git a/lib/rpmfi.c b/lib/rpmfi.c
-index 689ead2c5..8c69d3e40 100644
---- a/lib/rpmfi.c
-+++ b/lib/rpmfi.c
-@@ -19,6 +19,7 @@
- #include "lib/fsm.h"	/* rpmpsm stuff for now */
- #include "lib/rpmug.h"
- #include "rpmio/rpmio_internal.h"       /* fdInit/FiniDigest */
-+#include "rpmio/rpmbase64.h"
- 
- #include "debug.h"
- 
-@@ -1520,6 +1521,63 @@ static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
-     return bin;
- }
- 
-+/*
-+ * Convert a tag of base64 strings to binary presentation.
-+ * This handles variable length strings by finding the longest string
-+ * before building the output array. Dummy strings in the tag should be
-+ * added as '\0'
-+ */
-+static uint8_t *base2bin(Header h, rpmTagVal tag, rpm_count_t num, int *len)
-+{
-+    struct rpmtd_s td;
-+    uint8_t *bin = NULL, *t = NULL;
-+    size_t maxlen = 0;
-+    int status, i= 0;
-+    void **arr = xmalloc(num * sizeof(void *));
-+    size_t *lengths = xcalloc(num, sizeof(size_t));
-+    const char *s;
-+
-+    if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) != num)
-+	goto out;
-+
-+    while ((s = rpmtdNextString(&td))) {
-+	/* Insert a dummy entry for empty strings */
-+	if (*s == '\0') {
-+	    arr[i++] = NULL;
-+	    continue;
-+	}
-+	status = rpmBase64Decode(s, &arr[i], &lengths[i]);
-+	if (lengths[i] > maxlen)
-+	    maxlen = lengths[i];
-+	if (status) {
-+	    rpmlog(RPMLOG_DEBUG, _("%s: base64 decode failed, len %li\n"),
-+		   __func__, lengths[i]);
-+	    goto out;
-+	}
-+	i++;
-+    }
-+
-+    if (maxlen) {
-+	rpmlog(RPMLOG_DEBUG, _("%s: base64 decode success, len %li\n"),
-+	       __func__, maxlen);
-+
-+	t = bin = xcalloc(num, maxlen);
-+
-+	for (i = 0; i < num; i++) {
-+	    memcpy(t, arr[i], lengths[i]);
-+	    free(arr[i]);
-+	    t += maxlen;
-+	}
-+	*len = maxlen;
-+    }
-+ out:
-+    free(arr);
-+    free(lengths);
-+    rpmtdFreeData(&td);
-+
-+    return bin;
-+}
-+
- static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
- {
-     headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ? 
--- 
-2.27.0
-
diff --git a/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch b/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch
deleted file mode 100644
index 051c0bc..0000000
--- a/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch
+++ /dev/null
@@ -1,206 +0,0 @@
-From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Thu, 9 Apr 2020 12:58:17 -0400
-Subject: [PATCH 21/33] rpmsignverity: Add verity signature headers to the
- package
-
-This adds the array of verity signatures, and a signature length
-header. We use 4K block for the Merkle tree, and rely on the kernel
-doing the right thing.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- lib/rpmtag.h         |   6 ++-
- sign/rpmsignverity.c | 112 +++++++++++++++++++++++++++++--------------
- sign/rpmsignverity.h |   7 +++
- 3 files changed, 87 insertions(+), 38 deletions(-)
-
-diff --git a/lib/rpmtag.h b/lib/rpmtag.h
-index 40ff5fa5d..478457ecb 100644
---- a/lib/rpmtag.h
-+++ b/lib/rpmtag.h
-@@ -67,6 +67,7 @@ typedef enum rpmTag_e {
-     RPMTAG_SHA256HEADER		= RPMTAG_SIG_BASE+17,	/* s */
-     /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */
-     /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
-+    RPMTAG_VERITYSIGNATURES	= RPMTAG_SIG_BASE+20,	/* s[] */
- 
-     RPMTAG_NAME  		= 1000,	/* s */
- #define	RPMTAG_N	RPMTAG_NAME	/* s */
-@@ -427,6 +428,7 @@ typedef enum rpmSigTag_e {
-     RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,
-     RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 18,
-     RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 19,
-+    RPMSIGTAG_VERITYSIGNATURES		= RPMTAG_VERITYSIGNATURES,
- } rpmSigTag;
- 
- 
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index 5346c3bc8..a9818bd08 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -33,23 +33,66 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)
- 	return retval;
- }
- 
-+static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
-+			       char *keypass, char *cert)
-+{
-+    struct libfsverity_merkle_tree_params params;
-+    struct libfsverity_signature_params sig_params;
-+    struct libfsverity_digest *digest = NULL;
-+    rpm_loff_t file_size;
-+    char *digest_hex, *sig_hex = NULL;
-+    uint8_t *sig;
-+    int status;
-+
-+    file_size = rpmfiFSize(fi);
-+
-+    memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
-+    params.version = 1;
-+    params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
-+    params.block_size = RPM_FSVERITY_BLKSZ;
-+    params.salt_size = 0 /* salt_size */;
-+    params.salt = NULL /* salt */;
-+    params.file_size = file_size;
-+    status = libfsverity_compute_digest(fi, rpmVerityRead, &params, &digest);
-+    if (status) {
-+	rpmlog(RPMLOG_DEBUG, _("failed to compute digest\n"));
-+	goto out;
-+    }
-+
-+    digest_hex = pgpHexStr(digest->digest, digest->digest_size);
-+    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
-+	   digest->digest_size, digest_hex);
-+    free(digest_hex);
-+
-+    memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
-+    sig_params.keyfile = key;
-+    sig_params.certfile = cert;
-+    if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) {
-+	rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
-+	goto out;
-+    }
-+
-+    sig_hex = pgpHexStr(sig, *sig_size + 1);
-+ out:
-+    free(digest);
-+    free(sig);
-+    return sig_hex;
-+}
-+
- rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
- 		    char *keypass, char *cert)
- {
--    int rc, status;
-+    int rc;
-     FD_t gzdi;
-     rpmfiles files = NULL;
-     rpmfi fi = NULL;
-     rpmts ts = rpmtsCreate();
--    struct libfsverity_digest *digest = NULL;
--    struct libfsverity_merkle_tree_params params;
--    struct libfsverity_signature_params sig_params;
-+    struct rpmtd_s td;
-     rpm_loff_t file_size;
-     off_t offset = Ftell(fd);
-     const char *compr;
-     char *rpmio_flags = NULL;
--    char *digest_hex;
--    uint8_t *sig;
-+    char *sig_hex;
-     size_t sig_size;
- 
-     Fseek(fd, 0, SEEK_SET);
-@@ -75,43 +118,40 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     fi = rpmfiNewArchiveReader(gzdi, files,
- 			       RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);
- 
-+    /*
-+     * Should this be sigh from the cloned fd or the sigh we received?
-+     */
-+    headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
-+
-+    rpmtdReset(&td);
-+    td.tag = RPMSIGTAG_VERITYSIGNATURES;
-+    td.type = RPM_STRING_ARRAY_TYPE;
-+    td.count = 1;
-+
-     while (rpmfiNext(fi) >= 0) {
--	if (!S_ISREG(rpmfiFMode(fi)))
--	    continue;
- 	file_size = rpmfiFSize(fi);
--	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"),
--	       rpmfiFN(fi), file_size);
--
--	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
--	params.version = 1;
--	params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
--	params.block_size = sysconf(_SC_PAGESIZE);
--	params.salt_size = 0 /* salt_size */;
--	params.salt = NULL /* salt */;
--	params.file_size = file_size;
--	status = libfsverity_compute_digest(fi, rpmVerityRead,
--					    &params, &digest);
--	if (!status) {
--	    digest_hex = pgpHexStr(digest->digest, digest->digest_size);
--	    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
--		   digest->digest_size, digest_hex);
--	    free(digest_hex);
--	}
--	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
--	sig_params.keyfile = key;
--	sig_params.certfile = cert;
--	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {
--	    rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
-+
-+	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),
-+	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));
-+
-+	sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
-+	td.data = &sig_hex;
-+	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);
-+#if 0
-+	rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex);
-+#endif
-+	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {
-+	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
- 	    rc = RPMRC_FAIL;
- 	    goto out;
- 	}
--	rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));
--
--	free(digest);
--	free(sig);
-+	free(sig_hex);
-     }
- 
--out:
-+    rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));
-+
-+    rc = RPMRC_OK;
-+ out:
-     Fseek(fd, offset, SEEK_SET);
- 
-     rpmfilesFree(files);
-diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
-index f3ad3bb18..69bbaf7f7 100644
---- a/sign/rpmsignverity.h
-+++ b/sign/rpmsignverity.h
-@@ -8,6 +8,13 @@
- extern "C" {
- #endif
- 
-+/*
-+ * Block size used to generate the Merkle tree for fsverity. For now
-+ * we only support 4K blocks, if we ever decide to support different
-+ * block sizes, we will need a tag to indicate this.
-+ */
-+#define RPM_FSVERITY_BLKSZ	4096
-+
- /**
-  * Sign file digests in header into signature header
-  * @param fd		file descriptor of RPM
--- 
-2.27.0
-
diff --git a/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch b/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch
deleted file mode 100644
index dba0ca6..0000000
--- a/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch
+++ /dev/null
@@ -1,162 +0,0 @@
-From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 13 Apr 2020 18:14:15 -0400
-Subject: [PATCH 22/33] rpmSignVerity: Generate signatures for files not
- present in archive
-
-This generates signatures for all files in the archive, then picks up
-ghost files from the header metadata and generates signatures for them
-as well. It finally submits them to RPMTAG_VERITYSIGNATURES in header
-file order as we cannot rely on archive order and header order being
-the same.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- lib/package.c        |  1 +
- sign/rpmsignverity.c | 55 ++++++++++++++++++++++++++++++++++----------
- 2 files changed, 44 insertions(+), 12 deletions(-)
-
-diff --git a/lib/package.c b/lib/package.c
-index b7d996a12..c6108f686 100644
---- a/lib/package.c
-+++ b/lib/package.c
-@@ -45,6 +45,7 @@ struct taglate_s {
-     { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 },
-     { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },
-     { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },
-+    { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 },
-     { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },
-     { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },
-     { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index a9818bd08..3bb23a18d 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -41,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
-     struct libfsverity_digest *digest = NULL;
-     rpm_loff_t file_size;
-     char *digest_hex, *sig_hex = NULL;
--    uint8_t *sig;
-+    uint8_t *sig = NULL;
-     int status;
- 
-     file_size = rpmfiFSize(fi);
-@@ -72,7 +72,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
- 	goto out;
-     }
- 
--    sig_hex = pgpHexStr(sig, *sig_size + 1);
-+    sig_hex = pgpHexStr(sig, *sig_size);
-  out:
-     free(digest);
-     free(sig);
-@@ -86,6 +86,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     FD_t gzdi;
-     rpmfiles files = NULL;
-     rpmfi fi = NULL;
-+    rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
-     rpmts ts = rpmtsCreate();
-     struct rpmtd_s td;
-     rpm_loff_t file_size;
-@@ -93,11 +94,14 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     const char *compr;
-     char *rpmio_flags = NULL;
-     char *sig_hex;
-+    char **signatures = NULL;
-     size_t sig_size;
-+    int nr_files, idx;
- 
-     Fseek(fd, 0, SEEK_SET);
-     rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
- 		    RPMVSF_NOHDRCHK);
-+
-     rc = rpmReadPackageFile(ts, fd, "fsverity", &h);
-     if (rc != RPMRC_OK) {
- 	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),
-@@ -113,6 +117,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
- 
-     gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
-     free(rpmio_flags);
-+    if (!gzdi)
-+	rpmlog(RPMLOG_DEBUG, _("Fdopen() failed\n"));
- 
-     files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
-     fi = rpmfiNewArchiveReader(gzdi, files,
-@@ -123,39 +129,64 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-      */
-     headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
- 
--    rpmtdReset(&td);
--    td.tag = RPMSIGTAG_VERITYSIGNATURES;
--    td.type = RPM_STRING_ARRAY_TYPE;
--    td.count = 1;
-+    /*
-+     * The payload doesn't include special files, like ghost files, and
-+     * we cannot rely on the file order in the payload to match that of
-+     * the header. Instead we allocate an array of pointers and populate
-+     * it as we go along. Then walk the header fi and account for the
-+     * special files. Last we walk the array and populate the header.
-+     */
-+    nr_files = rpmfiFC(hfi);
-+    signatures = xcalloc(nr_files, sizeof(char *));
-+
-+    rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),
-+	   nr_files, rpmfiFC(fi));
- 
-     while (rpmfiNext(fi) >= 0) {
- 	file_size = rpmfiFSize(fi);
-+	idx = rpmfiFX(fi);
- 
- 	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),
- 	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));
- 
--	sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
-+	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
-+    }
-+
-+    while (rpmfiNext(hfi) >= 0) {
-+	idx = rpmfiFX(hfi);
-+	if (signatures[idx])
-+	    continue;
-+	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert);
-+    }
-+
-+    rpmtdReset(&td);
-+    td.tag = RPMSIGTAG_VERITYSIGNATURES;
-+    td.type = RPM_STRING_ARRAY_TYPE;
-+    td.count = 1;
-+    for (idx = 0; idx < nr_files; idx++) {
-+	sig_hex = signatures[idx];
- 	td.data = &sig_hex;
--	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);
--#if 0
--	rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex);
--#endif
- 	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {
- 	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
- 	    rc = RPMRC_FAIL;
- 	    goto out;
- 	}
--	free(sig_hex);
-+	rpmlog(RPMLOG_DEBUG, _("signature: %s\n"), signatures[idx]);
-+	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);
-+	free(signatures[idx]);
-+	signatures[idx] = NULL;
-     }
- 
-     rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));
- 
-     rc = RPMRC_OK;
-  out:
-+    signatures = _free(signatures);
-     Fseek(fd, offset, SEEK_SET);
- 
-     rpmfilesFree(files);
-     rpmfiFree(fi);
-+    rpmfiFree(hfi);
-     rpmtsFree(ts);
-     return rc;
- }
--- 
-2.27.0
-
diff --git a/0023-Process-verity-tag-on-package-read.patch b/0023-Process-verity-tag-on-package-read.patch
deleted file mode 100644
index c0b6b74..0000000
--- a/0023-Process-verity-tag-on-package-read.patch
+++ /dev/null
@@ -1,189 +0,0 @@
-From 34e751ccee43f799dd32f6b9c64020106dba9fac Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 13 Apr 2020 18:21:36 -0400
-Subject: [PATCH 23/33] Process verity tag on package read
-
-This processes verity signature tags on package read, and provides
-accessor functions to access them.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- lib/rpmfi.c          | 27 +++++++++++++++++++++++++++
- lib/rpmfi.h          |  8 ++++++++
- lib/rpmfiles.h       | 10 ++++++++++
- sign/rpmsignverity.c | 20 ++++++++++++++++----
- 4 files changed, 61 insertions(+), 4 deletions(-)
-
-diff --git a/lib/rpmfi.c b/lib/rpmfi.c
-index 8c69d3e40..5fdbe02a2 100644
---- a/lib/rpmfi.c
-+++ b/lib/rpmfi.c
-@@ -116,8 +116,10 @@ struct rpmfiles_s {
- 
-     int digestalgo;		/*!< File digest algorithm */
-     uint32_t *signatureoffs;	/*!< File signature offsets */
-+    int veritysiglength;	/*!< Verity signature length */
-     unsigned char * digests;	/*!< File digests in binary. */
-     unsigned char * signatures; /*!< File signatures in binary. */
-+    unsigned char * veritysigs; /*!< Verity signatures in binary. */
- 
-     struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */
-     rpm_off_t * replacedSizes;	/*!< (TR_ADDED) */
-@@ -582,6 +584,19 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
-     return signature;
- }
- 
-+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)
-+{
-+    const unsigned char *vsignature = NULL;
-+
-+    if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
-+	if (fi->veritysigs != NULL)
-+	    vsignature = fi->veritysigs + (fi->veritysiglength * ix);
-+	if (len)
-+	    *len = fi->veritysiglength;
-+    }
-+    return vsignature;
-+}
-+
- const char * rpmfilesFLink(rpmfiles fi, int ix)
- {
-     const char * flink = NULL;
-@@ -1268,6 +1283,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)
- 	fi->digests = _free(fi->digests);
- 	fi->signatures = _free(fi->signatures);
- 	fi->signatureoffs = _free(fi->signatureoffs);
-+	fi->veritysigs = _free(fi->veritysigs);
- 	fi->fcaps = _free(fi->fcaps);
- 
- 	fi->cdict = _free(fi->cdict);
-@@ -1649,6 +1665,12 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
- 				 totalfc, &fi->signatureoffs);
-     }
- 
-+    fi->veritysigs = NULL;
-+    if (!(flags & RPMFI_NOVERITYSIGNATURES)) {
-+	fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES,
-+				  totalfc, &fi->veritysiglength);
-+    }
-+
-     /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
-     if (!(flags & RPMFI_NOFILEMTIMES))
- 	_hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
-@@ -1939,6 +1961,11 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)
-     return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);
- }
- 
-+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len)
-+{
-+    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len);
-+}
-+
- uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
- {
-     return rpmfilesFDepends(fi->files,  fi ? fi->i : -1, fddictp);
-diff --git a/lib/rpmfi.h b/lib/rpmfi.h
-index 6ef70cd28..fcb9d3acd 100644
---- a/lib/rpmfi.h
-+++ b/lib/rpmfi.h
-@@ -190,6 +190,14 @@ char * rpmfiFDigestHex(rpmfi fi, int *algo);
-  */
- const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen);
- 
-+/** \ingroup rpmfi
-+ * Return current verity (binary) signature of file info set iterator.
-+ * @param fi		file info set iterator
-+ * @retval siglen	signature length (pass NULL to ignore)
-+ * @return		current verity signature, NULL on invalid
-+ */
-+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen);
-+
- /** \ingroup rpmfi
-  * Return current file linkto (i.e. symlink(2) target) from file info set iterator.
-  * @param fi		file info set iterator
-diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
-index daf572cf4..81b3d01a1 100644
---- a/lib/rpmfiles.h
-+++ b/lib/rpmfiles.h
-@@ -119,6 +119,7 @@ enum rpmfiFlags_e {
-     RPMFI_NOFILEVERIFYFLAGS	= (1 << 16),
-     RPMFI_NOFILEFLAGS		= (1 << 17),
-     RPMFI_NOFILESIGNATURES	= (1 << 18),
-+    RPMFI_NOVERITYSIGNATURES	= (1 << 19),
- };
- 
- typedef rpmFlags rpmfiFlags;
-@@ -442,6 +443,15 @@ const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *le
-  */
- const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len);
- 
-+/** \ingroup rpmfiles
-+ * Return file verity signature (binary)
-+ * @param fi            file info set
-+ * @param ix            file index
-+ * @retval len       signature length (pass NULL to ignore)
-+ * @return              verity signature, NULL on invalid
-+ */
-+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len);
-+
- /** \ingroup rpmfiles
-  * Return file rdev from file info set.
-  * @param fi		file info set
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index 3bb23a18d..177561957 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -15,6 +15,7 @@
- #include "lib/rpmtypes.h"	/* rpmRC */
- #include <libfsverity.h>
- #include "rpmio/rpmio_internal.h"
-+#include "rpmio/rpmbase64.h"
- #include "lib/rpmvs.h"
- 
- #include "sign/rpmsignverity.h"
-@@ -40,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
-     struct libfsverity_signature_params sig_params;
-     struct libfsverity_digest *digest = NULL;
-     rpm_loff_t file_size;
--    char *digest_hex, *sig_hex = NULL;
-+    char *digest_hex, *digest_base64, *sig_base64 = NULL, *sig_hex = NULL;
-     uint8_t *sig = NULL;
-     int status;
- 
-@@ -60,8 +61,14 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
-     }
- 
-     digest_hex = pgpHexStr(digest->digest, digest->digest_size);
--    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
--	   digest->digest_size, digest_hex);
-+    digest_base64 = rpmBase64Encode(digest->digest, digest->digest_size, -1);
-+    rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest(%i): %s, idx %i\n"),
-+	   file_size, rpmfiFN(fi), digest->digest_size, digest_hex,
-+	   rpmfiFX(fi));
-+    rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest sz (%i): base64 sz (%li), %s, idx %i\n"),
-+	   file_size, rpmfiFN(fi), digest->digest_size, strlen(digest_base64),
-+	   digest_base64, rpmfiFX(fi));
-+
-     free(digest_hex);
- 
-     memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
-@@ -73,10 +80,15 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
-     }
- 
-     sig_hex = pgpHexStr(sig, *sig_size);
-+    sig_base64 = rpmBase64Encode(sig, *sig_size, -1);
-+    rpmlog(RPMLOG_DEBUG, _("%s: sig_size(%li), base64_size(%li), idx %i: signature:\n%s\n"),
-+	   rpmfiFN(fi), *sig_size, strlen(sig_base64), rpmfiFX(fi), sig_hex);
-  out:
-+    free(sig_hex);
-+
-     free(digest);
-     free(sig);
--    return sig_hex;
-+    return sig_base64;
- }
- 
- rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
--- 
-2.27.0
-
diff --git a/0024-Generate-a-zero-length-signature-for-symlinks.patch b/0024-Generate-a-zero-length-signature-for-symlinks.patch
deleted file mode 100644
index 2fc3f5a..0000000
--- a/0024-Generate-a-zero-length-signature-for-symlinks.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 202359dc598f2162175e3a8552c9b338d27b8989 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Tue, 14 Apr 2020 10:33:32 -0400
-Subject: [PATCH 24/33] Generate a zero-length signature for symlinks
-
-The fsverity utility follows the symlink when generating a signature.
-Since we don't want to sign the same file twice, we need to skip these
-links, and instead just generate a dummy zero-length signature here.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- sign/rpmsignverity.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index 177561957..2c7d21620 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -45,7 +45,10 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
-     uint8_t *sig = NULL;
-     int status;
- 
--    file_size = rpmfiFSize(fi);
-+    if (S_ISLNK(rpmfiFMode(fi)))
-+	file_size = 0;
-+    else
-+	file_size = rpmfiFSize(fi);
- 
-     memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
-     params.version = 1;
--- 
-2.27.0
-
diff --git a/0025-rpmsignverity.c-Clean-up-debug-logging.patch b/0025-rpmsignverity.c-Clean-up-debug-logging.patch
deleted file mode 100644
index bb6e4f3..0000000
--- a/0025-rpmsignverity.c-Clean-up-debug-logging.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 7e50b3f4b2ebb963d1080a0a1469517ef81f780c Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Tue, 14 Apr 2020 12:08:09 -0400
-Subject: [PATCH 25/33] rpmsignverity.c: Clean up debug logging
-
-Put most logging in one place and avoid printing the same info twice.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- sign/rpmsignverity.c | 5 -----
- 1 file changed, 5 deletions(-)
-
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index 2c7d21620..445e1197c 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -104,7 +104,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
-     rpmts ts = rpmtsCreate();
-     struct rpmtd_s td;
--    rpm_loff_t file_size;
-     off_t offset = Ftell(fd);
-     const char *compr;
-     char *rpmio_flags = NULL;
-@@ -158,12 +157,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
- 	   nr_files, rpmfiFC(fi));
- 
-     while (rpmfiNext(fi) >= 0) {
--	file_size = rpmfiFSize(fi);
- 	idx = rpmfiFX(fi);
- 
--	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),
--	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));
--
- 	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
-     }
- 
--- 
-2.27.0
-
diff --git a/0026-fsverity-add-tag-for-fsverity-algorithm.patch b/0026-fsverity-add-tag-for-fsverity-algorithm.patch
deleted file mode 100644
index 74b2fc1..0000000
--- a/0026-fsverity-add-tag-for-fsverity-algorithm.patch
+++ /dev/null
@@ -1,161 +0,0 @@
-From e339fdbbd0b81dc1fcdc2032e861b8a5fa6e062d Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 20 Apr 2020 13:40:26 -0400
-Subject: [PATCH 26/33] fsverity - add tag for fsverity algorithm
-
-The default algorith is SHA256, but fsverity allows for other
-algorithms, so add a tag to handle this.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- lib/package.c        |  1 +
- lib/rpmfi.c          |  2 ++
- lib/rpmtag.h         |  2 ++
- sign/rpmsignverity.c | 32 ++++++++++++++++++++++++++++----
- 4 files changed, 33 insertions(+), 4 deletions(-)
-
-diff --git a/lib/package.c b/lib/package.c
-index c6108f686..3c761d365 100644
---- a/lib/package.c
-+++ b/lib/package.c
-@@ -46,6 +46,7 @@ struct taglate_s {
-     { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },
-     { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },
-     { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 },
-+    { RPMSIGTAG_VERITYSIGNATUREALGO, RPMTAG_VERITYSIGNATUREALGO, 1, 0 },
-     { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },
-     { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },
-     { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },
-diff --git a/lib/rpmfi.c b/lib/rpmfi.c
-index 5fdbe02a2..70f05f509 100644
---- a/lib/rpmfi.c
-+++ b/lib/rpmfi.c
-@@ -118,6 +118,7 @@ struct rpmfiles_s {
-     int digestalgo;		/*!< File digest algorithm */
-     uint32_t *signatureoffs;	/*!< File signature offsets */
-     int veritysiglength;	/*!< Verity signature length */
-+    uint16_t verityalgo;	/*!< Verity algorithm */
-     unsigned char * digests;	/*!< File digests in binary. */
-     unsigned char * signatures; /*!< File signatures in binary. */
-     unsigned char * veritysigs; /*!< Verity signatures in binary. */
-@@ -1667,6 +1668,7 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
- 
-     fi->veritysigs = NULL;
-     if (!(flags & RPMFI_NOVERITYSIGNATURES)) {
-+	fi->verityalgo = headerGetNumber(h, RPMTAG_VERITYSIGNATUREALGO);
- 	fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES,
- 				  totalfc, &fi->veritysiglength);
-     }
-diff --git a/lib/rpmtag.h b/lib/rpmtag.h
-index 478457ecb..8d1efcc79 100644
---- a/lib/rpmtag.h
-+++ b/lib/rpmtag.h
-@@ -68,6 +68,7 @@ typedef enum rpmTag_e {
-     /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */
-     /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
-     RPMTAG_VERITYSIGNATURES	= RPMTAG_SIG_BASE+20,	/* s[] */
-+    RPMTAG_VERITYSIGNATUREALGO	= RPMTAG_SIG_BASE+21,	/* i */
- 
-     RPMTAG_NAME  		= 1000,	/* s */
- #define	RPMTAG_N	RPMTAG_NAME	/* s */
-@@ -431,6 +432,7 @@ typedef enum rpmSigTag_e {
-     RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 18,
-     RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 19,
-     RPMSIGTAG_VERITYSIGNATURES		= RPMTAG_VERITYSIGNATURES,
-+    RPMSIGTAG_VERITYSIGNATUREALGO	= RPMTAG_VERITYSIGNATUREALGO,
- } rpmSigTag;
- 
- 
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index 445e1197c..55096e732 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -35,7 +35,7 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)
- }
- 
- static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
--			       char *keypass, char *cert)
-+			       char *keypass, char *cert, uint16_t algo)
- {
-     struct libfsverity_merkle_tree_params params;
-     struct libfsverity_signature_params sig_params;
-@@ -52,7 +52,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
- 
-     memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
-     params.version = 1;
--    params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
-+    params.hash_algorithm = algo;
-     params.block_size = RPM_FSVERITY_BLKSZ;
-     params.salt_size = 0 /* salt_size */;
-     params.salt = NULL /* salt */;
-@@ -111,6 +111,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     char **signatures = NULL;
-     size_t sig_size;
-     int nr_files, idx;
-+    uint16_t algo;
-+    uint32_t algo32;
- 
-     Fseek(fd, 0, SEEK_SET);
-     rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
-@@ -142,6 +144,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-      * Should this be sigh from the cloned fd or the sigh we received?
-      */
-     headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
-+    headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO);
- 
-     /*
-      * The payload doesn't include special files, like ghost files, and
-@@ -153,20 +156,24 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     nr_files = rpmfiFC(hfi);
-     signatures = xcalloc(nr_files, sizeof(char *));
- 
-+    algo = FS_VERITY_HASH_ALG_SHA256;
-+
-     rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),
- 	   nr_files, rpmfiFC(fi));
- 
-     while (rpmfiNext(fi) >= 0) {
- 	idx = rpmfiFX(fi);
- 
--	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
-+	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert,
-+					    algo);
-     }
- 
-     while (rpmfiNext(hfi) >= 0) {
- 	idx = rpmfiFX(hfi);
- 	if (signatures[idx])
- 	    continue;
--	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert);
-+	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert,
-+					    algo);
-     }
- 
-     rpmtdReset(&td);
-@@ -187,6 +194,23 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
- 	signatures[idx] = NULL;
-     }
- 
-+    if (sig_size == 0) {
-+	rpmlog(RPMLOG_ERR, _("Zero length fsverity signature\n"));
-+	rc = RPMRC_FAIL;
-+	goto out;
-+    }
-+
-+    rpmtdReset(&td);
-+
-+    /* RPM doesn't like new 16 bit types, so use a 32 bit tag */
-+    algo32 = algo;
-+    rpmtdReset(&td);
-+    td.tag = RPMSIGTAG_VERITYSIGNATUREALGO;
-+    td.type = RPM_INT32_TYPE;
-+    td.data = &algo32;
-+    td.count = 1;
-+    headerPut(sigh, &td, HEADERPUT_DEFAULT);
-+
-     rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));
- 
-     rc = RPMRC_OK;
--- 
-2.27.0
-
diff --git a/0027-plugins-fsverity-Install-fsverity-signatures.patch b/0027-plugins-fsverity-Install-fsverity-signatures.patch
deleted file mode 100644
index c302c97..0000000
--- a/0027-plugins-fsverity-Install-fsverity-signatures.patch
+++ /dev/null
@@ -1,257 +0,0 @@
-From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 20 Apr 2020 11:11:25 -0400
-Subject: [PATCH 27/33] plugins/fsverity: Install fsverity signatures
-
-This plugin installs fsverity signatures for regular files, when a signature
-is found in the RPM. It tries to enable them unconditionally, but fails
-gracefully if fsverity isn't supported or enabled.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- configure.ac        |  29 ++++++++
- macros.in           |   4 +
- plugins/Makefile.am |   7 ++
- plugins/fsverity.c  | 177 ++++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 217 insertions(+)
- create mode 100644 plugins/fsverity.c
-
-diff --git a/configure.ac b/configure.ac
-index cc7144440..7d3c31831 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -1049,6 +1049,11 @@ AS_IF([test "$enable_plugins" != no],[
- ])
- AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])
- 
-+AS_IF([test "$enable_plugins" != no],[
-+AC_CHECK_HEADERS([linux/fsverity.h],[FSVERITY_IOCTL="yes"])
-+])
-+AM_CONDITIONAL(FSVERITY_IOCTL,[test "x$FSVERITY_IOCTL" = xyes])
-+
- #=================
- # Check for fapolicyd support
- AC_ARG_WITH(fapolicyd,
-diff --git a/macros.in b/macros.in
-index fe8862903..3c722146b 100644
---- a/macros.in
-+++ b/macros.in
-@@ -767,6 +767,9 @@ package or when debugging this package.\
- # a wrong or missing signature.
- #%_ima_sign_config_files	0
- 
-+# Set to 1 to have fsverity signatures written for %config files.
-+#%_fsverity_sign_config_files	0
-+
- #
- # Default output format string for rpm -qa
- #
-@@ -1185,6 +1188,7 @@ package or when debugging this package.\
- %__transaction_syslog		%{__plugindir}/syslog.so
- %__transaction_ima		%{__plugindir}/ima.so
- %__transaction_fapolicyd	%{__plugindir}/fapolicyd.so
-+%__transaction_fsverity		%{__plugindir}/fsverity.so
- %__transaction_prioreset	%{__plugindir}/prioreset.so
- %__transaction_audit		%{__plugindir}/audit.so
- 
-diff --git a/plugins/Makefile.am b/plugins/Makefile.am
-index cbfb81e19..e51b71f62 100644
---- a/plugins/Makefile.am
-+++ b/plugins/Makefile.am
-@@ -48,3 +48,10 @@ audit_la_sources = audit.c
- audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@
- plugins_LTLIBRARIES += audit.la
- endif
-+
-+if FSVERITY_IOCTL
-+fsverity_la_sources = fsverity.c
-+fsverity_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
-+plugins_LTLIBRARIES += fsverity.la
-+endif
-+
-diff --git a/plugins/fsverity.c b/plugins/fsverity.c
-new file mode 100644
-index 000000000..15ddcf33e
---- /dev/null
-+++ b/plugins/fsverity.c
-@@ -0,0 +1,177 @@
-+/**
-+ * Copyright (C) 2020 Facebook
-+ *
-+ * Author: Jes Sorensen <jsorensen@fb.com>
-+ */
-+
-+#include "system.h"
-+
-+#include <errno.h>
-+#include <fcntl.h>
-+#include <sys/ioctl.h>
-+#include <linux/fsverity.h>
-+
-+#include <rpm/rpmfi.h>
-+#include <rpm/rpmte.h>
-+#include <rpm/rpmfiles.h>
-+#include <rpm/rpmtypes.h>
-+#include <rpm/rpmlog.h>
-+#include <rpmio/rpmstring.h>
-+#include <rpmio/rpmmacro.h>
-+
-+#include "lib/rpmfs.h"
-+#include "lib/rpmplugin.h"
-+#include "lib/rpmte_internal.h"
-+
-+#include "sign/rpmsignverity.h"
-+
-+static int sign_config_files = 0;
-+
-+/*
-+ * This unconditionally tries to apply the fsverity signature to a file,
-+ * but fails gracefully if the file system doesn't support it or the
-+ * verity feature flag isn't enabled in the file system (ext4).
-+ */
-+static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
-+				       const char *path, const char *dest,
-+				       mode_t file_mode, rpmFsmOp op)
-+{
-+    struct fsverity_enable_arg arg;
-+    const unsigned char * signature = NULL;
-+    size_t len;
-+    int rc = RPMRC_OK;
-+    int fd;
-+    rpmFileAction action = XFO_ACTION(op);
-+    char *buffer;
-+
-+    /* Ignore skipped files and unowned directories */
-+    if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) {
-+	rpmlog(RPMLOG_DEBUG, "fsverity skipping early: path %s dest %s\n",
-+	       path, dest);
-+	goto exit;
-+    }
-+
-+    /*
-+     * Do not install signatures for config files unless the
-+     * user explicitly asks for it.
-+     */
-+    if (rpmfiFFlags(fi) & RPMFILE_CONFIG) {
-+	if (!(rpmfiFMode(fi) & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
-+	    !sign_config_files) {
-+	    rpmlog(RPMLOG_DEBUG, "fsverity skipping: path %s dest %s\n",
-+		   path, dest);
-+
-+	    goto exit;
-+	}
-+    }
-+
-+    /*
-+     * Right now fsverity doesn't deal with symlinks or directories, so do
-+     * not try to install signatures for non regular files.
-+     */
-+    if (!S_ISREG(rpmfiFMode(fi))) {
-+	rpmlog(RPMLOG_DEBUG, "fsverity skipping non regular: path %s dest %s\n",
-+	       path, dest);
-+	goto exit;
-+    }
-+
-+    signature = rpmfiVSignature(fi, &len);
-+    if (!signature || !len) {
-+	rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n",
-+	       path, dest);
-+	goto exit;
-+    }
-+
-+    memset(&arg, 0, sizeof(arg));
-+    arg.version = 1;
-+    arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
-+    arg.block_size = RPM_FSVERITY_BLKSZ;
-+    arg.sig_ptr = (uintptr_t)signature;
-+    arg.sig_size = len;
-+
-+    buffer = pgpHexStr(signature, arg.sig_size);
-+    rpmlog(RPMLOG_DEBUG, "applying signature: %s\n", buffer);
-+    free(buffer);
-+
-+    fd = open(path, O_RDONLY);
-+    if (fd < 0) {
-+	rpmlog(RPMLOG_ERR, "failed to open path %s\n", path);
-+	goto exit;
-+    }
-+
-+    /*
-+     * Enable fsverity on the file.
-+     * fsverity not supported by file system (ENOTTY) and fsverity not
-+     * enabled on file system are expected and not considered
-+     * errors. Every other non-zero error code will result in the
-+     * installation failing.
-+     */
-+    if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) != 0) {
-+	switch(errno) {
-+	case EBADMSG:
-+	    rpmlog(RPMLOG_DEBUG, "invalid or malformed fsverity signature for %s\n", path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	case EEXIST:
-+	    rpmlog(RPMLOG_DEBUG, "fsverity signature already enabled %s\n",
-+		   path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	case EINVAL:
-+	    rpmlog(RPMLOG_DEBUG, "invalid arguments for ioctl %s\n", path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	case EKEYREJECTED:
-+	    rpmlog(RPMLOG_DEBUG, "signature doesn't match file %s\n", path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	case EMSGSIZE:
-+	    rpmlog(RPMLOG_DEBUG, "invalid signature size for %s\n", path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	case ENOPKG:
-+	    rpmlog(RPMLOG_DEBUG, "unsupported signature algoritm (%i) for %s\n",
-+		   arg.hash_algorithm, path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	case ETXTBSY:
-+	    rpmlog(RPMLOG_DEBUG, "file is open by other process %s\n",
-+		   path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	case ENOTTY:
-+	    rpmlog(RPMLOG_DEBUG, "fsverity not supported by file system for %s\n",
-+		   path);
-+	    break;
-+	case EOPNOTSUPP:
-+	    rpmlog(RPMLOG_DEBUG, "fsverity not enabled on file system for %s\n",
-+		   path);
-+	    break;
-+	default:
-+	    rpmlog(RPMLOG_DEBUG, "failed to enable verity (errno %i) for %s\n",
-+		   errno, path);
-+	    rc = RPMRC_FAIL;
-+	    break;
-+	}
-+    }
-+
-+    rpmlog(RPMLOG_DEBUG, "fsverity enabled signature for: path %s dest %s\n",
-+	   path, dest);
-+    close(fd);
-+exit:
-+    return rc;
-+}
-+
-+static rpmRC fsverity_init(rpmPlugin plugin, rpmts ts)
-+{
-+    sign_config_files = rpmExpandNumeric("%{?_fsverity_sign_config_files}");
-+
-+    rpmlog(RPMLOG_DEBUG, "fsverity_init\n");
-+
-+    return RPMRC_OK;
-+}
-+
-+struct rpmPluginHooks_s fsverity_hooks = {
-+    .init = fsverity_init,
-+    .fsm_file_prepare = fsverity_fsm_file_prepare,
-+};
--- 
-2.27.0
-
diff --git a/0028-fsverity-plugin-Use-tag-for-algorithm.patch b/0028-fsverity-plugin-Use-tag-for-algorithm.patch
deleted file mode 100644
index 0b9bb41..0000000
--- a/0028-fsverity-plugin-Use-tag-for-algorithm.patch
+++ /dev/null
@@ -1,116 +0,0 @@
-From 5a5286ac37cd58779cc0e5b69088d9acc8f40c4e Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 20 Apr 2020 14:13:51 -0400
-Subject: [PATCH 28/33] fsverity plugin: Use tag for algorithm
-
-This uses the algorithm from the tag, if available. Fallback is SHA256.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- lib/rpmfi.c        | 9 ++++++---
- lib/rpmfi.h        | 3 ++-
- lib/rpmfiles.h     | 3 ++-
- plugins/fsverity.c | 8 ++++++--
- 4 files changed, 16 insertions(+), 7 deletions(-)
-
-diff --git a/lib/rpmfi.c b/lib/rpmfi.c
-index 70f05f509..3e2b4e676 100644
---- a/lib/rpmfi.c
-+++ b/lib/rpmfi.c
-@@ -585,7 +585,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
-     return signature;
- }
- 
--const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)
-+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len,
-+					 uint16_t *algo)
- {
-     const unsigned char *vsignature = NULL;
- 
-@@ -594,6 +595,8 @@ const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)
- 	    vsignature = fi->veritysigs + (fi->veritysiglength * ix);
- 	if (len)
- 	    *len = fi->veritysiglength;
-+	if (algo)
-+	    *algo = fi->verityalgo;
-     }
-     return vsignature;
- }
-@@ -1963,9 +1966,9 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)
-     return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);
- }
- 
--const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len)
-+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len, uint16_t *algo)
- {
--    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len);
-+    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len, algo);
- }
- 
- uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
-diff --git a/lib/rpmfi.h b/lib/rpmfi.h
-index fcb9d3acd..6fd2747d6 100644
---- a/lib/rpmfi.h
-+++ b/lib/rpmfi.h
-@@ -194,9 +194,10 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen);
-  * Return current verity (binary) signature of file info set iterator.
-  * @param fi		file info set iterator
-  * @retval siglen	signature length (pass NULL to ignore)
-+ * @retval algo		fsverity algorithm
-  * @return		current verity signature, NULL on invalid
-  */
--const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen);
-+const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen, uint16_t *algo);
- 
- /** \ingroup rpmfi
-  * Return current file linkto (i.e. symlink(2) target) from file info set iterator.
-diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
-index 81b3d01a1..64b33281a 100644
---- a/lib/rpmfiles.h
-+++ b/lib/rpmfiles.h
-@@ -450,7 +450,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len);
-  * @retval len       signature length (pass NULL to ignore)
-  * @return              verity signature, NULL on invalid
-  */
--const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len);
-+const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len,
-+					 uint16_t *algo);
- 
- /** \ingroup rpmfiles
-  * Return file rdev from file info set.
-diff --git a/plugins/fsverity.c b/plugins/fsverity.c
-index 15ddcf33e..1e7f38b38 100644
---- a/plugins/fsverity.c
-+++ b/plugins/fsverity.c
-@@ -39,6 +39,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
-     struct fsverity_enable_arg arg;
-     const unsigned char * signature = NULL;
-     size_t len;
-+    uint16_t algo = 0;
-     int rc = RPMRC_OK;
-     int fd;
-     rpmFileAction action = XFO_ACTION(op);
-@@ -75,7 +76,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
- 	goto exit;
-     }
- 
--    signature = rpmfiVSignature(fi, &len);
-+    signature = rpmfiVSignature(fi, &len, &algo);
-     if (!signature || !len) {
- 	rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n",
- 	       path, dest);
-@@ -84,7 +85,10 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
- 
-     memset(&arg, 0, sizeof(arg));
-     arg.version = 1;
--    arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
-+    if (algo)
-+	arg.hash_algorithm = algo;
-+    else
-+	arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
-     arg.block_size = RPM_FSVERITY_BLKSZ;
-     arg.sig_ptr = (uintptr_t)signature;
-     arg.sig_size = len;
--- 
-2.27.0
-
diff --git a/0029-Add-fsverity-tags-to-rpmgeneral.at.patch b/0029-Add-fsverity-tags-to-rpmgeneral.at.patch
deleted file mode 100644
index 6575b99..0000000
--- a/0029-Add-fsverity-tags-to-rpmgeneral.at.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 3132053a066b3dc8aa38b358ecd316ee60fd0f7c Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 20 Apr 2020 18:52:08 -0400
-Subject: [PATCH 29/33] Add fsverity tags to rpmgeneral.at
-
-Make sure we pass the checks with the new tags in place.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- tests/rpmgeneral.at | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at
-index 45d38698b..8a7dc827f 100644
---- a/tests/rpmgeneral.at
-+++ b/tests/rpmgeneral.at
-@@ -291,6 +291,8 @@ VERBOSE
- VERIFYSCRIPT
- VERIFYSCRIPTFLAGS
- VERIFYSCRIPTPROG
-+VERITYSIGNATUREALGO
-+VERITYSIGNATURES
- VERSION
- XPM
- ])
--- 
-2.27.0
-
diff --git a/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch b/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch
deleted file mode 100644
index d872d5e..0000000
--- a/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch
+++ /dev/null
@@ -1,117 +0,0 @@
-From 46db4f6827840e828f42424454410b930895d9a7 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Mon, 13 Apr 2020 18:24:31 -0400
-Subject: [PATCH 30/33] Add --delfilesign flag to delete IMA and fsverity file
- signatures
-
-This allows a user to remove both types of file signatures from the
-package. Previously there was no way to delete IMA signatures, only
-replace them by first removing the package signature and then
-resigning the package and the files.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- rpmsign.c        | 12 ++++++++++++
- sign/rpmgensig.c | 17 ++++++++++++++++-
- sign/rpmsign.h   |  9 +++++++++
- 3 files changed, 37 insertions(+), 1 deletion(-)
-
-diff --git a/rpmsign.c b/rpmsign.c
-index 074dd8b13..e43811e9f 100644
---- a/rpmsign.c
-+++ b/rpmsign.c
-@@ -14,6 +14,7 @@ enum modes {
-     MODE_ADDSIGN = (1 << 0),
-     MODE_RESIGN  = (1 << 1),
-     MODE_DELSIGN = (1 << 2),
-+    MODE_DELFILESIGN = (1 << 3),
- };
- 
- static int mode = MODE_NONE;
-@@ -35,6 +36,10 @@ static struct poptOption signOptsTable[] = {
- 	N_("sign package(s) (identical to --addsign)"), NULL },
-     { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
- 	N_("delete package signatures"), NULL },
-+#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
-+    { "delfilesign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode,
-+      MODE_DELFILESIGN,	N_("delete IMA and fsverity file signatures"), NULL },
-+#endif
-     { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
- 	&sargs.signflags, RPMSIGN_FLAG_RPMV3,
- 	N_("create rpm v3 header+payload signatures") },
-@@ -207,6 +212,13 @@ int main(int argc, char *argv[])
- 		ec++;
- 	}
- 	break;
-+    case MODE_DELFILESIGN:
-+	ec = 0;
-+	while ((arg = poptGetArg(optCon)) != NULL) {
-+	    if (rpmPkgDelFileSign(arg, &sargs) < 0)
-+		ec++;
-+	}
-+	break;
-     case MODE_NONE:
- 	printUsage(optCon, stderr, 0);
- 	break;
-diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
-index 8d5c5858f..02cf0bc62 100644
---- a/sign/rpmgensig.c
-+++ b/sign/rpmgensig.c
-@@ -336,6 +336,14 @@ static void deleteSigs(Header sigh)
-     headerDel(sigh, RPMSIGTAG_PGP5);
- }
- 
-+static void deleteFileSigs(Header sigh)
-+{
-+    headerDel(sigh, RPMSIGTAG_FILESIGNATURELENGTH);
-+    headerDel(sigh, RPMSIGTAG_FILESIGNATURES);
-+    headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
-+    headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO);
-+}
-+
- static int haveSignature(rpmtd sigtd, Header h)
- {
-     pgpDigParams sig1 = NULL;
-@@ -580,7 +588,9 @@ static int rpmSign(const char *rpm, int deleting, int flags)
- 	    goto exit;
-     }
- 
--    if (deleting) {	/* Nuke all the signature tags. */
-+    if (deleting == 2) {	/* Nuke IMA + fsverity file signature tags. */
-+	deleteFileSigs(sigh);
-+    } else if (deleting) {	/* Nuke all the signature tags. */
- 	deleteSigs(sigh);
-     } else {
- 	/* Signature target containing header + payload */
-@@ -745,3 +755,8 @@ int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args)
- {
-     return rpmSign(path, 1, 0);
- }
-+
-+int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args)
-+{
-+    return rpmSign(path, 2, 0);
-+}
-diff --git a/sign/rpmsign.h b/sign/rpmsign.h
-index 2b8a10a1a..5169741dd 100644
---- a/sign/rpmsign.h
-+++ b/sign/rpmsign.h
-@@ -44,6 +44,15 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args);
-  */
- int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args);
- 
-+
-+/** \ingroup rpmsign
-+ * Delete file signature(s) from a package
-+ * @param path		path to package
-+ * @param args		signing parameters (or NULL for defaults)
-+ * @return		0 on success
-+ */
-+int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args);
-+
- #ifdef __cplusplus
- }
- #endif
--- 
-2.27.0
-
diff --git a/0031-Update-man-page-for-rpmsign.patch b/0031-Update-man-page-for-rpmsign.patch
deleted file mode 100644
index 938e0f1..0000000
--- a/0031-Update-man-page-for-rpmsign.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 4d243b7e692e3803a764343dfed23feb1c656f0b Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Tue, 12 May 2020 13:42:34 -0400
-Subject: [PATCH 31/33] Update man page for rpmsign
-
-This documents the new arguments --signverity and --certpath required
-to sign a package with fsverity signatures.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- doc/rpmsign.8 | 20 ++++++++++++++++++++
- 1 file changed, 20 insertions(+)
-
-diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
-index f7ceae89b..a212746fe 100644
---- a/doc/rpmsign.8
-+++ b/doc/rpmsign.8
-@@ -9,6 +9,8 @@ rpmsign \- RPM Package Signing
- 
- \fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
- 
-+\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
-+
- .SS "rpmsign-options"
- .PP
- [\fb--rpmv3\fR]
-@@ -30,6 +32,12 @@ packages with a MD5/SHA1 checksums cannot be signed in FIPS mode.
- .PP
- Delete all signatures from each package \fIPACKAGE_FILE\fR given.
- 
-+\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
-+
-+.PP
-+Delete all IMA and fsverity file signatures from each package
-+\fIPACKAGE_FILE\fR given.
-+
- .SS "SIGN OPTIONS"
- .PP
- .TP
-@@ -44,12 +52,23 @@ signature verifiable with rpm < 4.14 or other interoperability reasons.
- \fB--fskpath \fIKEY\fB\fR
- Used with \fB--signfiles\fR, use file signing key \fIKey\fR.
- .TP
-+\fB--certpath \fICERT\fB\fR
-+Used with \fB--signverity\fR, use file signing certificate \fICert\fR.
-+.TP
- \fB--signfiles\fR
- Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must
- be set to a supported algorithm before building the package. The
- supported algorithms are SHA1, SHA256, SHA384, and SHA512, which are
- represented as 2, 8, 9, and 10 respectively.  The file signing key (RSA
- private key) must be set before signing the package, it can be configured on the command line with \fB--fskpath\fR or the macro %_file_signing_key.
-+.TP
-+\fB--signverity\fR
-+Sign package files with fsverity signatures. The file signing key (RSA
-+private key) and the signing certificate must be set before signing
-+the package. The key can be configured on the command line with
-+\fB--fskpath\fR or the macro %_file_signing_key, and the cert can be
-+configured on the command line with \fB--certpath\fR or the macro
-+%_file_signing_cert.
- 
- .SS "USING GPG TO SIGN PACKAGES"
- .PP
-@@ -110,4 +129,5 @@ Jeff Johnson <jbj@redhat.com>
- Erik Troan <ewt@redhat.com>
- Panu Matilainen <pmatilai@redhat.com>
- Fionnuala Gunter <fin@linux.vnet.ibm.com>
-+Jes Sorensen <jsorensen@fb.com>
- .fi
--- 
-2.27.0
-
diff --git a/0031-rpmcow-denylist.patch b/0031-rpmcow-denylist.patch
index da7aee3..676d8be 100644
--- a/0031-rpmcow-denylist.patch
+++ b/0031-rpmcow-denylist.patch
@@ -13,6 +13,15 @@ Date:   Wed Oct 19 23:05:17 2022 +0200
     specific packages.
 
 Signed-off-by: Richard Phibel <richardphibel@meta.com>
+---
+ build/pack.c         |   2 +-
+ lib/package.c        |   6 +--
+ lib/rpmlead.c        |  43 +++++++++---------
+ lib/rpmlead.h        |  37 +++++++++++++++-
+ rpm2extents.c        | 102 ++++++++++++++++++++++++++++++++-----------
+ sign/rpmgensig.c     |   2 +-
+ tests/rpm2extents.at |  11 +++++
+ 7 files changed, 148 insertions(+), 55 deletions(-)
 
 diff --git a/build/pack.c b/build/pack.c
 index 8d6f74935ebb8a4d65aa2bcb666825a99162be9c..e2f05b6412d3e0d814a1160a0dcdfad5c323a8f8 100644
@@ -31,7 +40,7 @@ diff --git a/lib/package.c b/lib/package.c
 index 90bd0d8a719353e8965c140b40e2dceef80a2ed1..fd41abbf6b4df07afa2caf1c47d9724765ee84e8 100644
 --- a/lib/package.c
 +++ b/lib/package.c
-@@ -412,11 +412,7 @@ rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp)
+@@ -410,11 +410,7 @@ rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp)
      Header h = NULL;
      Header sigh = NULL;
  
@@ -353,7 +362,7 @@ diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
 index b4897f1de444080c8dc6c4913b5f33de20796822..d54e254ff41a0441d04fbcf27f26e4809f563b79 100644
 --- a/sign/rpmgensig.c
 +++ b/sign/rpmgensig.c
-@@ -672,7 +672,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)
+@@ -610,7 +610,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)
  	}
  
  	/* Write the lead/signature of the output rpm */
diff --git a/0032-rpmcow-workaround.patch b/0032-rpmcow-workaround.patch
index 69d5178..57e9f44 100644
--- a/0032-rpmcow-workaround.patch
+++ b/0032-rpmcow-workaround.patch
@@ -1,7 +1,5 @@
 From: Richard Phibel <richardphibel@meta.com>
 
-Subject: RPM with Copy on Write: workaround for corrupt signature header
-
 commit 7976c921f60ec5d20c50c4c702ec5636b39210ba
 Author: Richard Phibel <richardphibel@meta.com>
 Date:   Wed Oct 26 18:57:19 2022 +0200
@@ -14,6 +12,9 @@ Date:   Wed Oct 26 18:57:19 2022 +0200
     unloadImmutableRegion.
 
 Signed-off-by: Richard Phibel <richardphibel@meta.com>
+---
+ rpm2extents.c | 281 +++++++++++++++++++++++++++-----------------------
+ 1 file changed, 153 insertions(+), 128 deletions(-)
 
 diff --git a/rpm2extents.c b/rpm2extents.c
 index 702d3765d76faf618992ca112011d2312d7fcdcc..b641511fff884e3c8fb396f28acbd8e2c736e28a 100644
diff --git a/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch b/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
deleted file mode 100644
index 6a20363..0000000
--- a/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
+++ /dev/null
@@ -1,168 +0,0 @@
-From 3669fecaba2858aeca44d1bfc265760611ea8834 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Wed, 10 Jun 2020 12:30:54 -0400
-Subject: [PATCH 32/33] rpmsign: Add argument to specify algorithm for fsverity
- signatures
-
-The argument --verity-algo can be used to specify the algorithm for
-the fsverity signatures. If nothing is specified, this will default to
-sha256. The available algorithms depend on libfsverity, currently
-sha256 and sha512 are supported.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- doc/rpmsign.8        |  3 +++
- rpmsign.c            |  7 +++++++
- sign/rpmgensig.c     | 22 ++++++++++++++++++++--
- sign/rpmsignverity.c |  6 +++---
- sign/rpmsignverity.h |  2 +-
- 5 files changed, 34 insertions(+), 6 deletions(-)
-
-diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
-index a212746fe..5165e39f9 100644
---- a/doc/rpmsign.8
-+++ b/doc/rpmsign.8
-@@ -55,6 +55,9 @@ Used with \fB--signfiles\fR, use file signing key \fIKey\fR.
- \fB--certpath \fICERT\fB\fR
- Used with \fB--signverity\fR, use file signing certificate \fICert\fR.
- .TP
-+\fB--verityalgo \fIALG\fB\fR
-+Used with \fB--signverity\fR, to specify the signing algorithm. sha256 and sha512 are supported, with sha256 being the default if this argument is not specified. This can also be specified with the macro %_verity_algorithm
-+.TP
- \fB--signfiles\fR
- Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must
- be set to a supported algorithm before building the package. The
-diff --git a/rpmsign.c b/rpmsign.c
-index e43811e9f..12299379c 100644
---- a/rpmsign.c
-+++ b/rpmsign.c
-@@ -25,6 +25,7 @@ static char * fileSigningKey = NULL;
- #endif
- #ifdef WITH_FSVERITY
- static char * fileSigningCert = NULL;
-+static char * verityAlgorithm = NULL;
- #endif
- 
- static struct rpmSignArgs sargs = {NULL, 0, 0};
-@@ -52,6 +53,9 @@ static struct poptOption signOptsTable[] = {
-     { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
- 	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,
- 	N_("generate fsverity signatures for package(s) files"), NULL},
-+    { "verityalgo", '\0', POPT_ARG_STRING, &verityAlgorithm, 0,
-+	N_("algorithm to use for verity signatures, default sha256"),
-+	N_("<algorithm>") },
-     { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,
- 	N_("use file signing cert <cert>"),
- 	N_("<cert>") },
-@@ -138,6 +142,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
-     if (fileSigningCert) {
- 	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);
-     }
-+    if (verityAlgorithm) {
-+	rpmPushMacro(NULL, "_verity_algorithm", NULL, verityAlgorithm, RMIL_GLOBAL);
-+    }
- #endif
- 
-     if (flags_sign_files(sargs->signflags)) {
-diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
-index 02cf0bc62..b3b02828a 100644
---- a/sign/rpmgensig.c
-+++ b/sign/rpmgensig.c
-@@ -8,6 +8,10 @@
- #include <sys/wait.h>
- #include <popt.h>
- #include <fcntl.h>
-+#include <fcntl.h>
-+#ifdef WITH_FSVERITY
-+#include <libfsverity.h>
-+#endif
- 
- #include <rpm/rpmlib.h>			/* RPMSIGTAG & related */
- #include <rpm/rpmmacro.h>
-@@ -458,23 +462,37 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
- static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
- {
- #ifdef WITH_FSVERITY
--    rpmRC rc;
-+    rpmRC rc = RPMRC_OK;
-     char *key = rpmExpand("%{?_file_signing_key}", NULL);
-     char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
-     char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
-+    char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL);
-+    uint16_t algo = 0;
- 
-     if (rstreq(keypass, "")) {
- 	free(keypass);
- 	keypass = NULL;
-     }
- 
-+    if (algorithm && strlen(algorithm) > 0) {
-+	    algo = libfsverity_find_hash_alg_by_name(algorithm);
-+	    rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"),
-+		   algorithm, algo);
-+	    if (!algo) {
-+		    rpmlog(RPMLOG_ERR, _("Unsupported fsverity algorithm %s\n"),
-+			   algorithm);
-+		    rc = RPMRC_FAIL;
-+		    goto out;
-+	    }
-+    }
-     if (key && cert) {
--	rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);
-+	    rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo);
-     } else {
- 	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));
- 	rc = RPMRC_FAIL;
-     }
- 
-+ out:
-     free(keypass);
-     free(key);
-     free(cert);
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index 55096e732..e6c830cdc 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -95,7 +95,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
- }
- 
- rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
--		    char *keypass, char *cert)
-+		    char *keypass, char *cert, uint16_t algo)
- {
-     int rc;
-     FD_t gzdi;
-@@ -111,7 +111,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     char **signatures = NULL;
-     size_t sig_size;
-     int nr_files, idx;
--    uint16_t algo;
-     uint32_t algo32;
- 
-     Fseek(fd, 0, SEEK_SET);
-@@ -156,7 +155,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     nr_files = rpmfiFC(hfi);
-     signatures = xcalloc(nr_files, sizeof(char *));
- 
--    algo = FS_VERITY_HASH_ALG_SHA256;
-+    if (!algo)
-+	    algo = FS_VERITY_HASH_ALG_SHA256;
- 
-     rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),
- 	   nr_files, rpmfiFC(fi));
-diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
-index 69bbaf7f7..d869e8d8e 100644
---- a/sign/rpmsignverity.h
-+++ b/sign/rpmsignverity.h
-@@ -27,7 +27,7 @@ extern "C" {
-  */
- RPM_GNUC_INTERNAL
- rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
--		    char *keypass, char *cert);
-+		    char *keypass, char *cert, uint16_t algo);
- 
- #ifdef _cplusplus
- }
--- 
-2.27.0
-
diff --git a/0033-Enable-fsverity-in-CI.patch b/0033-Enable-fsverity-in-CI.patch
deleted file mode 100644
index 0fc6fde..0000000
--- a/0033-Enable-fsverity-in-CI.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 84ee9dc61b14056fec489bb099f1f212b3b169a9 Mon Sep 17 00:00:00 2001
-From: Jes Sorensen <jsorensen@fb.com>
-Date: Fri, 28 Aug 2020 11:10:41 -0400
-Subject: [PATCH 33/33] Enable fsverity in CI
-
-Add fsverity-utils and fsverity-utils-devel as dependencies.
-
-Signed-off-by: Jes Sorensen <jsorensen@fb.com>
----
- Makefile.am | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/Makefile.am b/Makefile.am
-index 8e92f0cde..3c1451049 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -17,6 +17,7 @@ DISTCHECK_CONFIGURE_FLAGS = \
-	--with-selinux \
- 	--with-imaevm \
- 	--with-fapolicyd \
-+	--with-fsverity \
- 	--disable-dependency-tracking
- 
- include $(top_srcdir)/rpm.am
--- 
-2.27.0
-
diff --git a/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch b/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch
deleted file mode 100644
index 692ab33..0000000
--- a/0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch
+++ /dev/null
@@ -1,257 +0,0 @@
-From aee5af8e4fe7908df90649eb699c3a1decf06b0c Mon Sep 17 00:00:00 2001
-From: Yu Wu <wuyu@fb.com>
-Date: Wed, 3 Nov 2021 23:13:15 -0700
-Subject: [PATCH 1/2] rpmsign: Adopting PKCS#11 opaque keys support in
- libfsverity for fsverity signatures
-
----
- rpmsign.c            | 29 ++++++++++++++++++++----
- sign/rpmgensig.c     | 53 +++++++++++++++++++++++++++++++++++++++-----
- sign/rpmsignverity.c | 24 +++++++++++++-------
- sign/rpmsignverity.h |  9 +++++---
- 4 files changed, 94 insertions(+), 21 deletions(-)
-
-diff --git a/rpmsign.c b/rpmsign.c
-index 12299379ce..63b8616382 100644
---- a/rpmsign.c
-+++ b/rpmsign.c
-@@ -24,6 +24,9 @@ static int fskpass = 0;
- static char * fileSigningKey = NULL;
- #endif
- #ifdef WITH_FSVERITY
-+static char * pkcs11Engine = NULL;
-+static char * pkcs11Module = NULL;
-+static char * pkcs11KeyId = NULL;
- static char * fileSigningCert = NULL;
- static char * verityAlgorithm = NULL;
- #endif
-@@ -59,6 +62,15 @@ static struct poptOption signOptsTable[] = {
-     { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,
- 	N_("use file signing cert <cert>"),
- 	N_("<cert>") },
-+    { "pkcs11_engine", '\0', POPT_ARG_STRING, &pkcs11Engine, 0,
-+	N_("use pkcs#11 token for fsverity signing key with openssl engine <pkcs11_engine>"),
-+	N_("<pkcs11_engine>") },
-+    { "pkcs11_module", '\0', POPT_ARG_STRING, &pkcs11Module, 0,
-+	N_("use pkcs#11 token for fsverity signing key with openssl module <pkcs11_module>"),
-+	N_("<pkcs11_module>") },
-+    { "pkcs11_keyid", '\0', POPT_ARG_STRING, &pkcs11KeyId, 0,
-+	N_("use pkcs#11 token for fsverity signing key with keyid <pkcs11_keyid>"),
-+	N_("<pkcs11_keyid>") },
- #endif
- #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
-     { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
-@@ -139,6 +151,15 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
-     }
- 
- #ifdef WITH_FSVERITY
-+    if (pkcs11Engine) {
-+    rpmPushMacro(NULL, "_pkcs11_engine", NULL, pkcs11Engine, RMIL_GLOBAL);
-+    }
-+    if (pkcs11Module) {
-+    rpmPushMacro(NULL, "_pkcs11_module", NULL, pkcs11Module, RMIL_GLOBAL);
-+    }
-+    if (pkcs11KeyId) {
-+    rpmPushMacro(NULL, "_pkcs11_keyid", NULL, pkcs11KeyId, RMIL_GLOBAL);
-+    }
-     if (fileSigningCert) {
- 	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);
-     }
-@@ -149,9 +170,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
- 
-     if (flags_sign_files(sargs->signflags)) {
- 	char *fileSigningKeyPassword = NULL;
--	char *key = rpmExpand("%{?_file_signing_key}", NULL);
--	if (rstreq(key, "")) {
--	    fprintf(stderr, _("You must set \"%%_file_signing_key\" in your macro file or on the command line with --fskpath\n"));
-+	char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
-+	if (rstreq(cert, "")) {
-+	    fprintf(stderr, _("You must set \"%%_file_signing_cert\" in your macro file or on the command line with --certpath\n"));
- 	    goto exit;
- 	}
- 
-@@ -166,7 +187,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
- 	    free(fileSigningKeyPassword);
- 	}
- 
--	free(key);
-+	free(cert);
-     }
- #endif
- 
-diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
-index d8c84e9377..cb264679b6 100644
---- a/sign/rpmgensig.c
-+++ b/sign/rpmgensig.c
-@@ -461,15 +461,56 @@ static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
-     rpmRC rc = RPMRC_OK;
-     char *key = rpmExpand("%{?_file_signing_key}", NULL);
-     char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
-+    char *pkcs11_engine = rpmExpand("%{?_pkcs11_engine}", NULL);
-+    char *pkcs11_module = rpmExpand("%{?_pkcs11_module}", NULL);
-+    char *pkcs11_keyid = rpmExpand("%{?_pkcs11_keyid}", NULL);
-     char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
-     char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL);
-     uint16_t algo = 0;
- 
-+    if (rstreq(key, "")) {
-+	free(key);
-+	key = NULL;
-+    }
-+
-+    if (rstreq(pkcs11_engine, "")) {
-+	free(pkcs11_engine);
-+	pkcs11_engine = NULL;
-+    }
-+
-+    if (rstreq(pkcs11_module, "")) {
-+	free(pkcs11_module);
-+	pkcs11_module = NULL;
-+    }
-+
-+    if (rstreq(pkcs11_keyid, "")) {
-+	free(pkcs11_keyid);
-+	pkcs11_keyid = NULL;
-+    }
-+
-     if (rstreq(keypass, "")) {
- 	free(keypass);
- 	keypass = NULL;
-     }
- 
-+    if (key) {
-+        if (pkcs11_engine || pkcs11_module || pkcs11_keyid) {
-+            rpmlog(
-+                RPMLOG_ERR,
-+                _("fsverity signatures require a key specified either by file or by PKCS#11 token, not both\n"));
-+            rc = RPMRC_FAIL;
-+            goto out;
-+        }
-+    } else {
-+        if (!pkcs11_engine || !pkcs11_module) {
-+            rpmlog(
-+                RPMLOG_ERR,
-+                _("fsverity signatures require both PKCS#11 engine and module to use PKCS#11 token\n"));
-+            rc = RPMRC_FAIL;
-+            goto out;
-+        }
-+    }
-+
-     if (algorithm && strlen(algorithm) > 0) {
- 	    algo = libfsverity_find_hash_alg_by_name(algorithm);
- 	    rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"),
-@@ -481,16 +522,16 @@ static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
- 		    goto out;
- 	    }
-     }
--    if (key && cert) {
--	    rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo);
--    } else {
--	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));
--	rc = RPMRC_FAIL;
--    }
-+
-+    rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass,
-+                pkcs11_engine, pkcs11_module, pkcs11_keyid, cert, algo);
- 
-  out:
-     free(keypass);
-     free(key);
-+    free(pkcs11_engine);
-+    free(pkcs11_module);
-+    free(pkcs11_keyid);
-     free(cert);
-     return rc;
- #else
-diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
-index e6c830cdcb..b7924e7ad1 100644
---- a/sign/rpmsignverity.c
-+++ b/sign/rpmsignverity.c
-@@ -34,8 +34,9 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)
- 	return retval;
- }
- 
--static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
--			       char *keypass, char *cert, uint16_t algo)
-+static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, char *keypass,
-+			    char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid,
-+			    char *cert, uint16_t algo)
- {
-     struct libfsverity_merkle_tree_params params;
-     struct libfsverity_signature_params sig_params;
-@@ -76,6 +77,9 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
- 
-     memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
-     sig_params.keyfile = key;
-+    sig_params.pkcs11_engine = pkcs11_engine;
-+    sig_params.pkcs11_module = pkcs11_module;
-+    sig_params.pkcs11_keyid = pkcs11_keyid;
-     sig_params.certfile = cert;
-     if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) {
- 	rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
-@@ -94,8 +98,9 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
-     return sig_base64;
- }
- 
--rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
--		    char *keypass, char *cert, uint16_t algo)
-+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, char *keypass,
-+	        char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid,
-+	        char *cert, uint16_t algo)
- {
-     int rc;
-     FD_t gzdi;
-@@ -125,6 +130,9 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     }
- 
-     rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key);
-+    rpmlog(RPMLOG_DEBUG, _("pkcs11_engine: %s\n"), pkcs11_engine);
-+    rpmlog(RPMLOG_DEBUG, _("pkcs11_module: %s\n"), pkcs11_module);
-+    rpmlog(RPMLOG_DEBUG, _("pkcs11_keyid: %s\n"), pkcs11_keyid);
-     rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert);
- 
-     compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
-@@ -164,16 +172,16 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
-     while (rpmfiNext(fi) >= 0) {
- 	idx = rpmfiFX(fi);
- 
--	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert,
--					    algo);
-+	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, pkcs11_engine,
-+					    pkcs11_module, pkcs11_keyid, cert, algo);
-     }
- 
-     while (rpmfiNext(hfi) >= 0) {
- 	idx = rpmfiFX(hfi);
- 	if (signatures[idx])
- 	    continue;
--	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert,
--					    algo);
-+	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, pkcs11_engine,
-+					    pkcs11_module, pkcs11_keyid, cert, algo);
-     }
- 
-     rpmtdReset(&td);
-diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
-index d869e8d8e8..32d2d6359a 100644
---- a/sign/rpmsignverity.h
-+++ b/sign/rpmsignverity.h
-@@ -22,12 +22,15 @@ extern "C" {
-  * @param h		package header
-  * @param key		signing key
-  * @param keypass	signing key password
-+ * @param pkcs11_engine		PKCS#11 engine to use PKCS#11 token support for signing key
-+ * @param pkcs11_module		PKCS#11 module to use PKCS#11 token support for signing key
-+ * @param pkcs11_keyid		PKCS#11 key identifier
-  * @param cert		signing cert
-  * @return		RPMRC_OK on success
-  */
--RPM_GNUC_INTERNAL
--rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
--		    char *keypass, char *cert, uint16_t algo);
-+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, char *keypass,
-+		    char *pkcs11_engine, char *pkcs11_module, char *pkcs11_keyid,
-+		    char *cert, uint16_t algo);
- 
- #ifdef _cplusplus
- }
diff --git a/0036-bsearchr_static.patch b/0036-bsearchr_static.patch
new file mode 100644
index 0000000..fe8e8fc
--- /dev/null
+++ b/0036-bsearchr_static.patch
@@ -0,0 +1,11 @@
+--- a/plugins/reflink.c
++++ b/plugins/reflink.c
+@@ -63,7 +63,7 @@ typedef struct reflink_state_s * reflink_state;
+  * bsearch_r: implements a re-entrant version of stdlib's bsearch.
+  * code taken and adapted from /usr/include/bits/stdlib-bsearch.h
+  */
+-inline void *
++static void *
+ bsearch_r (const void *__key, const void *__base, size_t __nmemb, size_t __size,
+ 	 __compar_d_fn_t __compar, void *__arg)
+ {
diff --git a/0037-plugin_path.patch b/0037-plugin_path.patch
new file mode 100644
index 0000000..3ba625f
--- /dev/null
+++ b/0037-plugin_path.patch
@@ -0,0 +1,35 @@
+--- a/plugins/reflink.c
++++ b/plugins/reflink.c
+@@ -277,13 +277,17 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa
+     fcr.dest_offset = 0;
+     if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) {
+ 	rpm_ino_t inode = rpmfiFInode(fi);
++        char fullpath[PATH_MAX];
++
++        snprintf(fullpath, sizeof(fullpath), "%s/%s", rpmfiDN(fi), path);
++
+ 	/* check for hard link entry in table. GetEntry overwrites hlix with
+ 	 * the address of the first match.
+ 	 */
+ 	if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hl_target,
+ 				   NULL, NULL)) {
+ 	    /* entry is in table, use hard link */
+-	    if (link(hl_target[0], path) != 0) {
++	    if (link(hl_target[0], fullpath) != 0) {
+ 		rpmlog(RPMLOG_ERR,
+ 		       _("reflink: Unable to hard link %s -> %s due to %s\n"),
+ 		       hl_target[0], path, strerror(errno));
+@@ -296,11 +300,11 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa
+ 	 */
+ 	if (rpmfiFNlink(fi) > 1) {
+ 	    /* minor optimization: only store files with more than one link */
+-	    inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path));
++	    inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(fullpath));
+ 	}
+ 	/* derived from wfd_open in fsm.c */
+ 	mode_t old_umask = umask(0577);
+-	dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
++	dst = open(fullpath, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
+ 	umask(old_umask);
+ 	if (dst == -1) {
+ 	    rpmlog(RPMLOG_ERR,
diff --git a/1534.patch b/1534.patch
deleted file mode 100644
index e2a7cf6..0000000
--- a/1534.patch
+++ /dev/null
@@ -1,1162 +0,0 @@
-From 22d18785b2c41f1a8937b712920b4342f7596a7e Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Mon, 8 Feb 2021 10:45:59 +0200
-Subject: [PATCH 1/9] Clean up file unpack iteration logic a bit
-
-Handle rpmfiNext() in the while-condition directly to make it more like
-similar other constructs elsewhere, adjust for the end of iteration
-code after the loop. Also take the file index from rpmfiNext() so
-we don't need multiple calls to rpmfiFX() later.
----
- lib/fsm.c | 19 +++++++------------
- 1 file changed, 7 insertions(+), 12 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index 35dcda081c..7c291adb02 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -841,6 +841,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     struct stat sb;
-     int saveerrno = errno;
-     int rc = 0;
-+    int fx = -1;
-     int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
-     int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
-     int firsthardlink = -1;
-@@ -862,17 +863,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     /* Detect and create directories not explicitly in package. */
-     rc = fsmMkdirs(files, fs, plugins);
- 
--    while (!rc) {
--	/* Read next payload header. */
--	rc = rpmfiNext(fi);
--
--	if (rc < 0) {
--	    if (rc == RPMERR_ITER_END)
--		rc = 0;
--	    break;
--	}
--
--	action = rpmfsGetAction(fs, rpmfiFX(fi));
-+    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
-+	action = rpmfsGetAction(fs, fx);
- 	skip = XFA_SKIPPING(action);
- 	if (action != FA_TOUCH) {
- 	    suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
-@@ -896,7 +888,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	if (rc) {
- 	    skip = 1;
- 	} else {
--	    setFileState(fs, rpmfiFX(fi));
-+	    setFileState(fs, fx);
- 	}
- 
-         if (!skip) {
-@@ -1005,6 +997,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	fpath = _free(fpath);
-     }
- 
-+    if (!rc && fx != RPMERR_ITER_END)
-+	rc = fx;
-+
-     rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ));
-     rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
- 
-
-From c0dc57b820791dd76ce8baafac59b9a58ab0f0d3 Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 08:25:28 +0200
-Subject: [PATCH 2/9] Drop unused filename variable
-
----
- lib/fsm.c | 2 --
- 1 file changed, 2 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index 7c291adb02..41b6267ddc 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -959,11 +959,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	    /* On FA_TOUCH no hardlinks are created thus this is skipped. */
- 	    /* we skip the hard linked file containing the content */
- 	    /* write the content to the first used instead */
--	    char *fn = rpmfilesFN(files, firsthardlink);
- 	    rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm);
- 	    wfd_close(&firstlinkfile);
- 	    firsthardlink = -1;
--	    free(fn);
- 	}
- 
-         if (rc) {
-
-From dcb5791066afd5caa1003a5d35903a7f5dc79cc2 Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 09:57:17 +0200
-Subject: [PATCH 3/9] Don't update path info if rename failed on file commit
-
----
- lib/fsm.c | 16 +++++++++-------
- 1 file changed, 9 insertions(+), 7 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index 41b6267ddc..c581a918a5 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -773,14 +773,16 @@ static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *su
- 	/* Rename temporary to final file name if needed. */
- 	if (dest != *path) {
- 	    rc = fsmRename(*path, dest);
--	    if (!rc && nsuffix) {
--		char * opath = fsmFsPath(fi, NULL);
--		rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
--		       opath, dest);
--		free(opath);
-+	    if (!rc) {
-+		if (nsuffix) {
-+		    char * opath = fsmFsPath(fi, NULL);
-+		    rpmlog(RPMLOG_WARNING, _("%s created as %s\n"),
-+			   opath, dest);
-+		    free(opath);
-+		}
-+		free(*path);
-+		*path = dest;
- 	    }
--	    free(*path);
--	    *path = dest;
- 	}
-     }
- 
-
-From 7fdf248e7d29a244b97c46b19be0df64992fdfae Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 09:47:19 +0200
-Subject: [PATCH 4/9] Refactor file install and remove around a common struct
-
-Collect the common state info into a struct shared by both file install
-and remove, update code accordingly. The change looks much more drastic
-than it is - it's just adding fp-> prefix to a lot of places.
-While we're at it, remember the state data throughout the operation.
-
-No functional changes here, just paving way for the next steps which
-will look clearer with these pre-requisites in place.
----
- lib/fsm.c | 158 +++++++++++++++++++++++++++++-------------------------
- 1 file changed, 85 insertions(+), 73 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index c581a918a5..9dba30560f 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -38,6 +38,14 @@ static int strict_erasures = 0;
- #define _dirPerms 0755
- #define _filePerms 0644
- 
-+struct filedata_s {
-+    int skip;
-+    rpmFileAction action;
-+    const char *suffix;
-+    char *fpath;
-+    struct stat sb;
-+};
-+
- /* 
-  * XXX Forward declarations for previously exported functions to avoid moving 
-  * things around needlessly 
-@@ -840,19 +848,16 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
-     rpmfs fs = rpmteGetFileStates(te);
-     rpmPlugins plugins = rpmtsPlugins(ts);
--    struct stat sb;
-     int saveerrno = errno;
-     int rc = 0;
-     int fx = -1;
-+    int fc = rpmfilesFC(files);
-     int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
-     int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
-     int firsthardlink = -1;
-     FD_t firstlinkfile = NULL;
--    int skip;
--    rpmFileAction action;
-     char *tid = NULL;
--    const char *suffix;
--    char *fpath = NULL;
-+    struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
- 
-     if (fi == NULL) {
- 	rc = RPMERR_BAD_MAGIC;
-@@ -866,96 +871,99 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     rc = fsmMkdirs(files, fs, plugins);
- 
-     while (!rc && (fx = rpmfiNext(fi)) >= 0) {
--	action = rpmfsGetAction(fs, fx);
--	skip = XFA_SKIPPING(action);
--	if (action != FA_TOUCH) {
--	    suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
-+	struct filedata_s *fp = &fdata[fx];
-+	fp->action = rpmfsGetAction(fs, fx);
-+	fp->skip = XFA_SKIPPING(fp->action);
-+	if (fp->action != FA_TOUCH) {
-+	    fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
- 	} else {
--	    suffix = NULL;
-+	    fp->suffix = NULL;
- 	}
--	fpath = fsmFsPath(fi, suffix);
-+	fp->fpath = fsmFsPath(fi, fp->suffix);
- 
- 	/* Remap file perms, owner, and group. */
--	rc = rpmfiStat(fi, 1, &sb);
-+	rc = rpmfiStat(fi, 1, &fp->sb);
- 
--	fsmDebug(fpath, action, &sb);
-+	fsmDebug(fp->fpath, fp->action, &fp->sb);
- 
-         /* Exit on error. */
-         if (rc)
-             break;
- 
- 	/* Run fsm file pre hook for all plugins */
--	rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
--				      sb.st_mode, action);
-+	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
-+				      fp->sb.st_mode, fp->action);
- 	if (rc) {
--	    skip = 1;
-+	    fp->skip = 1;
- 	} else {
- 	    setFileState(fs, fx);
- 	}
- 
--        if (!skip) {
-+        if (!fp->skip) {
- 	    int setmeta = 1;
- 
- 	    /* Directories replacing something need early backup */
--	    if (!suffix) {
--		rc = fsmBackup(fi, action);
-+	    if (!fp->suffix) {
-+		rc = fsmBackup(fi, fp->action);
- 	    }
- 	    /* Assume file does't exist when tmp suffix is in use */
--	    if (!suffix) {
--		rc = fsmVerify(fpath, fi);
-+	    if (!fp->suffix) {
-+		rc = fsmVerify(fp->fpath, fi);
- 	    } else {
- 		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);
-+	    if (rc == RPMERR_ENOENT && fp->action == FA_TOUCH) {
-+		rpmlog(RPMLOG_DEBUG, "file %s vanished unexpectedly\n",
-+			fp->fpath);
-+		fp->action = FA_CREATE;
-+		fsmDebug(fp->fpath, fp->action, &fp->sb);
- 	    }
- 
- 	    /* When touching we don't need any of this... */
--	    if (action == FA_TOUCH)
-+	    if (fp->action == FA_TOUCH)
- 		goto touch;
- 
--            if (S_ISREG(sb.st_mode)) {
-+            if (S_ISREG(fp->sb.st_mode)) {
- 		if (rc == RPMERR_ENOENT) {
--		    rc = fsmMkfile(fi, fpath, files, psm, nodigest,
-+		    rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest,
- 				   &setmeta, &firsthardlink, &firstlinkfile);
- 		}
--            } else if (S_ISDIR(sb.st_mode)) {
-+            } else if (S_ISDIR(fp->sb.st_mode)) {
-                 if (rc == RPMERR_ENOENT) {
--                    mode_t mode = sb.st_mode;
-+                    mode_t mode = fp->sb.st_mode;
-                     mode &= ~07777;
-                     mode |=  00700;
--                    rc = fsmMkdir(fpath, mode);
-+                    rc = fsmMkdir(fp->fpath, mode);
-                 }
--            } else if (S_ISLNK(sb.st_mode)) {
-+            } else if (S_ISLNK(fp->sb.st_mode)) {
- 		if (rc == RPMERR_ENOENT) {
--		    rc = fsmSymlink(rpmfiFLink(fi), fpath);
-+		    rc = fsmSymlink(rpmfiFLink(fi), fp->fpath);
- 		}
--            } else if (S_ISFIFO(sb.st_mode)) {
-+            } else if (S_ISFIFO(fp->sb.st_mode)) {
-                 /* This mimics cpio S_ISSOCK() behavior but probably isn't right */
-                 if (rc == RPMERR_ENOENT) {
--                    rc = fsmMkfifo(fpath, 0000);
-+                    rc = fsmMkfifo(fp->fpath, 0000);
-                 }
--            } else if (S_ISCHR(sb.st_mode) ||
--                       S_ISBLK(sb.st_mode) ||
--                       S_ISSOCK(sb.st_mode))
-+            } else if (S_ISCHR(fp->sb.st_mode) ||
-+                       S_ISBLK(fp->sb.st_mode) ||
-+                       S_ISSOCK(fp->sb.st_mode))
-             {
-                 if (rc == RPMERR_ENOENT) {
--                    rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev);
-+                    rc = fsmMknod(fp->fpath, fp->sb.st_mode, fp->sb.st_rdev);
-                 }
-             } else {
-                 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
--                if (!IS_DEV_LOG(fpath))
-+                if (!IS_DEV_LOG(fp->fpath))
-                     rc = RPMERR_UNKNOWN_FILETYPE;
-             }
- 
- touch:
- 	    /* Set permissions, timestamps etc for non-hardlink entries */
- 	    if (!rc && setmeta) {
--		rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps);
-+		rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
-+				&fp->sb, nofcaps);
- 	    }
-         } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
- 	    /* On FA_TOUCH no hardlinks are created thus this is skipped. */
-@@ -967,10 +975,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	}
- 
-         if (rc) {
--            if (!skip) {
-+            if (!fp->skip) {
-                 /* XXX only erase if temp fn w suffix is in use */
--                if (suffix) {
--		    (void) fsmRemove(fpath, sb.st_mode);
-+                if (fp->suffix) {
-+		    (void) fsmRemove(fp->fpath, fp->sb.st_mode);
-                 }
-                 errno = saveerrno;
-             }
-@@ -978,23 +986,22 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	    /* Notify on success. */
- 	    rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
- 
--	    if (!skip) {
-+	    if (!fp->skip) {
- 		/* Backup file if needed. Directories are handled earlier */
--		if (suffix)
--		    rc = fsmBackup(fi, action);
-+		if (fp->suffix)
-+		    rc = fsmBackup(fi, fp->action);
- 
- 		if (!rc)
--		    rc = fsmCommit(&fpath, fi, action, suffix);
-+		    rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix);
- 	    }
- 	}
- 
- 	if (rc)
--	    *failedFile = xstrdup(fpath);
-+	    *failedFile = xstrdup(fp->fpath);
- 
- 	/* Run fsm file post hook for all plugins */
--	rpmpluginsCallFsmFilePost(plugins, fi, fpath,
--				  sb.st_mode, action, rc);
--	fpath = _free(fpath);
-+	rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
-+				  fp->sb.st_mode, fp->action, rc);
-     }
- 
-     if (!rc && fx != RPMERR_ITER_END)
-@@ -1010,7 +1017,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     rpmfiFree(fi);
-     Fclose(payload);
-     free(tid);
--    free(fpath);
-+    for (int i = 0; i < fc; i++)
-+	free(fdata[i].fpath);
-+    free(fdata);
- 
-     return rc;
- }
-@@ -1022,29 +1031,31 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
-     rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK);
-     rpmfs fs = rpmteGetFileStates(te);
-     rpmPlugins plugins = rpmtsPlugins(ts);
--    struct stat sb;
-+    int fc = rpmfilesFC(files);
-+    int fx = -1;
-+    struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
-     int rc = 0;
--    char *fpath = NULL;
- 
--    while (!rc && rpmfiNext(fi) >= 0) {
--	rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi));
--	fpath = fsmFsPath(fi, NULL);
--	rc = fsmStat(fpath, 1, &sb);
-+    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
-+	struct filedata_s *fp = &fdata[fx];
-+	fp->action = rpmfsGetAction(fs, rpmfiFX(fi));
-+	fp->fpath = fsmFsPath(fi, NULL);
-+	rc = fsmStat(fp->fpath, 1, &fp->sb);
- 
--	fsmDebug(fpath, action, &sb);
-+	fsmDebug(fp->fpath, fp->action, &fp->sb);
- 
- 	/* Run fsm file pre hook for all plugins */
--	rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
--				      sb.st_mode, action);
-+	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
-+				      fp->sb.st_mode, fp->action);
- 
--	if (!XFA_SKIPPING(action))
--	    rc = fsmBackup(fi, action);
-+	if (!XFA_SKIPPING(fp->action))
-+	    rc = fsmBackup(fi, fp->action);
- 
-         /* Remove erased files. */
--        if (action == FA_ERASE) {
-+        if (fp->action == FA_ERASE) {
- 	    int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST));
- 
--	    rc = fsmRemove(fpath, sb.st_mode);
-+	    rc = fsmRemove(fp->fpath, fp->sb.st_mode);
- 
- 	    /*
- 	     * Missing %ghost or %missingok entries are not errors.
-@@ -1069,20 +1080,20 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
- 	    if (rc) {
- 		int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;
- 		rpmlog(lvl, _("%s %s: remove failed: %s\n"),
--			S_ISDIR(sb.st_mode) ? _("directory") : _("file"),
--			fpath, strerror(errno));
-+			S_ISDIR(fp->sb.st_mode) ? _("directory") : _("file"),
-+			fp->fpath, strerror(errno));
-             }
-         }
- 
- 	/* Run fsm file post hook for all plugins */
--	rpmpluginsCallFsmFilePost(plugins, fi, fpath,
--				  sb.st_mode, action, rc);
-+	rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
-+				  fp->sb.st_mode, fp->action, rc);
- 
-         /* XXX Failure to remove is not (yet) cause for failure. */
-         if (!strict_erasures) rc = 0;
- 
- 	if (rc)
--	    *failedFile = xstrdup(fpath);
-+	    *failedFile = xstrdup(fp->fpath);
- 
- 	if (rc == 0) {
- 	    /* Notify on success. */
-@@ -1090,10 +1101,11 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
- 	    rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi);
- 	    rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount);
- 	}
--	fpath = _free(fpath);
-     }
- 
--    free(fpath);
-+    for (int i = 0; i < fc; i++)
-+	free(fdata[i].fpath);
-+    free(fdata);
-     rpmfiFree(fi);
- 
-     return rc;
-
-From 202c9e9cd2e199b7e7c9655704a98ab2d4fad69c Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 10:08:27 +0200
-Subject: [PATCH 5/9] Refactor fsmMkfile() to take advantage of the new state
- struct
-
-Move setmeta into the struct too (we'll want this later anyhow),
-and now we only need to pass the struct to fsmMkfile(). One less
-argument to pass around, it has way too many still.
-
-No functional changes.
----
- lib/fsm.c | 22 +++++++++++-----------
- 1 file changed, 11 insertions(+), 11 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index 9dba30560f..80ca234b1e 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -39,6 +39,7 @@ static int strict_erasures = 0;
- #define _filePerms 0644
- 
- struct filedata_s {
-+    int setmeta;
-     int skip;
-     rpmFileAction action;
-     const char *suffix;
-@@ -279,8 +280,8 @@ static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest)
-     return rc;
- }
- 
--static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
--		     rpmpsm psm, int nodigest, int *setmeta,
-+static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
-+		     rpmpsm psm, int nodigest,
- 		     int * firsthardlink, FD_t *firstlinkfile)
- {
-     int rc = 0;
-@@ -290,11 +291,11 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
- 	/* Create first hardlinked file empty */
- 	if (*firsthardlink < 0) {
- 	    *firsthardlink = rpmfiFX(fi);
--	    rc = wfd_open(firstlinkfile, dest);
-+	    rc = wfd_open(firstlinkfile, fp->fpath);
- 	} else {
- 	    /* Create hard links for others */
- 	    char *fn = rpmfilesFN(files, *firsthardlink);
--	    rc = link(fn, dest);
-+	    rc = link(fn, fp->fpath);
- 	    if (rc < 0) {
- 		rc = RPMERR_LINK_FAILED;
- 	    }
-@@ -305,14 +306,14 @@ static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
-        existing) file with content */
-     if (numHardlinks<=1) {
- 	if (!rc)
--	    rc = expandRegular(fi, dest, psm, nodigest);
-+	    rc = expandRegular(fi, fp->fpath, psm, nodigest);
-     } else if (rpmfiArchiveHasContent(fi)) {
- 	if (!rc)
- 	    rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
- 	wfd_close(firstlinkfile);
- 	*firsthardlink = -1;
-     } else {
--	*setmeta = 0;
-+	fp->setmeta = 0;
-     }
- 
-     return rc;
-@@ -874,6 +875,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	struct filedata_s *fp = &fdata[fx];
- 	fp->action = rpmfsGetAction(fs, fx);
- 	fp->skip = XFA_SKIPPING(fp->action);
-+	fp->setmeta = 1;
- 	if (fp->action != FA_TOUCH) {
- 	    fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
- 	} else {
-@@ -900,8 +902,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	}
- 
-         if (!fp->skip) {
--	    int setmeta = 1;
--
- 	    /* Directories replacing something need early backup */
- 	    if (!fp->suffix) {
- 		rc = fsmBackup(fi, fp->action);
-@@ -927,8 +927,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 
-             if (S_ISREG(fp->sb.st_mode)) {
- 		if (rc == RPMERR_ENOENT) {
--		    rc = fsmMkfile(fi, fp->fpath, files, psm, nodigest,
--				   &setmeta, &firsthardlink, &firstlinkfile);
-+		    rc = fsmMkfile(fi, fp, files, psm, nodigest,
-+				   &firsthardlink, &firstlinkfile);
- 		}
-             } else if (S_ISDIR(fp->sb.st_mode)) {
-                 if (rc == RPMERR_ENOENT) {
-@@ -961,7 +961,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 
- touch:
- 	    /* Set permissions, timestamps etc for non-hardlink entries */
--	    if (!rc && setmeta) {
-+	    if (!rc && fp->setmeta) {
- 		rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
- 				&fp->sb, nofcaps);
- 	    }
-
-From f014fc46325efe92b79841145f8dc0cb40896c64 Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 10:24:22 +0200
-Subject: [PATCH 6/9] Clarify file installation temporary suffix rule
-
-We only use a temporary suffix for regular files that we are actually
-creating, skipped and touched files should not have it. Add XFA_CREATING()
-macro to accomppany XFA_SKIPPING() to easily check whether the file
-is being created or something else.
-
-No functional changes but makes the logic clearer.
----
- lib/fsm.c      | 5 +----
- lib/rpmfiles.h | 3 +++
- 2 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index 80ca234b1e..554ea712f5 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -876,11 +876,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	fp->action = rpmfsGetAction(fs, fx);
- 	fp->skip = XFA_SKIPPING(fp->action);
- 	fp->setmeta = 1;
--	if (fp->action != FA_TOUCH) {
-+	if (XFA_CREATING(fp->action))
- 	    fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
--	} else {
--	    fp->suffix = NULL;
--	}
- 	fp->fpath = fsmFsPath(fi, fp->suffix);
- 
- 	/* Remap file perms, owner, and group. */
-diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
-index 7ce1712323..e0adbd8aff 100644
---- a/lib/rpmfiles.h
-+++ b/lib/rpmfiles.h
-@@ -121,6 +121,9 @@ typedef enum rpmFileAction_e {
- #define XFA_SKIPPING(_a)	\
-     ((_a) == FA_SKIP || (_a) == FA_SKIPNSTATE || (_a) == FA_SKIPNETSHARED || (_a) == FA_SKIPCOLOR)
- 
-+#define XFA_CREATING(_a)	\
-+    ((_a) == FA_CREATE || (_a) == FA_BACKUP || (_a) == FA_SAVE || (_a) == FA_ALTNAME)
-+
- /**
-  * We pass these around as an array with a sentinel.
-  */
-
-From fc54439f8a10901cd72028cdbdb924e3e7501624 Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 10:24:22 +0200
-Subject: [PATCH 7/9] Clarify file installation temporary suffix rule
-
-We only use a temporary suffix for regular files that we are actually
-creating, skipped and touched files should not have it. Add XFA_CREATING()
-macro to accomppany XFA_SKIPPING() to easily check whether the file
-is being created or something else.
-
-No functional changes but makes the logic clearer.
----
- lib/fsm.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index 554ea712f5..094f5e2bb6 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -876,8 +876,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	fp->action = rpmfsGetAction(fs, fx);
- 	fp->skip = XFA_SKIPPING(fp->action);
- 	fp->setmeta = 1;
--	if (XFA_CREATING(fp->action))
--	    fp->suffix = S_ISDIR(rpmfiFMode(fi)) ? NULL : tid;
-+	if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi)))
-+	    fp->suffix = tid;
- 	fp->fpath = fsmFsPath(fi, fp->suffix);
- 
- 	/* Remap file perms, owner, and group. */
-
-From 9294ffa898bc7f1f77ff80c0a3f4f0f70c4dfef2 Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 11:25:10 +0200
-Subject: [PATCH 8/9] Handle hardlink tracking with a file state pointer
-
-No functional changes, just makes it a little cleaner as firstlink now
-points to the actual file data instead of a index number somewhere.
----
- lib/fsm.c | 20 +++++++++-----------
- 1 file changed, 9 insertions(+), 11 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index 094f5e2bb6..f86383a986 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -282,24 +282,22 @@ static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest)
- 
- static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
- 		     rpmpsm psm, int nodigest,
--		     int * firsthardlink, FD_t *firstlinkfile)
-+		     struct filedata_s ** firstlink, FD_t *firstlinkfile)
- {
-     int rc = 0;
-     int numHardlinks = rpmfiFNlink(fi);
- 
-     if (numHardlinks > 1) {
- 	/* Create first hardlinked file empty */
--	if (*firsthardlink < 0) {
--	    *firsthardlink = rpmfiFX(fi);
-+	if (*firstlink == NULL) {
-+	    *firstlink = fp;
- 	    rc = wfd_open(firstlinkfile, fp->fpath);
- 	} else {
- 	    /* Create hard links for others */
--	    char *fn = rpmfilesFN(files, *firsthardlink);
--	    rc = link(fn, fp->fpath);
-+	    rc = link((*firstlink)->fpath, fp->fpath);
- 	    if (rc < 0) {
- 		rc = RPMERR_LINK_FAILED;
- 	    }
--	    free(fn);
- 	}
-     }
-     /* Write normal files or fill the last hardlinked (already
-@@ -311,7 +309,7 @@ static int fsmMkfile(rpmfi fi, struct filedata_s *fp, rpmfiles files,
- 	if (!rc)
- 	    rc = rpmfiArchiveReadToFilePsm(fi, *firstlinkfile, nodigest, psm);
- 	wfd_close(firstlinkfile);
--	*firsthardlink = -1;
-+	*firstlink = NULL;
-     } else {
- 	fp->setmeta = 0;
-     }
-@@ -855,10 +853,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     int fc = rpmfilesFC(files);
-     int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
-     int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
--    int firsthardlink = -1;
-     FD_t firstlinkfile = NULL;
-     char *tid = NULL;
-     struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
-+    struct filedata_s *firstlink = NULL;
- 
-     if (fi == NULL) {
- 	rc = RPMERR_BAD_MAGIC;
-@@ -925,7 +923,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-             if (S_ISREG(fp->sb.st_mode)) {
- 		if (rc == RPMERR_ENOENT) {
- 		    rc = fsmMkfile(fi, fp, files, psm, nodigest,
--				   &firsthardlink, &firstlinkfile);
-+				   &firstlink, &firstlinkfile);
- 		}
-             } else if (S_ISDIR(fp->sb.st_mode)) {
-                 if (rc == RPMERR_ENOENT) {
-@@ -962,13 +960,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 		rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
- 				&fp->sb, nofcaps);
- 	    }
--        } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
-+        } else if (firstlink && rpmfiArchiveHasContent(fi)) {
- 	    /* On FA_TOUCH no hardlinks are created thus this is skipped. */
- 	    /* we skip the hard linked file containing the content */
- 	    /* write the content to the first used instead */
- 	    rc = rpmfiArchiveReadToFilePsm(fi, firstlinkfile, nodigest, psm);
- 	    wfd_close(&firstlinkfile);
--	    firsthardlink = -1;
-+	    firstlink = NULL;
- 	}
- 
-         if (rc) {
-
-From d6a9a00396a89d14858c6b6e2548eca2065c1d64 Mon Sep 17 00:00:00 2001
-From: Panu Matilainen <pmatilai@redhat.com>
-Date: Wed, 10 Feb 2021 14:15:33 +0200
-Subject: [PATCH 9/9] Handle file install failures more gracefully
-
-Run the file installation in multiple stages:
-1) gather intel
-2) unpack the archive to temporary files
-3) set file metadatas
-4) commit files to final location
-5) mop up leftovers on failure
-
-This means we no longer leave behind a trail of untracked, potentially
-harmful junk on installation failure.
-
-If commit step fails the package can still be left in an inconsistent stage,
-this could be further improved by first backing up old files to temporary
-location to allow undo on failure, but leaving that for some other day.
-Also unowned directories will still be left behind.
-
-And yes, this is a somewhat scary change as it's the biggest ever change
-to how rpm lays down files on install. Adopt the hardlink test spec
-over to install tests and add some more tests for the new behavior.
-
-Fixes: #967 (+ multiple reports over the years)
----
- lib/fsm.c                       | 147 ++++++++++++++++++++------------
- tests/data/SPECS/hlinktest.spec |   4 +
- tests/rpmbuild.at               |  32 -------
- tests/rpmi.at                   |  92 ++++++++++++++++++++
- 4 files changed, 189 insertions(+), 86 deletions(-)
-
-diff --git a/lib/fsm.c b/lib/fsm.c
-index f86383a986..6efd25bddd 100644
---- a/lib/fsm.c
-+++ b/lib/fsm.c
-@@ -38,7 +38,17 @@ static int strict_erasures = 0;
- #define _dirPerms 0755
- #define _filePerms 0644
- 
-+enum filestage_e {
-+    FILE_COMMIT = -1,
-+    FILE_NONE   = 0,
-+    FILE_PRE    = 1,
-+    FILE_UNPACK = 2,
-+    FILE_PREP   = 3,
-+    FILE_POST   = 4,
-+};
-+
- struct filedata_s {
-+    int stage;
-     int setmeta;
-     int skip;
-     rpmFileAction action;
-@@ -844,10 +854,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-               rpmpsm psm, char ** failedFile)
- {
-     FD_t payload = rpmtePayload(te);
--    rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
-+    rpmfi fi = NULL;
-     rpmfs fs = rpmteGetFileStates(te);
-     rpmPlugins plugins = rpmtsPlugins(ts);
--    int saveerrno = errno;
-     int rc = 0;
-     int fx = -1;
-     int fc = rpmfilesFC(files);
-@@ -858,20 +867,17 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-     struct filedata_s *fdata = xcalloc(fc, sizeof(*fdata));
-     struct filedata_s *firstlink = NULL;
- 
--    if (fi == NULL) {
--	rc = RPMERR_BAD_MAGIC;
--	goto exit;
--    }
--
-     /* transaction id used for temporary path suffix while installing */
-     rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
- 
--    /* Detect and create directories not explicitly in package. */
--    rc = fsmMkdirs(files, fs, plugins);
--
-+    /* Collect state data for the whole operation */
-+    fi = rpmfilesIter(files, RPMFI_ITER_FWD);
-     while (!rc && (fx = rpmfiNext(fi)) >= 0) {
- 	struct filedata_s *fp = &fdata[fx];
--	fp->action = rpmfsGetAction(fs, fx);
-+	if (rpmfiFFlags(fi) & RPMFILE_GHOST)
-+            fp->action = FA_SKIP;
-+	else
-+	    fp->action = rpmfsGetAction(fs, fx);
- 	fp->skip = XFA_SKIPPING(fp->action);
- 	fp->setmeta = 1;
- 	if (XFA_CREATING(fp->action) && !S_ISDIR(rpmfiFMode(fi)))
-@@ -881,20 +887,32 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	/* Remap file perms, owner, and group. */
- 	rc = rpmfiStat(fi, 1, &fp->sb);
- 
-+	setFileState(fs, fx);
- 	fsmDebug(fp->fpath, fp->action, &fp->sb);
- 
--        /* Exit on error. */
--        if (rc)
--            break;
--
- 	/* Run fsm file pre hook for all plugins */
- 	rc = rpmpluginsCallFsmFilePre(plugins, fi, fp->fpath,
- 				      fp->sb.st_mode, fp->action);
--	if (rc) {
--	    fp->skip = 1;
--	} else {
--	    setFileState(fs, fx);
--	}
-+	fp->stage = FILE_PRE;
-+    }
-+    fi = rpmfiFree(fi);
-+
-+    if (rc)
-+	goto exit;
-+
-+    fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
-+    if (fi == NULL) {
-+        rc = RPMERR_BAD_MAGIC;
-+        goto exit;
-+    }
-+
-+    /* Detect and create directories not explicitly in package. */
-+    if (!rc)
-+	rc = fsmMkdirs(files, fs, plugins);
-+
-+    /* Process the payload */
-+    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
-+	struct filedata_s *fp = &fdata[fx];
- 
-         if (!fp->skip) {
- 	    /* Directories replacing something need early backup */
-@@ -918,7 +936,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 
- 	    /* When touching we don't need any of this... */
- 	    if (fp->action == FA_TOUCH)
--		goto touch;
-+		continue;
- 
-             if (S_ISREG(fp->sb.st_mode)) {
- 		if (rc == RPMERR_ENOENT) {
-@@ -954,12 +972,6 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
-                     rc = RPMERR_UNKNOWN_FILETYPE;
-             }
- 
--touch:
--	    /* Set permissions, timestamps etc for non-hardlink entries */
--	    if (!rc && fp->setmeta) {
--		rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
--				&fp->sb, nofcaps);
--	    }
-         } else if (firstlink && rpmfiArchiveHasContent(fi)) {
- 	    /* On FA_TOUCH no hardlinks are created thus this is skipped. */
- 	    /* we skip the hard linked file containing the content */
-@@ -969,47 +981,74 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
- 	    firstlink = NULL;
- 	}
- 
--        if (rc) {
--            if (!fp->skip) {
--                /* XXX only erase if temp fn w suffix is in use */
--                if (fp->suffix) {
--		    (void) fsmRemove(fp->fpath, fp->sb.st_mode);
--                }
--                errno = saveerrno;
--            }
--        } else {
--	    /* Notify on success. */
-+	/* Notify on success. */
-+	if (rc)
-+	    *failedFile = xstrdup(fp->fpath);
-+	else
- 	    rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
-+	fp->stage = FILE_UNPACK;
-+    }
-+    fi = rpmfiFree(fi);
- 
--	    if (!fp->skip) {
--		/* Backup file if needed. Directories are handled earlier */
--		if (fp->suffix)
--		    rc = fsmBackup(fi, fp->action);
-+    if (!rc && fx < 0 && fx != RPMERR_ITER_END)
-+	rc = fx;
- 
--		if (!rc)
--		    rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix);
--	    }
-+    /* Set permissions, timestamps etc for non-hardlink entries */
-+    fi = rpmfilesIter(files, RPMFI_ITER_FWD);
-+    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
-+	struct filedata_s *fp = &fdata[fx];
-+	if (!fp->skip && fp->setmeta) {
-+	    rc = fsmSetmeta(fp->fpath, fi, plugins, fp->action,
-+			    &fp->sb, nofcaps);
- 	}
--
- 	if (rc)
- 	    *failedFile = xstrdup(fp->fpath);
-+	fp->stage = FILE_PREP;
-+    }
-+    fi = rpmfiFree(fi);
- 
--	/* Run fsm file post hook for all plugins */
--	rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
--				  fp->sb.st_mode, fp->action, rc);
-+    /* If all went well, commit files to final destination */
-+    fi = rpmfilesIter(files, RPMFI_ITER_FWD);
-+    while (!rc && (fx = rpmfiNext(fi)) >= 0) {
-+	struct filedata_s *fp = &fdata[fx];
-+
-+	if (!fp->skip) {
-+	    /* Backup file if needed. Directories are handled earlier */
-+	    if (!rc && fp->suffix)
-+		rc = fsmBackup(fi, fp->action);
-+
-+	    if (!rc)
-+		rc = fsmCommit(&fp->fpath, fi, fp->action, fp->suffix);
-+
-+	    if (!rc)
-+		fp->stage = FILE_COMMIT;
-+	    else
-+		*failedFile = xstrdup(fp->fpath);
-+	}
-     }
-+    fi = rpmfiFree(fi);
- 
--    if (!rc && fx != RPMERR_ITER_END)
--	rc = fx;
-+    /* Walk backwards in case we need to erase */
-+    fi = rpmfilesIter(files, RPMFI_ITER_BACK);
-+    while ((fx = rpmfiNext(fi)) >= 0) {
-+	struct filedata_s *fp = &fdata[fx];
-+	/* Run fsm file post hook for all plugins for all processed files */
-+	if (fp->stage) {
-+	    rpmpluginsCallFsmFilePost(plugins, fi, fp->fpath,
-+				      fp->sb.st_mode, fp->action, rc);
-+	}
-+
-+	/* On failure, erase non-committed files */
-+	if (rc && fp->stage > FILE_NONE && !fp->skip) {
-+	    (void) fsmRemove(fp->fpath, fp->sb.st_mode);
-+	}
-+    }
- 
-     rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ));
-     rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
- 
- exit:
--
--    /* No need to bother with close errors on read */
--    rpmfiArchiveClose(fi);
--    rpmfiFree(fi);
-+    fi = rpmfiFree(fi);
-     Fclose(payload);
-     free(tid);
-     for (int i = 0; i < fc; i++)
-diff --git a/tests/data/SPECS/hlinktest.spec b/tests/data/SPECS/hlinktest.spec
-index 753c174cd8..3f1437d89c 100644
---- a/tests/data/SPECS/hlinktest.spec
-+++ b/tests/data/SPECS/hlinktest.spec
-@@ -1,5 +1,6 @@
- %bcond_with unpackaged_dirs
- %bcond_with unpackaged_files
-+%bcond_with owned_dir
- 
- Summary:          Testing hard link behavior
- Name:             hlinktest
-@@ -43,4 +44,7 @@ touch $RPM_BUILD_ROOT/teet
- 
- %files
- %defattr(-,root,root)
-+%if %{with owned_dir}
-+%dir /foo
-+%endif
- /foo/*
-diff --git a/tests/rpmbuild.at b/tests/rpmbuild.at
-index 1f0e679c44..f0eef4eff0 100644
---- a/tests/rpmbuild.at
-+++ b/tests/rpmbuild.at
-@@ -253,38 +253,6 @@ drwxrwxrwx zoot     zoot     /j/dir
- [])
- AT_CLEANUP
- 
--# ------------------------------
--# hardlink tests
--AT_SETUP([rpmbuild hardlink])
--AT_KEYWORDS([build])
--RPMDB_INIT
--AT_CHECK([
--RPMDB_INIT
--
--runroot rpmbuild \
--  -bb --quiet /data/SPECS/hlinktest.spec
--
--runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm
--
--runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest
--runroot rpm -V --nouser --nogroup hlinktest
--ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l
--
--],
--[0],
--[2 /foo/aaaa
--1 /foo/copyllo
--4 /foo/hello
--4 /foo/hello-bar
--4 /foo/hello-foo
--4 /foo/hello-world
--2 /foo/zzzz
--87
--1
--],
--[])
--AT_CLEANUP
--
- AT_SETUP([rpmbuild unpackaged files])
- AT_KEYWORDS([build])
- RPMDB_INIT
-diff --git a/tests/rpmi.at b/tests/rpmi.at
-index 42dc52ba35..295fbc230f 100644
---- a/tests/rpmi.at
-+++ b/tests/rpmi.at
-@@ -722,3 +722,95 @@ runroot rpm -V --nouser --nogroup suicidal
- [],
- [])
- AT_CLEANUP
-+
-+# ------------------------------
-+# hardlink tests
-+AT_SETUP([rpm -i hardlinks])
-+AT_KEYWORDS([build install])
-+RPMDB_INIT
-+
-+# Need a reproducable test package
-+runroot rpmbuild \
-+  --define "%optflags -O2 -g" \
-+  --define "%_target_platform noarch-linux" \
-+  --define "%_binary_payload w.ufdio" \
-+  --define "%_buildhost localhost" \
-+  --define "%use_source_date_epoch_as_buildtime 1" \
-+  --define "%source_date_epoch_from_changelog 1" \
-+  --define "%clamp_mtime_to_source_date_epoch 1" \
-+  --with owned_dir \
-+  -bb --quiet /data/SPECS/hlinktest.spec
-+
-+pkg="/build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm"
-+
-+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/1.rpm"
-+dd if=/dev/zero of="${RPMTEST}/tmp/1.rpm" \
-+   conv=notrunc bs=1 seek=8180 count=6 2> /dev/null
-+
-+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/2.rpm"
-+dd if=/dev/zero of="${RPMTEST}/tmp/2.rpm" \
-+   conv=notrunc bs=1 seek=8150 count=6 2> /dev/null
-+
-+cp "${RPMTEST}/${pkg}" "${RPMTEST}/tmp/3.rpm"
-+dd if=/dev/zero of="${RPMTEST}/tmp/3.rpm" \
-+   conv=notrunc bs=1 seek=8050 count=6 2> /dev/null
-+
-+AT_CHECK([
-+RPMDB_INIT
-+runroot rpm -i --noverify /tmp/1.rpm
-+# test that nothing of the contents remains after failure
-+test -d "${RPMTEST}/foo"
-+],
-+[1],
-+[],
-+[error: unpacking of archive failed: cpio: Archive file not in header
-+error: hlinktest-1.0-1.noarch: install failed
-+])
-+
-+AT_CHECK([
-+RPMDB_INIT
-+runroot rpm -i --noverify /tmp/2.rpm
-+# test that nothing of the contents remains after failure
-+test -d "${RPMTEST}/foo"
-+],
-+[1],
-+[],
-+[error: unpacking of archive failed: cpio: Bad/unreadable  header
-+error: hlinktest-1.0-1.noarch: install failed
-+])
-+
-+AT_CHECK([
-+RPMDB_INIT
-+runroot rpm -i --noverify /tmp/3.rpm 2>&1| sed 's/;.*:/:/g'
-+# test that nothing of the contents remains after failure
-+test -d "${RPMTEST}/foo"
-+],
-+[1],
-+[error: unpacking of archive failed on file /foo/hello-world: Digest mismatch
-+error: hlinktest-1.0-1.noarch: install failed
-+],
-+[])
-+
-+AT_CHECK([
-+RPMDB_INIT
-+runroot rpm -i /build/RPMS/noarch/hlinktest-1.0-1.noarch.rpm
-+runroot rpm -q --qf "[[%{filenlinks} %{filenames}\n]]%{longsize}\n" hlinktest
-+ls -i "${RPMTEST}"/foo/hello* | awk {'print $1'} | sort -u | wc -l
-+runroot rpm -e hlinktest
-+
-+],
-+[0],
-+[1 /foo
-+2 /foo/aaaa
-+1 /foo/copyllo
-+4 /foo/hello
-+4 /foo/hello-bar
-+4 /foo/hello-foo
-+4 /foo/hello-world
-+2 /foo/zzzz
-+87
-+1
-+],
-+[])
-+AT_CLEANUP
-+
diff --git a/rpm.spec b/rpm.spec
index 47e8925..a6d0afa 100644
--- a/rpm.spec
+++ b/rpm.spec
@@ -15,16 +15,6 @@
 %bcond_without libarchive
 # build with libimaevm.so
 %bcond_without libimaevm
-%ifarch ppc64le
-# no fsverity on RHEL based ppc64le
-# due to PAGESIZE == 64k
-# https://pagure.io/centos-sig-hyperscale/package-bugs/issue/8
-# build without libfsverity.so
-%bcond_with libfsverity
-%else
-# build with libfsverity.so
-%bcond_without libfsverity
-%endif
 # build with zstd support?
 %bcond_without zstd
 # build with ndb backend?
@@ -42,7 +32,7 @@
 
 %global rpmver 4.16.1.3
 #global snapver rc1
-%global rel 25.2
+%global rel 33.1
 %global sover 9
 
 %global srcver %{rpmver}%{?snapver:-%{snapver}}
@@ -109,6 +99,26 @@ Patch122: rpm-4.16.1.3-Support-long-languages-names-for-QT.patch
 Patch123: rpm-4.14.3-rpm2archive-parse-popt-options.patch
 Patch124: rpm-4.14.3-rpm2archive-Don-t-print-usage.patch
 Patch125: rpm-4.16.1.3-IMA-without-xattr.patch
+# Backport fsm to fix CVEs
+Patch126: 0001-Eliminate-code-duplication-from-rpmfiNext.patch
+Patch127: 0001-Add-optional-callback-on-directory-changes-during-rp.patch
+Patch128: 0001-Pass-file-descriptor-to-file-prepare-plugin-hook-use.patch
+Patch129: 0001-Swap-over-to-dirfd-basename-based-operation-within-t.patch
+Patch130: 0001-Use-file-state-machine-from-rpm-4.19.patch
+Patch131: 0001-Emit-full-paths-for-file-disposition-diagnostics-on-.patch
+Patch132: 0001-Fix-wrong-return-code-on-O_DIRECTORY-open-of-invalid.patch
+Patch133: 0001-Print-full-path-if-file-removal-fails.patch
+Patch134: 0001-Don-t-warn-about-missing-user-group-on-skipped-files.patch
+
+Patch140: 0001-Fix-short-circuiting-of-version-strings-in-expressio.patch
+Patch141: 0001-Fix-a-copy-paste-help-description-of-whatconflicts-R.patch
+Patch142: 0001-Expose-and-document-rpmdb-verifydb-operation.patch
+Patch143: 0001-Don-t-segfault-on-missing-priority-tag.patch
+Patch144: 0001-Use-unsigned-integers-for-buildtime-too-for-Y2K38-sa.patch
+Patch145: 0001-Fix-potential-use-of-uninitialized-pipe-array.patch
+Patch146: 0001-Fix-potential-use-of-uninitialized-pgp-struct.patch
+Patch147: 0001-Add-SourceLicense-tag-to-spec-syntax.patch
+Patch148: 0001-Talk-about-rpmsign-in-the-rpmsign-man-page.patch
 
 # These are not yet upstream
 Patch906: rpm-4.7.1-geode-i686.patch
@@ -130,36 +140,13 @@ Patch916: 0006-debugedit-Handle-DWARF-5-debug_line-and-debug_line_s.patch
 Patch1000: rpm-4.16.1.3-hashtab-use-after-free-fix.patch
 Patch1001: rpm-4.16.1.3-find_debuginfo_vendor_opts.patch
 Patch1002: 0001-Macroize-find-debuginfo-script-location.patch
-%if %{with zstd}
-Patch1003: rpm-4.16.1.3-backport-multithreaded-zstd.patch
-%endif
+Patch1003: 0001-Fix-root-relocation-regression.patch
+Patch1004: 0001-Skip-to-hashed-subpacket-data-directly.patch
 
-# fsverity support
-%if %{with libfsverity}
-Patch1964: 0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch
-Patch1965: 0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch
-Patch1966: 0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch
-Patch1967: 0018-rpmsign-Handle-certpath-for-signing-certificate.patch
-Patch1968: 0019-Implement-rpmSignVerity.patch
-Patch1969: 0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch
-Patch1970: 0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch
-Patch1971: 0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch
-Patch1972: 0023-Process-verity-tag-on-package-read.patch
-Patch1973: 0024-Generate-a-zero-length-signature-for-symlinks.patch
-Patch1974: 0025-rpmsignverity.c-Clean-up-debug-logging.patch
-Patch1975: 0026-fsverity-add-tag-for-fsverity-algorithm.patch
-Patch1976: 0027-plugins-fsverity-Install-fsverity-signatures.patch
-Patch1977: 0028-fsverity-plugin-Use-tag-for-algorithm.patch
-Patch1978: 0029-Add-fsverity-tags-to-rpmgeneral.at.patch
-Patch1979: 0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch
-Patch1980: 0031-Update-man-page-for-rpmsign.patch
-Patch1981: 0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
-Patch1982: 0033-Enable-fsverity-in-CI.patch
-Patch1983: 0034-rpmsign-Adopting-PKCS11-opaque-keys-support-in-libfsverity-for-fsverity-signatures.patch
+%if %{with zstd}
+Patch2000: rpm-4.16.1.3-backport-multithreaded-zstd.patch
 %endif
 
-Patch9800: 1534.patch
-
 # Copy-on-Write
 Patch9901: 0001-RPM-with-Copy-on-Write.patch
 Patch9902: 0002-Remove-use-of-bool-type-for-consistency.patch
@@ -196,6 +183,8 @@ Patch9932: 0032-rpmcow-workaround.patch
 Patch9933: 0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch
 Patch9934: 0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch
 Patch9935: 0035-rpmcow-fix-segfault-in-rpm2extents.patch
+Patch9936: 0036-bsearchr_static.patch
+Patch9937: 0037-plugin_path.patch
 Provides: rpm(pr1470)
 Provides: rpm(pr1470_1)
 
@@ -262,10 +251,6 @@ BuildRequires: audit-libs-devel
 BuildRequires: ima-evm-utils-devel >= 1.0
 %endif
 
-%if %{with libfsverity}
-BuildRequires: fsverity-utils-devel >= 1.4
-%endif
-
 # For the rpmdb migration scriptlet (#2055033)
 Requires(pre): coreutils
 Requires(pre): findutils
@@ -423,17 +408,6 @@ Requires: rpm-libs%{_isa} = %{version}-%{release}
 %description plugin-ima
 %{summary}.
 
-%if %{with libfsverity}
-%package plugin-fsverity
-Summary: Rpm plugin fsverity file signatures
-Group: System Environment/Base
-Requires: rpm-libs%{_isa} = %{version}-%{release}
-
-%description plugin-fsverity
-%{summary}
-
-%endif
-
 %package plugin-fapolicyd
 Summary: Rpm plugin for fapolicyd functionality
 Requires: rpm-libs%{_isa} = %{version}-%{release}
@@ -521,7 +495,6 @@ done;
     %{?with_ndb: --enable-ndb} \
     %{!?with_libarchive: --without-archive} \
     %{?with_libimaevm: --with-imaevm} \
-    %{?with_libfsverity: --with-fsverity} \
     %{?with_zstd: --enable-zstd} \
     %{?with_sqlite: --enable-sqlite} \
     %{?with_bdb_ro: --enable-bdb-ro} \
@@ -696,11 +669,6 @@ fi
 %if %{with plugins}
 %dir %{_libdir}/rpm-plugins
 
-%if %{with libfsverity}
-%files plugin-fsverity
-%{_libdir}/rpm-plugins/fsverity.so
-%endif
-
 %files plugin-syslog
 %{_libdir}/rpm-plugins/syslog.so
 %{_mandir}/man8/rpm-plugin-syslog.8*
@@ -795,6 +763,49 @@ fi
 %doc doc/librpm/html/*
 
 %changelog
+* Wed Aug 07 2024 Matteo Croce <teknoraver@meta.com> - 4.16.1.3-33.1
+- Port COW over latest Red Hat package
+- Drop the fs-verity patches
+- Patch 1534.patch contained a backport of upstream PR #1534:
+  https://github.com/rpm-software-management/rpm/pull/1534
+  Since the new file state machine was backported in 4.16.1.3-26, drop it
+
+* Mon Aug 05 2024 Michal Domonkos <mdomonko@redhat.com> - 4.16.1.3-33
+- Fix root relocation regression (RHEL-28967)
+- Don't confuse OpenScanHub with false array overrun (RHEL-22607)
+
+* Fri Jul 12 2024 Michal Domonkos <mdomonko@redhat.com> - 4.16.1.3-32
+- Revert incorrect fix for false array overrun (RHEL-22607)
+
+* Fri Jul 12 2024 Michal Domonkos <mdomonko@redhat.com> - 4.16.1.3-31
+- Fix potential use of uninitialized pipe array (RHEL-22604)
+- Fix potential use of uninitialized pgp struct (RHEL-22605)
+- Don't confuse OpenScanHub with false array overrun (RHEL-22607)
+- Add SourceLicense tag to spec syntax (RHEL-28798)
+- Talk about rpmsign in the rpmsign(8) man page (RHEL-40895)
+
+* Mon Jun 03 2024 Michal Domonkos <mdomonko@redhat.com> - 4.16.1.3-30
+- Don't segfault on missing priority tag (RHEL-35249)
+- Use unsigned integers for buildtime too for Y2K38 safety (RHEL-22602)
+- Rebuild against libimaevm.so.4 (RHEL-32505)
+
+* Wed Dec 13 2023 Florian Festi <ffesti@redhat.com> - 4.16.1.3-29
+- Actually add --verifydb to the man page (RHEL-14591)
+- Don't warn about missing user/group on skipped files (RHEL-18037)
+
+* Mon Dec 11 2023 Florian Festi <ffesti@redhat.com> - 4.16.1.3-28
+- Fix warning if file removal fails
+
+* Mon Nov 27 2023 Florian Festi <ffesti@redhat.com> - 4.16.1.3-27
+- Fix short circuiting of version strings in expressions (RHEL-15688)
+- Fix description of whatconflicts in the man page (RHEL-6303)
+- Expose and document rpmdb --verifydb operation (RHEL-14591)
+- Fixes to the file handling backport
+
+* Fri Nov 10 2023 Florian Festi <ffesti@redhat.com> - 4.16.1.3-26
+- Backport file handling code from rpm-4.19 to fix CVE-2021-35937,
+  CVE-2021-35938 and CVE-2021-35939
+
 * Wed Jul 3 2024 Michal Grzedzicki <mge@meta.com> - 4.16.1.3-25.2
 - Fix segfault in rpm2extents
 
@@ -883,7 +894,6 @@ fi
 * Fri Feb 25 2022 Manu Bretelle <chantra@fb.com> - 4.16.1.3-11.1
 - Added fsverity backport
 - Added measure plugin support
-- Apply GH1534 in preparation of RPM cow patch
 - Add support for RPM CoW
 
 * Mon Feb 14 2022 Michal Domonkos <mdomonko@redhat.com> - 4.16.1.3-11