diff --git a/0001-RPM-with-Copy-on-Write.patch b/0001-RPM-with-Copy-on-Write.patch index 49a0f32..ca8eaed 100644 --- a/0001-RPM-with-Copy-on-Write.patch +++ b/0001-RPM-with-Copy-on-Write.patch @@ -1,7 +1,7 @@ -From 7bd31ce85b2ed377f495c31fcea2422a07739e24 Mon Sep 17 00:00:00 2001 +From 55de6f0be10d96b56de214b677ed185bf12d15ee Mon Sep 17 00:00:00 2001 From: Matthew Almond Date: Fri, 8 Nov 2019 09:29:43 -0800 -Subject: [PATCH 01/30] RPM with Copy on Write +Subject: [PATCH] RPM with Copy on Write This is part of https://fedoraproject.org/wiki/Changes/RPMCoW @@ -85,28 +85,48 @@ 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 | 61 +++++- - lib/package.c | 40 ++++ - lib/rpmlib.h | 9 + - lib/rpmplugins.c | 21 +- - lib/rpmte.c | 5 + - lib/rpmte.h | 2 + - lib/rpmtypes.h | 3 +- - macros.in | 1 + - plugins/Makefile.am | 4 + - plugins/reflink.c | 340 +++++++++++++++++++++++++++++ - rpm2extents.c | 519 ++++++++++++++++++++++++++++++++++++++++++++ - rpmio/rpmpgp.c | 10 + - rpmio/rpmpgp.h | 9 + - 16 files changed, 1020 insertions(+), 13 deletions(-) + Makefile.am | 8 +- + build/pack.c | 2 +- + lib/Makefile.am | 3 +- + lib/Makefile.in | 51 +-- + lib/fsm.c | 45 ++- + lib/package.c | 36 ++ + lib/rpmchecksig.c | 117 +++++-- + lib/rpmcli.h | 10 + + lib/rpmextents.c | 110 ++++++ + lib/rpmextents_internal.h | 58 ++++ + lib/rpmlead.c | 43 ++- + lib/rpmlead.h | 37 +- + lib/rpmlib.h | 9 + + lib/rpmplugin.h | 9 + + lib/rpmplugins.c | 92 ++++- + lib/rpmplugins.h | 17 + + lib/rpmte.c | 5 + + lib/rpmte.h | 2 + + lib/rpmtypes.h | 3 +- + lib/transaction.c | 29 +- + macros.in | 1 + + plugins/Makefile.am | 4 + + plugins/reflink.c | 401 +++++++++++++++++++++ + rpm2extents.c | 708 ++++++++++++++++++++++++++++++++++++++ + rpmio/rpmpgp.c | 10 + + rpmio/rpmpgp.h | 9 + + scripts/rpm2extents_dump | 94 +++++ + sign/rpmgensig.c | 2 +- + tests/Makefile.am | 1 + + tests/atlocal.in | 22 ++ + tests/rpm2extents.at | 151 ++++++++ + tests/rpmtests.at | 1 + + 32 files changed, 1996 insertions(+), 94 deletions(-) + create mode 100644 lib/rpmextents.c + create mode 100644 lib/rpmextents_internal.h create mode 100644 plugins/reflink.c create mode 100644 rpm2extents.c + create mode 100755 scripts/rpm2extents_dump + create mode 100644 tests/rpm2extents.at diff --git a/Makefile.am b/Makefile.am -index e5c75d7b4..288668819 100644 +index 78bc131..43fbd94 100644 --- a/Makefile.am +++ b/Makefile.am @@ -106,7 +106,7 @@ pkginclude_HEADERS += build/rpmfc.h @@ -129,109 +149,198 @@ index e5c75d7b4..288668819 100644 rpm2archive_SOURCES = rpm2archive.c debug.h system.h rpm2archive_LDADD = lib/librpm.la rpmio/librpmio.la rpm2archive_LDADD += @WITH_POPT_LIB@ @WITH_ARCHIVE_LIB@ -diff --git a/lib/depends.c b/lib/depends.c -index 30234df3d..8998afcd3 100644 ---- a/lib/depends.c -+++ b/lib/depends.c -@@ -80,6 +80,8 @@ static rpmRC headerCheckPayloadFormat(Header h) { - */ - if (!payloadfmt) return rc; +@@ -199,7 +203,7 @@ bin_PROGRAMS += rpmgraph + rpmgraph_SOURCES = tools/rpmgraph.c + rpmgraph_LDADD = lib/librpm.la rpmio/librpmio.la @WITH_POPT_LIB@ -+ if (rstreq(payloadfmt, "clon")) return rc; -+ - if (!rstreq(payloadfmt, "cpio")) { - char *nevra = headerGetAsString(h, RPMTAG_NEVRA); - if (payloadfmt && rstreq(payloadfmt, "drpm")) { +-dist_bin_SCRIPTS = scripts/gendiff ++dist_bin_SCRIPTS = scripts/gendiff scripts/rpm2extents_dump + + rpmconfig_DATA = rpmrc + rpmrc: $(top_srcdir)/rpmrc.in +diff --git a/build/pack.c b/build/pack.c +index 8d6f749..e2f05b6 100644 +--- a/build/pack.c ++++ b/build/pack.c +@@ -493,7 +493,7 @@ static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp, + } + + /* Write the lead section into the package. */ +- if (rpmLeadWrite(fd, pkg->header)) { ++ if (rpmLeadWriteFromHeader(fd, pkg->header)) { + rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd)); + goto exit; + } +diff --git a/lib/Makefile.am b/lib/Makefile.am +index c561ad5..4a83e9a 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -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 \ +- rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h ++ rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h \ ++ rpmextents.c rpmextents_internal.h + + librpm_la_LDFLAGS = -version-info $(rpm_version_info) + +diff --git a/lib/Makefile.in b/lib/Makefile.in +index 1aafaac..bf911fa 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 +@@ -586,8 +587,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) \ +@@ -748,6 +750,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 +@@ -978,6 +981,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 +@@ -1077,6 +1081,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/fsm.c b/lib/fsm.c -index 935a0a5c6..90193c749 100644 +index 9dd50b7..e562220 100644 --- a/lib/fsm.c +++ b/lib/fsm.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - #ifdef WITH_CAP - #include -@@ -17,6 +18,7 @@ - #include - #include - #include -+#include - - #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ - #include "fsm.h" -@@ -54,6 +56,7 @@ struct filedata_s { - int stage; - int setmeta; - int skip; -+ bool plugin_contents; - rpmFileAction action; - const char *suffix; - char *fpath; -@@ -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; -+ -+ if (payloadfmt && rstreq(payloadfmt, "clon")) { -+ cpio = false; -+ } - - /* transaction id used for temporary path suffix while installing */ - rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); -@@ -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); +@@ -868,6 +868,24 @@ static rpmfi fsmIterFini(rpmfi fi, struct diriter_s *di) + return rpmfiFree(fi); + } -- setFileState(fs, fx); -+ switch (rc) { -+ case RPMRC_OK: -+ setFileState(fs, fx); -+ break; ++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: -+ fp->plugin_contents = true; -+ // reduce reads on cpio to this value. Could be zero if -+ // this is from a hard link. -+ rc = RPMRC_OK; -+ break; ++ 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: -+ fp->action = FA_SKIP; -+ fp->skip = XFA_SKIPPING(fp->action); -+ } - fsmDebug(rpmfiDN(fi), fp->fpath, fp->action, &fp->sb); - - fp->stage = FILE_PRE; -@@ -919,8 +942,12 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, ++ return RPMRC_FAIL; ++ } ++} ++ + int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + rpmpsm psm, char ** failedFile) + { +@@ -919,8 +937,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (rc) goto exit; - fi = fsmIter(payload, files, - payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); -+ if (cpio) { -+ fi = fsmIter(payload, files, -+ payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); -+ } else { -+ fi = rpmfilesIter(files, RPMFI_ITER_FWD); -+ } ++ rc = fiIterator(plugins, payload, files, &fi); ++ if (rc) ++ goto exit; if (fi == NULL) { rc = RPMERR_BAD_MAGIC; -@@ -943,6 +970,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, +@@ -943,6 +962,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, if (!fp->skip) { int mayopen = 0; int fd = -1; + -+ 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); -@@ -952,9 +982,14 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, +@@ -952,9 +974,10 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, } /* Run fsm file pre hook for all plugins */ @@ -239,55 +348,51 @@ index 935a0a5c6..90193c749 100644 + 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, +@@ -982,11 +1005,18 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, + if (fp->action == FA_TOUCH) + goto setmeta; - if (S_ISREG(fp->sb.st_mode)) { +- 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)){ ++ rc = plugin_rc; ++ } else if(plugin_rc == RPMRC_PLUGIN_CONTENTS){ ++ rc = RPMRC_OK; ++ /* The reflink plugins handles hardlink differently, metadata has to be set. */ ++ fp->setmeta = 1; ++ } else if (S_ISREG(fp->sb.st_mode)) { if (rc == RPMERR_ENOENT) { -- rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, + rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, - &firstlink, &firstlinkfile, &di.firstdir, - &fd); -+ if (fp->plugin_contents) { -+ rc = RPMRC_OK; -+ } else { -+ rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, -+ &firstlink, &firstlinkfile, -+ &di.firstdir, &fd); -+ } ++ &firstlink, &firstlinkfile, ++ &di.firstdir, &fd); } } else if (S_ISDIR(fp->sb.st_mode)) { if (rc == RPMERR_ENOENT) { -@@ -1054,11 +1093,17 @@ setmeta: - rc = fx; +@@ -1055,10 +1085,13 @@ setmeta: /* 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); -+ } + fi = fsmIter(NULL, files, RPMFI_ITER_FWD, &di); ++ while (!rc && (fx = rpmfiNext(fi)) >= 0) { struct filedata_s *fp = &fdata[fx]; 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/lib/package.c b/lib/package.c -index 281275029..90bd0d8a7 100644 +index 8c2b66b..fb7ec7b 100644 --- a/lib/package.c +++ b/lib/package.c -@@ -402,5 +402,45 @@ exit: +@@ -402,5 +402,41 @@ exit: return rc; } @@ -299,11 +404,7 @@ index 281275029..90bd0d8a7 100644 + Header h = NULL; + Header sigh = NULL; + -+ rpmRC rc = rpmLeadRead(fd, &msg); -+ if (rc != RPMRC_OK) -+ goto exit; -+ -+ rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg); ++ rpmRC rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg); + if (rc != RPMRC_OK) + goto exit; + @@ -314,14 +415,14 @@ index 281275029..90bd0d8a7 100644 + rc = hdrblobImport(sigblob, 0, &sigh, &msg); + if (rc) + goto exit; - ++ + rc = hdrblobImport(blob, 0, &h, &msg); + if (rc) + goto exit; - ++ + *sigp = headerLink(sigh); + *hdrp = headerLink(h); -+ + +exit: + if (rc != RPMRC_OK && msg) + rpmlog(RPMLOG_ERR, "%s: %s\n", Fdescr(fd), msg); @@ -330,11 +431,534 @@ index 281275029..90bd0d8a7 100644 + headerFree(sigh); + headerFree(h); + free(msg); + ++ return rc; ++} +diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c +index 40a3ab8..7f85615 100644 +--- a/lib/rpmchecksig.c ++++ b/lib/rpmchecksig.c +@@ -20,6 +20,7 @@ + #include "rpmio/rpmio_internal.h" /* fdSetBundle() */ + #include "lib/rpmlead.h" + #include "lib/header_internal.h" ++#include "lib/rpmextents_internal.h" + #include "lib/rpmvs.h" + + #include "debug.h" +@@ -221,36 +222,24 @@ exit: + } + + static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, +- FD_t fd, const char *fn) ++ FD_t fd, rpmsinfoCb cb, void *cbdata) + { + char *msg = NULL; +- struct vfydata_s vd = { .seen = 0, +- .bad = 0, +- .verbose = rpmIsVerbose(), +- }; + int rc; +- struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); + +- rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : ""); ++ ++ if(isTranscodedRpm(fd) == RPMRC_OK){ ++ return extentsVerifySigs(fd, 1); ++ } ++ ++ struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); + + rc = rpmpkgRead(vs, fd, NULL, NULL, &msg); + + if (rc) + goto exit; + +- rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); +- +- if (!vd.verbose) { +- if (vd.seen & RPMSIG_DIGEST_TYPE) { +- rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_DIGEST_TYPE) ? +- _("DIGESTS") : _("digests")); +- } +- if (vd.seen & RPMSIG_SIGNATURE_TYPE) { +- rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ? +- _("SIGNATURES") : _("signatures")); +- } +- rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK")); +- } ++ rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata); + + exit: + if (rc && msg) +@@ -260,15 +249,39 @@ exit: + return rc; + } + ++static void rpmkgVerifySigsPreLogging(struct vfydata_s *vd, const char *fn){ ++ rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd->verbose ? "\n" : ""); ++} ++ ++static void rpmkgVerifySigsPostLogging(struct vfydata_s *vd, int rc){ ++ if (!vd->verbose) { ++ if (vd->seen & RPMSIG_DIGEST_TYPE) { ++ rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_DIGEST_TYPE) ? ++ _("DIGESTS") : _("digests")); ++ } ++ if (vd->seen & RPMSIG_SIGNATURE_TYPE) { ++ rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_SIGNATURE_TYPE) ? ++ _("SIGNATURES") : _("signatures")); ++ } ++ rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK")); ++ } ++} ++ + /* Wrapper around rpmkVerifySigs to preserve API */ + int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn) + { + int rc = 1; /* assume failure */ ++ struct vfydata_s vd = { .seen = 0, ++ .bad = 0, ++ .verbose = rpmIsVerbose(), ++ }; + if (ts && qva && fd && fn) { + rpmKeyring keyring = rpmtsGetKeyring(ts, 1); + rpmVSFlags vsflags = rpmtsVfyFlags(ts); + int vfylevel = rpmtsVfyLevel(ts); +- rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, fn); ++ rpmkgVerifySigsPreLogging(&vd, fn); ++ rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, vfyCb, &vd); ++ rpmkgVerifySigsPostLogging(&vd, rc); + rpmKeyringFree(keyring); + } + return rc; +@@ -290,12 +303,22 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv) + + while ((arg = *argv++) != NULL) { + FD_t fd = Fopen(arg, "r.ufdio"); ++ struct vfydata_s vd = { .seen = 0, ++ .bad = 0, ++ .verbose = rpmIsVerbose(), ++ }; + if (fd == NULL || Ferror(fd)) { + rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), + arg, Fstrerror(fd)); + res++; +- } else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, arg)) { ++ } else { ++ rpmkgVerifySigsPreLogging(&vd, arg); ++ int rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, ++ vfyCb, &vd); ++ rpmkgVerifySigsPostLogging(&vd, rc); ++ if (rc) { + res++; ++ } + } + + Fclose(fd); +@@ -304,3 +327,53 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv) + rpmKeyringFree(keyring); + return res; + } ++ ++struct vfydatafd_s { ++ size_t len; ++ char msg[BUFSIZ]; ++}; ++ ++ ++static int vfyFDCb(struct rpmsinfo_s *sinfo, void *cbdata) ++{ ++ struct vfydatafd_s *vd = cbdata; ++ char *vmsg, *msg; ++ size_t n; ++ size_t remainder = BUFSIZ - vd->len >= 0 ? BUFSIZ - vd->len : 0; ++ ++ vmsg = rpmsinfoMsg(sinfo); ++ rasprintf(&msg, " %s\n", vmsg); ++ n = rstrlcpy(vd->msg + vd->len, msg, remainder); ++ free(vmsg); ++ free(msg); ++ if(n <= remainder){ ++ vd->len += n; ++ } ++ return 1; ++} ++ + ++int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi, char **msg) ++{ ++ rpmRC rc = RPMRC_FAIL; ++ rpmKeyring keyring = rpmtsGetKeyring(ts, 1); ++ rpmVSFlags vsflags = rpmtsVfyFlags(ts); ++ int vfylevel = rpmtsVfyLevel(ts); ++ struct vfydatafd_s vd = {.len = 0}; ++ ++ vsflags |= rpmcliVSFlags; ++ if (rpmcliVfyLevelMask) { ++ vfylevel &= ~rpmcliVfyLevelMask; ++ rpmtsSetVfyLevel(ts, vfylevel); ++ } ++ ++ if (!rpmpkgVerifySigs(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) { ++ rc = RPMRC_OK; ++ } ++ *msg = strdup(vd.msg); ++ rpmsqPoll(); ++ ++ rpmKeyringFree(keyring); + return rc; +} ++ +diff --git a/lib/rpmcli.h b/lib/rpmcli.h +index 3961418..450f7be 100644 +--- a/lib/rpmcli.h ++++ b/lib/rpmcli.h +@@ -411,6 +411,16 @@ int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv); + */ + int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv); + ++ ++/** \ingroup rpmcli ++ * Verify package signatures. ++ * @param ts transaction set ++ * @param fd a file descriptor to verify ++ * @param msg a string containing textual information about the verification, similar to rpmcliVerifySignatures output. ++ * @return 0 on success ++ */ ++int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd, char **msg); ++ + #ifdef __cplusplus + } + #endif +diff --git a/lib/rpmextents.c b/lib/rpmextents.c +new file mode 100644 +index 0000000..ac43264 +--- /dev/null ++++ b/lib/rpmextents.c +@@ -0,0 +1,110 @@ ++ ++#include "system.h" ++ ++#include ++#include ++#include ++#include ++ ++ ++#include "lib/rpmextents_internal.h" ++ ++ ++int extentsVerifySigs(FD_t fd, int print_content){ ++ rpm_loff_t current; ++ int32_t rc; ++ size_t len; ++ uint64_t content_len; ++ char *content = NULL; ++ struct extents_footer_t footer; ++ ++ current = Ftell(fd); ++ ++ if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) { ++ rc = -1; ++ goto exit; ++ } ++ if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) { ++ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to seek signature verification offset\n")); ++ rc = -1; ++ goto exit; ++ } ++ len = sizeof(rc); ++ if (Fread(&rc, len, 1, fd) != len) { ++ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read Signature Verification RC\n")); ++ rc = -1; ++ goto exit; ++ } ++ ++ if(print_content) { ++ len = sizeof(content_len); ++ if (Fread(&content_len, len, 1, fd) != len) { ++ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n")); ++ goto exit; ++ } ++ ++ content = rmalloc(content_len + 1); ++ if(content == NULL) { ++ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n")); ++ goto exit; ++ } ++ content[content_len] = 0; ++ if (Fread(content, content_len, 1, fd) != content_len) { ++ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n")); ++ goto exit; ++ } ++ ++ rpmlog(RPMLOG_NOTICE, "%s", content); ++ } ++exit: ++ if(content){ ++ rfree(content); ++ } ++ if (Fseek(fd, current, SEEK_SET) < 0) { ++ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: unable to seek back to original location\n")); ++ } ++ return rc; ++ ++} ++ ++rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) { ++ ++ rpmRC rc = RPMRC_NOTFOUND; ++ rpm_loff_t current; ++ size_t len; ++ ++ // If the file is not seekable, we cannot detect whether or not it is transcoded. ++ if(Fseek(fd, 0, SEEK_CUR) < 0) { ++ return RPMRC_FAIL; ++ } ++ current = Ftell(fd); ++ ++ len = sizeof(struct extents_footer_t); ++ if(Fseek(fd, -len, SEEK_END) < 0) { ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ if (Fread(footer, len, 1, fd) != len) { ++ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read footer\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ if (footer->magic != EXTENTS_MAGIC) { ++ rc = RPMRC_NOTFOUND; ++ goto exit; ++ } ++ rc = RPMRC_OK; ++exit: ++ if (Fseek(fd, current, SEEK_SET) < 0) { ++ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n")); ++ rc = RPMRC_FAIL; ++ } ++ return rc; ++} ++ ++rpmRC isTranscodedRpm(FD_t fd) { ++ struct extents_footer_t footer; ++ return extentsFooterFromFD(fd, &footer); ++} ++ ++ +diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h +new file mode 100644 +index 0000000..0a3318c +--- /dev/null ++++ b/lib/rpmextents_internal.h +@@ -0,0 +1,58 @@ ++#ifndef _RPMEXTENTS_INTERNAL_H ++#define _RPMEXTENTS_INTERNAL_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++ ++/** \ingroup rpmextents ++ * RPM extents library ++ */ ++ ++/* magic value at end of file (64 bits) that indicates this is a transcoded ++ * rpm. ++ */ ++#define EXTENTS_MAGIC 3472329499408095051 ++ ++typedef uint64_t extents_magic_t; ++ ++struct __attribute__ ((__packed__)) extents_footer_offsets_t { ++ off64_t checksig_offset; ++ off64_t table_offset; ++ off64_t csum_offset; ++}; ++ ++struct __attribute__ ((__packed__)) extents_footer_t { ++ struct extents_footer_offsets_t offsets; ++ extents_magic_t magic; ++}; ++ ++/** \ingroup rpmextents ++ * Checks the results of the signature verification ran during transcoding. ++ * @param fd The FD_t of the transcoded RPM ++ * @param print_content Whether or not to print the result from rpmsig ++ * @return The number of checks that `rpmvsVerify` failed during transcoding. ++ */ ++int extentsVerifySigs(FD_t fd, int print_content); ++ ++/** \ingroup rpmextents ++ * Read the RPM Extents footer from a file descriptor. ++ * @param fd The FD_t of the transcoded RPM ++ * @param[out] footer A pointer to an allocated extents_footer_t with a copy of the footer. ++ * @return RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure. ++ */ ++rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer); ++ ++/** \ingroup rpmextents ++ * Check if a RPM is a transcoded RPM ++ * @param fd The FD_t of the transcoded RPM ++ * return RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure. ++ */ ++rpmRC isTranscodedRpm(FD_t fd); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif /* _RPMEXTENTS_INTERNAL_H */ +diff --git a/lib/rpmlead.c b/lib/rpmlead.c +index 45b1c6f..8210512 100644 +--- a/lib/rpmlead.c ++++ b/lib/rpmlead.c +@@ -24,24 +24,6 @@ static unsigned char const lead_magic[] = { + RPMLEAD_MAGIC0, RPMLEAD_MAGIC1, RPMLEAD_MAGIC2, RPMLEAD_MAGIC3 + }; + +-/** \ingroup lead +- * The lead data structure. +- * The lead needs to be 8 byte aligned. +- * @deprecated The lead (except for signature_type) is legacy. +- * @todo Don't use any information from lead. +- */ +-struct rpmlead_s { +- unsigned char magic[4]; +- unsigned char major; +- unsigned char minor; +- short type; +- short archnum; +- char name[66]; +- short osnum; +- short signature_type; /*!< Signature header type (RPMSIG_HEADERSIG) */ +- char reserved[16]; /*!< Pad to 96 bytes -- 8 byte aligned! */ +-}; +- + static int rpmLeadFromHeader(Header h, struct rpmlead_s *l) + { + if (h != NULL) { +@@ -70,13 +52,23 @@ static int rpmLeadFromHeader(Header h, struct rpmlead_s *l) + } + + /* The lead needs to be 8 byte aligned */ +-rpmRC rpmLeadWrite(FD_t fd, Header h) ++rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h) + { + rpmRC rc = RPMRC_FAIL; + struct rpmlead_s l; + +- if (rpmLeadFromHeader(h, &l)) { +- ++ if (rpmLeadFromHeader(h, &l)) { ++ rc = rpmLeadWrite(fd, l); ++ } ++ ++ return rc; ++} ++ ++/* The lead needs to be 8 byte aligned */ ++rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l) ++{ ++ rpmRC rc = RPMRC_FAIL; ++ + l.type = htons(l.type); + l.archnum = htons(l.archnum); + l.osnum = htons(l.osnum); +@@ -84,7 +76,6 @@ rpmRC rpmLeadWrite(FD_t fd, Header h) + + if (Fwrite(&l, 1, sizeof(l), fd) == sizeof(l)) + rc = RPMRC_OK; +- } + + return rc; + } +@@ -107,6 +98,11 @@ static rpmRC rpmLeadCheck(struct rpmlead_s *lead, char **msg) + } + + rpmRC rpmLeadRead(FD_t fd, char **emsg) ++{ ++ return rpmLeadReadAndReturn(fd, emsg, NULL); ++} ++ ++rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret) + { + rpmRC rc = RPMRC_OK; + struct rpmlead_s l; +@@ -136,5 +132,8 @@ rpmRC rpmLeadRead(FD_t fd, char **emsg) + free(err); + } + ++ if (ret) ++ *ret = l; ++ + return rc; + } +diff --git a/lib/rpmlead.h b/lib/rpmlead.h +index b344ed4..cc63512 100644 +--- a/lib/rpmlead.h ++++ b/lib/rpmlead.h +@@ -19,13 +19,39 @@ extern "C" { + + #define RPMLEAD_SIZE 96 /*!< Don't rely on sizeof(struct) */ + ++/** \ingroup lead ++ * The lead data structure. ++ * The lead needs to be 8 byte aligned. ++ * @deprecated The lead (except for signature_type) is legacy. ++ * @todo Don't use any information from lead. ++ */ ++struct rpmlead_s { ++ unsigned char magic[4]; ++ unsigned char major; ++ unsigned char minor; ++ short type; ++ short archnum; ++ char name[66]; ++ short osnum; ++ short signature_type; /*!< Signature header type (RPMSIG_HEADERSIG) */ ++ char reserved[16]; /*!< Pad to 96 bytes -- 8 byte aligned! */ ++}; ++ + /** \ingroup lead + * Write lead to file handle. + * @param fd file handle + * @param h package header + * @return RPMRC_OK on success, RPMRC_FAIL on error + */ +-rpmRC rpmLeadWrite(FD_t fd, Header h); ++rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h); ++ ++/** \ingroup lead ++ * Write lead to file handle. ++ * @param fd file handle ++ * @param l lead ++ * @return RPMRC_OK on success, RPMRC_FAIL on error ++ */ ++rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l); + + /** \ingroup lead + * Read lead from file handle. +@@ -35,6 +61,15 @@ rpmRC rpmLeadWrite(FD_t fd, Header h); + */ + rpmRC rpmLeadRead(FD_t fd, char **emsg); + ++/** \ingroup lead ++ * Read lead from file handle and return it. ++ * @param fd file handle ++ * @param[out] emsg failure message on error (malloced) ++ * @param[out] ret address of lead ++ * @return RPMRC_OK on success, RPMRC_FAIL/RPMRC_NOTFOUND on error ++ */ ++rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret); ++ + #ifdef __cplusplus + } + #endif diff --git a/lib/rpmlib.h b/lib/rpmlib.h -index 0879d04e5..a09ba0daf 100644 +index cee47df..af61379 100644 --- a/lib/rpmlib.h +++ b/lib/rpmlib.h @@ -156,6 +156,15 @@ rpmRC rpmReadHeader(rpmts ts, FD_t fd, Header *hdrp, char ** msg); @@ -353,8 +977,35 @@ index 0879d04e5..a09ba0daf 100644 /** \ingroup rpmtrans * Install source package. * @param ts transaction set +diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h +index fab4b3e..c82d6be 100644 +--- a/lib/rpmplugin.h ++++ b/lib/rpmplugin.h +@@ -60,6 +60,13 @@ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi, + 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, ++ const char* path, ++ mode_t file_mode, rpmFsmOp op); ++typedef rpmRC (*plugin_fsm_file_archive_reader_func)(rpmPlugin plugin, ++ FD_t payload, ++ rpmfiles files, rpmfi *fi); ++ + + typedef struct rpmPluginHooks_s * rpmPluginHooks; + struct rpmPluginHooks_s { +@@ -80,6 +87,8 @@ struct rpmPluginHooks_s { + plugin_fsm_file_pre_func fsm_file_pre; + plugin_fsm_file_post_func fsm_file_post; + plugin_fsm_file_prepare_func fsm_file_prepare; ++ plugin_fsm_file_install_func fsm_file_install; ++ plugin_fsm_file_archive_reader_func fsm_file_archive_reader; + }; + + #ifdef __cplusplus diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c -index 62d75c4cf..c5084d398 100644 +index f06fd78..1e0c345 100644 --- a/lib/rpmplugins.c +++ b/lib/rpmplugins.c @@ -364,14 +364,29 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path, @@ -390,8 +1041,111 @@ index 62d75c4cf..c5084d398 100644 } } free(apath); +@@ -420,3 +435,74 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, + + return rc; + } ++ ++rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, ++ const char *path, mode_t file_mode, ++ rpmFsmOp op) ++{ ++ plugin_fsm_file_install_func hookFunc; ++ int i; ++ rpmRC rc = RPMRC_OK; ++ rpmRC hook_rc; ++ ++ for (i = 0; i < plugins->count; i++) { ++ rpmPlugin plugin = plugins->plugins[i]; ++ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_install); ++ if (hookFunc) { ++ hook_rc = hookFunc(plugin, fi, path, file_mode, op); ++ if (hook_rc == RPMRC_FAIL) { ++ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_install failed\n", plugin->name); ++ 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. ++ */ ++ rc = RPMRC_FAIL; ++ } else { ++ /* Plugin will handle content */ ++ rc = RPMRC_PLUGIN_CONTENTS; ++ } ++ } ++ } ++ } ++ ++ return rc; ++} ++ ++rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload, ++ rpmfiles files, rpmfi *fi) ++{ ++ plugin_fsm_file_archive_reader_func hookFunc; ++ int i; ++ rpmRC rc = RPMRC_OK; ++ rpmRC hook_rc; ++ ++ for (i = 0; i < plugins->count; i++) { ++ rpmPlugin plugin = plugins->plugins[i]; ++ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_archive_reader); ++ if (hookFunc) { ++ hook_rc = hookFunc(plugin, payload, files, fi); ++ if (hook_rc == RPMRC_FAIL) { ++ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_archive_reader failed\n", plugin->name); ++ 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. ++ */ ++ rc = RPMRC_FAIL; ++ } else { ++ /* Plugin will handle content */ ++ rc = RPMRC_PLUGIN_CONTENTS; ++ } ++ } ++ } ++ } ++ ++ return rc; ++} ++ ++ +diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h +index ddf5d70..db01bff 100644 +--- a/lib/rpmplugins.h ++++ b/lib/rpmplugins.h +@@ -168,6 +168,23 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, + int fd, const char *path, const char *dest, + mode_t mode, rpmFsmOp op); + ++/** \ingroup rpmplugins ++ * Call the fsm file install plugin hook ++ * @param plugins plugins structure ++ * @param fi file info iterator (or NULL) ++ * @param path file object path ++ * @param file_mode file object mode ++ * @param op file operation + associated flags ++ * @return RPMRC_OK on success, RPMRC_FAIL otherwise ++ */ ++RPM_GNUC_INTERNAL ++rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, ++ const char* path, mode_t file_mode, ++ rpmFsmOp op); ++ ++RPM_GNUC_INTERNAL ++rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload, ++ rpmfiles files, rpmfi *fi); + #ifdef __cplusplus + } + #endif diff --git a/lib/rpmte.c b/lib/rpmte.c -index 3663604e7..d43dc41ad 100644 +index 0551a0f..61b3905 100644 --- a/lib/rpmte.c +++ b/lib/rpmte.c @@ -421,6 +421,11 @@ FD_t rpmteSetFd(rpmte te, FD_t fd) @@ -407,7 +1161,7 @@ index 3663604e7..d43dc41ad 100644 { return (te != NULL ? te->key : NULL); diff --git a/lib/rpmte.h b/lib/rpmte.h -index 81acf7a19..6fc0a9f91 100644 +index 188c3c1..47dec4b 100644 --- a/lib/rpmte.h +++ b/lib/rpmte.h @@ -209,6 +209,8 @@ const char * rpmteNEVR(rpmte te); @@ -420,7 +1174,7 @@ index 81acf7a19..6fc0a9f91 100644 * Retrieve key from transaction element. * @param te transaction element diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h -index e8e69b506..af2611e9e 100644 +index e8e69b5..af2611e 100644 --- a/lib/rpmtypes.h +++ b/lib/rpmtypes.h @@ -106,7 +106,8 @@ typedef enum rpmRC_e { @@ -433,8 +1187,57 @@ index e8e69b506..af2611e9e 100644 } rpmRC; #ifdef __cplusplus +diff --git a/lib/transaction.c b/lib/transaction.c +index 55bc2d9..9603d5e 100644 +--- a/lib/transaction.c ++++ b/lib/transaction.c +@@ -37,6 +37,7 @@ + #include "lib/rpmfi_internal.h" /* only internal apis */ + #include "lib/rpmte_internal.h" /* only internal apis */ + #include "lib/rpmts_internal.h" ++#include "lib/rpmextents_internal.h" + #include "lib/rpmvs.h" + #include "rpmio/rpmhook.h" + #include "lib/rpmtriggers.h" +@@ -1286,19 +1287,25 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total) + + rpmtsNotify(ts, p, RPMCALLBACK_VERIFY_PROGRESS, oc++, total); + FD_t fd = rpmtsNotify(ts, p, RPMCALLBACK_INST_OPEN_FILE, 0, 0); +- if (fd != NULL) { +- prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg); +- rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0); ++ if(fd != NULL && isTranscodedRpm(fd) == RPMRC_OK) { ++ /* Transcoded RPMs are validated at transcoding time */ ++ prc = RPMRC_OK; ++ verified = 1; ++ } else { ++ if (fd != NULL) { ++ prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg); ++ rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0); ++ } ++ if (prc == RPMRC_OK) ++ prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); ++ ++ /* Record verify result */ ++ if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK) ++ verified |= RPMSIG_SIGNATURE_TYPE; ++ if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK) ++ verified |= RPMSIG_DIGEST_TYPE; + } + +- if (prc == RPMRC_OK) +- prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); +- +- /* Record verify result */ +- if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK) +- verified |= RPMSIG_SIGNATURE_TYPE; +- if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK) +- verified |= RPMSIG_DIGEST_TYPE; + rpmteSetVerified(p, verified); + + if (prc) diff --git a/macros.in b/macros.in -index e90cefa9a..363252b0f 100644 +index 877f3ed..a9cc673 100644 --- a/macros.in +++ b/macros.in @@ -1189,6 +1189,7 @@ package or when debugging this package.\ @@ -446,7 +1249,7 @@ index e90cefa9a..363252b0f 100644 %__transaction_selinux %{__plugindir}/selinux.so %__transaction_syslog %{__plugindir}/syslog.so diff --git a/plugins/Makefile.am b/plugins/Makefile.am -index 3a929d0ce..ad0d3bce7 100644 +index f7b95a4..154acb0 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -33,6 +33,10 @@ prioreset_la_SOURCES = prioreset.c @@ -462,10 +1265,10 @@ index 3a929d0ce..ad0d3bce7 100644 plugins_LTLIBRARIES += syslog.la diff --git a/plugins/reflink.c b/plugins/reflink.c new file mode 100644 -index 000000000..d7f19acd9 +index 0000000..127888e --- /dev/null +++ b/plugins/reflink.c -@@ -0,0 +1,340 @@ +@@ -0,0 +1,401 @@ +#include "system.h" + +#include @@ -481,6 +1284,7 @@ index 000000000..d7f19acd9 +#include +#include "lib/rpmlib.h" +#include "lib/rpmplugin.h" ++#include "lib/rpmextents_internal.h" +#include "lib/rpmte_internal.h" +#include +#include "rpmio/rpmio_internal.h" @@ -496,38 +1300,79 @@ index 000000000..d7f19acd9 +#undef HTDATATYPE +#define HASHTYPE inodeIndexHash +#define HTKEYTYPE rpm_ino_t -+#define HTDATATYPE int ++#define HTDATATYPE const char * +#include "lib/rpmhash.H" +#include "lib/rpmhash.C" + -+/* -+We use this in find to indicate a key wasn't found. This is an unrecoverable -+error, but we can at least show a decent error. 0 is never a valid offset -+because it's the offset of the start of the file. -+*/ ++/* We use this in find to indicate a key wasn't found. This is an ++ * unrecoverable error, but we can at least show a decent error. 0 is never a ++ * valid offset because it's the offset of the start of the file. ++ */ +#define NOT_FOUND 0 + +#define BUFFER_SIZE (1024 * 128) + -+/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ -+#define MAGIC 3472329499408095051 -+ +struct reflink_state_s { -+ /* Stuff that's used across rpms */ -+ long fundamental_block_size; -+ char *buffer; -+ -+ /* stuff that's used/updated per psm */ -+ uint32_t keys, keysize; -+ -+ // table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) -+ unsigned char *table; -+ FD_t fd; -+ rpmfiles files; -+ inodeIndexHash inodeIndexes; ++ /* Stuff that's used across rpms */ ++ long fundamental_block_size; ++ char *buffer; ++ ++ /* stuff that's used/updated per psm */ ++ uint32_t keys, keysize; ++ ++ /* table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) */ ++ unsigned char *table; ++ FD_t fd; ++ rpmfiles files; ++ inodeIndexHash inodeIndexes; ++ int transcoded; +}; + -+typedef struct reflink_state_s * reflink_state; ++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 * ++bsearch_r (const void *__key, const void *__base, size_t __nmemb, size_t __size, ++ __compar_d_fn_t __compar, void *__arg) ++{ ++ size_t __l, __u, __idx; ++ const void *__p; ++ int __comparison; ++ ++ __l = 0; ++ __u = __nmemb; ++ while (__l < __u) ++ { ++ __idx = (__l + __u) / 2; ++ __p = (const void *) (((const char *) __base) + (__idx * __size)); ++ __comparison = (*__compar) (__key, __p, __arg); ++ if (__comparison < 0) ++ __u = __idx; ++ else if (__comparison > 0) ++ __l = __idx + 1; ++ else ++ { ++#if __GNUC_PREREQ(4, 6) ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wcast-qual" ++#endif ++ return (void *) __p; ++#if __GNUC_PREREQ(4, 6) ++# pragma GCC diagnostic pop ++#endif ++ } ++ } ++ ++ return NULL; ++} ++ ++static int cmpdigest(const void *k1, const void *k2, void *data) { ++ rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2); ++ return memcmp(k1, k2, *(int *)data); ++} + +static int inodeCmp(rpm_ino_t a, rpm_ino_t b) +{ @@ -541,116 +1386,109 @@ index 000000000..d7f19acd9 +} + +static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) { -+ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); -+ -+ /* -+ IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and -+ length arguments to be aligned to the fundamental block size. ++ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); ++ ++ /* IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset ++ * and length arguments to be aligned to the fundamental block size. ++ * ++ * The value of "fundamental block size" is directly related to the ++ * system's page size, so we should use that. ++ */ ++ state->fundamental_block_size = sysconf(_SC_PAGESIZE); ++ state->buffer = rcalloc(1, BUFFER_SIZE); ++ rpmPluginSetData(plugin, state); + -+ The value of "fundamental block size" is directly related to the system's -+ page size, so we should use that. -+ */ -+ state->fundamental_block_size = sysconf(_SC_PAGESIZE); -+ state->buffer = rcalloc(1, BUFFER_SIZE); -+ rpmPluginSetData(plugin, state); -+ -+ return RPMRC_OK; ++ return RPMRC_OK; +} + +static void reflink_cleanup(rpmPlugin plugin) { -+ reflink_state state = rpmPluginGetData(plugin); -+ free(state->buffer); -+ free(state); ++ reflink_state state = rpmPluginGetData(plugin); ++ free(state->buffer); ++ free(state); +} + +static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { ++ rpmRC rc; ++ size_t len; ++ + reflink_state state = rpmPluginGetData(plugin); + state->fd = rpmteFd(te); + if (state->fd == 0) { -+ rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n")); -+ return RPMRC_OK; ++ rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n")); ++ return RPMRC_OK; + } ++ + rpm_loff_t current = Ftell(state->fd); -+ uint64_t magic; -+ if (Fseek(state->fd, -(sizeof(magic)), SEEK_END) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n")); -+ if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ /* yes this gets a bit repetitive */ -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -+ } -+ return RPMRC_FAIL; -+ } -+ size_t len = sizeof(magic); -+ if (Fread(&magic, len, 1, state->fd) != len) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n")); -+ if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -+ } -+ return RPMRC_FAIL; -+ } -+ if (magic != MAGIC) { -+ rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n")); -+ if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -+ return RPMRC_FAIL; -+ } -+ return RPMRC_OK; ++ rc = isTranscodedRpm(state->fd); ++ ++ switch(rc){ ++ // Fail to parse the file, fail the plugin. ++ case RPMRC_FAIL: ++ return RPMRC_FAIL; ++ // This is not a transcoded file, do nothing. ++ case RPMRC_NOTFOUND: ++ return RPMRC_OK; ++ default: ++ break; + } + rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); -+ Header h = rpmteHeader(te); ++ state->transcoded = 1; + -+ /* replace/add header that main fsm.c can read */ -+ headerDel(h, RPMTAG_PAYLOADFORMAT); -+ headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon"); -+ headerFree(h); + state->files = rpmteFiles(te); -+ /* tail of file contains offset_table, offset_checksums -+ then magic -+ */ -+ if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd); -+ return RPMRC_FAIL; ++ /* tail of file contains offset_table, offset_checksums then magic */ ++ if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(extents_magic_t)), SEEK_END) < 0) { ++ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), ++ state->fd); ++ return RPMRC_FAIL; + } + rpm_loff_t table_start; + len = sizeof(table_start); + if (Fread(&table_start, len, 1, state->fd) != len) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); -+ return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); ++ return RPMRC_FAIL; + } + if (Fseek(state->fd, table_start, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); -+ return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); ++ return RPMRC_FAIL; + } + len = sizeof(state->keys); + if (Fread(&state->keys, len, 1, state->fd) != len) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); -+ return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); ++ return RPMRC_FAIL; + } + len = sizeof(state->keysize); + if (Fread(&state->keysize, len, 1, state->fd) != len) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); -+ return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); ++ return RPMRC_FAIL; + } -+ rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize); -+ // now get digest table if there is a reason to have one. ++ rpmlog( ++ RPMLOG_DEBUG, ++ _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), ++ table_start, state->keys, state->keysize ++ ); ++ /* now get digest table if there is a reason to have one. */ + if (state->keys == 0 || state->keysize == 0) { -+ // no files (or no digests(!)) -+ state->table = NULL; ++ /* no files (or no digests(!)) */ ++ state->table = NULL; + } else { -+ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); -+ state->table = rcalloc(1, table_size); -+ if (Fread(state->table, table_size, 1, state->fd) != table_size) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); -+ return RPMRC_FAIL; -+ } -+ state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL); ++ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); ++ state->table = rcalloc(1, table_size); ++ if (Fread(state->table, table_size, 1, state->fd) != table_size) { ++ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); ++ return RPMRC_FAIL; ++ } ++ state->inodeIndexes = inodeIndexHashCreate( ++ state->keys, inodeId, inodeCmp, NULL, (inodeIndexHashFreeData)rfree ++ ); + } + -+ // seek back to original location -+ // might not be needed if we seek to offset immediately ++ /* Seek back to original location. ++ * Might not be needed if we seek to offset immediately ++ */ + if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -+ return RPMRC_FAIL; ++ rpmlog(RPMLOG_ERR, ++ _("reflink: unable to seek back to original location\n")); ++ return RPMRC_FAIL; + } + return RPMRC_OK; +} @@ -660,141 +1498,166 @@ index 000000000..d7f19acd9 + reflink_state state = rpmPluginGetData(plugin); + state->files = rpmfilesFree(state->files); + if (state->table) { -+ free(state->table); -+ state->table = NULL; ++ free(state->table); ++ state->table = NULL; + } + if (state->inodeIndexes) { -+ inodeIndexHashFree(state->inodeIndexes); -+ state->inodeIndexes = NULL; ++ inodeIndexHashFree(state->inodeIndexes); ++ state->inodeIndexes = NULL; + } ++ state->transcoded = 0; + return RPMRC_OK; +} + + -+// have a prototype, warnings system ++/* have a prototype, warnings system */ +rpm_loff_t find(const unsigned char *digest, reflink_state state); + +rpm_loff_t find(const unsigned char *digest, reflink_state state) { -+# if defined(__GNUC__) -+ /* GCC nested function because bsearch's comparison function can't access -+ state-keysize otherwise -+ */ -+ int cmpdigest(const void *k1, const void *k2) { -+ rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2); -+ return memcmp(k1, k2, state->keysize); -+ } -+# endif -+ rpmlog(RPMLOG_DEBUG, _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"), digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t)); -+ char *entry = bsearch(digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t), cmpdigest); -+ if (entry == NULL) { -+ return NOT_FOUND; -+ } -+ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); -+ return offset; ++ rpmlog(RPMLOG_DEBUG, ++ _("reflink: bsearch_r(key=%p, base=%p, nmemb=%d, size=%lu)\n"), ++ digest, state->table, state->keys, ++ state->keysize + sizeof(rpm_loff_t)); ++ char *entry = bsearch_r(digest, state->table, state->keys, ++ state->keysize + sizeof(rpm_loff_t), cmpdigest, ++ &state->keysize); ++ if (entry == NULL) { ++ return NOT_FOUND; ++ } ++ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); ++ return offset; +} + -+static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op) ++static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* path, ++ mode_t file_mode, rpmFsmOp op) +{ + struct file_clone_range fcr; + rpm_loff_t size; + int dst, rc; -+ int *hlix; ++ const char **hl_target = NULL; + + reflink_state state = rpmPluginGetData(plugin); + if (state->table == NULL) { -+ // no table means rpm is not in reflink format, so leave. Now. -+ return RPMRC_OK; ++ /* no table means rpm is not in reflink format, so leave. Now. */ ++ return RPMRC_OK; + } + if (op == FA_TOUCH) { -+ // we're not overwriting an existing file -+ return RPMRC_OK; ++ /* we're not overwriting an existing file. */ ++ return RPMRC_OK; + } + fcr.dest_offset = 0; + if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) { -+ rpm_ino_t inode = rpmfiFInode(fi); -+ /* check for hard link entry in table. GetEntry overwrites hlix with the address of the first match */ -+ if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, NULL)) { -+ // entry is in table, use hard link -+ char *fn = rpmfilesFN(state->files, hlix[0]); -+ if (link(fn, path) != 0) { -+ rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno)); -+ free(fn); -+ return RPMRC_FAIL; -+ } -+ free(fn); -+ return RPMRC_PLUGIN_CONTENTS; -+ } -+ /* if we didn't hard link, then we'll track this inode as being created soon */ -+ if (rpmfiFNlink(fi) > 1) { -+ /* minor optimization: only store files with more than one link */ -+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); -+ } -+ /* derived from wfd_open in fsm.c */ -+ mode_t old_umask = umask(0577); -+ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); -+ umask(old_umask); -+ if (dst == -1) { -+ rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi)); -+ return RPMRC_FAIL; -+ } -+ size = rpmfiFSize(fi); -+ if (size > 0) { -+ /* round src_length down to fundamental_block_size multiple */ -+ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; -+ if ((size % state->fundamental_block_size) > 0) { -+ /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */ -+ fcr.src_length += state->fundamental_block_size; -+ } -+ fcr.src_fd = Fileno(state->fd); -+ if (fcr.src_fd == -1) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); -+ return RPMRC_FAIL; -+ } -+ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); -+ if (fcr.src_offset == NOT_FOUND) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); -+ return RPMRC_FAIL; -+ } -+ rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); -+ rc = ioctl(dst, FICLONERANGE, &fcr); -+ if (rc) { -+ rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno)); -+ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ rpm_loff_t left = size; -+ size_t len, read, written; -+ while (left) { -+ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); -+ read = Fread(state->buffer, len, 1, state->fd); -+ if (read != len) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ written = write(dst, state->buffer, len); -+ if (read != written) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ left -= len; -+ } -+ } else { -+ /* reflink worked, so truncate */ -+ rc = ftruncate(dst, size); -+ if (rc) { -+ rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno)); -+ return RPMRC_FAIL; -+ } -+ } -+ } -+ close(dst); -+ return RPMRC_PLUGIN_CONTENTS; ++ rpm_ino_t inode = rpmfiFInode(fi); ++ /* 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) { ++ rpmlog(RPMLOG_ERR, ++ _("reflink: Unable to hard link %s -> %s due to %s\n"), ++ hl_target[0], path, strerror(errno)); ++ return RPMRC_FAIL; ++ } ++ return RPMRC_PLUGIN_CONTENTS; ++ } ++ /* if we didn't hard link, then we'll track this inode as being ++ * created soon ++ */ ++ if (rpmfiFNlink(fi) > 1) { ++ /* minor optimization: only store files with more than one link */ ++ inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path)); ++ } ++ /* derived from wfd_open in fsm.c */ ++ mode_t old_umask = umask(0577); ++ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); ++ umask(old_umask); ++ if (dst == -1) { ++ rpmlog(RPMLOG_ERR, ++ _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), ++ path, strerror(errno), rpmfiFFlags(fi)); ++ return RPMRC_FAIL; ++ } ++ size = rpmfiFSize(fi); ++ if (size > 0) { ++ /* round src_length down to fundamental_block_size multiple */ ++ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; ++ if ((size % state->fundamental_block_size) > 0) { ++ /* round up to next fundamental_block_size. We expect the data ++ * in the rpm to be similarly padded. ++ */ ++ fcr.src_length += state->fundamental_block_size; ++ } ++ fcr.src_fd = Fileno(state->fd); ++ if (fcr.src_fd == -1) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); ++ return RPMRC_FAIL; ++ } ++ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); ++ if (fcr.src_offset == NOT_FOUND) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); ++ return RPMRC_FAIL; ++ } ++ rpmlog(RPMLOG_DEBUG, ++ _("reflink: Reflinking %llu bytes at %llu to %s orig size=%ld, file=%lld\n"), ++ fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); ++ rc = ioctl(dst, FICLONERANGE, &fcr); ++ if (rc) { ++ rpmlog(RPMLOG_WARNING, ++ _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), ++ path, rc, errno, strerror(errno)); ++ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, ++ _("reflink: unable to seek on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ rpm_loff_t left = size; ++ size_t len, read, written; ++ while (left) { ++ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); ++ read = Fread(state->buffer, len, 1, state->fd); ++ if (read != len) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, ++ _("reflink: short read on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ written = write(dst, state->buffer, len); ++ if (read != written) { ++ close(dst); ++ rpmlog(RPMLOG_ERR, ++ _("reflink: short write on copying bits\n")); ++ return RPMRC_FAIL; ++ } ++ left -= len; ++ } ++ } else { ++ /* reflink worked, so truncate */ ++ rc = ftruncate(dst, size); ++ if (rc) { ++ rpmlog(RPMLOG_ERR, ++ _("reflink: Unable to truncate %s to %ld due to %s\n"), ++ path, size, strerror(errno)); ++ return RPMRC_FAIL; ++ } ++ } ++ } ++ close(dst); ++ return RPMRC_PLUGIN_CONTENTS; ++ } ++ return RPMRC_OK; ++} ++ ++static rpmRC reflink_fsm_file_archive_reader(rpmPlugin plugin, FD_t payload, ++ rpmfiles files, rpmfi *fi) { ++ reflink_state state = rpmPluginGetData(plugin); ++ if(state->transcoded) { ++ *fi = rpmfilesIter(files, RPMFI_ITER_FWD); ++ return RPMRC_PLUGIN_CONTENTS; + } + return RPMRC_OK; +} @@ -804,19 +1667,22 @@ index 000000000..d7f19acd9 + .cleanup = reflink_cleanup, + .psm_pre = reflink_psm_pre, + .psm_post = reflink_psm_post, -+ .fsm_file_pre = reflink_fsm_file_pre, ++ .fsm_file_install = reflink_fsm_file_install, ++ .fsm_file_archive_reader = reflink_fsm_file_archive_reader, +}; diff --git a/rpm2extents.c b/rpm2extents.c new file mode 100644 -index 000000000..5662b86a6 +index 0000000..c29831d --- /dev/null +++ b/rpm2extents.c -@@ -0,0 +1,519 @@ +@@ -0,0 +1,708 @@ +/* rpm2extents: convert payload to inline extents */ + +#include "system.h" + ++#include +#include /* rpmReadPackageFile .. */ ++#include +#include +#include +#include @@ -824,8 +1690,10 @@ index 000000000..5662b86a6 + +#include +#include "lib/rpmlead.h" ++#include "lib/rpmts.h" +#include "lib/signature.h" +#include "lib/header_internal.h" ++#include "lib/rpmextents_internal.h" +#include "rpmio/rpmio_internal.h" + +#include @@ -838,7 +1706,7 @@ index 000000000..5662b86a6 +#include "debug.h" + +/* hash of void * (pointers) to file digests to offsets within output. -+ The length of the key depends on what the FILEDIGESTALGO is. ++ * The length of the key depends on what the FILEDIGESTALGO is. + */ +#undef HASHTYPE +#undef HTKEYTYPE @@ -848,9 +1716,6 @@ index 000000000..5662b86a6 +#include "lib/rpmhash.H" +#include "lib/rpmhash.C" + -+/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ -+#define MAGIC 3472329499408095051 -+ +struct digestoffset { + const unsigned char * digest; + rpm_loff_t pos; @@ -863,119 +1728,221 @@ index 000000000..5662b86a6 + return (unit - (pos % unit)) % unit; +} + -+static int digestor( ++static struct poptOption optionsTable[] = { ++ { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0, ++ N_("Common options for all rpm modes and executables:"), NULL }, ++ ++ POPT_AUTOALIAS ++ POPT_AUTOHELP ++ POPT_TABLEEND ++}; ++ ++ ++static void FDDigestInit(FD_t fdi, uint8_t algos[], uint32_t algos_len){ ++ int algo; ++ ++ for (algo = 0; algo < algos_len; algo++) { ++ fdInitDigest(fdi, algos[algo], 0); ++ } ++} ++ ++static int FDWriteDigests( + FD_t fdi, + FD_t fdo, -+ FD_t validationo, + uint8_t algos[], -+ uint32_t algos_len -+) ++ uint32_t algos_len) +{ -+ ssize_t fdilength; + const char *filedigest, *algo_name; + size_t filedigest_len, len; + uint32_t algo_name_len, algo_digest_len; + int algo; + rpmRC rc = RPMRC_FAIL; + -+ for (algo = 0; algo < algos_len; algo++) -+ { -+ fdInitDigest(fdi, algos[algo], 0); -+ } -+ fdilength = ufdCopy(fdi, fdo); -+ if (fdilength == -1) -+ { -+ fprintf(stderr, _("digest cat failed\n")); -+ goto exit; -+ } ++ ssize_t fdilength = fdOp(fdi, FDSTAT_READ)->bytes; + + len = sizeof(fdilength); -+ if (Fwrite(&fdilength, len, 1, validationo) != len) -+ { -+ fprintf(stderr, _("Unable to write input length %zd\n"), fdilength); -+ goto exit; ++ if (Fwrite(&fdilength, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, _("Unable to write input length %zd: %d, %s\n"), ++ fdilength, errno, strerror(errno)); ++ goto exit; + } + len = sizeof(algos_len); -+ if (Fwrite(&algos_len, len, 1, validationo) != len) -+ { -+ fprintf(stderr, _("Unable to write number of validation digests\n")); -+ goto exit; ++ if (Fwrite(&algos_len, len, 1, fdo) != len) { ++ algo_digest_len = (uint32_t)filedigest_len; ++ rpmlog(RPMLOG_ERR, _("Unable to write number of digests: %d, %s\n"), ++ errno, strerror(errno)); ++ goto exit; + } -+ for (algo = 0; algo < algos_len; algo++) -+ { -+ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); -+ -+ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); -+ algo_name_len = (uint32_t)strlen(algo_name); -+ algo_digest_len = (uint32_t)filedigest_len; -+ -+ len = sizeof(algo_name_len); -+ if (Fwrite(&algo_name_len, len, 1, validationo) != len) -+ { -+ fprintf( -+ stderr, -+ _("Unable to write validation algo name length\n") -+ ); -+ goto exit; -+ } -+ len = sizeof(algo_digest_len); -+ if (Fwrite(&algo_digest_len, len, 1, validationo) != len) -+ { -+ fprintf( -+ stderr, -+ _("Unable to write number of bytes for validation digest\n") -+ ); -+ goto exit; -+ } -+ if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len) -+ { -+ fprintf(stderr, _("Unable to write validation algo name\n")); -+ goto exit; -+ } -+ if ( -+ Fwrite( -+ filedigest, -+ algo_digest_len, -+ 1, -+ validationo -+ ) != algo_digest_len -+ ) -+ { -+ fprintf( -+ stderr, -+ _("Unable to write validation digest value %u, %zu\n"), -+ algo_digest_len, -+ filedigest_len -+ ); -+ goto exit; -+ } ++ for (algo = 0; algo < algos_len; algo++) { ++ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); ++ ++ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); ++ algo_name_len = (uint32_t)strlen(algo_name); ++ algo_digest_len = (uint32_t)filedigest_len; ++ ++ len = sizeof(algo_name_len); ++ if (Fwrite(&algo_name_len, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, ++ _("Unable to write digest algo name length: %d, %s\n"), ++ errno, strerror(errno)); ++ goto exit; ++ } ++ len = sizeof(algo_digest_len); ++ if (Fwrite(&algo_digest_len, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, ++ _("Unable to write number of bytes for digest: %d, %s\n"), ++ errno, strerror(errno)); ++ goto exit; ++ } ++ if (Fwrite(algo_name, algo_name_len, 1, fdo) != algo_name_len) { ++ rpmlog(RPMLOG_ERR, _("Unable to write digest algo name: %d, %s\n"), ++ errno, strerror(errno)); ++ goto exit; ++ } ++ if (Fwrite(filedigest, algo_digest_len, 1, fdo ) != algo_digest_len) { ++ rpmlog(RPMLOG_ERR, ++ _("Unable to write digest value %u, %zu: %d, %s\n"), ++ algo_digest_len, filedigest_len, ++ errno, strerror(errno)); ++ goto exit; ++ } ++ } ++ rc = RPMRC_OK; ++exit: ++ return rc; ++} ++ ++/** ++ * Check if package is in deny list. ++ * @param package_name package name ++ * @return true if package is in deny list ++ */ ++static inline int isInDenyList(char *package_name) ++{ ++ int is_in_deny_list = 0; ++ if (package_name) { ++ char *e_denylist = getenv("LIBREPO_TRANSCODE_RPMS_DENYLIST"); ++ char *denytlist_item = strtok(e_denylist, ","); ++ while (denytlist_item) { ++ if (strstr(package_name, denytlist_item)) { ++ is_in_deny_list = 1; ++ break; ++ } ++ denytlist_item = strtok(NULL, ","); ++ } ++ } ++ return is_in_deny_list; ++} ++ ++static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) { ++ size_t len; ++ rpmRC rc = RPMRC_FAIL; ++ ++ if(rpmvsrc){ ++ rpmlog(RPMLOG_WARNING, ++ _("Error verifying package signatures:\n%s\n"), msg); ++ } ++ ++ len = sizeof(rpmvsrc); ++ if (Fwrite(&rpmvsrc, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, ++ _("Unable to write signature verification RC code %d: %d, %s\n"), ++ rpmvsrc, errno, strerror(errno)); ++ goto exit; ++ } ++ size_t content_len = msg ? strlen(msg) : 0; ++ len = sizeof(content_len); ++ if (Fwrite(&content_len, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, ++ _("Unable to write signature verification output length %zd: %d, %s\n"), ++ content_len, errno, strerror(errno)); ++ goto exit; ++ } ++ if (Fwrite(msg, content_len, 1, fdo) != content_len) { ++ rpmlog(RPMLOG_ERR, ++ _("Unable to write signature verification output %s: %d, %s\n"), ++ msg, errno, strerror(errno)); ++ goto exit; ++ } ++ ++ rc = RPMRC_OK; ++exit: ++ ++ return rc; ++} ++ ++static rpmRC validator(FD_t fdi, FD_t digesto, FD_t sigo, ++ uint8_t algos[], ++ uint32_t algos_len){ ++ int rpmvsrc; ++ rpmRC rc = RPMRC_FAIL; ++ char *msg = NULL; ++ rpmts ts = rpmtsCreate(); ++ ++ rpmtsSetRootDir(ts, rpmcliRootDir); ++ ++ FDDigestInit(fdi, algos, algos_len); ++ ++ rpmvsrc = rpmcliVerifySignaturesFD(ts, fdi, &msg); ++ ++ // Write result of digest computation ++ if(FDWriteDigests(fdi, digesto, algos, algos_len) != RPMRC_OK) { ++ rpmlog(RPMLOG_ERR, _("Failed to write digests: %d, %s\n"), ++ errno, strerror(errno)); ++ goto exit; ++ } ++ ++ // Write result of signature validation. ++ if(FDWriteSignaturesValidation(sigo, rpmvsrc, msg)) { ++ rpmlog(RPMLOG_ERR, ++ _("Failed to write signature verification result: %d, %s\n"), ++ errno, strerror(errno)); ++ goto exit; + } + rc = RPMRC_OK; +exit: ++ if(msg) { ++ free(msg); ++ } ++ rpmtsFree(ts); + return rc; +} + -+static rpmRC process_package(FD_t fdi, FD_t validationi) ++static void sanitizeSignatureHeader(Header * sigh) ++{ ++ struct rpmtd_s td; ++ ++ /* This is inspired by the code in unloadImmutableRegion. See https://github.com/rpm-software-management/rpm/pull/1330 */ ++ if (!headerGet(*sigh, RPMTAG_HEADERSIGNATURES, &td, HEADERGET_DEFAULT)) { ++ /* Signature header corrupt/missing */ ++ rpmlog(RPMLOG_WARNING, _("Error verifying signature header\n")); ++ rpmtdFreeData(&td); ++ Header nh = headerCopy(*sigh); ++ headerFree(*sigh); ++ *sigh = headerLink(nh); ++ headerFree(nh); ++ } ++ rpmtdFreeData(&td); ++} ++ ++static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) +{ + uint32_t diglen; + /* GNU C extension: can use diglen from outer context */ -+ int digestSetCmp(const unsigned char * a, const unsigned char * b) -+ { -+ return memcmp(a, b, diglen); ++ int digestSetCmp(const unsigned char * a, const unsigned char * b) { ++ return memcmp(a, b, diglen); + } + -+ unsigned int digestSetHash(const unsigned char * digest) -+ { ++ unsigned int digestSetHash(const unsigned char * digest) { + /* assumes sizeof(unsigned int) < diglen */ + return *(unsigned int *)digest; + } + -+ int digestoffsetCmp(const void * a, const void * b) -+ { -+ return digestSetCmp( -+ ((struct digestoffset *)a)->digest, -+ ((struct digestoffset *)b)->digest -+ ); ++ int digestoffsetCmp(const void * a, const void * b) { ++ return digestSetCmp( ++ ((struct digestoffset *)a)->digest, ++ ((struct digestoffset *)b)->digest ++ ); + } + + FD_t fdo; @@ -986,353 +1953,439 @@ index 000000000..5662b86a6 + rpm_mode_t mode; + char *rpmio_flags = NULL, *zeros; + const unsigned char *digest; -+ rpm_loff_t pos, size, pad, validation_pos; ++ rpm_loff_t pos, size, pad, digest_pos, validation_pos, digest_table_pos; + uint32_t offset_ix = 0; + size_t len; + int next = 0; ++ struct rpmlead_s l; ++ rpmfiles files = NULL; ++ rpmfi fi = NULL; ++ char *msg = NULL; ++ struct digestoffset *offsets = NULL; ++ digestSet ds = NULL; + + fdo = fdDup(STDOUT_FILENO); + -+ if (rpmReadPackageRaw(fdi, &sigh, &h)) -+ { -+ fprintf(stderr, _("Error reading package\n")); -+ exit(EXIT_FAILURE); -+ } ++ rc = rpmLeadReadAndReturn(fdi, &msg, &l); ++ if (rc != RPMRC_OK) ++ goto exit; + -+ if (rpmLeadWrite(fdo, h)) -+ { -+ fprintf( -+ stderr, -+ _("Unable to write package lead: %s\n"), -+ Fstrerror(fdo) -+ ); -+ exit(EXIT_FAILURE); -+ } ++ /* Skip conversion if package is in deny list */ ++ if (isInDenyList(l.name)) { ++ rpmlog(RPMLOG_WARNING, _("package %s is in deny list: conversion skipped\n"), l.name); ++ if (rpmLeadWrite(fdo, l)) { ++ rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"), ++ Fstrerror(fdo)); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } + -+ if (rpmWriteSignature(fdo, sigh)) -+ { -+ fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo)); -+ exit(EXIT_FAILURE); -+ } ++ ssize_t fdilength = ufdCopy(fdi, fdo); ++ if (fdilength == -1) { ++ rpmlog(RPMLOG_ERR, _("process_package cat failed\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } + -+ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) -+ { -+ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); -+ exit(EXIT_FAILURE); -+ } ++ goto exit; ++ } else { ++ if (rpmReadPackageRaw(fdi, &sigh, &h)) { ++ rpmlog(RPMLOG_ERR, _("Error reading package\n")); ++ exit(EXIT_FAILURE); ++ } + -+ /* Retrieve payload size and compression type. */ -+ { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); -+ rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); -+ } ++ sanitizeSignatureHeader(&sigh); + -+ gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ -+ free(rpmio_flags); ++ if (rpmLeadWriteFromHeader(fdo, h)) { ++ rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"), ++ Fstrerror(fdo)); ++ exit(EXIT_FAILURE); ++ } + -+ if (gzdi == NULL) -+ { -+ fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); -+ exit(EXIT_FAILURE); -+ } ++ if (rpmWriteSignature(fdo, sigh)) { ++ rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"), ++ Fstrerror(fdo)); ++ exit(EXIT_FAILURE); ++ } + -+ rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); -+ rpmfi fi = rpmfiNewArchiveReader( -+ gzdi, -+ files, -+ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST -+ ); ++ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) { ++ rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"), ++ Fstrerror(fdo)); ++ exit(EXIT_FAILURE); ++ } + -+ /* this is encoded in the file format, so needs to be fixed size (for -+ now?) -+ */ -+ diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi)); -+ digestSet ds = digestSetCreate( -+ rpmfiFC(fi), -+ digestSetHash, -+ digestSetCmp, -+ NULL -+ ); -+ struct digestoffset offsets[rpmfiFC(fi)]; -+ pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); ++ /* Retrieve payload size and compression type. */ ++ { ++ const char *compr = ++ headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); ++ rpmio_flags = ++ rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); ++ } + -+ /* main headers are aligned to 8 byte boundry */ -+ pos += pad_to(pos, 8); -+ pos += headerSizeof(h, HEADER_MAGIC_YES); ++ gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ ++ free(rpmio_flags); + -+ zeros = xcalloc(fundamental_block_size, 1); ++ if (gzdi == NULL) { ++ rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), ++ Fstrerror(gzdi)); ++ exit(EXIT_FAILURE); ++ } + -+ while (next >= 0) -+ { -+ next = rpmfiNext(fi); -+ if (next == RPMERR_ITER_END) -+ { -+ rc = RPMRC_OK; -+ break; -+ } -+ mode = rpmfiFMode(fi); -+ if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) -+ { -+ /* not a regular file, or the archive doesn't contain any content for -+ this entry -+ */ -+ continue; -+ } -+ digest = rpmfiFDigest(fi, NULL, NULL); -+ if (digestSetGetEntry(ds, digest, NULL)) -+ { -+ /* This specific digest has already been included, so skip it */ -+ continue; -+ } -+ pad = pad_to(pos, fundamental_block_size); -+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) -+ { -+ fprintf(stderr, _("Unable to write padding\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ /* round up to next fundamental_block_size */ -+ pos += pad; -+ digestSetAddEntry(ds, digest); -+ offsets[offset_ix].digest = digest; -+ offsets[offset_ix].pos = pos; -+ offset_ix++; -+ size = rpmfiFSize(fi); -+ rc = rpmfiArchiveReadToFile(fi, fdo, 0); -+ if (rc != RPMRC_OK) -+ { -+ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); -+ goto exit; -+ } -+ pos += size; -+ } -+ Fclose(gzdi); /* XXX gzdi == fdi */ ++ files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); ++ fi = rpmfiNewArchiveReader(gzdi, files, ++ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST); ++ ++ /* this is encoded in the file format, so needs to be fixed size (for ++ * now?) ++ */ ++ diglen = (uint32_t) rpmDigestLength(rpmfiDigestAlgo(fi)); ++ ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, NULL); ++ offsets = xcalloc(rpmfiFC(fi), sizeof(*offsets)); ++ pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); ++ ++ /* main headers are aligned to 8 byte boundry */ ++ pos += pad_to(pos, 8); ++ pos += headerSizeof(h, HEADER_MAGIC_YES); ++ ++ zeros = xcalloc(fundamental_block_size, 1); ++ ++ while (next >= 0) { ++ next = rpmfiNext(fi); ++ if (next == RPMERR_ITER_END) { ++ rc = RPMRC_OK; ++ break; ++ } ++ mode = rpmfiFMode(fi); ++ if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) { ++ /* not a regular file, or the archive doesn't contain any content ++ * for this entry. ++ */ ++ continue; ++ } ++ digest = rpmfiFDigest(fi, NULL, NULL); ++ if (digestSetGetEntry(ds, digest, NULL)) { ++ /* This specific digest has already been included, so skip it. */ ++ continue; ++ } ++ pad = pad_to(pos, fundamental_block_size); ++ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { ++ rpmlog(RPMLOG_ERR, _("Unable to write padding\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ /* round up to next fundamental_block_size */ ++ pos += pad; ++ digestSetAddEntry(ds, digest); ++ offsets[offset_ix].digest = digest; ++ offsets[offset_ix].pos = pos; ++ offset_ix++; ++ size = rpmfiFSize(fi); ++ rc = rpmfiArchiveReadToFile(fi, fdo, 0); ++ if (rc != RPMRC_OK) { ++ char *errstr = rpmfileStrerror(rc); ++ rpmlog(RPMLOG_ERR, ++ _("rpmfiArchiveReadToFile failed while extracting " ++ "\"%s\" with RC %d: %s\n"), ++ rpmfiFN(fi), rc, errstr); ++ free(errstr); ++ goto exit; ++ } ++ pos += size; ++ } ++ Fclose(gzdi); /* XXX gzdi == fdi */ + -+ qsort( -+ offsets, -+ (size_t)offset_ix, -+ sizeof(struct digestoffset), -+ digestoffsetCmp -+ ); ++ qsort(offsets, (size_t) offset_ix, sizeof(struct digestoffset), ++ digestoffsetCmp); + -+ len = sizeof(offset_ix); -+ if (Fwrite(&offset_ix, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write length of table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ len = sizeof(diglen); -+ if (Fwrite(&diglen, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write length of digest\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ len = sizeof(rpm_loff_t); -+ for (int x = 0; x < offset_ix; x++) -+ { -+ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) -+ { -+ fprintf(stderr, _("Unable to write digest\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write offset\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ } -+ validation_pos = ( -+ pos + sizeof(offset_ix) + sizeof(diglen) + -+ offset_ix * (diglen + sizeof(rpm_loff_t)) -+ ); ++ validation_pos = pos; ++ ssize_t validation_len = ufdCopy(validationi, fdo); ++ if (validation_len == -1) { ++ rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } + -+ ssize_t validation_len = ufdCopy(validationi, fdo); -+ if (validation_len == -1) -+ { -+ fprintf(stderr, _("digest table ufdCopy failed\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ /* add more padding so the last file can be cloned. It doesn't matter that -+ the table and validation etc are in this space. In fact, it's pretty -+ efficient if it is -+ */ -+ -+ pad = pad_to( -+ ( -+ validation_pos + validation_len + 2 * sizeof(rpm_loff_t) + -+ sizeof(uint64_t) -+ ), -+ fundamental_block_size -+ ); -+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) -+ { -+ fprintf(stderr, _("Unable to write final padding\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ zeros = _free(zeros); -+ if (Fwrite(&pos, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write offset of digest table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ if (Fwrite(&validation_pos, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write offset of validation table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ uint64_t magic = MAGIC; -+ len = sizeof(magic); -+ if (Fwrite(&magic, len, 1, fdo) != len) -+ { -+ fprintf(stderr, _("Unable to write magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; ++ digest_table_pos = validation_pos + validation_len; ++ ++ len = sizeof(offset_ix); ++ if (Fwrite(&offset_ix, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, _("Unable to write length of table\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ len = sizeof(diglen); ++ if (Fwrite(&diglen, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ len = sizeof(rpm_loff_t); ++ for (int x = 0; x < offset_ix; x++) { ++ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) { ++ rpmlog(RPMLOG_ERR, _("Unable to write digest\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, _("Unable to write offset\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ } ++ digest_pos = ++ (digest_table_pos + sizeof(offset_ix) + sizeof(diglen) + ++ offset_ix * (diglen + sizeof(rpm_loff_t)) ++ ); ++ ++ ssize_t digest_len = ufdCopy(digestori, fdo); ++ if (digest_len == -1) { ++ rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ ++ /* add more padding so the last file can be cloned. It doesn't matter that ++ * the table and validation etc are in this space. In fact, it's pretty ++ * efficient if it is. ++ */ ++ ++ pad = ++ pad_to((validation_pos + validation_len + ++ 2 * sizeof(rpm_loff_t) + sizeof(uint64_t)), ++ fundamental_block_size); ++ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { ++ rpmlog(RPMLOG_ERR, _("Unable to write final padding\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } ++ zeros = _free(zeros); ++ struct extents_footer_t footer = {.offsets = ++ { validation_pos, digest_table_pos, digest_pos },.magic = ++ EXTENTS_MAGIC }; ++ len = sizeof(footer); ++ if (Fwrite(&footer, len, 1, fdo) != len) { ++ rpmlog(RPMLOG_ERR, _("Unable to write footer\n")); ++ rc = RPMRC_FAIL; ++ goto exit; ++ } + } + -+exit: ++ exit: + rpmfilesFree(files); + rpmfiFree(fi); + headerFree(h); ++ headerFree(sigh); ++ free(offsets); ++ Fclose(fdo); ++ digestSetFree(ds); + return rc; +} + -+int main(int argc, char *argv[]) ++static off_t ufdTee(FD_t sfd, FD_t *fds, int len) +{ -+ rpmRC rc; -+ int cprc = 0; -+ uint8_t algos[argc - 1]; -+ int mainpipefd[2]; -+ int metapipefd[2]; -+ pid_t cpid, w; ++ char buf[BUFSIZ]; ++ ssize_t rdbytes, wrbytes; ++ off_t total = 0; ++ ++ while (1) { ++ rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd); ++ ++ if (rdbytes > 0) { ++ for(int i=0; i < len; i++) { ++ wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, fds[i]); ++ if (wrbytes != rdbytes) { ++ rpmlog(RPMLOG_ERR, ++ _("Error wriing to FD %d: %s\n"), ++ i, Fstrerror(fds[i])); ++ total = -1; ++ break; ++ } ++ } ++ if(total == -1){ ++ break; ++ } ++ total += wrbytes; ++ } else { ++ if (rdbytes < 0) ++ total = -1; ++ break; ++ } ++ } ++ ++ return total; ++} ++ ++static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) { ++ rpmRC rc = RPMRC_FAIL; ++ off_t offt = -1; ++ // tee-ed stdin ++ int processorpipefd[2]; ++ int validatorpipefd[2]; ++ // metadata ++ int meta_digestpipefd[2]; ++ int meta_rpmsignpipefd[2]; ++ ++ pid_t cpids[2], w; + int wstatus; ++ FD_t fds[2]; + -+ xsetprogname(argv[0]); /* Portability call -- see system.h */ -+ rpmReadConfigFiles(NULL, NULL); ++ if (pipe(processorpipefd) == -1) { ++ rpmlog(RPMLOG_ERR, _("Processor pipe failure\n")); ++ return RPMRC_FAIL; ++ } + -+ if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) -+ { -+ fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]); -+ exit(EXIT_FAILURE); ++ if (pipe(validatorpipefd) == -1) { ++ rpmlog(RPMLOG_ERR, _("Validator pipe failure\n")); ++ return RPMRC_FAIL; + } + -+ if (argc == 1) -+ { -+ fprintf( -+ stderr, -+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n") -+ ); -+ exit(EXIT_FAILURE); ++ if (pipe(meta_digestpipefd) == -1) { ++ rpmlog(RPMLOG_ERR, _("Meta digest pipe failure\n")); ++ return RPMRC_FAIL; + } + -+ for (int x = 0; x < (argc - 1); x++) -+ { -+ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) -+ { -+ fprintf( -+ stderr, -+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -+ argv[x + 1] -+ ); -+ exit(EXIT_FAILURE); -+ } ++ if (pipe(meta_rpmsignpipefd) == -1) { ++ rpmlog(RPMLOG_ERR, _("Meta rpm signature pipe failure\n")); ++ return RPMRC_FAIL; + } + ++ cpids[0] = fork(); ++ if (cpids[0] == 0) { ++ /* child: validator */ ++ close(processorpipefd[0]); ++ close(processorpipefd[1]); ++ close(validatorpipefd[1]); ++ close(meta_digestpipefd[0]); ++ close(meta_rpmsignpipefd[0]); ++ FD_t fdi = fdDup(validatorpipefd[0]); ++ FD_t digesto = fdDup(meta_digestpipefd[1]); ++ FD_t sigo = fdDup(meta_rpmsignpipefd[1]); ++ close(meta_digestpipefd[1]); ++ close(meta_rpmsignpipefd[1]); ++ rc = validator(fdi, digesto, sigo, algos, algos_len); ++ if(rc != RPMRC_OK) { ++ rpmlog(RPMLOG_ERR, _("Validator failed with RC %d\n"), rc); ++ } ++ Fclose(fdi); ++ Fclose(digesto); ++ Fclose(sigo); ++ if (rc != RPMRC_OK) { ++ exit(EXIT_FAILURE); ++ } ++ exit(EXIT_SUCCESS); ++ } else { ++ /* parent: main program */ ++ cpids[1] = fork(); ++ if (cpids[1] == 0) { ++ /* child: process_package */ ++ close(validatorpipefd[0]); ++ close(validatorpipefd[1]); ++ close(processorpipefd[1]); ++ close(meta_digestpipefd[1]); ++ close(meta_rpmsignpipefd[1]); ++ FD_t fdi = fdDup(processorpipefd[0]); ++ close(processorpipefd[0]); ++ FD_t sigi = fdDup(meta_rpmsignpipefd[0]); ++ close(meta_rpmsignpipefd[0]); ++ FD_t digestori = fdDup(meta_digestpipefd[0]); ++ close(meta_digestpipefd[0]); ++ ++ rc = process_package(fdi, digestori, sigi); ++ if(rc != RPMRC_OK) { ++ rpmlog(RPMLOG_ERR, _("Package processor failed: %d\n"), rc); ++ } ++ Fclose(digestori); ++ Fclose(sigi); ++ /* fdi is normally closed through the stacked file gzdi in the ++ * function ++ */ ++ ++ if (rc != RPMRC_OK) { ++ exit(EXIT_FAILURE); ++ } ++ exit(EXIT_SUCCESS); ++ ++ ++ } else { ++ /* Actual parent. Read from fdi and write to both processes */ ++ close(processorpipefd[0]); ++ close(validatorpipefd[0]); ++ fds[0] = fdDup(processorpipefd[1]); ++ fds[1] = fdDup(validatorpipefd[1]); ++ close(validatorpipefd[1]); ++ close(processorpipefd[1]); ++ close(meta_digestpipefd[0]); ++ close(meta_digestpipefd[1]); ++ close(meta_rpmsignpipefd[0]); ++ close(meta_rpmsignpipefd[1]); + -+ if (pipe(mainpipefd) == -1) -+ { -+ fprintf(stderr, _("Main pipe failure\n")); -+ exit(EXIT_FAILURE); ++ rc = RPMRC_OK; ++ offt = ufdTee(fdi, fds, 2); ++ if(offt == -1){ ++ rpmlog(RPMLOG_ERR, _("Failed to tee RPM\n")); ++ rc = RPMRC_FAIL; ++ } ++ Fclose(fds[0]); ++ Fclose(fds[1]); ++ w = waitpid(cpids[0], &wstatus, 0); ++ if (w == -1) { ++ rpmlog(RPMLOG_ERR, _("waitpid cpids[0] failed\n")); ++ rc = RPMRC_FAIL; ++ } ++ w = waitpid(cpids[1], &wstatus, 0); ++ if (w == -1) { ++ rpmlog(RPMLOG_ERR, _("waitpid cpids[1] failed\n")); ++ rc = RPMRC_FAIL; ++ } ++ } + } -+ if (pipe(metapipefd) == -1) -+ { -+ fprintf(stderr, _("Meta pipe failure\n")); -+ exit(EXIT_FAILURE); ++ ++ return rc; ++} ++ ++int main(int argc, char *argv[]) { ++ rpmRC rc; ++ poptContext optCon = NULL; ++ const char **args = NULL; ++ int nb_algos = 0; ++ ++ xsetprogname(argv[0]); /* Portability call -- see system.h */ ++ rpmReadConfigFiles(NULL, NULL); ++ optCon = rpmcliInit(argc, argv, optionsTable); ++ poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); ++ ++ if (poptPeekArg(optCon) == NULL) { ++ rpmlog(RPMLOG_ERR, ++ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")); ++ poptPrintUsage(optCon, stderr, 0); ++ exit(EXIT_FAILURE); + } -+ cpid = fork(); -+ if (cpid == 0) -+ { -+ /* child: digestor */ -+ close(mainpipefd[0]); -+ close(metapipefd[0]); -+ FD_t fdi = fdDup(STDIN_FILENO); -+ FD_t fdo = fdDup(mainpipefd[1]); -+ FD_t validationo = fdDup(metapipefd[1]); -+ rc = digestor(fdi, fdo, validationo, algos, argc - 1); -+ Fclose(validationo); -+ Fclose(fdo); -+ Fclose(fdi); -+ } else { -+ /* parent: main program */ -+ close(mainpipefd[1]); -+ close(metapipefd[1]); -+ FD_t fdi = fdDup(mainpipefd[0]); -+ FD_t validationi = fdDup(metapipefd[0]); -+ rc = process_package(fdi, validationi); -+ Fclose(validationi); -+ /* fdi is normally closed through the stacked file gzdi in the function. */ -+ /* wait for child process (digestor for stdin) to complete. */ -+ if (rc != RPMRC_OK) -+ { -+ if (kill(cpid, SIGTERM) != 0) -+ { -+ fprintf( -+ stderr, -+ _("Failed to kill digest process when main process failed: %s\n"), -+ strerror(errno) -+ ); -+ } -+ } -+ w = waitpid(cpid, &wstatus, 0); -+ if (w == -1) -+ { -+ fprintf(stderr, _("waitpid failed\n")); -+ cprc = EXIT_FAILURE; -+ } else if (WIFEXITED(wstatus)) -+ { -+ cprc = WEXITSTATUS(wstatus); -+ if (cprc != 0) -+ { -+ fprintf( -+ stderr, -+ _("Digest process non-zero exit code %d\n"), -+ cprc -+ ); -+ } -+ } else if (WIFSIGNALED(wstatus)) -+ { -+ fprintf( -+ stderr, -+ _("Digest process was terminated with a signal: %d\n"), -+ WTERMSIG(wstatus) -+ ); -+ cprc = EXIT_FAILURE; -+ } else -+ { -+ /* don't think this can happen, but covering all bases */ -+ fprintf(stderr, _("Unhandled circumstance in waitpid\n")); -+ cprc = EXIT_FAILURE; -+ } -+ if (cprc != EXIT_SUCCESS) -+ { -+ rc = RPMRC_FAIL; -+ } ++ ++ args = poptGetArgs(optCon); ++ ++ for (nb_algos=0; args[nb_algos]; nb_algos++); ++ uint8_t algos[nb_algos]; ++ for (int x = 0; x < nb_algos; x++) { ++ if (pgpStringVal(PGPVAL_HASHALGO, args[x], &algos[x]) != 0) ++ { ++ rpmlog(RPMLOG_ERR, ++ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), ++ args[x]); ++ exit(EXIT_FAILURE); ++ } + } -+ if (rc != RPMRC_OK) -+ { -+ /* translate rpmRC into generic failure return code. */ -+ return EXIT_FAILURE; ++ ++ FD_t fdi = fdDup(STDIN_FILENO); ++ rc = teeRpm(fdi, algos, nb_algos); ++ Fclose(fdi); ++ if (rc != RPMRC_OK) { ++ /* translate rpmRC into generic failure return code. */ ++ return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c -index 015c15a5c..7b972b4a6 100644 +index 43a2a99..f8d5562 100644 --- a/rpmio/rpmpgp.c +++ b/rpmio/rpmpgp.c @@ -298,6 +298,16 @@ int pgpValTok(pgpValTbl vs, const char * s, const char * se) @@ -1353,7 +2406,7 @@ index 015c15a5c..7b972b4a6 100644 * Decode length from 1, 2, or 5 octet body length encoding, used in * new format packet headers and V4 signature subpackets. diff --git a/rpmio/rpmpgp.h b/rpmio/rpmpgp.h -index c53e29b01..2b57318ba 100644 +index 469b5b3..7a1fefd 100644 --- a/rpmio/rpmpgp.h +++ b/rpmio/rpmpgp.h @@ -973,6 +973,15 @@ typedef rpmFlags rpmDigestFlags; @@ -1372,6 +2425,337 @@ index c53e29b01..2b57318ba 100644 /** \ingroup rpmpgp * Return (native-endian) integer from big-endian representation. * @param s pointer to big-endian integer +diff --git a/scripts/rpm2extents_dump b/scripts/rpm2extents_dump +new file mode 100755 +index 0000000..596a59a +--- /dev/null ++++ b/scripts/rpm2extents_dump +@@ -0,0 +1,94 @@ ++#!/usr/bin/env python3 ++ ++import argparse ++import binascii ++import os ++import struct ++import sys ++ ++MAGIC_SIZE = 8 ++MAGIC_STR = b'KWTSH100' ++ ++POS_SIZE = 8 ++ ++def keep_position(func): ++ def wrapper(*args, **kwargs): ++ curr = args[0].tell() ++ res = func(*args, **kwargs) ++ f.seek(curr, os.SEEK_SET) ++ return res ++ return wrapper ++ ++def read_validation_digest(f, validation_offset): ++ digests = [] ++ # validation ++ f.seek(validation_offset, os.SEEK_SET) ++ val_content_len, val_digests_num = struct.unpack('=QI', f.read(8+4)) ++ for i in range(val_digests_num): ++ algo_name_len, digest_len = struct.unpack('=II', f.read(8)) ++ algo_name, digest = struct.unpack(f'{algo_name_len}s{digest_len}s', f.read(algo_name_len+digest_len)) ++ digests.append((algo_name, binascii.hexlify(digest))) ++ return digests ++ ++ ++def read_digests_table(f, digest_offset): ++ digests = [] ++ # validation ++ f.seek(digest_offset, os.SEEK_SET) ++ table_len, digest_len = struct.unpack('=II', f.read(8)) ++ ++ for i in range(table_len): ++ digest, pos = struct.unpack(f'{digest_len}sQ', f.read(digest_len + 8)) ++ digests.append((pos, binascii.hexlify(digest))) ++ return digests ++ ++def read_signature_output(f, signature_offset): ++ f.seek(signature_offset, os.SEEK_SET) ++ signature_rc, signature_output_len = struct.unpack('=IQ', f.read(12)) ++ return signature_rc, f.read(signature_output_len) ++ ++@keep_position ++def parse_file(f): ++ digests = [] ++ pos_table_offset = f.seek(-8 - 3*POS_SIZE, os.SEEK_END) ++ signature_offset, digest_offset, validation_offset = struct.unpack('=QQQ', f.read(3*POS_SIZE)) ++ ++ validation_digests = read_validation_digest(f, validation_offset) ++ digests_table = read_digests_table(f, digest_offset) ++ signature_ouput = read_signature_output(f, signature_offset) ++ ++ return validation_digests, digests_table, signature_ouput ++ ++@keep_position ++def is_transcoded(f): ++ f.seek(-MAGIC_SIZE, os.SEEK_END) ++ magic = f.read(MAGIC_SIZE) ++ return magic == MAGIC_STR ++ ++def arg_parse(): ++ parser = argparse.ArgumentParser() ++ parser.add_argument('--dump-signature', action='store_true') ++ parser.add_argument('--dump-file-digest-table', action='store_true') ++ parser.add_argument('--dump-digests', action='store_true') ++ parser.add_argument('file') ++ ++ return parser.parse_args() ++ ++if __name__ == '__main__': ++ args = arg_parse() ++ f = open(args.file, 'rb') ++ if not is_transcoded(f): ++ sys.exit(1) ++ ++ validation_digests, digests_table, signature_output = parse_file(f) ++ if(args.dump_file_digest_table): ++ for digest in digests_table: ++ print(f"FileDigest {hex(digest[0])}: {digest[1]}") ++ ++ if(args.dump_digests): ++ for validation_digest in validation_digests: ++ print(f"HeaderDigest {validation_digest[0]} {validation_digest[1]}") ++ ++ if(args.dump_signature): ++ print(f"RPMSignOutput RC {signature_output[0]}\nRPMSignOutput Content {signature_output[1].decode()}") ++ +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index 4608e1a..6159088 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -610,7 +610,7 @@ static int rpmSign(const char *rpm, int deleting, int flags) + } + + /* Write the lead/signature of the output rpm */ +- rc = rpmLeadWrite(ofd, h); ++ rc = rpmLeadWriteFromHeader(ofd, h); + if (rc != RPMRC_OK) { + rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm, + Fstrerror(ofd)); +diff --git a/tests/Makefile.am b/tests/Makefile.am +index 6d9f1f8..4a588a6 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -36,6 +36,7 @@ TESTSUITE_AT += rpmspec.at + TESTSUITE_AT += rpmio.at + TESTSUITE_AT += rpmorder.at + TESTSUITE_AT += rpmvfylevel.at ++TESTSUITE_AT += rpm2extents.at + EXTRA_DIST += $(TESTSUITE_AT) + + ## testsuite data +diff --git a/tests/atlocal.in b/tests/atlocal.in +index 7d1deb8..ff0703a 100644 +--- a/tests/atlocal.in ++++ b/tests/atlocal.in +@@ -50,6 +50,19 @@ else + CAP_DISABLED=true; + fi + ++FSTYPE=$(stat -f -c %T /) ++REFLINKABLE_FS=("xfs" "brtfs") ++ ++REFLINK_DISABLED=true; ++for item in "${REFLINKABLE_FS[@]}" ++do ++ if test "${FSTYPE}" = "${item}" ++ then ++ REFLINK_DISABLED=false; ++ break ++ fi ++done ++ + function setup_env() + { + if [ -d testing ]; then +@@ -82,6 +95,15 @@ function runroot() + ) + } + ++function runroot_plugins() ++{ ++ setup_env ++ (unset RPM_CONFIGDIR RPM_POPTEXEC_PATH; cd ${RPMTEST} && \ ++ MAGIC="/magic/magic" FAKECHROOT_BASE="${RPMTEST}" fakechroot "$@" --define "_buildhost testhost" --define "_topdir /build" --nouserns ++ ) ++} ++ ++ + function runroot_other() + { + setup_env +diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at +new file mode 100644 +index 0000000..c9c79c5 +--- /dev/null ++++ b/tests/rpm2extents.at +@@ -0,0 +1,151 @@ ++# rpm2extents.at: Some very basic checks ++# ++# Copyright (C) 2022 Manu Bretelle ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ ++AT_BANNER([rpm2extents tests]) ++ ++# ------------------------------ ++ ++# check that transcoder write magic at the end ++AT_SETUP([rpm2extents magic]) ++AT_KEYWORDS([rpm2extents]) ++AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | tail -c8], ++[0], ++[KWTSH100], ++[ignore]) ++AT_CLEANUP ++ ++# Check that transcoder writes checksig return code and content. ++# ++AT_SETUP([rpm2extents signature]) ++AT_KEYWORDS([rpm2extents]) ++AT_CHECK([ ++RPMDB_INIT ++ ++runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null ++rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm ++runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub ++runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm ++rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm ++], ++[0], ++[RPMSignOutput RC 2 ++RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY ++ Header SHA256 digest: OK ++ Header SHA1 digest: OK ++ Payload SHA256 digest: OK ++ V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY ++ MD5 digest: OK ++ ++RPMSignOutput RC 0 ++RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK ++ Header SHA256 digest: OK ++ Header SHA1 digest: OK ++ Payload SHA256 digest: OK ++ V4 RSA/SHA256 Signature, key ID 1964c5fc: OK ++ MD5 digest: OK ++ ++], ++[]) ++AT_CLEANUP ++ ++AT_SETUP([rpm2extents signature verification]) ++AT_KEYWORDS([rpm2extents]) ++AT_CHECK([ ++RPMDB_INIT ++ ++runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null ++runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $? ++runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub ++runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm ++runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $? ++], ++[0], ++[/tmp/hello-2.0-1.x86_64-signed.rpm: ++ Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY ++ Header SHA256 digest: OK ++ Header SHA1 digest: OK ++ Payload SHA256 digest: OK ++ V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY ++ MD5 digest: OK ++1 ++/tmp/hello-2.0-1.x86_64-signed.rpm: ++ Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK ++ Header SHA256 digest: OK ++ Header SHA1 digest: OK ++ Payload SHA256 digest: OK ++ V4 RSA/SHA256 Signature, key ID 1964c5fc: OK ++ MD5 digest: OK ++0 ++], ++[]) ++AT_CLEANUP ++ ++# check that package in denylist is not transcoded ++AT_SETUP([rpm2extents denylist]) ++AT_KEYWORDS([rpm2extents]) ++AT_CHECK([ ++export LIBREPO_TRANSCODE_RPMS_DENYLIST="vim,hello,cowsay" ++runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | runroot_other cmp /data/RPMS/hello-2.0-1.x86_64.rpm -], ++[0], ++[], ++[ignore]) ++AT_CLEANUP ++ ++AT_SETUP([rpm2extents install package]) ++AT_KEYWORDS([rpm2extents reflink]) ++AT_SKIP_IF([$REFLINK_DISABLED]) ++AT_CHECK([ ++RPMDB_INIT ++ ++runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64.rpm 2> /dev/null ++runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm ++test -f ${RPMTEST}/usr/bin/hello ++], ++[0], ++[], ++[]) ++AT_CLEANUP ++ ++AT_SETUP([reflink ignores non-transcoded package]) ++AT_KEYWORDS([reflink]) ++AT_CHECK([ ++RPMDB_INIT ++ ++runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $? ++# Check that the file is properly installed in chroot ++test -f ${RPMTEST}/usr/bin/hello ++], ++[0], ++[], ++[]) ++AT_CLEANUP ++ ++AT_SETUP([reflink hardlink package]) ++AT_KEYWORDS([reflink hardlink]) ++AT_SKIP_IF([$REFLINK_DISABLED]) ++AT_CHECK([ ++RPMDB_INIT ++ ++PKG=hlinktest-1.0-1.noarch.rpm ++runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null ++runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG} ++], ++[0], ++[], ++[]) ++AT_CLEANUP +diff --git a/tests/rpmtests.at b/tests/rpmtests.at +index 48b86bd..e219a16 100644 +--- a/tests/rpmtests.at ++++ b/tests/rpmtests.at +@@ -22,3 +22,4 @@ m4_include([rpmreplace.at]) + m4_include([rpmconfig.at]) + m4_include([rpmconfig2.at]) + m4_include([rpmconfig3.at]) ++m4_include([rpm2extents.at]) -- -2.35.1 +2.47.0 diff --git a/0002-Remove-use-of-bool-type-for-consistency.patch b/0002-Remove-use-of-bool-type-for-consistency.patch deleted file mode 100644 index 5b1e7ad..0000000 --- a/0002-Remove-use-of-bool-type-for-consistency.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 845b5c3882b1eecb31d712b61a4e91fe0eb70712 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -Date: Sun, 31 Jan 2021 12:30:33 -0800 -Subject: [PATCH 02/30] Remove use of bool type for consistency - ---- - 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 - #include - #include --#include - #include - #ifdef WITH_CAP - #include -@@ -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; -+ int cpio = 1; - - if (payloadfmt && rstreq(payloadfmt, "clon")) { -- cpio = false; -+ cpio = 0; - } - - /* transaction id used for temporary path suffix while installing */ -@@ -924,7 +923,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - setFileState(fs, fx); - break; - case RPMRC_PLUGIN_CONTENTS: -- fp->plugin_contents = true; -+ fp->plugin_contents = 1; - // 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 deleted file mode 100644 index f827cd0..0000000 --- a/0003-Match-formatting-style-of-existing-code.patch +++ /dev/null @@ -1,1231 +0,0 @@ -From aa31421bfe835dadd29da3aa46ee446038f80d02 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -Date: Sun, 31 Jan 2021 13:51:16 -0800 -Subject: [PATCH 03/30] Match formatting/style of existing code - -The existing code contains some variability in formatting. I'm not sure -if { is meant to be on the end of the line, or on a new line, but I've -standardized on the former. - -The indentation is intended to match the existing convention: 4 column -indent, but 8 column wide tab characters. This is easy to follow/use in -vim, but is surprisingly difficult to get right in vscode. I am doing -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. ---- - plugins/reflink.c | 407 ++++++++++++++++++--------------- - rpm2extents.c | 562 ++++++++++++++++++++-------------------------- - 2 files changed, 459 insertions(+), 510 deletions(-) - -diff --git a/plugins/reflink.c b/plugins/reflink.c -index d7f19acd9..9eaa87094 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -32,31 +32,32 @@ - #include "lib/rpmhash.H" - #include "lib/rpmhash.C" - --/* --We use this in find to indicate a key wasn't found. This is an unrecoverable --error, but we can at least show a decent error. 0 is never a valid offset --because it's the offset of the start of the file. --*/ -+/* We use this in find to indicate a key wasn't found. This is an -+ * unrecoverable error, but we can at least show a decent error. 0 is never a -+ * valid offset because it's the offset of the start of the file. -+ */ - #define NOT_FOUND 0 - - #define BUFFER_SIZE (1024 * 128) - --/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ -+/* magic value at end of file (64 bits) that indicates this is a transcoded -+ * rpm. -+ */ - #define MAGIC 3472329499408095051 - - struct reflink_state_s { -- /* Stuff that's used across rpms */ -- long fundamental_block_size; -- char *buffer; -+ /* Stuff that's used across rpms */ -+ long fundamental_block_size; -+ char *buffer; - -- /* stuff that's used/updated per psm */ -- uint32_t keys, keysize; -+ /* stuff that's used/updated per psm */ -+ uint32_t keys, keysize; - -- // table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) -- unsigned char *table; -- FD_t fd; -- rpmfiles files; -- inodeIndexHash inodeIndexes; -+ /* table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) */ -+ unsigned char *table; -+ FD_t fd; -+ rpmfiles files; -+ inodeIndexHash inodeIndexes; - }; - - typedef struct reflink_state_s * reflink_state; -@@ -73,60 +74,62 @@ static unsigned int inodeId(rpm_ino_t a) - } - - static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) { -- reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); -+ reflink_state state = rcalloc(1, sizeof(struct reflink_state_s)); - -- /* -- IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and -- length arguments to be aligned to the fundamental block size. -+ /* IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset -+ * and length arguments to be aligned to the fundamental block size. -+ * -+ * The value of "fundamental block size" is directly related to the -+ * system's page size, so we should use that. -+ */ -+ state->fundamental_block_size = sysconf(_SC_PAGESIZE); -+ state->buffer = rcalloc(1, BUFFER_SIZE); -+ rpmPluginSetData(plugin, state); - -- The value of "fundamental block size" is directly related to the system's -- page size, so we should use that. -- */ -- state->fundamental_block_size = sysconf(_SC_PAGESIZE); -- state->buffer = rcalloc(1, BUFFER_SIZE); -- rpmPluginSetData(plugin, state); -- -- return RPMRC_OK; -+ return RPMRC_OK; - } - - static void reflink_cleanup(rpmPlugin plugin) { -- reflink_state state = rpmPluginGetData(plugin); -- free(state->buffer); -- free(state); -+ reflink_state state = rpmPluginGetData(plugin); -+ free(state->buffer); -+ free(state); - } - - static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { - reflink_state state = rpmPluginGetData(plugin); - state->fd = rpmteFd(te); - if (state->fd == 0) { -- rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n")); -- return RPMRC_OK; -+ rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n")); -+ return RPMRC_OK; - } - rpm_loff_t current = Ftell(state->fd); - uint64_t magic; - if (Fseek(state->fd, -(sizeof(magic)), SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n")); -- if (Fseek(state->fd, current, SEEK_SET) < 0) { -- /* yes this gets a bit repetitive */ -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -- } -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n")); -+ if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ /* yes this gets a bit repetitive */ -+ rpmlog(RPMLOG_ERR, -+ _("reflink: unable to seek back to original location\n")); -+ } -+ return RPMRC_FAIL; - } - size_t len = sizeof(magic); - if (Fread(&magic, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n")); -- if (Fseek(state->fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -- } -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n")); -+ if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: unable to seek back to original location\n")); -+ } -+ return RPMRC_FAIL; - } - if (magic != MAGIC) { -- rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n")); -- if (Fseek(state->fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -- return RPMRC_FAIL; -- } -- return RPMRC_OK; -+ rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n")); -+ if (Fseek(state->fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: unable to seek back to original location\n")); -+ return RPMRC_FAIL; -+ } -+ return RPMRC_OK; - } - rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); - Header h = rpmteHeader(te); -@@ -136,53 +139,60 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { - headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon"); - headerFree(h); - state->files = rpmteFiles(te); -- /* tail of file contains offset_table, offset_checksums -- then magic -- */ -+ /* tail of file contains offset_table, offset_checksums then magic */ - if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), -+ state->fd); -+ return RPMRC_FAIL; - } - rpm_loff_t table_start; - len = sizeof(table_start); - if (Fread(&table_start, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n")); -+ return RPMRC_FAIL; - } - if (Fseek(state->fd, table_start, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n")); -+ return RPMRC_FAIL; - } - len = sizeof(state->keys); - if (Fread(&state->keys, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n")); -+ return RPMRC_FAIL; - } - len = sizeof(state->keysize); - if (Fread(&state->keysize, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n")); -+ return RPMRC_FAIL; - } -- rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize); -- // now get digest table if there is a reason to have one. -+ rpmlog( -+ RPMLOG_DEBUG, -+ _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), -+ table_start, state->keys, state->keysize -+ ); -+ /* now get digest table if there is a reason to have one. */ - if (state->keys == 0 || state->keysize == 0) { -- // no files (or no digests(!)) -- state->table = NULL; -+ /* no files (or no digests(!)) */ -+ state->table = NULL; - } else { -- int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); -- state->table = rcalloc(1, table_size); -- if (Fread(state->table, table_size, 1, state->fd) != table_size) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); -- return RPMRC_FAIL; -- } -- state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL); -+ int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t)); -+ state->table = rcalloc(1, table_size); -+ if (Fread(state->table, table_size, 1, state->fd) != table_size) { -+ rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n")); -+ return RPMRC_FAIL; -+ } -+ state->inodeIndexes = inodeIndexHashCreate( -+ state->keys, inodeId, inodeCmp, NULL, NULL -+ ); - } - -- // seek back to original location -- // might not be needed if we seek to offset immediately -+ /* Seek back to original location. -+ * Might not be needed if we seek to offset immediately -+ */ - if (Fseek(state->fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n")); -- return RPMRC_FAIL; -+ rpmlog(RPMLOG_ERR, -+ _("reflink: unable to seek back to original location\n")); -+ return RPMRC_FAIL; - } - return RPMRC_OK; - } -@@ -192,40 +202,45 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res) - reflink_state state = rpmPluginGetData(plugin); - state->files = rpmfilesFree(state->files); - if (state->table) { -- free(state->table); -- state->table = NULL; -+ free(state->table); -+ state->table = NULL; - } - if (state->inodeIndexes) { -- inodeIndexHashFree(state->inodeIndexes); -- state->inodeIndexes = NULL; -+ inodeIndexHashFree(state->inodeIndexes); -+ state->inodeIndexes = NULL; - } - return RPMRC_OK; - } - - --// have a prototype, warnings system -+/* have a prototype, warnings system */ - rpm_loff_t find(const unsigned char *digest, reflink_state state); - - rpm_loff_t find(const unsigned char *digest, reflink_state state) { - # if defined(__GNUC__) -- /* GCC nested function because bsearch's comparison function can't access -- state-keysize otherwise -- */ -- int cmpdigest(const void *k1, const void *k2) { -- rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2); -- return memcmp(k1, k2, state->keysize); -- } -+ /* GCC nested function because bsearch's comparison function can't access -+ * state-keysize otherwise -+ */ -+ int cmpdigest(const void *k1, const void *k2) { -+ rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2); -+ return memcmp(k1, k2, state->keysize); -+ } - # endif -- rpmlog(RPMLOG_DEBUG, _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"), digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t)); -- char *entry = bsearch(digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t), cmpdigest); -- if (entry == NULL) { -- return NOT_FOUND; -- } -- rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); -- return offset; -+ rpmlog(RPMLOG_DEBUG, -+ _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"), -+ digest, state->table, state->keys, -+ state->keysize + sizeof(rpm_loff_t)); -+ char *entry = bsearch(digest, state->table, state->keys, -+ state->keysize + sizeof(rpm_loff_t), cmpdigest); -+ if (entry == NULL) { -+ return NOT_FOUND; -+ } -+ rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize); -+ return offset; - } - --static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op) -+static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, -+ mode_t file_mode, rpmFsmOp op) - { - struct file_clone_range fcr; - rpm_loff_t size; -@@ -234,99 +249,119 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, - - reflink_state state = rpmPluginGetData(plugin); - if (state->table == NULL) { -- // no table means rpm is not in reflink format, so leave. Now. -- return RPMRC_OK; -+ /* no table means rpm is not in reflink format, so leave. Now. */ -+ return RPMRC_OK; - } - if (op == FA_TOUCH) { -- // we're not overwriting an existing file -- return RPMRC_OK; -+ /* we're not overwriting an existing file. */ -+ return RPMRC_OK; - } - fcr.dest_offset = 0; - if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) { -- rpm_ino_t inode = rpmfiFInode(fi); -- /* check for hard link entry in table. GetEntry overwrites hlix with the address of the first match */ -- if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, NULL)) { -- // entry is in table, use hard link -- char *fn = rpmfilesFN(state->files, hlix[0]); -- if (link(fn, path) != 0) { -- rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno)); -- free(fn); -- return RPMRC_FAIL; -- } -- free(fn); -- return RPMRC_PLUGIN_CONTENTS; -- } -- /* if we didn't hard link, then we'll track this inode as being created soon */ -- if (rpmfiFNlink(fi) > 1) { -- /* minor optimization: only store files with more than one link */ -- inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); -- } -- /* derived from wfd_open in fsm.c */ -- mode_t old_umask = umask(0577); -- dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); -- umask(old_umask); -- if (dst == -1) { -- rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi)); -- return RPMRC_FAIL; -- } -- size = rpmfiFSize(fi); -- if (size > 0) { -- /* round src_length down to fundamental_block_size multiple */ -- fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; -- if ((size % state->fundamental_block_size) > 0) { -- /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */ -- fcr.src_length += state->fundamental_block_size; -- } -- fcr.src_fd = Fileno(state->fd); -- if (fcr.src_fd == -1) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); -- return RPMRC_FAIL; -- } -- fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); -- if (fcr.src_offset == NOT_FOUND) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); -- return RPMRC_FAIL; -- } -- rpmlog(RPMLOG_DEBUG, _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); -- rc = ioctl(dst, FICLONERANGE, &fcr); -- if (rc) { -- rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno)); -- if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n")); -- return RPMRC_FAIL; -- } -- rpm_loff_t left = size; -- size_t len, read, written; -- while (left) { -- len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); -- read = Fread(state->buffer, len, 1, state->fd); -- if (read != len) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n")); -- return RPMRC_FAIL; -- } -- written = write(dst, state->buffer, len); -- if (read != written) { -- close(dst); -- rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n")); -- return RPMRC_FAIL; -- } -- left -= len; -- } -- } else { -- /* reflink worked, so truncate */ -- rc = ftruncate(dst, size); -- if (rc) { -- rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno)); -- return RPMRC_FAIL; -- } -- } -- } -- close(dst); -- return RPMRC_PLUGIN_CONTENTS; -+ rpm_ino_t inode = rpmfiFInode(fi); -+ /* check for hard link entry in table. GetEntry overwrites hlix with -+ * the address of the first match. -+ */ -+ if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, -+ NULL)) { -+ /* entry is in table, use hard link */ -+ char *fn = rpmfilesFN(state->files, hlix[0]); -+ if (link(fn, path) != 0) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: Unable to hard link %s -> %s due to %s\n"), -+ fn, path, strerror(errno)); -+ free(fn); -+ return RPMRC_FAIL; -+ } -+ free(fn); -+ return RPMRC_PLUGIN_CONTENTS; -+ } -+ /* if we didn't hard link, then we'll track this inode as being -+ * created soon -+ */ -+ if (rpmfiFNlink(fi) > 1) { -+ /* minor optimization: only store files with more than one link */ -+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); -+ } -+ /* derived from wfd_open in fsm.c */ -+ mode_t old_umask = umask(0577); -+ dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); -+ umask(old_umask); -+ if (dst == -1) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), -+ path, strerror(errno), rpmfiFFlags(fi)); -+ return RPMRC_FAIL; -+ } -+ size = rpmfiFSize(fi); -+ if (size > 0) { -+ /* round src_length down to fundamental_block_size multiple */ -+ fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size; -+ if ((size % state->fundamental_block_size) > 0) { -+ /* round up to next fundamental_block_size. We expect the data -+ * in the rpm to be similarly padded. -+ */ -+ fcr.src_length += state->fundamental_block_size; -+ } -+ fcr.src_fd = Fileno(state->fd); -+ if (fcr.src_fd == -1) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n")); -+ return RPMRC_FAIL; -+ } -+ fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state); -+ if (fcr.src_offset == NOT_FOUND) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, _("reflink: digest not found\n")); -+ return RPMRC_FAIL; -+ } -+ rpmlog(RPMLOG_DEBUG, -+ _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), -+ fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); -+ rc = ioctl(dst, FICLONERANGE, &fcr); -+ if (rc) { -+ rpmlog(RPMLOG_WARNING, -+ _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), -+ path, rc, errno, strerror(errno)); -+ if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, -+ _("reflink: unable to seek on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ rpm_loff_t left = size; -+ size_t len, read, written; -+ while (left) { -+ len = (left > BUFFER_SIZE ? BUFFER_SIZE : left); -+ read = Fread(state->buffer, len, 1, state->fd); -+ if (read != len) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, -+ _("reflink: short read on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ written = write(dst, state->buffer, len); -+ if (read != written) { -+ close(dst); -+ rpmlog(RPMLOG_ERR, -+ _("reflink: short write on copying bits\n")); -+ return RPMRC_FAIL; -+ } -+ left -= len; -+ } -+ } else { -+ /* reflink worked, so truncate */ -+ rc = ftruncate(dst, size); -+ if (rc) { -+ rpmlog(RPMLOG_ERR, -+ _("reflink: Unable to truncate %s to %ld due to %s\n"), -+ path, size, strerror(errno)); -+ return RPMRC_FAIL; -+ } -+ } -+ } -+ close(dst); -+ return RPMRC_PLUGIN_CONTENTS; - } - return RPMRC_OK; - } -diff --git a/rpm2extents.c b/rpm2extents.c -index 5662b86a6..c111be0a2 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -24,7 +24,7 @@ - #include "debug.h" - - /* hash of void * (pointers) to file digests to offsets within output. -- The length of the key depends on what the FILEDIGESTALGO is. -+ * The length of the key depends on what the FILEDIGESTALGO is. - */ - #undef HASHTYPE - #undef HTKEYTYPE -@@ -34,7 +34,9 @@ - #include "lib/rpmhash.H" - #include "lib/rpmhash.C" - --/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */ -+/* magic value at end of file (64 bits) that indicates this is a transcoded -+ * rpm. -+ */ - #define MAGIC 3472329499408095051 - - struct digestoffset { -@@ -64,77 +66,54 @@ static int digestor( - int algo; - rpmRC rc = RPMRC_FAIL; - -- for (algo = 0; algo < algos_len; algo++) -- { -- fdInitDigest(fdi, algos[algo], 0); -+ for (algo = 0; algo < algos_len; algo++) { -+ fdInitDigest(fdi, algos[algo], 0); - } - fdilength = ufdCopy(fdi, fdo); -- if (fdilength == -1) -- { -- fprintf(stderr, _("digest cat failed\n")); -- goto exit; -+ if (fdilength == -1) { -+ fprintf(stderr, _("digest cat failed\n")); -+ goto exit; - } - - len = sizeof(fdilength); -- if (Fwrite(&fdilength, len, 1, validationo) != len) -- { -- fprintf(stderr, _("Unable to write input length %zd\n"), fdilength); -- goto exit; -+ if (Fwrite(&fdilength, len, 1, validationo) != len) { -+ fprintf(stderr, _("Unable to write input length %zd\n"), fdilength); -+ goto exit; - } - len = sizeof(algos_len); -- if (Fwrite(&algos_len, len, 1, validationo) != len) -- { -- fprintf(stderr, _("Unable to write number of validation digests\n")); -- goto exit; -+ if (Fwrite(&algos_len, len, 1, validationo) != len) { -+ fprintf(stderr, _("Unable to write number of validation digests\n")); -+ goto exit; - } -- for (algo = 0; algo < algos_len; algo++) -- { -- fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); -- -- algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); -- algo_name_len = (uint32_t)strlen(algo_name); -- algo_digest_len = (uint32_t)filedigest_len; -- -- len = sizeof(algo_name_len); -- if (Fwrite(&algo_name_len, len, 1, validationo) != len) -- { -- fprintf( -- stderr, -- _("Unable to write validation algo name length\n") -- ); -- goto exit; -- } -- len = sizeof(algo_digest_len); -- if (Fwrite(&algo_digest_len, len, 1, validationo) != len) -- { -- fprintf( -- stderr, -- _("Unable to write number of bytes for validation digest\n") -- ); -- goto exit; -- } -- if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len) -- { -- fprintf(stderr, _("Unable to write validation algo name\n")); -- goto exit; -- } -- if ( -- Fwrite( -- filedigest, -- algo_digest_len, -- 1, -- validationo -- ) != algo_digest_len -- ) -- { -- fprintf( -- stderr, -- _("Unable to write validation digest value %u, %zu\n"), -- algo_digest_len, -- filedigest_len -- ); -- goto exit; -- } -+ for (algo = 0; algo < algos_len; algo++) { -+ fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0); -+ -+ algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]); -+ algo_name_len = (uint32_t)strlen(algo_name); -+ algo_digest_len = (uint32_t)filedigest_len; -+ -+ len = sizeof(algo_name_len); -+ if (Fwrite(&algo_name_len, len, 1, validationo) != len) { -+ fprintf(stderr, -+ _("Unable to write validation algo name length\n")); -+ goto exit; -+ } -+ len = sizeof(algo_digest_len); -+ if (Fwrite(&algo_digest_len, len, 1, validationo) != len) { -+ fprintf(stderr, -+ _("Unable to write number of bytes for validation digest\n")); -+ goto exit; -+ } -+ if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len) { -+ fprintf(stderr, _("Unable to write validation algo name\n")); -+ goto exit; -+ } -+ if (Fwrite(filedigest, algo_digest_len, 1, validationo ) != algo_digest_len) { -+ fprintf(stderr, -+ _("Unable to write validation digest value %u, %zu\n"), -+ algo_digest_len, filedigest_len); -+ goto exit; -+ } - } - rc = RPMRC_OK; - exit: -@@ -145,23 +124,20 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - { - uint32_t diglen; - /* GNU C extension: can use diglen from outer context */ -- int digestSetCmp(const unsigned char * a, const unsigned char * b) -- { -- return memcmp(a, b, diglen); -+ int digestSetCmp(const unsigned char * a, const unsigned char * b) { -+ return memcmp(a, b, diglen); - } - -- unsigned int digestSetHash(const unsigned char * digest) -- { -+ unsigned int digestSetHash(const unsigned char * digest) { - /* assumes sizeof(unsigned int) < diglen */ - return *(unsigned int *)digest; - } - -- int digestoffsetCmp(const void * a, const void * b) -- { -- return digestSetCmp( -- ((struct digestoffset *)a)->digest, -- ((struct digestoffset *)b)->digest -- ); -+ int digestoffsetCmp(const void * a, const void * b) { -+ return digestSetCmp( -+ ((struct digestoffset *)a)->digest, -+ ((struct digestoffset *)b)->digest -+ ); - } - - FD_t fdo; -@@ -179,65 +155,52 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - - fdo = fdDup(STDOUT_FILENO); - -- if (rpmReadPackageRaw(fdi, &sigh, &h)) -- { -- fprintf(stderr, _("Error reading package\n")); -- exit(EXIT_FAILURE); -+ if (rpmReadPackageRaw(fdi, &sigh, &h)) { -+ fprintf(stderr, _("Error reading package\n")); -+ exit(EXIT_FAILURE); - } - - if (rpmLeadWrite(fdo, h)) - { -- fprintf( -- stderr, -- _("Unable to write package lead: %s\n"), -- Fstrerror(fdo) -- ); -- exit(EXIT_FAILURE); -+ fprintf(stderr, _("Unable to write package lead: %s\n"), -+ Fstrerror(fdo)); -+ exit(EXIT_FAILURE); - } - -- if (rpmWriteSignature(fdo, sigh)) -- { -- fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo)); -- exit(EXIT_FAILURE); -+ if (rpmWriteSignature(fdo, sigh)) { -+ fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo)); -+ exit(EXIT_FAILURE); - } - -- if (headerWrite(fdo, h, HEADER_MAGIC_YES)) -- { -- fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); -- exit(EXIT_FAILURE); -+ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) { -+ fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); -+ exit(EXIT_FAILURE); - } - - /* Retrieve payload size and compression type. */ -- { const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); -- rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); -+ { -+ const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); -+ rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); - } - - gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ - free(rpmio_flags); - -- if (gzdi == NULL) -- { -- fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); -- exit(EXIT_FAILURE); -+ if (gzdi == NULL) { -+ fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); -+ exit(EXIT_FAILURE); - } - - rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); -- rpmfi fi = rpmfiNewArchiveReader( -- gzdi, -- files, -- RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST -- ); -+ rpmfi fi = rpmfiNewArchiveReader(gzdi, files, -+ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST); - - /* this is encoded in the file format, so needs to be fixed size (for -- now?) -- */ -+ * now?) -+ */ - diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi)); -- digestSet ds = digestSetCreate( -- rpmfiFC(fi), -- digestSetHash, -- digestSetCmp, -- NULL -- ); -+ digestSet ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, -+ NULL); - struct digestoffset offsets[rpmfiFC(fi)]; - pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); - -@@ -247,139 +210,114 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - - zeros = xcalloc(fundamental_block_size, 1); - -- while (next >= 0) -- { -- next = rpmfiNext(fi); -- if (next == RPMERR_ITER_END) -- { -- rc = RPMRC_OK; -- break; -- } -- mode = rpmfiFMode(fi); -- if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) -- { -- /* not a regular file, or the archive doesn't contain any content for -- this entry -- */ -- continue; -- } -- digest = rpmfiFDigest(fi, NULL, NULL); -- if (digestSetGetEntry(ds, digest, NULL)) -- { -- /* This specific digest has already been included, so skip it */ -- continue; -- } -- pad = pad_to(pos, fundamental_block_size); -- if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) -- { -- fprintf(stderr, _("Unable to write padding\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- /* round up to next fundamental_block_size */ -- pos += pad; -- digestSetAddEntry(ds, digest); -- offsets[offset_ix].digest = digest; -- offsets[offset_ix].pos = pos; -- offset_ix++; -- size = rpmfiFSize(fi); -- rc = rpmfiArchiveReadToFile(fi, fdo, 0); -- if (rc != RPMRC_OK) -- { -- fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); -- goto exit; -- } -- pos += size; -+ while (next >= 0) { -+ next = rpmfiNext(fi); -+ if (next == RPMERR_ITER_END) { -+ rc = RPMRC_OK; -+ break; -+ } -+ mode = rpmfiFMode(fi); -+ if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) { -+ /* not a regular file, or the archive doesn't contain any content -+ * for this entry. -+ */ -+ continue; -+ } -+ digest = rpmfiFDigest(fi, NULL, NULL); -+ if (digestSetGetEntry(ds, digest, NULL)) { -+ /* This specific digest has already been included, so skip it. */ -+ continue; -+ } -+ pad = pad_to(pos, fundamental_block_size); -+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -+ fprintf(stderr, _("Unable to write padding\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ /* round up to next fundamental_block_size */ -+ pos += pad; -+ digestSetAddEntry(ds, digest); -+ offsets[offset_ix].digest = digest; -+ offsets[offset_ix].pos = pos; -+ offset_ix++; -+ size = rpmfiFSize(fi); -+ rc = rpmfiArchiveReadToFile(fi, fdo, 0); -+ if (rc != RPMRC_OK) { -+ fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); -+ goto exit; -+ } -+ pos += size; - } - Fclose(gzdi); /* XXX gzdi == fdi */ - -- qsort( -- offsets, -- (size_t)offset_ix, -- sizeof(struct digestoffset), -- digestoffsetCmp -- ); -+ qsort(offsets, (size_t)offset_ix, sizeof(struct digestoffset), -+ digestoffsetCmp); - - len = sizeof(offset_ix); -- if (Fwrite(&offset_ix, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write length of table\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&offset_ix, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write length of table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - len = sizeof(diglen); -- if (Fwrite(&diglen, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write length of digest\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&diglen, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write length of digest\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - len = sizeof(rpm_loff_t); -- for (int x = 0; x < offset_ix; x++) -- { -- if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) -- { -- fprintf(stderr, _("Unable to write digest\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write offset\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -+ for (int x = 0; x < offset_ix; x++) { -+ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) { -+ fprintf(stderr, _("Unable to write digest\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } - } - validation_pos = ( -- pos + sizeof(offset_ix) + sizeof(diglen) + -- offset_ix * (diglen + sizeof(rpm_loff_t)) -+ pos + sizeof(offset_ix) + sizeof(diglen) + -+ offset_ix * (diglen + sizeof(rpm_loff_t)) - ); - - ssize_t validation_len = ufdCopy(validationi, fdo); -- if (validation_len == -1) -- { -- fprintf(stderr, _("digest table ufdCopy failed\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (validation_len == -1) { -+ fprintf(stderr, _("digest table ufdCopy failed\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - /* add more padding so the last file can be cloned. It doesn't matter that -- the table and validation etc are in this space. In fact, it's pretty -- efficient if it is -+ * the table and validation etc are in this space. In fact, it's pretty -+ * efficient if it is. - */ - -- pad = pad_to( -- ( -- validation_pos + validation_len + 2 * sizeof(rpm_loff_t) + -- sizeof(uint64_t) -- ), -- fundamental_block_size -- ); -- if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) -- { -- fprintf(stderr, _("Unable to write final padding\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ pad = pad_to((validation_pos + validation_len + 2 * sizeof(rpm_loff_t) + -+ sizeof(uint64_t)), fundamental_block_size); -+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -+ fprintf(stderr, _("Unable to write final padding\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - zeros = _free(zeros); -- if (Fwrite(&pos, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write offset of digest table\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset of digest table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } -- if (Fwrite(&validation_pos, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write offset of validation table\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&validation_pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset of validation table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - uint64_t magic = MAGIC; - len = sizeof(magic); -- if (Fwrite(&magic, len, 1, fdo) != len) -- { -- fprintf(stderr, _("Unable to write magic\n")); -- rc = RPMRC_FAIL; -- goto exit; -+ if (Fwrite(&magic, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } - - exit: -@@ -389,8 +327,7 @@ exit: - return rc; - } - --int main(int argc, char *argv[]) --{ -+int main(int argc, char *argv[]) { - rpmRC rc; - int cprc = 0; - uint8_t algos[argc - 1]; -@@ -402,118 +339,95 @@ int main(int argc, char *argv[]) - xsetprogname(argv[0]); /* Portability call -- see system.h */ - rpmReadConfigFiles(NULL, NULL); - -- if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) -- { -- fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]); -- exit(EXIT_FAILURE); -+ if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) { -+ fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]); -+ exit(EXIT_FAILURE); - } - -- if (argc == 1) -- { -- fprintf( -- stderr, -- _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n") -- ); -- exit(EXIT_FAILURE); -+ if (argc == 1) { -+ fprintf(stderr, -+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")); -+ exit(EXIT_FAILURE); - } - -- for (int x = 0; x < (argc - 1); x++) -- { -- if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) -- { -- fprintf( -- stderr, -- _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -- argv[x + 1] -- ); -- exit(EXIT_FAILURE); -- } -+ for (int x = 0; x < (argc - 1); x++) { -+ if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) -+ { -+ fprintf(stderr, -+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -+ argv[x + 1]); -+ exit(EXIT_FAILURE); -+ } - } - - -- if (pipe(mainpipefd) == -1) -- { -- fprintf(stderr, _("Main pipe failure\n")); -- exit(EXIT_FAILURE); -+ if (pipe(mainpipefd) == -1) { -+ fprintf(stderr, _("Main pipe failure\n")); -+ exit(EXIT_FAILURE); - } -- if (pipe(metapipefd) == -1) -- { -- fprintf(stderr, _("Meta pipe failure\n")); -- exit(EXIT_FAILURE); -+ if (pipe(metapipefd) == -1) { -+ fprintf(stderr, _("Meta pipe failure\n")); -+ exit(EXIT_FAILURE); - } - cpid = fork(); -- if (cpid == 0) -- { -- /* child: digestor */ -- close(mainpipefd[0]); -- close(metapipefd[0]); -- FD_t fdi = fdDup(STDIN_FILENO); -- FD_t fdo = fdDup(mainpipefd[1]); -- FD_t validationo = fdDup(metapipefd[1]); -- rc = digestor(fdi, fdo, validationo, algos, argc - 1); -- Fclose(validationo); -- Fclose(fdo); -- Fclose(fdi); -+ if (cpid == 0) { -+ /* child: digestor */ -+ close(mainpipefd[0]); -+ close(metapipefd[0]); -+ FD_t fdi = fdDup(STDIN_FILENO); -+ FD_t fdo = fdDup(mainpipefd[1]); -+ FD_t validationo = fdDup(metapipefd[1]); -+ rc = digestor(fdi, fdo, validationo, algos, argc - 1); -+ Fclose(validationo); -+ Fclose(fdo); -+ Fclose(fdi); - } else { -- /* parent: main program */ -- close(mainpipefd[1]); -- close(metapipefd[1]); -- FD_t fdi = fdDup(mainpipefd[0]); -- FD_t validationi = fdDup(metapipefd[0]); -- rc = process_package(fdi, validationi); -- Fclose(validationi); -- /* fdi is normally closed through the stacked file gzdi in the function. */ -- /* wait for child process (digestor for stdin) to complete. */ -- if (rc != RPMRC_OK) -- { -- if (kill(cpid, SIGTERM) != 0) -- { -- fprintf( -- stderr, -- _("Failed to kill digest process when main process failed: %s\n"), -- strerror(errno) -- ); -- } -- } -- w = waitpid(cpid, &wstatus, 0); -- if (w == -1) -- { -- fprintf(stderr, _("waitpid failed\n")); -- cprc = EXIT_FAILURE; -- } else if (WIFEXITED(wstatus)) -- { -- cprc = WEXITSTATUS(wstatus); -- if (cprc != 0) -- { -- fprintf( -- stderr, -- _("Digest process non-zero exit code %d\n"), -- cprc -- ); -- } -- } else if (WIFSIGNALED(wstatus)) -- { -- fprintf( -- stderr, -- _("Digest process was terminated with a signal: %d\n"), -- WTERMSIG(wstatus) -- ); -- cprc = EXIT_FAILURE; -- } else -- { -- /* don't think this can happen, but covering all bases */ -- fprintf(stderr, _("Unhandled circumstance in waitpid\n")); -- cprc = EXIT_FAILURE; -- } -- if (cprc != EXIT_SUCCESS) -- { -- rc = RPMRC_FAIL; -- } -+ /* parent: main program */ -+ close(mainpipefd[1]); -+ close(metapipefd[1]); -+ FD_t fdi = fdDup(mainpipefd[0]); -+ FD_t validationi = fdDup(metapipefd[0]); -+ rc = process_package(fdi, validationi); -+ Fclose(validationi); -+ /* fdi is normally closed through the stacked file gzdi in the -+ * function. -+ * Wait for child process (digestor for stdin) to complete. -+ */ -+ if (rc != RPMRC_OK) { -+ if (kill(cpid, SIGTERM) != 0) { -+ fprintf(stderr, -+ _("Failed to kill digest process when main process failed: %s\n"), -+ strerror(errno)); -+ } -+ } -+ w = waitpid(cpid, &wstatus, 0); -+ if (w == -1) { -+ fprintf(stderr, _("waitpid failed\n")); -+ cprc = EXIT_FAILURE; -+ } else if (WIFEXITED(wstatus)) { -+ cprc = WEXITSTATUS(wstatus); -+ if (cprc != 0) { -+ fprintf(stderr, -+ _("Digest process non-zero exit code %d\n"), -+ cprc); -+ } -+ } else if (WIFSIGNALED(wstatus)) { -+ fprintf(stderr, -+ _("Digest process was terminated with a signal: %d\n"), -+ WTERMSIG(wstatus)); -+ cprc = EXIT_FAILURE; -+ } else { -+ /* Don't think this can happen, but covering all bases */ -+ fprintf(stderr, _("Unhandled circumstance in waitpid\n")); -+ cprc = EXIT_FAILURE; -+ } -+ if (cprc != EXIT_SUCCESS) { -+ rc = RPMRC_FAIL; -+ } - } -- if (rc != RPMRC_OK) -- { -- /* translate rpmRC into generic failure return code. */ -- return EXIT_FAILURE; -+ if (rc != RPMRC_OK) { -+ /* translate rpmRC into generic failure return code. */ -+ return EXIT_FAILURE; - } - return EXIT_SUCCESS; - } --- -2.35.1 - diff --git a/0004-Fix-printf-formatting-in-reflink.c.patch b/0004-Fix-printf-formatting-in-reflink.c.patch deleted file mode 100644 index c33f3d5..0000000 --- a/0004-Fix-printf-formatting-in-reflink.c.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 15127592f8cc3221129f61b79319d88c7727bec3 Mon Sep 17 00:00:00 2001 -From: Matthew Almond -Date: Sun, 31 Jan 2021 15:24:25 -0800 -Subject: [PATCH 04/30] Fix printf formatting in reflink.c - -There were some mismatches on field "sizes". This should eliminate the -error messages. ---- - plugins/reflink.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/plugins/reflink.c b/plugins/reflink.c -index 9eaa87094..513887604 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -316,7 +316,7 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, - return RPMRC_FAIL; - } - rpmlog(RPMLOG_DEBUG, -- _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"), -+ _("reflink: Reflinking %llu bytes at %llu to %s orig size=%ld, file=%lld\n"), - fcr.src_length, fcr.src_offset, path, size, fcr.src_fd); - rc = ioctl(dst, FICLONERANGE, &fcr); - if (rc) { --- -2.35.1 - diff --git a/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch b/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch deleted file mode 100644 index d41aeb3..0000000 --- a/0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch +++ /dev/null @@ -1,73 +0,0 @@ -From fd4060dcfbe4127fb0d19f1878d0d8b9f34c7b9a Mon Sep 17 00:00:00 2001 -From: chantra -Date: Fri, 28 Jan 2022 08:33:16 -0800 -Subject: [PATCH 05/30] [tests][rpm2extents] Add basic tests for rpm2extents - ---- - tests/Makefile.am | 1 + - tests/rpm2extents.at | 31 +++++++++++++++++++++++++++++++ - tests/rpmtests.at | 1 + - 3 files changed, 33 insertions(+) - create mode 100644 tests/rpm2extents.at - -diff --git a/tests/Makefile.am b/tests/Makefile.am -index f78e17c3e..fc8a24a5e 100644 ---- a/tests/Makefile.am -+++ b/tests/Makefile.am -@@ -36,6 +36,7 @@ TESTSUITE_AT += rpmio.at - TESTSUITE_AT += rpmio.at - TESTSUITE_AT += rpmorder.at - TESTSUITE_AT += rpmvfylevel.at -+TESTSUITE_AT += rpm2extents.at - EXTRA_DIST += $(TESTSUITE_AT) - - ## testsuite data -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -new file mode 100644 -index 000000000..f943b9af4 ---- /dev/null -+++ b/tests/rpm2extents.at -@@ -0,0 +1,31 @@ -+# rpm2extents.at: Some very basic checks -+# -+# Copyright (C) 2022 Manu Bretelle -+# -+# This program is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ -+AT_BANNER([rpm2extents tests]) -+ -+# ------------------------------ -+ -+# check that transcoder write magic at the end -+AT_SETUP([rpm2extents magic]) -+AT_KEYWORDS([rpm2extents]) -+AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | tail -c8], -+[0], -+[KWTSH100], -+[ignore]) -+AT_CLEANUP -+ -diff --git a/tests/rpmtests.at b/tests/rpmtests.at -index a1adab8e0..205fed6a3 100644 ---- a/tests/rpmtests.at -+++ b/tests/rpmtests.at -@@ -22,3 +22,4 @@ m4_include([rpmreplace.at]) - m4_include([rpmconfig.at]) - m4_include([rpmconfig2.at]) - m4_include([rpmconfig3.at]) -+m4_include([rpm2extents.at]) --- -2.35.1 - diff --git a/0006-rpm2extents-verify-package-signature-during-transcod.patch b/0006-rpm2extents-verify-package-signature-during-transcod.patch deleted file mode 100644 index c2eb42c..0000000 --- a/0006-rpm2extents-verify-package-signature-during-transcod.patch +++ /dev/null @@ -1,431 +0,0 @@ -From ea1177fcef609519f0c2377ebee236001d2a8fae Mon Sep 17 00:00:00 2001 -From: chantra -Date: Fri, 28 Jan 2022 08:31:39 -0800 -Subject: [PATCH 06/30] [rpm2extents] verify package signature during - transcoding - ---- - lib/rpmchecksig.c | 30 ++++++ - lib/rpmcli.h | 9 ++ - rpm2extents.c | 233 +++++++++++++++++++++++++++++++++++++++++----- - 3 files changed, 248 insertions(+), 24 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index 40a3ab83f..1a6b95323 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -304,3 +304,33 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv) - rpmKeyringFree(keyring); - return res; - } -+ -+int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi) -+{ -+ int res = 0; -+ rpmKeyring keyring = rpmtsGetKeyring(ts, 1); -+ rpmVSFlags vsflags = rpmtsVfyFlags(ts); -+ int vfylevel = rpmtsVfyLevel(ts); -+ -+ vsflags |= rpmcliVSFlags; -+ if (rpmcliVfyLevelMask) { -+ vfylevel &= ~rpmcliVfyLevelMask; -+ rpmtsSetVfyLevel(ts, vfylevel); -+ } -+ -+ FD_t fd = fdDup(Fileno(fdi)); -+ if (fd == NULL || Ferror(fd)) { -+ rpmlog(RPMLOG_ERR, _("fdDup failed: %s\n"), Fstrerror(fd)); -+ res++; -+ } else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, "stdin")) { -+ res++; -+ } -+ -+ lseek(Fileno(fd), SEEK_SET, 0); -+ Fclose(fd); -+ rpmsqPoll(); -+ -+ rpmKeyringFree(keyring); -+ return res; -+} -+ -diff --git a/lib/rpmcli.h b/lib/rpmcli.h -index 906fe9951..52443e459 100644 ---- a/lib/rpmcli.h -+++ b/lib/rpmcli.h -@@ -411,6 +411,15 @@ int rpmcliImportPubkeys(rpmts ts, ARGV_const_t argv); - */ - int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv); - -+ -+/** \ingroup rpmcli -+ * Verify package signatures -+ * @param ts transaction set -+ * @param fd a file descriptor to verify -+ * @return 0 on success -+ */ -+int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd); -+ - #ifdef __cplusplus - } - #endif -diff --git a/rpm2extents.c b/rpm2extents.c -index c111be0a2..d8e582676 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -2,7 +2,9 @@ - - #include "system.h" - -+#include - #include /* rpmReadPackageFile .. */ -+#include - #include - #include - #include -@@ -10,6 +12,7 @@ - - #include - #include "lib/rpmlead.h" -+#include "lib/rpmts.h" - #include "lib/signature.h" - #include "lib/header_internal.h" - #include "rpmio/rpmio_internal.h" -@@ -51,6 +54,16 @@ rpm_loff_t pad_to(rpm_loff_t pos, rpm_loff_t unit) - return (unit - (pos % unit)) % unit; - } - -+static struct poptOption optionsTable[] = { -+ { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0, -+ N_("Common options for all rpm modes and executables:"), NULL }, -+ -+ POPT_AUTOALIAS -+ POPT_AUTOHELP -+ POPT_TABLEEND -+}; -+ -+ - static int digestor( - FD_t fdi, - FD_t fdo, -@@ -120,7 +133,19 @@ exit: - return rc; - } - --static rpmRC process_package(FD_t fdi, FD_t validationi) -+static rpmRC validator(FD_t fdi){ -+ rpmts ts = rpmtsCreate(); -+ rpmtsSetRootDir(ts, rpmcliRootDir); -+ /* rpmlog prints NOTICE to stdout */ -+ // rpmlogSetFile(stderr); -+ if(rpmcliVerifySignaturesFD(ts, fdi)){ -+ fprintf(stderr, _("Error validating package\n")); -+ return RPMRC_FAIL; -+ } -+ return RPMRC_OK; -+} -+ -+static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - { - uint32_t diglen; - /* GNU C extension: can use diglen from outer context */ -@@ -148,7 +173,7 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - rpm_mode_t mode; - char *rpmio_flags = NULL, *zeros; - const unsigned char *digest; -- rpm_loff_t pos, size, pad, validation_pos; -+ rpm_loff_t pos, size, pad, digest_pos, validation_pos; - uint32_t offset_ix = 0; - size_t len; - int next = 0; -@@ -278,17 +303,26 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - goto exit; - } - } -- validation_pos = ( -+ digest_pos = ( - pos + sizeof(offset_ix) + sizeof(diglen) + - offset_ix * (diglen + sizeof(rpm_loff_t)) - ); - -+ ssize_t digest_len = ufdCopy(digestori, fdo); -+ if (digest_len == -1) { -+ fprintf(stderr, _("digest table ufdCopy failed\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ -+ validation_pos = digest_pos + digest_len; - ssize_t validation_len = ufdCopy(validationi, fdo); - if (validation_len == -1) { -- fprintf(stderr, _("digest table ufdCopy failed\n")); -+ fprintf(stderr, _("validation output ufdCopy failed\n")); - rc = RPMRC_FAIL; - goto exit; - } -+ - /* add more padding so the last file can be cloned. It doesn't matter that - * the table and validation etc are in this space. In fact, it's pretty - * efficient if it is. -@@ -307,11 +341,16 @@ static rpmRC process_package(FD_t fdi, FD_t validationi) - rc = RPMRC_FAIL; - goto exit; - } -- if (Fwrite(&validation_pos, len, 1, fdo) != len) { -+ if (Fwrite(&digest_pos, len, 1, fdo) != len) { - fprintf(stderr, _("Unable to write offset of validation table\n")); - rc = RPMRC_FAIL; - goto exit; - } -+ if (Fwrite(&validation_pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset of validation output\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } - uint64_t magic = MAGIC; - len = sizeof(magic); - if (Fwrite(&magic, len, 1, fdo) != len) { -@@ -327,10 +366,156 @@ exit: - return rc; - } - -+static off_t ufdTee(FD_t sfd, FD_t *fds, int len) -+{ -+ char buf[BUFSIZ]; -+ ssize_t rdbytes, wrbytes; -+ off_t total = 0; -+ -+ while (1) { -+ rdbytes = Fread(buf, sizeof(buf[0]), sizeof(buf), sfd); -+ -+ if (rdbytes > 0) { -+ for(int i=0; i < len; i++) { -+ wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, fds[i]); -+ if (wrbytes != rdbytes) { -+ fprintf(stderr, "Error wriing to FD %d: %s\n", i, Fstrerror(fds[i])); -+ total = -1; -+ break; -+ } -+ } -+ if(total == -1){ -+ break; -+ } -+ total += wrbytes; -+ } else { -+ if (rdbytes < 0) -+ total = -1; -+ break; -+ } -+ } -+ -+ return total; -+} -+ -+static int teeRpm(FD_t fdi, FD_t digestori) { -+ rpmRC rc; -+ off_t offt = -1; -+ int processorpipefd[2]; -+ int validatorpipefd[2]; -+ int rpmsignpipefd[2]; -+ pid_t cpids[2], w; -+ int wstatus; -+ FD_t fds[2]; -+ -+ if (pipe(processorpipefd) == -1) { -+ fprintf(stderr, _("Processor pipe failure\n")); -+ return RPMRC_FAIL; -+ } -+ -+ if (pipe(validatorpipefd) == -1) { -+ fprintf(stderr, _("Validator pipe failure\n")); -+ return RPMRC_FAIL; -+ } -+ -+ if (pipe(rpmsignpipefd) == -1) { -+ fprintf(stderr, _("Validator pipe failure\n")); -+ return RPMRC_FAIL; -+ } -+ -+ cpids[0] = fork(); -+ if (cpids[0] == 0) { -+ /* child: validator */ -+ close(processorpipefd[0]); -+ close(processorpipefd[1]); -+ close(validatorpipefd[1]); -+ close(rpmsignpipefd[0]); -+ FD_t fdi = fdDup(validatorpipefd[0]); -+ // redirect STDOUT to the pipe -+ close(STDOUT_FILENO); -+ FD_t fdo = fdDup(rpmsignpipefd[1]); -+ close(rpmsignpipefd[1]); -+ rc = validator(fdi); -+ if(rc != RPMRC_OK) { -+ fprintf(stderr, _("Validator failed\n")); -+ } -+ Fclose(fdi); -+ Fclose(fdo); -+ if (rc != RPMRC_OK) { -+ exit(EXIT_FAILURE); -+ } -+ exit(EXIT_SUCCESS); -+ } else { -+ /* parent: main program */ -+ cpids[1] = fork(); -+ if (cpids[1] == 0) { -+ /* child: process_package */ -+ close(validatorpipefd[0]); -+ close(validatorpipefd[1]); -+ close(processorpipefd[1]); -+ close(rpmsignpipefd[1]); -+ FD_t fdi = fdDup(processorpipefd[0]); -+ close(processorpipefd[0]); -+ FD_t validatori = fdDup(rpmsignpipefd[0]); -+ close(rpmsignpipefd[0]); -+ -+ rc = process_package(fdi, digestori, validatori); -+ if(rc != RPMRC_OK) { -+ fprintf(stderr, _("Validator failed\n")); -+ } -+ Fclose(digestori); -+ Fclose(validatori); -+ /* fdi is normally closed through the stacked file gzdi in the -+ * function -+ */ -+ -+ if (rc != RPMRC_OK) { -+ exit(EXIT_FAILURE); -+ } -+ exit(EXIT_SUCCESS); -+ -+ -+ } else { -+ /* Actual parent. Read from fdi and write to both processes */ -+ close(processorpipefd[0]); -+ close(validatorpipefd[0]); -+ fds[0] = fdDup(processorpipefd[1]); -+ fds[1] = fdDup(validatorpipefd[1]); -+ close(validatorpipefd[1]); -+ close(processorpipefd[1]); -+ close(rpmsignpipefd[0]); -+ close(rpmsignpipefd[1]); -+ -+ offt = ufdTee(fdi, fds, 2); -+ if(offt == -1){ -+ fprintf(stderr, _("Failed to tee RPM\n")); -+ rc = RPMRC_FAIL; -+ } -+ Fclose(fds[0]); -+ Fclose(fds[1]); -+ w = waitpid(cpids[0], &wstatus, 0); -+ if (w == -1) { -+ fprintf(stderr, _("waitpid cpids[0] failed\n")); -+ rc = RPMRC_FAIL; -+ } -+ w = waitpid(cpids[1], &wstatus, 0); -+ if (w == -1) { -+ fprintf(stderr, _("waitpid cpids[1] failed\n")); -+ rc = RPMRC_FAIL; -+ } -+ } -+ } -+ -+ return rc; -+} -+ - int main(int argc, char *argv[]) { - rpmRC rc; - int cprc = 0; -- uint8_t algos[argc - 1]; -+ poptContext optCon = NULL; -+ const char **args = NULL; -+ int nb_algos = 0; -+ - int mainpipefd[2]; - int metapipefd[2]; - pid_t cpid, w; -@@ -338,29 +523,30 @@ int main(int argc, char *argv[]) { - - xsetprogname(argv[0]); /* Portability call -- see system.h */ - rpmReadConfigFiles(NULL, NULL); -+ optCon = rpmcliInit(argc, argv, optionsTable); -+ poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); - -- if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) { -- fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]); -- exit(EXIT_FAILURE); -- } -- -- if (argc == 1) { -+ if (poptPeekArg(optCon) == NULL) { - fprintf(stderr, - _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")); -+ poptPrintUsage(optCon, stderr, 0); - exit(EXIT_FAILURE); - } - -- for (int x = 0; x < (argc - 1); x++) { -- if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0) -+ args = poptGetArgs(optCon); -+ -+ for (nb_algos=0; args[nb_algos]; nb_algos++); -+ uint8_t algos[nb_algos]; -+ for (int x = 0; x < nb_algos; x++) { -+ if (pgpStringVal(PGPVAL_HASHALGO, args[x], &algos[x]) != 0) - { - fprintf(stderr, - _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -- argv[x + 1]); -+ args[x]); - exit(EXIT_FAILURE); - } - } - -- - if (pipe(mainpipefd) == -1) { - fprintf(stderr, _("Main pipe failure\n")); - exit(EXIT_FAILURE); -@@ -369,6 +555,7 @@ int main(int argc, char *argv[]) { - fprintf(stderr, _("Meta pipe failure\n")); - exit(EXIT_FAILURE); - } -+ - cpid = fork(); - if (cpid == 0) { - /* child: digestor */ -@@ -377,7 +564,7 @@ int main(int argc, char *argv[]) { - FD_t fdi = fdDup(STDIN_FILENO); - FD_t fdo = fdDup(mainpipefd[1]); - FD_t validationo = fdDup(metapipefd[1]); -- rc = digestor(fdi, fdo, validationo, algos, argc - 1); -+ rc = digestor(fdi, fdo, validationo, algos, nb_algos); - Fclose(validationo); - Fclose(fdo); - Fclose(fdi); -@@ -386,12 +573,10 @@ int main(int argc, char *argv[]) { - close(mainpipefd[1]); - close(metapipefd[1]); - FD_t fdi = fdDup(mainpipefd[0]); -- FD_t validationi = fdDup(metapipefd[0]); -- rc = process_package(fdi, validationi); -- Fclose(validationi); -- /* fdi is normally closed through the stacked file gzdi in the -- * function. -- * Wait for child process (digestor for stdin) to complete. -+ FD_t digestori = fdDup(metapipefd[0]); -+ rc = teeRpm(fdi, digestori); -+ Fclose(digestori); -+ /* Wait for child process (digestor for stdin) to complete. - */ - if (rc != RPMRC_OK) { - if (kill(cpid, SIGTERM) != 0) { -@@ -402,7 +587,7 @@ int main(int argc, char *argv[]) { - } - w = waitpid(cpid, &wstatus, 0); - if (w == -1) { -- fprintf(stderr, _("waitpid failed\n")); -+ fprintf(stderr, _("waitpid %d failed %s\n"), cpid, strerror(errno)); - cprc = EXIT_FAILURE; - } else if (WIFEXITED(wstatus)) { - cprc = WEXITSTATUS(wstatus); --- -2.35.1 - diff --git a/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch b/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch deleted file mode 100644 index 07c84fd..0000000 --- a/0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch +++ /dev/null @@ -1,282 +0,0 @@ -From a4755a5ed793ca439bb23b804ba7a8ab080ff110 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Fri, 28 Jan 2022 19:19:45 -0800 -Subject: [PATCH 07/30] [rpm2extents] write RC and output to transcodedfile - metadata - -create a new rpmcliVerifySignaturesFD function which takes a custom callback -that allows collecting a textual output of the validation, similar to what -rpmsign command would give. ---- - lib/rpmchecksig.c | 67 +++++++++++++++++++++++++++++++++++-------- - lib/rpmcli.h | 5 ++-- - rpm2extents.c | 73 +++++++++++++++++++++++++++++++---------------- - 3 files changed, 106 insertions(+), 39 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index 1a6b95323..fcdbb424f 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -260,6 +260,29 @@ exit: - return rc; - } - -+static int rpmpkgVerifySigsFD(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, -+ FD_t fd, rpmsinfoCb cb, void *cbdata) -+{ -+ char *msg = NULL; -+ int rc; -+ struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); -+ -+ rc = rpmpkgRead(vs, fd, NULL, NULL, &msg); -+ -+ if (rc) -+ goto exit; -+ -+ rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata); -+ -+exit: -+ if (rc && msg) -+ rpmlog(RPMLOG_ERR, "%s\n", msg); -+ rpmvsFree(vs); -+ free(msg); -+ return rc; -+} -+ -+ - /* Wrapper around rpmkVerifySigs to preserve API */ - int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn) - { -@@ -305,12 +328,38 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv) - return res; - } - --int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi) -+struct vfydatafd_s { -+ size_t len; -+ char msg[BUFSIZ]; -+}; -+ -+ -+static int vfyFDCb(struct rpmsinfo_s *sinfo, void *cbdata) - { -- int res = 0; -+ struct vfydatafd_s *vd = cbdata; -+ char *vmsg, *msg; -+ size_t n; -+ size_t remainder = BUFSIZ - vd->len; -+ -+ vmsg = rpmsinfoMsg(sinfo); -+ rasprintf(&msg, " %s\n", vmsg); -+ n = rstrlcpy(vd->msg + vd->len, msg, remainder); -+ free(vmsg); -+ free(msg); -+ if(n <= remainder){ -+ vd->len += n; -+ } -+ return 1; -+} -+ -+ -+int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi, char **msg) -+{ -+ rpmRC rc = RPMRC_FAIL; - rpmKeyring keyring = rpmtsGetKeyring(ts, 1); - rpmVSFlags vsflags = rpmtsVfyFlags(ts); - int vfylevel = rpmtsVfyLevel(ts); -+ struct vfydatafd_s vd = {.len = 0}; - - vsflags |= rpmcliVSFlags; - if (rpmcliVfyLevelMask) { -@@ -318,19 +367,13 @@ int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi) - rpmtsSetVfyLevel(ts, vfylevel); - } - -- FD_t fd = fdDup(Fileno(fdi)); -- if (fd == NULL || Ferror(fd)) { -- rpmlog(RPMLOG_ERR, _("fdDup failed: %s\n"), Fstrerror(fd)); -- res++; -- } else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, "stdin")) { -- res++; -+ if (!rpmpkgVerifySigsFD(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) { -+ rc = RPMRC_OK; - } -- -- lseek(Fileno(fd), SEEK_SET, 0); -- Fclose(fd); -+ *msg = strdup(vd.msg); - rpmsqPoll(); - - rpmKeyringFree(keyring); -- return res; -+ return rc; - } - -diff --git a/lib/rpmcli.h b/lib/rpmcli.h -index 52443e459..7ff48b37a 100644 ---- a/lib/rpmcli.h -+++ b/lib/rpmcli.h -@@ -413,12 +413,13 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv); - - - /** \ingroup rpmcli -- * Verify package signatures -+ * Verify package signatures. - * @param ts transaction set - * @param fd a file descriptor to verify -+ * @param msg a string containing textual information about the verification, similar to rpmcliVerifySignatures output. - * @return 0 on success - */ --int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd); -+int rpmcliVerifySignaturesFD(rpmts ts, FD_t fd, char **msg); - - #ifdef __cplusplus - } -diff --git a/rpm2extents.c b/rpm2extents.c -index d8e582676..065a00306 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -133,16 +133,38 @@ exit: - return rc; - } - --static rpmRC validator(FD_t fdi){ -+static rpmRC validator(FD_t fdi, FD_t fdo){ -+ int rc; -+ char *msg = NULL; - rpmts ts = rpmtsCreate(); -+ size_t len; -+ - rpmtsSetRootDir(ts, rpmcliRootDir); -- /* rpmlog prints NOTICE to stdout */ -- // rpmlogSetFile(stderr); -- if(rpmcliVerifySignaturesFD(ts, fdi)){ -+ rc = rpmcliVerifySignaturesFD(ts, fdi, &msg); -+ if(rc){ - fprintf(stderr, _("Error validating package\n")); -- return RPMRC_FAIL; - } -- return RPMRC_OK; -+ len = sizeof(rc); -+ if (Fwrite(&rc, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write validator RC code %d\n"), rc); -+ goto exit; -+ } -+ size_t validator_len = msg ? strlen(msg) : 0; -+ len = sizeof(validator_len); -+ if (Fwrite(&validator_len, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write validator output length code %zd\n"), validator_len); -+ goto exit; -+ } -+ if (Fwrite(msg, validator_len, 1, fdo) != validator_len) { -+ fprintf(stderr, _("Unable to write validator output %s\n"), msg); -+ goto exit; -+ } -+ -+exit: -+ if(msg) { -+ free(msg); -+ } -+ return rc ? RPMRC_FAIL : RPMRC_OK; - } - - static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) -@@ -173,7 +195,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - rpm_mode_t mode; - char *rpmio_flags = NULL, *zeros; - const unsigned char *digest; -- rpm_loff_t pos, size, pad, digest_pos, validation_pos; -+ rpm_loff_t pos, size, pad, digest_pos, validation_pos, digest_table_pos; - uint32_t offset_ix = 0; - size_t len; - int next = 0; -@@ -278,6 +300,16 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - qsort(offsets, (size_t)offset_ix, sizeof(struct digestoffset), - digestoffsetCmp); - -+ validation_pos = pos; -+ ssize_t validation_len = ufdCopy(validationi, fdo); -+ if (validation_len == -1) { -+ fprintf(stderr, _("validation output ufdCopy failed\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ -+ digest_table_pos = validation_pos + validation_len; -+ - len = sizeof(offset_ix); - if (Fwrite(&offset_ix, len, 1, fdo) != len) { - fprintf(stderr, _("Unable to write length of table\n")); -@@ -304,7 +336,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - } - } - digest_pos = ( -- pos + sizeof(offset_ix) + sizeof(diglen) + -+ digest_table_pos + sizeof(offset_ix) + sizeof(diglen) + - offset_ix * (diglen + sizeof(rpm_loff_t)) - ); - -@@ -315,14 +347,6 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - goto exit; - } - -- validation_pos = digest_pos + digest_len; -- ssize_t validation_len = ufdCopy(validationi, fdo); -- if (validation_len == -1) { -- fprintf(stderr, _("validation output ufdCopy failed\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- - /* add more padding so the last file can be cloned. It doesn't matter that - * the table and validation etc are in this space. In fact, it's pretty - * efficient if it is. -@@ -336,18 +360,18 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - goto exit; - } - zeros = _free(zeros); -- if (Fwrite(&pos, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write offset of digest table\n")); -+ if (Fwrite(&validation_pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset of validation output\n")); - rc = RPMRC_FAIL; - goto exit; - } -- if (Fwrite(&digest_pos, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write offset of validation table\n")); -+ if (Fwrite(&digest_table_pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset of digest table\n")); - rc = RPMRC_FAIL; - goto exit; - } -- if (Fwrite(&validation_pos, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write offset of validation output\n")); -+ if (Fwrite(&digest_pos, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write offset of validation table\n")); - rc = RPMRC_FAIL; - goto exit; - } -@@ -431,11 +455,9 @@ static int teeRpm(FD_t fdi, FD_t digestori) { - close(validatorpipefd[1]); - close(rpmsignpipefd[0]); - FD_t fdi = fdDup(validatorpipefd[0]); -- // redirect STDOUT to the pipe -- close(STDOUT_FILENO); - FD_t fdo = fdDup(rpmsignpipefd[1]); - close(rpmsignpipefd[1]); -- rc = validator(fdi); -+ rc = validator(fdi, fdo); - if(rc != RPMRC_OK) { - fprintf(stderr, _("Validator failed\n")); - } -@@ -486,6 +508,7 @@ static int teeRpm(FD_t fdi, FD_t digestori) { - close(rpmsignpipefd[0]); - close(rpmsignpipefd[1]); - -+ rc = RPMRC_OK; - offt = ufdTee(fdi, fds, 2); - if(offt == -1){ - fprintf(stderr, _("Failed to tee RPM\n")); --- -2.35.1 - diff --git a/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch b/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch deleted file mode 100644 index ddbf31d..0000000 --- a/0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch +++ /dev/null @@ -1,116 +0,0 @@ -From c705a6287f8c7fb5e37dad0ac87257731a41fa69 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Sat, 29 Jan 2022 07:00:27 +0000 -Subject: [PATCH 08/30] [rpm2extents] Add script to troubleshoot transcoded - file content This script is essentially dumping the metadata written at the - end of the transcoded files, it will also be used as part of the end-to-end - tests. - ---- - scripts/rpm2extents_dump | 94 ++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 94 insertions(+) - create mode 100755 scripts/rpm2extents_dump - -diff --git a/scripts/rpm2extents_dump b/scripts/rpm2extents_dump -new file mode 100755 -index 000000000..596a59a49 ---- /dev/null -+++ b/scripts/rpm2extents_dump -@@ -0,0 +1,94 @@ -+#!/usr/bin/env python3 -+ -+import argparse -+import binascii -+import os -+import struct -+import sys -+ -+MAGIC_SIZE = 8 -+MAGIC_STR = b'KWTSH100' -+ -+POS_SIZE = 8 -+ -+def keep_position(func): -+ def wrapper(*args, **kwargs): -+ curr = args[0].tell() -+ res = func(*args, **kwargs) -+ f.seek(curr, os.SEEK_SET) -+ return res -+ return wrapper -+ -+def read_validation_digest(f, validation_offset): -+ digests = [] -+ # validation -+ f.seek(validation_offset, os.SEEK_SET) -+ val_content_len, val_digests_num = struct.unpack('=QI', f.read(8+4)) -+ for i in range(val_digests_num): -+ algo_name_len, digest_len = struct.unpack('=II', f.read(8)) -+ algo_name, digest = struct.unpack(f'{algo_name_len}s{digest_len}s', f.read(algo_name_len+digest_len)) -+ digests.append((algo_name, binascii.hexlify(digest))) -+ return digests -+ -+ -+def read_digests_table(f, digest_offset): -+ digests = [] -+ # validation -+ f.seek(digest_offset, os.SEEK_SET) -+ table_len, digest_len = struct.unpack('=II', f.read(8)) -+ -+ for i in range(table_len): -+ digest, pos = struct.unpack(f'{digest_len}sQ', f.read(digest_len + 8)) -+ digests.append((pos, binascii.hexlify(digest))) -+ return digests -+ -+def read_signature_output(f, signature_offset): -+ f.seek(signature_offset, os.SEEK_SET) -+ signature_rc, signature_output_len = struct.unpack('=IQ', f.read(12)) -+ return signature_rc, f.read(signature_output_len) -+ -+@keep_position -+def parse_file(f): -+ digests = [] -+ pos_table_offset = f.seek(-8 - 3*POS_SIZE, os.SEEK_END) -+ signature_offset, digest_offset, validation_offset = struct.unpack('=QQQ', f.read(3*POS_SIZE)) -+ -+ validation_digests = read_validation_digest(f, validation_offset) -+ digests_table = read_digests_table(f, digest_offset) -+ signature_ouput = read_signature_output(f, signature_offset) -+ -+ return validation_digests, digests_table, signature_ouput -+ -+@keep_position -+def is_transcoded(f): -+ f.seek(-MAGIC_SIZE, os.SEEK_END) -+ magic = f.read(MAGIC_SIZE) -+ return magic == MAGIC_STR -+ -+def arg_parse(): -+ parser = argparse.ArgumentParser() -+ parser.add_argument('--dump-signature', action='store_true') -+ parser.add_argument('--dump-file-digest-table', action='store_true') -+ parser.add_argument('--dump-digests', action='store_true') -+ parser.add_argument('file') -+ -+ return parser.parse_args() -+ -+if __name__ == '__main__': -+ args = arg_parse() -+ f = open(args.file, 'rb') -+ if not is_transcoded(f): -+ sys.exit(1) -+ -+ validation_digests, digests_table, signature_output = parse_file(f) -+ if(args.dump_file_digest_table): -+ for digest in digests_table: -+ print(f"FileDigest {hex(digest[0])}: {digest[1]}") -+ -+ if(args.dump_digests): -+ for validation_digest in validation_digests: -+ print(f"HeaderDigest {validation_digest[0]} {validation_digest[1]}") -+ -+ if(args.dump_signature): -+ print(f"RPMSignOutput RC {signature_output[0]}\nRPMSignOutput Content {signature_output[1].decode()}") -+ --- -2.35.1 - diff --git a/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch b/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch deleted file mode 100644 index 150ba8a..0000000 --- a/0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 44b86112136e4804eb606636cbcb4ae847cad773 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Sat, 29 Jan 2022 07:05:18 +0000 -Subject: [PATCH 09/30] [rpm2extents] Add test verifying RC code and signature - validation text - -When transcoding an RPM, the RPM signatures are being validated on the fly and the result from the signature validation is being written at the tail of the transcoded file. -This test check that we get the expected results and is based on the rpmsigdig.at test. ---- - Makefile.am | 2 +- - tests/rpm2extents.at | 33 +++++++++++++++++++++++++++++++++ - 2 files changed, 34 insertions(+), 1 deletion(-) - -diff --git a/Makefile.am b/Makefile.am -index 288668819..96542c8c8 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -203,7 +203,7 @@ bin_PROGRAMS += rpmgraph - rpmgraph_SOURCES = tools/rpmgraph.c - rpmgraph_LDADD = lib/librpm.la rpmio/librpmio.la @WITH_POPT_LIB@ - --dist_bin_SCRIPTS = scripts/gendiff -+dist_bin_SCRIPTS = scripts/gendiff scripts/rpm2extents_dump - - rpmconfig_DATA = rpmrc - rpmrc: $(top_srcdir)/rpmrc.in -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index f943b9af4..baea987e4 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -29,3 +29,36 @@ AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rp - [ignore]) - AT_CLEANUP - -+# Check that tailer writes checksig return code and content. -+# -+AT_SETUP([rpm2extents signature]) -+AT_KEYWORDS([rpm2extents digest signature]) -+AT_CHECK([ -+RPMDB_INIT -+ -+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null -+rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm -+runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub -+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > /tmp/hello-2.0-1.x86_64-signed.rpm -+rpm2extents_dump --dump-signature /tmp/hello-2.0-1.x86_64-signed.rpm -+], -+[0], -+[RPMSignOutput RC 2 -+RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY -+ Header SHA256 digest: OK -+ Header SHA1 digest: OK -+ Payload SHA256 digest: OK -+ V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY -+ MD5 digest: OK -+ -+RPMSignOutput RC 0 -+RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK -+ Header SHA256 digest: OK -+ Header SHA1 digest: OK -+ Payload SHA256 digest: OK -+ V4 RSA/SHA256 Signature, key ID 1964c5fc: OK -+ MD5 digest: OK -+ -+], -+[]) -+AT_CLEANUP --- -2.35.1 - diff --git a/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch b/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch deleted file mode 100644 index ed7e994..0000000 --- a/0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch +++ /dev/null @@ -1,204 +0,0 @@ -From 7da1e826ccb08fdd404524146736b3f12a473e31 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Mon, 31 Jan 2022 14:42:25 -0800 -Subject: [PATCH 10/30] [rpm2extents] Make rpmkeys support reading metadata - from transcoded footer - -If the file is seekable and is a transcoded file, read signature validation from transcoded file tail metadata ---- - lib/rpmchecksig.c | 112 ++++++++++++++++++++++++++++++++++++++++++- - tests/rpm2extents.at | 34 ++++++++++++- - 2 files changed, 144 insertions(+), 2 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index fcdbb424f..6164d012c 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -24,6 +24,11 @@ - - #include "debug.h" - -+/* magic value at end of file (64 bits) that indicates this is a transcoded -+ * rpm. -+ */ -+#define MAGIC 3472329499408095051 -+ - static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen) - { - char const * const pgpmark = "-----BEGIN PGP "; -@@ -220,6 +225,107 @@ exit: - return rc; - } - -+static rpmRC isTranscodedRpm(FD_t fd) { -+ rpmRC rc = RPMRC_NOTFOUND; -+ rpm_loff_t current; -+ uint64_t magic; -+ size_t len; -+ -+ // If the file is not seekable, we cannot detect whether or not it is transcoded. -+ if(Fseek(fd, 0, SEEK_CUR) < 0) { -+ return RPMRC_FAIL; -+ } -+ current = Ftell(fd); -+ -+ if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ len = sizeof(magic); -+ if (Fread(&magic, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ if (magic != MAGIC) { -+ rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n")); -+ rc = RPMRC_NOTFOUND; -+ goto exit; -+ } -+ rc = RPMRC_OK; -+exit: -+ if (Fseek(fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n")); -+ } -+ return rc; -+} -+ -+static int rpmpkgVerifySigsTranscoded(FD_t fd){ -+ rpm_loff_t current; -+ uint64_t magic; -+ rpm_loff_t offset; -+ int32_t rc; -+ size_t len; -+ uint64_t content_len; -+ char *content = NULL; -+ -+ current = Ftell(fd); -+ -+ if(Fseek(fd, -(sizeof(magic) + 3 * sizeof(offset) ), SEEK_END) < 0) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: failed to seek for offset\n")); -+ rc = -1; -+ goto exit; -+ } -+ -+ len = sizeof(offset); -+ if (Fread(&offset, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification offset\n")); -+ rc = -1; -+ goto exit; -+ } -+ -+ if(Fseek(fd, offset, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to seek signature verification offset\n")); -+ rc = -1; -+ goto exit; -+ } -+ len = sizeof(rc); -+ if (Fread(&rc, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification RC\n")); -+ rc = -1; -+ goto exit; -+ } -+ -+ len = sizeof(content_len); -+ if (Fread(&content_len, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content length\n")); -+ goto exit; -+ } -+ -+ content = malloc(content_len + 1); -+ if(content == NULL) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to allocate memory to read signature content\n")); -+ goto exit; -+ } -+ content[content_len] = 0; -+ if (Fread(content, content_len, 1, fd) != content_len) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content\n")); -+ goto exit; -+ } -+ -+ rpmlog(RPMLOG_NOTICE, "%s", content); -+exit: -+ if(content){ -+ free(content); -+ } -+ if (Fseek(fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: unable to seek back to original location\n")); -+ } -+ return rc; -+ -+} -+ - static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, - FD_t fd, const char *fn) - { -@@ -229,10 +335,14 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, - .verbose = rpmIsVerbose(), - }; - int rc; -- struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); - - rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : ""); - -+ if(isTranscodedRpm(fd) == RPMRC_OK){ -+ return rpmpkgVerifySigsTranscoded(fd); -+ } -+ struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); -+ - rc = rpmpkgRead(vs, fd, NULL, NULL, &msg); - - if (rc) -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index baea987e4..18accfc75 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -29,7 +29,7 @@ AT_CHECK([runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rp - [ignore]) - AT_CLEANUP - --# Check that tailer writes checksig return code and content. -+# Check that transcoder writes checksig return code and content. - # - AT_SETUP([rpm2extents signature]) - AT_KEYWORDS([rpm2extents digest signature]) -@@ -62,3 +62,35 @@ RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK - ], - []) - AT_CLEANUP -+ -+AT_SETUP([rpm2extents signature verification]) -+AT_KEYWORDS([rpm2extents digest signature]) -+AT_CHECK([ -+RPMDB_INIT -+ -+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm 2> /dev/null -+runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $? -+runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub -+runroot_other cat /data/RPMS/hello-2.0-1.x86_64-signed.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64-signed.rpm -+runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $? -+], -+[0], -+[/tmp/hello-2.0-1.x86_64-signed.rpm: -+ Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY -+ Header SHA256 digest: OK -+ Header SHA1 digest: OK -+ Payload SHA256 digest: OK -+ V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY -+ MD5 digest: OK -+1 -+/tmp/hello-2.0-1.x86_64-signed.rpm: -+ Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK -+ Header SHA256 digest: OK -+ Header SHA1 digest: OK -+ Payload SHA256 digest: OK -+ V4 RSA/SHA256 Signature, key ID 1964c5fc: OK -+ MD5 digest: OK -+0 -+], -+[]) -+AT_CLEANUP --- -2.35.1 - diff --git a/0011-rpm2extents-Perform-digest-computation-within-the-va.patch b/0011-rpm2extents-Perform-digest-computation-within-the-va.patch deleted file mode 100644 index ea98bed..0000000 --- a/0011-rpm2extents-Perform-digest-computation-within-the-va.patch +++ /dev/null @@ -1,389 +0,0 @@ -From 86776bf17f1644c76fdf8b87042645cf77bd3873 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Wed, 2 Feb 2022 13:34:28 -0800 -Subject: [PATCH 11/30] [rpm2extents] Perform digest computation within the - validator - -The validator calls `rpmcliVerifySignaturesFD` which under the hood -performs `Fread`. Digests are computed/updated for each `Fread`. - -This diffs takes advantage of that by initializing the digest before -calling `rpmcliVerifySignaturesFD`. Once `rpmcliVerifySignaturesFD` as -returned and the file has been read, the digests are available. - -This saves us from spawning a `digestor` process, as well as performing -an extra file read within it. ---- - rpm2extents.c | 234 +++++++++++++++++++++++--------------------------- - 1 file changed, 106 insertions(+), 128 deletions(-) - -diff --git a/rpm2extents.c b/rpm2extents.c -index 065a00306..e316a2834 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -64,38 +64,37 @@ static struct poptOption optionsTable[] = { - }; - - --static int digestor( -+static void FDDigestInit(FD_t fdi, uint8_t algos[], uint32_t algos_len){ -+ int algo; -+ -+ for (algo = 0; algo < algos_len; algo++) { -+ fdInitDigest(fdi, algos[algo], 0); -+ } -+} -+ -+static int FDWriteDigests( - FD_t fdi, - FD_t fdo, -- FD_t validationo, - uint8_t algos[], -- uint32_t algos_len --) -+ uint32_t algos_len) - { -- ssize_t fdilength; - const char *filedigest, *algo_name; - size_t filedigest_len, len; - uint32_t algo_name_len, algo_digest_len; - int algo; - rpmRC rc = RPMRC_FAIL; - -- for (algo = 0; algo < algos_len; algo++) { -- fdInitDigest(fdi, algos[algo], 0); -- } -- fdilength = ufdCopy(fdi, fdo); -- if (fdilength == -1) { -- fprintf(stderr, _("digest cat failed\n")); -- goto exit; -- } -+ ssize_t fdilength = fdOp(fdi, FDSTAT_READ)->bytes; - - len = sizeof(fdilength); -- if (Fwrite(&fdilength, len, 1, validationo) != len) { -+ if (Fwrite(&fdilength, len, 1, fdo) != len) { - fprintf(stderr, _("Unable to write input length %zd\n"), fdilength); - goto exit; - } - len = sizeof(algos_len); -- if (Fwrite(&algos_len, len, 1, validationo) != len) { -- fprintf(stderr, _("Unable to write number of validation digests\n")); -+ if (Fwrite(&algos_len, len, 1, fdo) != len) { -+ algo_digest_len = (uint32_t)filedigest_len; -+ fprintf(stderr, _("Unable to write number of digests\n")); - goto exit; - } - for (algo = 0; algo < algos_len; algo++) { -@@ -106,24 +105,24 @@ static int digestor( - algo_digest_len = (uint32_t)filedigest_len; - - len = sizeof(algo_name_len); -- if (Fwrite(&algo_name_len, len, 1, validationo) != len) { -+ if (Fwrite(&algo_name_len, len, 1, fdo) != len) { - fprintf(stderr, -- _("Unable to write validation algo name length\n")); -+ _("Unable to write digest algo name length\n")); - goto exit; - } - len = sizeof(algo_digest_len); -- if (Fwrite(&algo_digest_len, len, 1, validationo) != len) { -+ if (Fwrite(&algo_digest_len, len, 1, fdo) != len) { - fprintf(stderr, -- _("Unable to write number of bytes for validation digest\n")); -+ _("Unable to write number of bytes for digest\n")); - goto exit; - } -- if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len) { -- fprintf(stderr, _("Unable to write validation algo name\n")); -+ if (Fwrite(algo_name, algo_name_len, 1, fdo) != algo_name_len) { -+ fprintf(stderr, _("Unable to write digest algo name\n")); - goto exit; - } -- if (Fwrite(filedigest, algo_digest_len, 1, validationo ) != algo_digest_len) { -+ if (Fwrite(filedigest, algo_digest_len, 1, fdo ) != algo_digest_len) { - fprintf(stderr, -- _("Unable to write validation digest value %u, %zu\n"), -+ _("Unable to write digest value %u, %zu\n"), - algo_digest_len, filedigest_len); - goto exit; - } -@@ -133,38 +132,66 @@ exit: - return rc; - } - --static rpmRC validator(FD_t fdi, FD_t fdo){ -- int rc; -- char *msg = NULL; -- rpmts ts = rpmtsCreate(); -+static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) { - size_t len; -+ rpmRC rc = RPMRC_FAIL; - -- rpmtsSetRootDir(ts, rpmcliRootDir); -- rc = rpmcliVerifySignaturesFD(ts, fdi, &msg); -- if(rc){ -- fprintf(stderr, _("Error validating package\n")); -+ if(rpmvsrc){ -+ fprintf(stderr, _("Error verifying package signatures\n")); - } -- len = sizeof(rc); -- if (Fwrite(&rc, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write validator RC code %d\n"), rc); -+ -+ len = sizeof(rpmvsrc); -+ if (Fwrite(&rpmvsrc, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write signature verification RC code %d\n"), rpmvsrc); -+ goto exit; -+ } -+ size_t content_len = msg ? strlen(msg) : 0; -+ len = sizeof(content_len); -+ if (Fwrite(&content_len, len, 1, fdo) != len) { -+ fprintf(stderr, _("Unable to write signature verification output length %zd\n"), content_len); - goto exit; - } -- size_t validator_len = msg ? strlen(msg) : 0; -- len = sizeof(validator_len); -- if (Fwrite(&validator_len, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write validator output length code %zd\n"), validator_len); -+ if (Fwrite(msg, content_len, 1, fdo) != content_len) { -+ fprintf(stderr, _("Unable to write signature verification output %s\n"), msg); - goto exit; - } -- if (Fwrite(msg, validator_len, 1, fdo) != validator_len) { -- fprintf(stderr, _("Unable to write validator output %s\n"), msg); -+ -+ rc = RPMRC_OK; -+exit: -+ -+ return rc; -+} -+ -+static rpmRC validator(FD_t fdi, FD_t digesto, FD_t sigo, -+ uint8_t algos[], -+ uint32_t algos_len){ -+ int rpmvsrc; -+ rpmRC rc = RPMRC_FAIL; -+ char *msg = NULL; -+ rpmts ts = rpmtsCreate(); -+ -+ rpmtsSetRootDir(ts, rpmcliRootDir); -+ -+ FDDigestInit(fdi, algos, algos_len); -+ -+ rpmvsrc = rpmcliVerifySignaturesFD(ts, fdi, &msg); -+ -+ // Write result of digest computation -+ if(FDWriteDigests(fdi, digesto, algos, algos_len) != RPMRC_OK) { -+ fprintf(stderr, _("Failed to write digests")); - goto exit; - } - -+ // Write result of signature validation. -+ if(FDWriteSignaturesValidation(sigo, rpmvsrc, msg)) { -+ goto exit; -+ } -+ rc = RPMRC_OK; - exit: - if(msg) { - free(msg); - } -- return rc ? RPMRC_FAIL : RPMRC_OK; -+ return rc; - } - - static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) -@@ -422,12 +449,16 @@ static off_t ufdTee(FD_t sfd, FD_t *fds, int len) - return total; - } - --static int teeRpm(FD_t fdi, FD_t digestori) { -- rpmRC rc; -+static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) { -+ rpmRC rc = RPMRC_FAIL; - off_t offt = -1; -+ // tee-ed stdin - int processorpipefd[2]; - int validatorpipefd[2]; -- int rpmsignpipefd[2]; -+ // metadata -+ int meta_digestpipefd[2]; -+ int meta_rpmsignpipefd[2]; -+ - pid_t cpids[2], w; - int wstatus; - FD_t fds[2]; -@@ -442,8 +473,13 @@ static int teeRpm(FD_t fdi, FD_t digestori) { - return RPMRC_FAIL; - } - -- if (pipe(rpmsignpipefd) == -1) { -- fprintf(stderr, _("Validator pipe failure\n")); -+ if (pipe(meta_digestpipefd) == -1) { -+ fprintf(stderr, _("Meta digest pipe failure\n")); -+ return RPMRC_FAIL; -+ } -+ -+ if (pipe(meta_rpmsignpipefd) == -1) { -+ fprintf(stderr, _("Meta rpm signature pipe failure\n")); - return RPMRC_FAIL; - } - -@@ -453,16 +489,20 @@ static int teeRpm(FD_t fdi, FD_t digestori) { - close(processorpipefd[0]); - close(processorpipefd[1]); - close(validatorpipefd[1]); -- close(rpmsignpipefd[0]); -+ close(meta_digestpipefd[0]); -+ close(meta_rpmsignpipefd[0]); - FD_t fdi = fdDup(validatorpipefd[0]); -- FD_t fdo = fdDup(rpmsignpipefd[1]); -- close(rpmsignpipefd[1]); -- rc = validator(fdi, fdo); -+ FD_t digesto = fdDup(meta_digestpipefd[1]); -+ FD_t sigo = fdDup(meta_rpmsignpipefd[1]); -+ close(meta_digestpipefd[1]); -+ close(meta_rpmsignpipefd[1]); -+ rc = validator(fdi, digesto, sigo, algos, algos_len); - if(rc != RPMRC_OK) { - fprintf(stderr, _("Validator failed\n")); - } - Fclose(fdi); -- Fclose(fdo); -+ Fclose(digesto); -+ Fclose(sigo); - if (rc != RPMRC_OK) { - exit(EXIT_FAILURE); - } -@@ -475,18 +515,21 @@ static int teeRpm(FD_t fdi, FD_t digestori) { - close(validatorpipefd[0]); - close(validatorpipefd[1]); - close(processorpipefd[1]); -- close(rpmsignpipefd[1]); -+ close(meta_digestpipefd[1]); -+ close(meta_rpmsignpipefd[1]); - FD_t fdi = fdDup(processorpipefd[0]); - close(processorpipefd[0]); -- FD_t validatori = fdDup(rpmsignpipefd[0]); -- close(rpmsignpipefd[0]); -+ FD_t sigi = fdDup(meta_rpmsignpipefd[0]); -+ close(meta_rpmsignpipefd[0]); -+ FD_t digestori = fdDup(meta_digestpipefd[0]); -+ close(meta_digestpipefd[0]); - -- rc = process_package(fdi, digestori, validatori); -+ rc = process_package(fdi, digestori, sigi); - if(rc != RPMRC_OK) { - fprintf(stderr, _("Validator failed\n")); - } - Fclose(digestori); -- Fclose(validatori); -+ Fclose(sigi); - /* fdi is normally closed through the stacked file gzdi in the - * function - */ -@@ -505,8 +548,10 @@ static int teeRpm(FD_t fdi, FD_t digestori) { - fds[1] = fdDup(validatorpipefd[1]); - close(validatorpipefd[1]); - close(processorpipefd[1]); -- close(rpmsignpipefd[0]); -- close(rpmsignpipefd[1]); -+ close(meta_digestpipefd[0]); -+ close(meta_digestpipefd[1]); -+ close(meta_rpmsignpipefd[0]); -+ close(meta_rpmsignpipefd[1]); - - rc = RPMRC_OK; - offt = ufdTee(fdi, fds, 2); -@@ -534,16 +579,10 @@ static int teeRpm(FD_t fdi, FD_t digestori) { - - int main(int argc, char *argv[]) { - rpmRC rc; -- int cprc = 0; - poptContext optCon = NULL; - const char **args = NULL; - int nb_algos = 0; - -- int mainpipefd[2]; -- int metapipefd[2]; -- pid_t cpid, w; -- int wstatus; -- - xsetprogname(argv[0]); /* Portability call -- see system.h */ - rpmReadConfigFiles(NULL, NULL); - optCon = rpmcliInit(argc, argv, optionsTable); -@@ -570,69 +609,8 @@ int main(int argc, char *argv[]) { - } - } - -- if (pipe(mainpipefd) == -1) { -- fprintf(stderr, _("Main pipe failure\n")); -- exit(EXIT_FAILURE); -- } -- if (pipe(metapipefd) == -1) { -- fprintf(stderr, _("Meta pipe failure\n")); -- exit(EXIT_FAILURE); -- } -- -- cpid = fork(); -- if (cpid == 0) { -- /* child: digestor */ -- close(mainpipefd[0]); -- close(metapipefd[0]); -- FD_t fdi = fdDup(STDIN_FILENO); -- FD_t fdo = fdDup(mainpipefd[1]); -- FD_t validationo = fdDup(metapipefd[1]); -- rc = digestor(fdi, fdo, validationo, algos, nb_algos); -- Fclose(validationo); -- Fclose(fdo); -- Fclose(fdi); -- } else { -- /* parent: main program */ -- close(mainpipefd[1]); -- close(metapipefd[1]); -- FD_t fdi = fdDup(mainpipefd[0]); -- FD_t digestori = fdDup(metapipefd[0]); -- rc = teeRpm(fdi, digestori); -- Fclose(digestori); -- /* Wait for child process (digestor for stdin) to complete. -- */ -- if (rc != RPMRC_OK) { -- if (kill(cpid, SIGTERM) != 0) { -- fprintf(stderr, -- _("Failed to kill digest process when main process failed: %s\n"), -- strerror(errno)); -- } -- } -- w = waitpid(cpid, &wstatus, 0); -- if (w == -1) { -- fprintf(stderr, _("waitpid %d failed %s\n"), cpid, strerror(errno)); -- cprc = EXIT_FAILURE; -- } else if (WIFEXITED(wstatus)) { -- cprc = WEXITSTATUS(wstatus); -- if (cprc != 0) { -- fprintf(stderr, -- _("Digest process non-zero exit code %d\n"), -- cprc); -- } -- } else if (WIFSIGNALED(wstatus)) { -- fprintf(stderr, -- _("Digest process was terminated with a signal: %d\n"), -- WTERMSIG(wstatus)); -- cprc = EXIT_FAILURE; -- } else { -- /* Don't think this can happen, but covering all bases */ -- fprintf(stderr, _("Unhandled circumstance in waitpid\n")); -- cprc = EXIT_FAILURE; -- } -- if (cprc != EXIT_SUCCESS) { -- rc = RPMRC_FAIL; -- } -- } -+ FD_t fdi = fdDup(STDIN_FILENO); -+ rc = teeRpm(fdi, algos, nb_algos); - if (rc != RPMRC_OK) { - /* translate rpmRC into generic failure return code. */ - return EXIT_FAILURE; --- -2.35.1 - diff --git a/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch b/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch deleted file mode 100644 index 9d19938..0000000 --- a/0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch +++ /dev/null @@ -1,299 +0,0 @@ -From ecab80b80e3917d3acf0f909c9cc84691a207fc0 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Thu, 3 Feb 2022 21:09:05 -0800 -Subject: [PATCH 12/30] [rpmextents] Create an internal library to make - rpmextents file manipulation easier and less duplicated - ---- - lib/Makefile.am | 3 ++- - lib/rpmchecksig.c | 42 +--------------------------------- - lib/rpmextents.c | 46 +++++++++++++++++++++++++++++++++++++ - lib/rpmextents_internal.h | 22 ++++++++++++++++++ - plugins/reflink.c | 48 +++++++++++++-------------------------- - rpm2extents.c | 8 ++----- - 6 files changed, 89 insertions(+), 80 deletions(-) - create mode 100644 lib/rpmextents.c - create mode 100644 lib/rpmextents_internal.h - -diff --git a/lib/Makefile.am b/lib/Makefile.am -index 5a1b6ca9b..2f1b3597f 100644 ---- a/lib/Makefile.am -+++ b/lib/Makefile.am -@@ -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 \ -- rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h -+ rpmtriggers.h rpmtriggers.c rpmvs.c rpmvs.h \ -+ rpmextents.c rpmextents_internal.h - - librpm_la_LDFLAGS = -version-info $(rpm_version_info) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index 6164d012c..dc1726a18 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -20,15 +20,11 @@ - #include "rpmio/rpmio_internal.h" /* fdSetBundle() */ - #include "lib/rpmlead.h" - #include "lib/header_internal.h" -+#include "lib/rpmextents_internal.h" - #include "lib/rpmvs.h" - - #include "debug.h" - --/* magic value at end of file (64 bits) that indicates this is a transcoded -- * rpm. -- */ --#define MAGIC 3472329499408095051 -- - static int doImport(rpmts ts, const char *fn, char *buf, ssize_t blen) - { - char const * const pgpmark = "-----BEGIN PGP "; -@@ -225,42 +221,6 @@ exit: - return rc; - } - --static rpmRC isTranscodedRpm(FD_t fd) { -- rpmRC rc = RPMRC_NOTFOUND; -- rpm_loff_t current; -- uint64_t magic; -- size_t len; -- -- // If the file is not seekable, we cannot detect whether or not it is transcoded. -- if(Fseek(fd, 0, SEEK_CUR) < 0) { -- return RPMRC_FAIL; -- } -- current = Ftell(fd); -- -- if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- len = sizeof(magic); -- if (Fread(&magic, len, 1, fd) != len) { -- rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- if (magic != MAGIC) { -- rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n")); -- rc = RPMRC_NOTFOUND; -- goto exit; -- } -- rc = RPMRC_OK; --exit: -- if (Fseek(fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n")); -- } -- return rc; --} -- - static int rpmpkgVerifySigsTranscoded(FD_t fd){ - rpm_loff_t current; - uint64_t magic; -diff --git a/lib/rpmextents.c b/lib/rpmextents.c -new file mode 100644 -index 000000000..015277751 ---- /dev/null -+++ b/lib/rpmextents.c -@@ -0,0 +1,46 @@ -+ -+#include "system.h" -+ -+#include -+#include -+ -+#include "lib/rpmextents_internal.h" -+ -+rpmRC isTranscodedRpm(FD_t fd) { -+ rpmRC rc = RPMRC_NOTFOUND; -+ rpm_loff_t current; -+ extents_magic_t magic; -+ size_t len; -+ -+ // If the file is not seekable, we cannot detect whether or not it is transcoded. -+ if(Fseek(fd, 0, SEEK_CUR) < 0) { -+ return RPMRC_FAIL; -+ } -+ current = Ftell(fd); -+ -+ if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ len = sizeof(magic); -+ if (Fread(&magic, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ if (magic != EXTENTS_MAGIC) { -+ rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n")); -+ rc = RPMRC_NOTFOUND; -+ goto exit; -+ } -+ rc = RPMRC_OK; -+exit: -+ if (Fseek(fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to seek back to original location\n")); -+ rc = RPMRC_FAIL; -+ } -+ return rc; -+} -+ -+ -diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h -new file mode 100644 -index 000000000..57cecfc31 ---- /dev/null -+++ b/lib/rpmextents_internal.h -@@ -0,0 +1,22 @@ -+#ifndef _RPMEXTENTS_INTERNAL_H -+#define _RPMEXTENTS_INTERNAL_H -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#include -+ -+/* magic value at end of file (64 bits) that indicates this is a transcoded -+ * rpm. -+ */ -+#define EXTENTS_MAGIC 3472329499408095051 -+ -+typedef uint64_t extents_magic_t; -+ -+rpmRC isTranscodedRpm(FD_t fd); -+ -+#ifdef __cplusplus -+} -+#endif -+#endif -diff --git a/plugins/reflink.c b/plugins/reflink.c -index 513887604..ec575f55e 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -13,6 +13,7 @@ - #include - #include "lib/rpmlib.h" - #include "lib/rpmplugin.h" -+#include "lib/rpmextents_internal.h" - #include "lib/rpmte_internal.h" - #include - #include "rpmio/rpmio_internal.h" -@@ -40,11 +41,6 @@ - - #define BUFFER_SIZE (1024 * 128) - --/* magic value at end of file (64 bits) that indicates this is a transcoded -- * rpm. -- */ --#define MAGIC 3472329499408095051 -- - struct reflink_state_s { - /* Stuff that's used across rpms */ - long fundamental_block_size; -@@ -96,40 +92,28 @@ static void reflink_cleanup(rpmPlugin plugin) { - } - - static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { -+ rpmRC rc; -+ size_t len; -+ - reflink_state state = rpmPluginGetData(plugin); - state->fd = rpmteFd(te); - if (state->fd == 0) { - rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n")); - return RPMRC_OK; - } -+ - rpm_loff_t current = Ftell(state->fd); -- uint64_t magic; -- if (Fseek(state->fd, -(sizeof(magic)), SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n")); -- if (Fseek(state->fd, current, SEEK_SET) < 0) { -- /* yes this gets a bit repetitive */ -- rpmlog(RPMLOG_ERR, -- _("reflink: unable to seek back to original location\n")); -- } -- return RPMRC_FAIL; -- } -- size_t len = sizeof(magic); -- if (Fread(&magic, len, 1, state->fd) != len) { -- rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n")); -- if (Fseek(state->fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, -- _("reflink: unable to seek back to original location\n")); -- } -- return RPMRC_FAIL; -- } -- if (magic != MAGIC) { -- rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n")); -- if (Fseek(state->fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, -- _("reflink: unable to seek back to original location\n")); -+ rc = isTranscodedRpm(state->fd); -+ -+ switch(rc){ -+ // Fail to parse the file, fail the plugin. -+ case RPMRC_FAIL: - return RPMRC_FAIL; -- } -- return RPMRC_OK; -+ // This is not a transcoded file, do nothing. -+ case RPMRC_NOTFOUND: -+ return RPMRC_OK; -+ default: -+ break; - } - rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); - Header h = rpmteHeader(te); -@@ -140,7 +124,7 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { - headerFree(h); - state->files = rpmteFiles(te); - /* tail of file contains offset_table, offset_checksums then magic */ -- if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) { -+ if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(extents_magic_t)), SEEK_END) < 0) { - rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), - state->fd); - return RPMRC_FAIL; -diff --git a/rpm2extents.c b/rpm2extents.c -index e316a2834..a326e3857 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -15,6 +15,7 @@ - #include "lib/rpmts.h" - #include "lib/signature.h" - #include "lib/header_internal.h" -+#include "lib/rpmextents_internal.h" - #include "rpmio/rpmio_internal.h" - - #include -@@ -37,11 +38,6 @@ - #include "lib/rpmhash.H" - #include "lib/rpmhash.C" - --/* magic value at end of file (64 bits) that indicates this is a transcoded -- * rpm. -- */ --#define MAGIC 3472329499408095051 -- - struct digestoffset { - const unsigned char * digest; - rpm_loff_t pos; -@@ -402,7 +398,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - rc = RPMRC_FAIL; - goto exit; - } -- uint64_t magic = MAGIC; -+ extents_magic_t magic = EXTENTS_MAGIC; - len = sizeof(magic); - if (Fwrite(&magic, len, 1, fdo) != len) { - fprintf(stderr, _("Unable to write magic\n")); --- -2.35.1 - 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 deleted file mode 100644 index 392e534..0000000 --- a/0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch +++ /dev/null @@ -1,214 +0,0 @@ -From 5c97d7f83f56015d6a37934cee4e55ed8d747890 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 8 Feb 2022 16:57:25 -0800 -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 ++++++++++++++ - 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, - 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, -+ const char* path, -+ mode_t file_mode, rpmFsmOp op); -+ - - typedef struct rpmPluginHooks_s * rpmPluginHooks; - struct rpmPluginHooks_s { -@@ -80,6 +84,7 @@ struct rpmPluginHooks_s { - plugin_fsm_file_pre_func fsm_file_pre; - plugin_fsm_file_post_func fsm_file_post; - plugin_fsm_file_prepare_func fsm_file_prepare; -+ plugin_fsm_file_install_func fsm_file_install; - }; - - #ifdef __cplusplus -diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c -index 3da3097af..850a025a0 100644 ---- a/lib/rpmplugins.c -+++ b/lib/rpmplugins.c -@@ -435,3 +435,40 @@ rpmRC rpmpluginsCallFsmFilePrepare(rpmPlugins plugins, rpmfi fi, - - return rc; - } -+ -+rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, -+ const char *path, mode_t file_mode, -+ rpmFsmOp op) -+{ -+ plugin_fsm_file_install_func hookFunc; -+ int i; -+ rpmRC rc = RPMRC_OK; -+ rpmRC hook_rc; -+ -+ for (i = 0; i < plugins->count; i++) { -+ rpmPlugin plugin = plugins->plugins[i]; -+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_install); -+ if (hookFunc) { -+ hook_rc = hookFunc(plugin, fi, path, file_mode, op); -+ if (hook_rc == RPMRC_FAIL) { -+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_install failed\n", plugin->name); -+ 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. -+ */ -+ rc = RPMRC_FAIL; -+ } else { -+ /* Plugin will handle content */ -+ rc = RPMRC_PLUGIN_CONTENTS; -+ } -+ } -+ } -+ } -+ -+ return rc; -+} -+ -+ -diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h -index 39762c376..5365cf698 100644 ---- a/lib/rpmplugins.h -+++ b/lib/rpmplugins.h -@@ -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 -+ * Call the fsm file install plugin hook -+ * @param plugins plugins structure -+ * @param fi file info iterator (or NULL) -+ * @param path file object path -+ * @param file_mode file object mode -+ * @param op file operation + associated flags -+ * @return RPMRC_OK on success, RPMRC_FAIL otherwise -+ */ -+RPM_GNUC_INTERNAL -+rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, -+ const char* path, mode_t file_mode, -+ rpmFsmOp op); -+ -+ - #ifdef __cplusplus - } - #endif --- -2.35.1 - diff --git a/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch b/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch deleted file mode 100644 index a904670..0000000 --- a/0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch +++ /dev/null @@ -1,89 +0,0 @@ -From ad46eb4132cbd2c4ee23686a1c52f2fc57afffc5 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 8 Feb 2022 17:06:55 -0800 -Subject: [PATCH 14/30] [fsm] Call new `rpmpluginsCallFsmFileInstall` in - `rpmPackageFilesInstall` - -Call `rpmpluginsCallFsmFileInstall` for every files to be installed by -`rpmPackageFilesInstall`, this allows for plugin such as reflink to -write (reflink) a file and make sure the parent directories have already -been created. -If this was done in `rpmpluginsCallFsmFilePre`, the directories may be -missing, which makes file installation fail. ---- - 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 -@@ -55,7 +55,6 @@ struct filedata_s { - int stage; - int setmeta; - int skip; -- int plugin_contents; - rpmFileAction action; - const char *suffix; - char *fpath; -@@ -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); - -- switch (rc) { -- case RPMRC_OK: -- setFileState(fs, fx); -- break; -- case RPMRC_PLUGIN_CONTENTS: -- fp->plugin_contents = 1; -- // reduce reads on cpio to this value. Could be zero if -- // 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; -@@ -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) - 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)){ -+ 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) { -- rc = RPMRC_OK; -- } else { -- rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, -- &firstlink, &firstlinkfile, -- &di.firstdir, &fd); -- } -+ 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) { --- -2.35.1 - diff --git a/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch b/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch deleted file mode 100644 index 8183898..0000000 --- a/0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch +++ /dev/null @@ -1,33 +0,0 @@ -From b2fc576828af873a1993bdaa2fcb7c860b94df3e Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 8 Feb 2022 17:10:23 -0800 -Subject: [PATCH 15/30] [reflink] use reflink_fsm_file_install hook instead of - reflink_fsm_file_pre - ---- - plugins/reflink.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/plugins/reflink.c b/plugins/reflink.c -index ec575f55e..7dda06d8e 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -223,7 +223,7 @@ rpm_loff_t find(const unsigned char *digest, reflink_state state) { - return offset; - } - --static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, -+static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* path, - mode_t file_mode, rpmFsmOp op) - { - struct file_clone_range fcr; -@@ -355,5 +355,5 @@ struct rpmPluginHooks_s reflink_hooks = { - .cleanup = reflink_cleanup, - .psm_pre = reflink_psm_pre, - .psm_post = reflink_psm_post, -- .fsm_file_pre = reflink_fsm_file_pre, -+ .fsm_file_install = reflink_fsm_file_install, - }; --- -2.35.1 - diff --git a/0016-test-new-runroot_plugins-function-to-run-command-in-.patch b/0016-test-new-runroot_plugins-function-to-run-command-in-.patch deleted file mode 100644 index 801de12..0000000 --- a/0016-test-new-runroot_plugins-function-to-run-command-in-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From e04b5d20a6d8c64dba7416edba8e435145a5d7d3 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 8 Feb 2022 17:12:09 -0800 -Subject: [PATCH 16/30] [test] new runroot_plugins function to run command in - fakeroot without having the plugins disabled - ---- - tests/atlocal.in | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/tests/atlocal.in b/tests/atlocal.in -index c3189d327..c18637362 100644 ---- a/tests/atlocal.in -+++ b/tests/atlocal.in -@@ -82,6 +82,15 @@ function runroot() - ) - } - -+function runroot_plugins() -+{ -+ setup_env -+ (unset RPM_CONFIGDIR RPM_POPTEXEC_PATH; cd ${RPMTEST} && \ -+ MAGIC="/magic/magic" FAKECHROOT_BASE="${RPMTEST}" fakechroot "$@" --define "_buildhost testhost" --define "_topdir /build" --nouserns -+ ) -+} -+ -+ - function runroot_other() - { - setup_env --- -2.35.1 - diff --git a/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch b/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch deleted file mode 100644 index 83d3967..0000000 --- a/0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch +++ /dev/null @@ -1,63 +0,0 @@ -From e86207d3395e0963f19363b047551100569900df Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 8 Feb 2022 17:12:55 -0800 -Subject: [PATCH 17/30] [test] Add test installing an RPM with reflink plugin - -The test only runs for reflinkable FS, like XFS and BTRFS. -dbus_announce is being disabled as it generates warning to stderr when -running within the fakeroot. ---- - tests/atlocal.in | 13 +++++++++++++ - tests/rpm2extents.at | 15 +++++++++++++++ - 2 files changed, 28 insertions(+) - -diff --git a/tests/atlocal.in b/tests/atlocal.in -index c18637362..a110564e2 100644 ---- a/tests/atlocal.in -+++ b/tests/atlocal.in -@@ -50,6 +50,19 @@ else - CAP_DISABLED=true; - fi - -+FSTYPE=$(stat -f -c %T /) -+REFLINKABLE_FS=("xfs" "brtfs") -+ -+REFLINK_DISABLED=true; -+for item in "${REFLINKABLE_FS[@]}" -+do -+ if test "${FSTYPE}" = "${item}" -+ then -+ REFLINK_DISABLED=false; -+ break -+ fi -+done -+ - function setup_env() - { - if [ -d testing ]; then -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index 18accfc75..44e46a68e 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -94,3 +94,18 @@ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $? - ], - []) - AT_CLEANUP -+ -+AT_SETUP([rpm2extents install package]) -+AT_KEYWORDS([rpm2extents install package]) -+AT_SKIP_IF([$REFLINK_DISABLED]) -+AT_CHECK([ -+RPMDB_INIT -+ -+runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64.rpm 2> /dev/null -+runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm -+test -f ${RPMTEST}/usr/bin/hello -+], -+[0], -+[], -+[]) -+AT_CLEANUP --- -2.35.1 - diff --git a/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch b/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch deleted file mode 100644 index e5b6ab4..0000000 --- a/0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 048db395b6de8544dc88231f0afebee8570daee6 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 8 Feb 2022 18:21:33 -0800 -Subject: [PATCH 18/30] [plugin] add `rpmpluginsCallFsmFileArchiveReader` - -This allows plugins to provide a custom `rpmfi` to -`rpmPackageFilesInstall` function in fsm.c. It enables supporting -transcoded files such as with reflink plugin. ---- - lib/rpmplugin.h | 4 ++++ - lib/rpmplugins.c | 34 ++++++++++++++++++++++++++++++++++ - lib/rpmplugins.h | 4 +++- - 3 files changed, 41 insertions(+), 1 deletion(-) - -diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h -index 877db81f3..6dbbcff35 100644 ---- a/lib/rpmplugin.h -+++ b/lib/rpmplugin.h -@@ -63,6 +63,9 @@ typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi, - typedef rpmRC (*plugin_fsm_file_install_func)(rpmPlugin plugin, rpmfi fi, - const char* path, - mode_t file_mode, rpmFsmOp op); -+typedef rpmRC (*plugin_fsm_file_archive_reader_func)(rpmPlugin plugin, -+ FD_t payload, -+ rpmfiles files, rpmfi *fi); - - - typedef struct rpmPluginHooks_s * rpmPluginHooks; -@@ -85,6 +88,7 @@ struct rpmPluginHooks_s { - plugin_fsm_file_post_func fsm_file_post; - plugin_fsm_file_prepare_func fsm_file_prepare; - plugin_fsm_file_install_func fsm_file_install; -+ plugin_fsm_file_archive_reader_func fsm_file_archive_reader; - }; - - #ifdef __cplusplus -diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c -index 850a025a0..901af1ac5 100644 ---- a/lib/rpmplugins.c -+++ b/lib/rpmplugins.c -@@ -471,4 +471,38 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, - return rc; - } - -+rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload, -+ rpmfiles files, rpmfi *fi) -+{ -+ plugin_fsm_file_archive_reader_func hookFunc; -+ int i; -+ rpmRC rc = RPMRC_OK; -+ rpmRC hook_rc; -+ -+ for (i = 0; i < plugins->count; i++) { -+ rpmPlugin plugin = plugins->plugins[i]; -+ RPMPLUGINS_SET_HOOK_FUNC(fsm_file_archive_reader); -+ if (hookFunc) { -+ hook_rc = hookFunc(plugin, payload, files, fi); -+ if (hook_rc == RPMRC_FAIL) { -+ rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_archive_reader failed\n", plugin->name); -+ 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. -+ */ -+ rc = RPMRC_FAIL; -+ } else { -+ /* Plugin will handle content */ -+ rc = RPMRC_PLUGIN_CONTENTS; -+ } -+ } -+ } -+ } -+ -+ return rc; -+} -+ - -diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h -index 5365cf698..88807c53c 100644 ---- a/lib/rpmplugins.h -+++ b/lib/rpmplugins.h -@@ -182,7 +182,9 @@ rpmRC rpmpluginsCallFsmFileInstall(rpmPlugins plugins, rpmfi fi, - const char* path, mode_t file_mode, - rpmFsmOp op); - -- -+RPM_GNUC_INTERNAL -+rpmRC rpmpluginsCallFsmFileArchiveReader(rpmPlugins plugins, FD_t payload, -+ rpmfiles files, rpmfi *fi); - #ifdef __cplusplus - } - #endif --- -2.35.1 - diff --git a/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch b/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch deleted file mode 100644 index 211772f..0000000 --- a/0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch +++ /dev/null @@ -1,175 +0,0 @@ -From 5f762af17c6e72e86e4710975dcdfd71fc5d1b07 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 8 Feb 2022 18:24:12 -0800 -Subject: [PATCH 19/30] [reflink] use `rpmpluginsCallFsmFileArchiveReader` to - provide custom rpmfi - -As the plugin can now be responsible to provide an Archive Reader to -`rpmPackageFilesInstall`, we also don't need to mutate the -`RPMTAG_PAYLOADFORMAT` header in memory, removing some special-casing. ---- - lib/depends.c | 2 -- - lib/fsm.c | 48 ++++++++++++++++++++++++++--------------------- - plugins/reflink.c | 18 +++++++++++++----- - 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 -@@ -80,8 +80,6 @@ static rpmRC headerCheckPayloadFormat(Header h) { - */ - if (!payloadfmt) return rc; - -- if (rstreq(payloadfmt, "clon")) return rc; -- - if (!rstreq(payloadfmt, "cpio")) { - char *nevra = headerGetAsString(h, RPMTAG_NEVRA); - if (payloadfmt && rstreq(payloadfmt, "drpm")) { -diff --git a/lib/fsm.c b/lib/fsm.c -index 711f553d3..6972602e0 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -17,7 +17,6 @@ - #include - #include - #include --#include - - #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ - #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; -- -- if (payloadfmt && rstreq(payloadfmt, "clon")) { -- cpio = 0; -- } - - /* transaction id used for temporary path suffix while installing */ - rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts)); -@@ -927,12 +937,9 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - if (rc) - goto exit; - -- if (cpio) { -- fi = fsmIter(payload, files, -- payload ? RPMFI_ITER_READ_ARCHIVE : RPMFI_ITER_FWD, &di); -- } else { -- fi = rpmfilesIter(files, RPMFI_ITER_FWD); -- } -+ 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; - -- 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]; - - 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 -+++ b/plugins/reflink.c -@@ -54,6 +54,7 @@ struct reflink_state_s { - FD_t fd; - rpmfiles files; - inodeIndexHash inodeIndexes; -+ int transcoded; - }; - - typedef struct reflink_state_s * reflink_state; -@@ -116,12 +117,8 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { - break; - } - rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n")); -- Header h = rpmteHeader(te); -+ state->transcoded = 1; - -- /* replace/add header that main fsm.c can read */ -- headerDel(h, RPMTAG_PAYLOADFORMAT); -- headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon"); -- headerFree(h); - state->files = rpmteFiles(te); - /* tail of file contains offset_table, offset_checksums then magic */ - if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(extents_magic_t)), SEEK_END) < 0) { -@@ -350,10 +347,21 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa - return RPMRC_OK; - } - -+static rpmRC reflink_fsm_file_archive_reader(rpmPlugin plugin, FD_t payload, -+ rpmfiles files, rpmfi *fi) { -+ reflink_state state = rpmPluginGetData(plugin); -+ if(state->transcoded) { -+ *fi = rpmfilesIter(files, RPMFI_ITER_FWD); -+ return RPMRC_PLUGIN_CONTENTS; -+ } -+ return RPMRC_OK; -+} -+ - struct rpmPluginHooks_s reflink_hooks = { - .init = reflink_init, - .cleanup = reflink_cleanup, - .psm_pre = reflink_psm_pre, - .psm_post = reflink_psm_post, - .fsm_file_install = reflink_fsm_file_install, -+ .fsm_file_archive_reader = reflink_fsm_file_archive_reader, - }; --- -2.35.1 - diff --git a/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch b/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch deleted file mode 100644 index 24f0711..0000000 --- a/0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 13aea986ada3ed7d26182d81d8878bcc807a6ab5 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Thu, 10 Feb 2022 08:49:17 -0800 -Subject: [PATCH 20/30] [reflink][tests] Can install standard RPM with reflink - -Add a test to validate that if a file is a non-transcoded RPM, the reflink plugin correctly ignores the file and let core RPM do the job. ---- - tests/rpm2extents.at | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index 44e46a68e..648304287 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -109,3 +109,17 @@ test -f ${RPMTEST}/usr/bin/hello - [], - []) - AT_CLEANUP -+ -+AT_SETUP([reflink ignores non-transcoded package]) -+AT_KEYWORDS([reflink]) -+AT_CHECK([ -+RPMDB_INIT -+ -+runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $? -+# Check that the file is properly installed in chroot -+test -f ${RPMTEST}/usr/bin/hello -+], -+[0], -+[], -+[]) -+AT_CLEANUP --- -2.35.1 - diff --git a/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch b/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch deleted file mode 100644 index 250aa6b..0000000 --- a/0021-tests-Fix-tests-AT_KEYWORDS-usage.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 3e363f853a4379e0199db81f777f4b610e158eae Mon Sep 17 00:00:00 2001 -From: chantra -Date: Thu, 10 Feb 2022 08:49:58 -0800 -Subject: [PATCH 21/30] [tests] Fix tests AT_KEYWORDS usage - ---- - tests/rpm2extents.at | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index 648304287..fa124ac03 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -32,7 +32,7 @@ AT_CLEANUP - # Check that transcoder writes checksig return code and content. - # - AT_SETUP([rpm2extents signature]) --AT_KEYWORDS([rpm2extents digest signature]) -+AT_KEYWORDS([rpm2extents]) - AT_CHECK([ - RPMDB_INIT - -@@ -64,7 +64,7 @@ RPMSignOutput Content Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK - AT_CLEANUP - - AT_SETUP([rpm2extents signature verification]) --AT_KEYWORDS([rpm2extents digest signature]) -+AT_KEYWORDS([rpm2extents]) - AT_CHECK([ - RPMDB_INIT - -@@ -96,7 +96,7 @@ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $? - AT_CLEANUP - - AT_SETUP([rpm2extents install package]) --AT_KEYWORDS([rpm2extents install package]) -+AT_KEYWORDS([rpm2extents reflink]) - AT_SKIP_IF([$REFLINK_DISABLED]) - AT_CHECK([ - RPMDB_INIT --- -2.35.1 - diff --git a/0022-reflink-fix-support-for-hardlinks.patch b/0022-reflink-fix-support-for-hardlinks.patch deleted file mode 100644 index e4d6558..0000000 --- a/0022-reflink-fix-support-for-hardlinks.patch +++ /dev/null @@ -1,132 +0,0 @@ -From fd8ffffced543e248847d63e9375fb95584f998d Mon Sep 17 00:00:00 2001 -From: chantra -Date: Fri, 11 Feb 2022 18:09:47 -0800 -Subject: [PATCH 22/30] [reflink] fix support for hardlinks - -a `suffix` made of ";${tid}" is now used until the changes are commited. As such, when -linking the file, we should link to the suffixed file. - -The `suffix` is currently internal only to rpmPackageFilesInstall and there is -no obvious way to use data from struct `filedata_s` without exposing it to -a bunch of other places such as rpmplugin*. -We already keep track of the first file index. We used to use this to fetch the -file name, but due to suffix, the file is not named correctly, e.g it -has the name we will want at the end, once the transaction is commited, -not the temporary name. -Instead of re-implementing a local suffix that may change over time as -the implementation evolves, we can store the name of the file we should link to -in the hash instead of the index, which we were then using to fetch the -file name. -When hardlinking, we can then retrieve the name of the target file -instead of the index, like we previously did, and hardlink to that -without any issues. -Add a test to validate that reflink can handle hardlinking. - -Originally, the test added would fail with: - -``` -error: reflink: Unable to hard link /foo/hello -> /foo/hello-bar;6207219c due to No such file or directory -error: Plugin reflink: hook fsm_file_install failed -error: unpacking of archive failed on file /foo/hello-bar;6207219c: -cpio: (error 0x2) -error: hlinktest-1.0-1.noarch: install failed -./rpm2extents.at:114: exit code was 1, expected 0 -499. rpm2extents.at:112: 499. reflink hardlink package -(rpm2extents.at:112): FAILED (rpm2extents.at:114) -``` - -After this change, the test passes. ---- - plugins/reflink.c | 19 ++++++++----------- - tests/rpm2extents.at | 15 +++++++++++++++ - 2 files changed, 23 insertions(+), 11 deletions(-) - -diff --git a/plugins/reflink.c b/plugins/reflink.c -index d5e6db27a..4fc1d74d1 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -29,7 +29,7 @@ - #undef HTDATATYPE - #define HASHTYPE inodeIndexHash - #define HTKEYTYPE rpm_ino_t --#define HTDATATYPE int -+#define HTDATATYPE const char * - #include "lib/rpmhash.H" - #include "lib/rpmhash.C" - -@@ -163,7 +163,7 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { - return RPMRC_FAIL; - } - state->inodeIndexes = inodeIndexHashCreate( -- state->keys, inodeId, inodeCmp, NULL, NULL -+ state->keys, inodeId, inodeCmp, NULL, (inodeIndexHashFreeData)rfree - ); - } - -@@ -226,7 +226,7 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa - struct file_clone_range fcr; - rpm_loff_t size; - int dst, rc; -- int *hlix; -+ const char **hl_target = NULL; - - reflink_state state = rpmPluginGetData(plugin); - if (state->table == NULL) { -@@ -243,18 +243,15 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa - /* check for hard link entry in table. GetEntry overwrites hlix with - * the address of the first match. - */ -- if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, -- NULL)) { -+ if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hl_target, -+ NULL, NULL)) { - /* entry is in table, use hard link */ -- char *fn = rpmfilesFN(state->files, hlix[0]); -- if (link(fn, path) != 0) { -+ if (link(hl_target[0], path) != 0) { - rpmlog(RPMLOG_ERR, - _("reflink: Unable to hard link %s -> %s due to %s\n"), -- fn, path, strerror(errno)); -- free(fn); -+ hl_target[0], path, strerror(errno)); - return RPMRC_FAIL; - } -- free(fn); - return RPMRC_PLUGIN_CONTENTS; - } - /* if we didn't hard link, then we'll track this inode as being -@@ -262,7 +259,7 @@ 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, rpmfiFX(fi)); -+ inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path)); - } - /* derived from wfd_open in fsm.c */ - mode_t old_umask = umask(0577); -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index fa124ac03..5c66de7f6 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -123,3 +123,18 @@ test -f ${RPMTEST}/usr/bin/hello - [], - []) - AT_CLEANUP -+ -+AT_SETUP([reflink hardlink package]) -+AT_KEYWORDS([reflink hardlink]) -+AT_SKIP_IF([$REFLINK_DISABLED]) -+AT_CHECK([ -+RPMDB_INIT -+ -+PKG=hlinktest-1.0-1.noarch.rpm -+runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null -+runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG} -+], -+[0], -+[], -+[]) -+AT_CLEANUP --- -2.35.1 - diff --git a/0023-rpm2extents-Improve-logging.patch b/0023-rpm2extents-Improve-logging.patch deleted file mode 100644 index 8ac52f7..0000000 --- a/0023-rpm2extents-Improve-logging.patch +++ /dev/null @@ -1,393 +0,0 @@ -From a2c959085250d186c54130b78af076095c3d3cd3 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Tue, 15 Feb 2022 09:11:33 -0800 -Subject: [PATCH 23/30] [rpm2extents] Improve logging - -``` -$ ls -l tests/data/RPMS/hello-2.0-1.x86_64.rpm --rw-r--r--. 1 chantra chantra 9915 Jan 19 09:10 tests/data/RPMS/hello-2.0-1.x86_64.rpm -$ cp tests/data/RPMS/hello-2.0-1.x86_64.rpm ~/trunc-hello-2.0-1.x86_64.rpm -$ truncate -s 9000 ~/trunc-hello-2.0-1.x86_64.rpm -$ ls -l ~/trunc-hello-2.0-1.x86_64.rpm --rw-r--r--. 1 chantra chantra 9000 Feb 15 09:13 /home/chantra/trunc-hello-2.0-1.x86_64.rpm -$ cat ~/trunc-hello-2.0-1.x86_64.rpm| ./rpm2extents SHA256 > /dev/null -error: rpmfiArchiveReadToFile failed while extracting "/usr/bin/hello" with RC -32784: cpio: read failed - Illegal seek -error: Package processor failed: -32784 -error: Unable to write input length 9000: 32, Broken pipe -error: Failed to write digests: 32, Broken pipe -error: Validator failed with RC 2 -``` -Before: -``` -$ cat ~/trunc-hello-2.0-1.x86_64.rpm| ./rpm2extents SHA256 > /dev/null -rpmfiArchiveReadToFile failed with -32784 -Validator failed -Unable to write input length 9000 -Failed to write digestsValidator failed -``` ---- - rpm2extents.c | 120 ++++++++++++++++++++++++++++++-------------------- - 1 file changed, 72 insertions(+), 48 deletions(-) - -diff --git a/rpm2extents.c b/rpm2extents.c -index a326e3857..e1a19fedb 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -84,13 +84,15 @@ static int FDWriteDigests( - - len = sizeof(fdilength); - if (Fwrite(&fdilength, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write input length %zd\n"), fdilength); -+ rpmlog(RPMLOG_ERR, _("Unable to write input length %zd: %d, %s\n"), -+ fdilength, errno, strerror(errno)); - goto exit; - } - len = sizeof(algos_len); - if (Fwrite(&algos_len, len, 1, fdo) != len) { - algo_digest_len = (uint32_t)filedigest_len; -- fprintf(stderr, _("Unable to write number of digests\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write number of digests: %d, %s\n"), -+ errno, strerror(errno)); - goto exit; - } - for (algo = 0; algo < algos_len; algo++) { -@@ -102,24 +104,28 @@ static int FDWriteDigests( - - len = sizeof(algo_name_len); - if (Fwrite(&algo_name_len, len, 1, fdo) != len) { -- fprintf(stderr, -- _("Unable to write digest algo name length\n")); -+ rpmlog(RPMLOG_ERR, -+ _("Unable to write digest algo name length: %d, %s\n"), -+ errno, strerror(errno)); - goto exit; - } - len = sizeof(algo_digest_len); - if (Fwrite(&algo_digest_len, len, 1, fdo) != len) { -- fprintf(stderr, -- _("Unable to write number of bytes for digest\n")); -+ rpmlog(RPMLOG_ERR, -+ _("Unable to write number of bytes for digest: %d, %s\n"), -+ errno, strerror(errno)); - goto exit; - } - if (Fwrite(algo_name, algo_name_len, 1, fdo) != algo_name_len) { -- fprintf(stderr, _("Unable to write digest algo name\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write digest algo name: %d, %s\n"), -+ errno, strerror(errno)); - goto exit; - } - if (Fwrite(filedigest, algo_digest_len, 1, fdo ) != algo_digest_len) { -- fprintf(stderr, -- _("Unable to write digest value %u, %zu\n"), -- algo_digest_len, filedigest_len); -+ rpmlog(RPMLOG_ERR, -+ _("Unable to write digest value %u, %zu: %d, %s\n"), -+ algo_digest_len, filedigest_len, -+ errno, strerror(errno)); - goto exit; - } - } -@@ -133,22 +139,29 @@ static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) { - rpmRC rc = RPMRC_FAIL; - - if(rpmvsrc){ -- fprintf(stderr, _("Error verifying package signatures\n")); -+ rpmlog(RPMLOG_WARNING, -+ _("Error verifying package signatures:\n%s\n"), msg); - } - - len = sizeof(rpmvsrc); - if (Fwrite(&rpmvsrc, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write signature verification RC code %d\n"), rpmvsrc); -+ rpmlog(RPMLOG_ERR, -+ _("Unable to write signature verification RC code %d: %d, %s\n"), -+ rpmvsrc, errno, strerror(errno)); - goto exit; - } - size_t content_len = msg ? strlen(msg) : 0; - len = sizeof(content_len); - if (Fwrite(&content_len, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write signature verification output length %zd\n"), content_len); -+ rpmlog(RPMLOG_ERR, -+ _("Unable to write signature verification output length %zd: %d, %s\n"), -+ content_len, errno, strerror(errno)); - goto exit; - } - if (Fwrite(msg, content_len, 1, fdo) != content_len) { -- fprintf(stderr, _("Unable to write signature verification output %s\n"), msg); -+ rpmlog(RPMLOG_ERR, -+ _("Unable to write signature verification output %s: %d, %s\n"), -+ msg, errno, strerror(errno)); - goto exit; - } - -@@ -174,12 +187,16 @@ static rpmRC validator(FD_t fdi, FD_t digesto, FD_t sigo, - - // Write result of digest computation - if(FDWriteDigests(fdi, digesto, algos, algos_len) != RPMRC_OK) { -- fprintf(stderr, _("Failed to write digests")); -+ rpmlog(RPMLOG_ERR, _("Failed to write digests: %d, %s\n"), -+ errno, strerror(errno)); - goto exit; - } - - // Write result of signature validation. - if(FDWriteSignaturesValidation(sigo, rpmvsrc, msg)) { -+ rpmlog(RPMLOG_ERR, -+ _("Failed to write signature verification result: %d, %s\n"), -+ errno, strerror(errno)); - goto exit; - } - rc = RPMRC_OK; -@@ -226,24 +243,24 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - fdo = fdDup(STDOUT_FILENO); - - if (rpmReadPackageRaw(fdi, &sigh, &h)) { -- fprintf(stderr, _("Error reading package\n")); -+ rpmlog(RPMLOG_ERR, _("Error reading package\n")); - exit(EXIT_FAILURE); - } - - if (rpmLeadWrite(fdo, h)) - { -- fprintf(stderr, _("Unable to write package lead: %s\n"), -+ rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"), - Fstrerror(fdo)); - exit(EXIT_FAILURE); - } - - if (rpmWriteSignature(fdo, sigh)) { -- fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo)); -+ rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"), Fstrerror(fdo)); - exit(EXIT_FAILURE); - } - - if (headerWrite(fdo, h, HEADER_MAGIC_YES)) { -- fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo)); -+ rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"), Fstrerror(fdo)); - exit(EXIT_FAILURE); - } - -@@ -257,7 +274,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - free(rpmio_flags); - - if (gzdi == NULL) { -- fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); -+ rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); - exit(EXIT_FAILURE); - } - -@@ -300,7 +317,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - } - pad = pad_to(pos, fundamental_block_size); - if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -- fprintf(stderr, _("Unable to write padding\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write padding\n")); - rc = RPMRC_FAIL; - goto exit; - } -@@ -313,7 +330,12 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - size = rpmfiFSize(fi); - rc = rpmfiArchiveReadToFile(fi, fdo, 0); - if (rc != RPMRC_OK) { -- fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc); -+ char *errstr = rpmfileStrerror(rc); -+ rpmlog(RPMLOG_ERR, -+ _("rpmfiArchiveReadToFile failed while extracting "\ -+ "\"%s\" with RC %d: %s\n"), -+ rpmfiFN(fi), rc, errstr); -+ free(errstr); - goto exit; - } - pos += size; -@@ -326,7 +348,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - validation_pos = pos; - ssize_t validation_len = ufdCopy(validationi, fdo); - if (validation_len == -1) { -- fprintf(stderr, _("validation output ufdCopy failed\n")); -+ rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n")); - rc = RPMRC_FAIL; - goto exit; - } -@@ -335,25 +357,25 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - - len = sizeof(offset_ix); - if (Fwrite(&offset_ix, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write length of table\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write length of table\n")); - rc = RPMRC_FAIL; - goto exit; - } - len = sizeof(diglen); - if (Fwrite(&diglen, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write length of digest\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n")); - rc = RPMRC_FAIL; - goto exit; - } - len = sizeof(rpm_loff_t); - for (int x = 0; x < offset_ix; x++) { - if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) { -- fprintf(stderr, _("Unable to write digest\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write digest\n")); - rc = RPMRC_FAIL; - goto exit; - } - if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write offset\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write offset\n")); - rc = RPMRC_FAIL; - goto exit; - } -@@ -365,7 +387,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - - ssize_t digest_len = ufdCopy(digestori, fdo); - if (digest_len == -1) { -- fprintf(stderr, _("digest table ufdCopy failed\n")); -+ rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n")); - rc = RPMRC_FAIL; - goto exit; - } -@@ -378,30 +400,30 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - pad = pad_to((validation_pos + validation_len + 2 * sizeof(rpm_loff_t) + - sizeof(uint64_t)), fundamental_block_size); - if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -- fprintf(stderr, _("Unable to write final padding\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write final padding\n")); - rc = RPMRC_FAIL; - goto exit; - } - zeros = _free(zeros); - if (Fwrite(&validation_pos, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write offset of validation output\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write offset of validation output\n")); - rc = RPMRC_FAIL; - goto exit; - } - if (Fwrite(&digest_table_pos, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write offset of digest table\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write offset of digest table\n")); - rc = RPMRC_FAIL; - goto exit; - } - if (Fwrite(&digest_pos, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write offset of validation table\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write offset of validation table\n")); - rc = RPMRC_FAIL; - goto exit; - } - extents_magic_t magic = EXTENTS_MAGIC; - len = sizeof(magic); - if (Fwrite(&magic, len, 1, fdo) != len) { -- fprintf(stderr, _("Unable to write magic\n")); -+ rpmlog(RPMLOG_ERR, _("Unable to write magic\n")); - rc = RPMRC_FAIL; - goto exit; - } -@@ -426,7 +448,9 @@ static off_t ufdTee(FD_t sfd, FD_t *fds, int len) - for(int i=0; i < len; i++) { - wrbytes = Fwrite(buf, sizeof(buf[0]), rdbytes, fds[i]); - if (wrbytes != rdbytes) { -- fprintf(stderr, "Error wriing to FD %d: %s\n", i, Fstrerror(fds[i])); -+ rpmlog(RPMLOG_ERR, -+ _("Error wriing to FD %d: %s\n"), -+ i, Fstrerror(fds[i])); - total = -1; - break; - } -@@ -460,22 +484,22 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) { - FD_t fds[2]; - - if (pipe(processorpipefd) == -1) { -- fprintf(stderr, _("Processor pipe failure\n")); -+ rpmlog(RPMLOG_ERR, _("Processor pipe failure\n")); - return RPMRC_FAIL; - } - - if (pipe(validatorpipefd) == -1) { -- fprintf(stderr, _("Validator pipe failure\n")); -+ rpmlog(RPMLOG_ERR, _("Validator pipe failure\n")); - return RPMRC_FAIL; - } - - if (pipe(meta_digestpipefd) == -1) { -- fprintf(stderr, _("Meta digest pipe failure\n")); -+ rpmlog(RPMLOG_ERR, _("Meta digest pipe failure\n")); - return RPMRC_FAIL; - } - - if (pipe(meta_rpmsignpipefd) == -1) { -- fprintf(stderr, _("Meta rpm signature pipe failure\n")); -+ rpmlog(RPMLOG_ERR, _("Meta rpm signature pipe failure\n")); - return RPMRC_FAIL; - } - -@@ -494,7 +518,7 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) { - close(meta_rpmsignpipefd[1]); - rc = validator(fdi, digesto, sigo, algos, algos_len); - if(rc != RPMRC_OK) { -- fprintf(stderr, _("Validator failed\n")); -+ rpmlog(RPMLOG_ERR, _("Validator failed with RC %d\n"), rc); - } - Fclose(fdi); - Fclose(digesto); -@@ -522,7 +546,7 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) { - - rc = process_package(fdi, digestori, sigi); - if(rc != RPMRC_OK) { -- fprintf(stderr, _("Validator failed\n")); -+ rpmlog(RPMLOG_ERR, _("Package processor failed: %d\n"), rc); - } - Fclose(digestori); - Fclose(sigi); -@@ -552,19 +576,19 @@ static rpmRC teeRpm(FD_t fdi, uint8_t algos[], uint32_t algos_len) { - rc = RPMRC_OK; - offt = ufdTee(fdi, fds, 2); - if(offt == -1){ -- fprintf(stderr, _("Failed to tee RPM\n")); -+ rpmlog(RPMLOG_ERR, _("Failed to tee RPM\n")); - rc = RPMRC_FAIL; - } - Fclose(fds[0]); - Fclose(fds[1]); - w = waitpid(cpids[0], &wstatus, 0); - if (w == -1) { -- fprintf(stderr, _("waitpid cpids[0] failed\n")); -+ rpmlog(RPMLOG_ERR, _("waitpid cpids[0] failed\n")); - rc = RPMRC_FAIL; - } - w = waitpid(cpids[1], &wstatus, 0); - if (w == -1) { -- fprintf(stderr, _("waitpid cpids[1] failed\n")); -+ rpmlog(RPMLOG_ERR, _("waitpid cpids[1] failed\n")); - rc = RPMRC_FAIL; - } - } -@@ -585,8 +609,8 @@ int main(int argc, char *argv[]) { - poptSetOtherOptionHelp(optCon, "[OPTIONS]* "); - - if (poptPeekArg(optCon) == NULL) { -- fprintf(stderr, -- _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")); -+ rpmlog(RPMLOG_ERR, -+ _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")); - poptPrintUsage(optCon, stderr, 0); - exit(EXIT_FAILURE); - } -@@ -598,9 +622,9 @@ int main(int argc, char *argv[]) { - for (int x = 0; x < nb_algos; x++) { - if (pgpStringVal(PGPVAL_HASHALGO, args[x], &algos[x]) != 0) - { -- fprintf(stderr, -- _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -- args[x]); -+ rpmlog(RPMLOG_ERR, -+ _("Unable to resolve '%s' as a digest algorithm, exiting\n"), -+ args[x]); - exit(EXIT_FAILURE); - } - } --- -2.35.1 - diff --git a/0024-rpm2extents-create-footer-struct-and-helpers.patch b/0024-rpm2extents-create-footer-struct-and-helpers.patch deleted file mode 100644 index baabce0..0000000 --- a/0024-rpm2extents-create-footer-struct-and-helpers.patch +++ /dev/null @@ -1,200 +0,0 @@ -From aabaa6c6587c37b84a1b9cfd98bff31f1b69345e Mon Sep 17 00:00:00 2001 -From: chantra -Date: Wed, 16 Feb 2022 17:00:09 -0800 -Subject: [PATCH 24/30] [rpm2extents] create footer struct and helpers - -new extents_footer and extents_footer_offset struct with a function to -load offsets from an FD. -Change existing code to use new struct/functions ---- - lib/rpmchecksig.c | 16 +++------------- - lib/rpmextents.c | 26 +++++++++++++++++--------- - lib/rpmextents_internal.h | 31 ++++++++++++++++++++++++++++++- - rpm2extents.c | 23 ++++------------------- - 4 files changed, 54 insertions(+), 42 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index dc1726a18..729f79f9f 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -223,29 +223,19 @@ exit: - - static int rpmpkgVerifySigsTranscoded(FD_t fd){ - rpm_loff_t current; -- uint64_t magic; -- rpm_loff_t offset; - int32_t rc; - size_t len; - uint64_t content_len; - char *content = NULL; -+ struct extents_footer_t footer; - - current = Ftell(fd); - -- if(Fseek(fd, -(sizeof(magic) + 3 * sizeof(offset) ), SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: failed to seek for offset\n")); -+ if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) { - rc = -1; - goto exit; - } -- -- len = sizeof(offset); -- if (Fread(&offset, len, 1, fd) != len) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification offset\n")); -- rc = -1; -- goto exit; -- } -- -- if(Fseek(fd, offset, SEEK_SET) < 0) { -+ if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) { - rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to seek signature verification offset\n")); - rc = -1; - goto exit; -diff --git a/lib/rpmextents.c b/lib/rpmextents.c -index 015277751..46b7aadff 100644 ---- a/lib/rpmextents.c -+++ b/lib/rpmextents.c -@@ -3,13 +3,16 @@ - - #include - #include -+#include -+#include -+ - - #include "lib/rpmextents_internal.h" - --rpmRC isTranscodedRpm(FD_t fd) { -+rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) { -+ - rpmRC rc = RPMRC_NOTFOUND; - rpm_loff_t current; -- extents_magic_t magic; - size_t len; - - // If the file is not seekable, we cannot detect whether or not it is transcoded. -@@ -18,19 +21,19 @@ rpmRC isTranscodedRpm(FD_t fd) { - } - current = Ftell(fd); - -- if(Fseek(fd, -(sizeof(magic)), SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for magic\n")); -+ len = sizeof(struct extents_footer_t); -+ if(Fseek(fd, -len, SEEK_END) < 0) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for footer: %s\n"), strerror(errno)); - rc = RPMRC_FAIL; - goto exit; - } -- len = sizeof(magic); -- if (Fread(&magic, len, 1, fd) != len) { -- rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read magic\n")); -+ if (Fread(footer, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: unable to read footer\n")); - rc = RPMRC_FAIL; - goto exit; - } -- if (magic != EXTENTS_MAGIC) { -- rpmlog(RPMLOG_DEBUG, _("isTranscodedRpm: not transcoded\n")); -+ if (footer->magic != EXTENTS_MAGIC) { -+ rpmlog(RPMLOG_ERR, _("isTranscodedRpm: not transcoded\n")); - rc = RPMRC_NOTFOUND; - goto exit; - } -@@ -43,4 +46,9 @@ exit: - return rc; - } - -+rpmRC isTranscodedRpm(FD_t fd) { -+ struct extents_footer_t footer; -+ return extentsFooterFromFD(fd, &footer); -+} -+ - -diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h -index 57cecfc31..f0c29c807 100644 ---- a/lib/rpmextents_internal.h -+++ b/lib/rpmextents_internal.h -@@ -7,6 +7,10 @@ extern "C" { - - #include - -+/** \ingroup rpmextents -+ * RPM extents library -+ */ -+ - /* magic value at end of file (64 bits) that indicates this is a transcoded - * rpm. - */ -@@ -14,9 +18,34 @@ extern "C" { - - typedef uint64_t extents_magic_t; - -+struct __attribute__ ((__packed__)) extents_footer_offsets_t { -+ off64_t checksig_offset; -+ off64_t table_offset; -+ off64_t csum_offset; -+}; -+ -+struct __attribute__ ((__packed__)) extents_footer_t { -+ struct extents_footer_offsets_t offsets; -+ extents_magic_t magic; -+}; -+ -+ -+/** \ingroup rpmextents -+ * Read the RPM Extents footer from a file descriptor. -+ * @param fd The FD_t of the transcoded RPM -+ * @param[out] footer A pointer to an allocated extents_footer_t with a copy of the footer. -+ * @return RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure. -+ */ -+rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer); -+ -+/** \ingroup rpmextents -+ * Check if a RPM is a transcoded RPM -+ * @param fd The FD_t of the transcoded RPM -+ * return RPMRC_OK on success, RPMRC_NOTFOUND if not a transcoded file, RPMRC_FAIL on any failure. -+ */ - rpmRC isTranscodedRpm(FD_t fd); - - #ifdef __cplusplus - } - #endif --#endif -+#endif /* _RPMEXTENTS_INTERNAL_H */ -diff --git a/rpm2extents.c b/rpm2extents.c -index e1a19fedb..7dd5128de 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -405,25 +405,10 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - goto exit; - } - zeros = _free(zeros); -- if (Fwrite(&validation_pos, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write offset of validation output\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- if (Fwrite(&digest_table_pos, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write offset of digest table\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- if (Fwrite(&digest_pos, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write offset of validation table\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- extents_magic_t magic = EXTENTS_MAGIC; -- len = sizeof(magic); -- if (Fwrite(&magic, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write magic\n")); -+ struct extents_footer_t footer = {.offsets = {validation_pos, digest_table_pos, digest_pos}, .magic = EXTENTS_MAGIC}; -+ len = sizeof(footer); -+ if (Fwrite(&footer, len, 1, fdo) != len) { -+ rpmlog(RPMLOG_ERR, _("Unable to write footer\n")); - rc = RPMRC_FAIL; - goto exit; - } --- -2.35.1 - diff --git a/0025-extents-move-more-functions-helpers-behind-rpmextent.patch b/0025-extents-move-more-functions-helpers-behind-rpmextent.patch deleted file mode 100644 index 71a54e6..0000000 --- a/0025-extents-move-more-functions-helpers-behind-rpmextent.patch +++ /dev/null @@ -1,176 +0,0 @@ -From 8235711d92d8783abe63d6e4f29afd495fc4b22e Mon Sep 17 00:00:00 2001 -From: chantra -Date: Wed, 16 Feb 2022 23:21:14 -0800 -Subject: [PATCH 25/30] [extents] move more functions/helpers behind - rpmextents_internal.h - ---- - lib/rpmchecksig.c | 58 ++------------------------------------- - lib/rpmextents.c | 56 +++++++++++++++++++++++++++++++++++++ - lib/rpmextents_internal.h | 6 ++++ - 3 files changed, 64 insertions(+), 56 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index 729f79f9f..5e8794e2d 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -221,61 +221,6 @@ exit: - return rc; - } - --static int rpmpkgVerifySigsTranscoded(FD_t fd){ -- rpm_loff_t current; -- int32_t rc; -- size_t len; -- uint64_t content_len; -- char *content = NULL; -- struct extents_footer_t footer; -- -- current = Ftell(fd); -- -- if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) { -- rc = -1; -- goto exit; -- } -- if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to seek signature verification offset\n")); -- rc = -1; -- goto exit; -- } -- len = sizeof(rc); -- if (Fread(&rc, len, 1, fd) != len) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read Signature Verification RC\n")); -- rc = -1; -- goto exit; -- } -- -- len = sizeof(content_len); -- if (Fread(&content_len, len, 1, fd) != len) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content length\n")); -- goto exit; -- } -- -- content = malloc(content_len + 1); -- if(content == NULL) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to allocate memory to read signature content\n")); -- goto exit; -- } -- content[content_len] = 0; -- if (Fread(content, content_len, 1, fd) != content_len) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: Failed to read signature content\n")); -- goto exit; -- } -- -- rpmlog(RPMLOG_NOTICE, "%s", content); --exit: -- if(content){ -- free(content); -- } -- if (Fseek(fd, current, SEEK_SET) < 0) { -- rpmlog(RPMLOG_ERR, _("rpmpkgVerifySigsTranscoded: unable to seek back to original location\n")); -- } -- return rc; -- --} -- - static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, - FD_t fd, const char *fn) - { -@@ -289,8 +234,9 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, - rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : ""); - - if(isTranscodedRpm(fd) == RPMRC_OK){ -- return rpmpkgVerifySigsTranscoded(fd); -+ return extentsVerifySigs(fd); - } -+ - struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); - - rc = rpmpkgRead(vs, fd, NULL, NULL, &msg); -diff --git a/lib/rpmextents.c b/lib/rpmextents.c -index 46b7aadff..f28596f0b 100644 ---- a/lib/rpmextents.c -+++ b/lib/rpmextents.c -@@ -9,6 +9,62 @@ - - #include "lib/rpmextents_internal.h" - -+ -+int extentsVerifySigs(FD_t fd){ -+ rpm_loff_t current; -+ int32_t rc; -+ size_t len; -+ uint64_t content_len; -+ char *content = NULL; -+ struct extents_footer_t footer; -+ -+ current = Ftell(fd); -+ -+ if(extentsFooterFromFD(fd, &footer) != RPMRC_OK) { -+ rc = -1; -+ goto exit; -+ } -+ if(Fseek(fd, footer.offsets.checksig_offset, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to seek signature verification offset\n")); -+ rc = -1; -+ goto exit; -+ } -+ len = sizeof(rc); -+ if (Fread(&rc, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read Signature Verification RC\n")); -+ rc = -1; -+ goto exit; -+ } -+ -+ len = sizeof(content_len); -+ if (Fread(&content_len, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n")); -+ goto exit; -+ } -+ -+ content = rmalloc(content_len + 1); -+ if(content == NULL) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n")); -+ goto exit; -+ } -+ content[content_len] = 0; -+ if (Fread(content, content_len, 1, fd) != content_len) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n")); -+ goto exit; -+ } -+ -+ rpmlog(RPMLOG_NOTICE, "%s", content); -+exit: -+ if(content){ -+ rfree(content); -+ } -+ if (Fseek(fd, current, SEEK_SET) < 0) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: unable to seek back to original location\n")); -+ } -+ return rc; -+ -+} -+ - rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) { - - rpmRC rc = RPMRC_NOTFOUND; -diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h -index f0c29c807..380c08425 100644 ---- a/lib/rpmextents_internal.h -+++ b/lib/rpmextents_internal.h -@@ -29,6 +29,12 @@ struct __attribute__ ((__packed__)) extents_footer_t { - extents_magic_t magic; - }; - -+/** \ingroup rpmextents -+ * Checks the results of the signature verification ran during transcoding. -+ * @param fd The FD_t of the transcoded RPM -+ * @return The number of checks that `rpmvsVerify` failed during transcoding. -+ */ -+int extentsVerifySigs(FD_t fd); - - /** \ingroup rpmextents - * Read the RPM Extents footer from a file descriptor. --- -2.35.1 - diff --git a/0026-fix-integer-underflow-in-vfyFDCb.patch b/0026-fix-integer-underflow-in-vfyFDCb.patch deleted file mode 100644 index 5fe1900..0000000 --- a/0026-fix-integer-underflow-in-vfyFDCb.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 3372e6c917e54b3a84c04ca4274000da04a98e86 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Thu, 17 Feb 2022 08:54:47 -0800 -Subject: [PATCH 26/30] fix integer underflow in vfyFDCb - ---- - lib/rpmchecksig.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index 5e8794e2d..7ad4e7034 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -345,7 +345,7 @@ static int vfyFDCb(struct rpmsinfo_s *sinfo, void *cbdata) - struct vfydatafd_s *vd = cbdata; - char *vmsg, *msg; - size_t n; -- size_t remainder = BUFSIZ - vd->len; -+ size_t remainder = BUFSIZ - vd->len >= 0 ? BUFSIZ - vd->len : 0; - - vmsg = rpmsinfoMsg(sinfo); - rasprintf(&msg, " %s\n", vmsg); --- -2.35.1 - diff --git a/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch b/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch deleted file mode 100644 index 7bb79b2..0000000 --- a/0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch +++ /dev/null @@ -1,169 +0,0 @@ -From 1e0850cf7649578e1d7da815751efaa8101773e7 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Fri, 18 Feb 2022 11:29:06 -0800 -Subject: [PATCH 27/30] [rpmchecksig] Refactor rpmpkgVerifySigs with custom - verify callback - -The current `rpmpkgVerifySigs` was conflating logging and the actual -package verification. - -This change makes it possible to pass the verify callback and its data to -`rpmpkgVerifySigs` so callers can customize how they handle the outcome -of signature verifications. ---- - lib/rpmchecksig.c | 78 ++++++++++++++++++++++------------------------- - lib/rpmextents.c | 1 - - 2 files changed, 36 insertions(+), 43 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index 7ad4e7034..c9fc3bbc9 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -222,16 +222,11 @@ exit: - } - - static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, -- FD_t fd, const char *fn) -+ FD_t fd, rpmsinfoCb cb, void *cbdata) - { - char *msg = NULL; -- struct vfydata_s vd = { .seen = 0, -- .bad = 0, -- .verbose = rpmIsVerbose(), -- }; - int rc; - -- rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd.verbose ? "\n" : ""); - - if(isTranscodedRpm(fd) == RPMRC_OK){ - return extentsVerifySigs(fd); -@@ -244,19 +239,7 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, - if (rc) - goto exit; - -- rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); -- -- if (!vd.verbose) { -- if (vd.seen & RPMSIG_DIGEST_TYPE) { -- rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_DIGEST_TYPE) ? -- _("DIGESTS") : _("digests")); -- } -- if (vd.seen & RPMSIG_SIGNATURE_TYPE) { -- rpmlog(RPMLOG_NOTICE, " %s", (vd.bad & RPMSIG_SIGNATURE_TYPE) ? -- _("SIGNATURES") : _("signatures")); -- } -- rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK")); -- } -+ rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata); - - exit: - if (rc && msg) -@@ -266,38 +249,39 @@ exit: - return rc; - } - --static int rpmpkgVerifySigsFD(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, -- FD_t fd, rpmsinfoCb cb, void *cbdata) --{ -- char *msg = NULL; -- int rc; -- struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); -- -- rc = rpmpkgRead(vs, fd, NULL, NULL, &msg); -- -- if (rc) -- goto exit; -- -- rc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, cb, cbdata); -- --exit: -- if (rc && msg) -- rpmlog(RPMLOG_ERR, "%s\n", msg); -- rpmvsFree(vs); -- free(msg); -- return rc; -+static void rpmkgVerifySigsPreLogging(struct vfydata_s *vd, const char *fn){ -+ rpmlog(RPMLOG_NOTICE, "%s:%s", fn, vd->verbose ? "\n" : ""); - } - -+static void rpmkgVerifySigsPostLogging(struct vfydata_s *vd, int rc){ -+ if (!vd->verbose) { -+ if (vd->seen & RPMSIG_DIGEST_TYPE) { -+ rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_DIGEST_TYPE) ? -+ _("DIGESTS") : _("digests")); -+ } -+ if (vd->seen & RPMSIG_SIGNATURE_TYPE) { -+ rpmlog(RPMLOG_NOTICE, " %s", (vd->bad & RPMSIG_SIGNATURE_TYPE) ? -+ _("SIGNATURES") : _("signatures")); -+ } -+ rpmlog(RPMLOG_NOTICE, " %s\n", rc ? _("NOT OK") : _("OK")); -+ } -+} - - /* Wrapper around rpmkVerifySigs to preserve API */ - int rpmVerifySignatures(QVA_t qva, rpmts ts, FD_t fd, const char * fn) - { - int rc = 1; /* assume failure */ -+ struct vfydata_s vd = { .seen = 0, -+ .bad = 0, -+ .verbose = rpmIsVerbose(), -+ }; - if (ts && qva && fd && fn) { - rpmKeyring keyring = rpmtsGetKeyring(ts, 1); - rpmVSFlags vsflags = rpmtsVfyFlags(ts); - int vfylevel = rpmtsVfyLevel(ts); -- rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, fn); -+ rpmkgVerifySigsPreLogging(&vd, fn); -+ rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, vfyCb, &vd); -+ rpmkgVerifySigsPostLogging(&vd, rc); - rpmKeyringFree(keyring); - } - return rc; -@@ -319,12 +303,22 @@ int rpmcliVerifySignatures(rpmts ts, ARGV_const_t argv) - - while ((arg = *argv++) != NULL) { - FD_t fd = Fopen(arg, "r.ufdio"); -+ struct vfydata_s vd = { .seen = 0, -+ .bad = 0, -+ .verbose = rpmIsVerbose(), -+ }; - if (fd == NULL || Ferror(fd)) { - rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), - arg, Fstrerror(fd)); - res++; -- } else if (rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, arg)) { -+ } else { -+ rpmkgVerifySigsPreLogging(&vd, arg); -+ int rc = rpmpkgVerifySigs(keyring, vfylevel, vsflags, fd, -+ vfyCb, &vd); -+ rpmkgVerifySigsPostLogging(&vd, rc); -+ if (rc) { - res++; -+ } - } - - Fclose(fd); -@@ -373,7 +367,7 @@ int rpmcliVerifySignaturesFD(rpmts ts, FD_t fdi, char **msg) - rpmtsSetVfyLevel(ts, vfylevel); - } - -- if (!rpmpkgVerifySigsFD(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) { -+ if (!rpmpkgVerifySigs(keyring, vfylevel, vsflags, fdi, vfyFDCb, &vd)) { - rc = RPMRC_OK; - } - *msg = strdup(vd.msg); -diff --git a/lib/rpmextents.c b/lib/rpmextents.c -index f28596f0b..59ba427a4 100644 ---- a/lib/rpmextents.c -+++ b/lib/rpmextents.c -@@ -89,7 +89,6 @@ rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) { - goto exit; - } - if (footer->magic != EXTENTS_MAGIC) { -- rpmlog(RPMLOG_ERR, _("isTranscodedRpm: not transcoded\n")); - rc = RPMRC_NOTFOUND; - goto exit; - } --- -2.35.1 - diff --git a/0028-reflink-remove-requirement-for-executable-stack-flag.patch b/0028-reflink-remove-requirement-for-executable-stack-flag.patch deleted file mode 100644 index a3158f6..0000000 --- a/0028-reflink-remove-requirement-for-executable-stack-flag.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 57aa660de4d1b8375cd56f7b8b5fcaf8ad9a5af7 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Fri, 25 Mar 2022 08:13:08 -0700 -Subject: [PATCH 28/30] [reflink] remove requirement for executable stack flag - -reflink was calling `bsearch` with a nested function comparator which -make GCC require the executable stack flag (see `man execstack`). -selinux prevents the use of this flag: -``` -error: Failed to dlopen /usr/lib64/rpm-plugins/reflink.so -/usr/lib64/rpm-plugins/reflink.so: cannot enable executable stack as -shared object requires: Permission denied -``` - -To fix this, either rpm could be granted the correct selinux permission, -but this would open up execstack for more the whole rpm process. -Fundamentally, this is happening because there is no re-entrant version -of `bsearch`. We could probably use a global variable and be done with -it given that each rpm is processed sequencially, but that contract may -not hold true for ever. -Here we are copying stdlib's `bsearch` and making it re-entrant by -allowing to pass an void * data parameter where we can pass the key -size. - -After applying this patch, when reflink.o is installed, it has the executable -flag cleared: -``` -- /usr/lib64/rpm-plugins/reflink.so -``` ---- - plugins/reflink.c | 60 +++++++++++++++++++++++++++++++++++++---------- - 1 file changed, 48 insertions(+), 12 deletions(-) - -diff --git a/plugins/reflink.c b/plugins/reflink.c -index 4fc1d74d1..69e6b51e6 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -59,6 +59,50 @@ struct reflink_state_s { - - 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 * -+bsearch_r (const void *__key, const void *__base, size_t __nmemb, size_t __size, -+ __compar_d_fn_t __compar, void *__arg) -+{ -+ size_t __l, __u, __idx; -+ const void *__p; -+ int __comparison; -+ -+ __l = 0; -+ __u = __nmemb; -+ while (__l < __u) -+ { -+ __idx = (__l + __u) / 2; -+ __p = (const void *) (((const char *) __base) + (__idx * __size)); -+ __comparison = (*__compar) (__key, __p, __arg); -+ if (__comparison < 0) -+ __u = __idx; -+ else if (__comparison > 0) -+ __l = __idx + 1; -+ else -+ { -+#if __GNUC_PREREQ(4, 6) -+# pragma GCC diagnostic push -+# pragma GCC diagnostic ignored "-Wcast-qual" -+#endif -+ return (void *) __p; -+#if __GNUC_PREREQ(4, 6) -+# pragma GCC diagnostic pop -+#endif -+ } -+ } -+ -+ return NULL; -+} -+ -+static int cmpdigest(const void *k1, const void *k2, void *data) { -+ rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2); -+ return memcmp(k1, k2, *(int *)data); -+} -+ - static int inodeCmp(rpm_ino_t a, rpm_ino_t b) - { - return (a != b); -@@ -198,21 +242,13 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res) - rpm_loff_t find(const unsigned char *digest, reflink_state state); - - rpm_loff_t find(const unsigned char *digest, reflink_state state) { --# if defined(__GNUC__) -- /* GCC nested function because bsearch's comparison function can't access -- * state-keysize otherwise -- */ -- int cmpdigest(const void *k1, const void *k2) { -- rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2); -- return memcmp(k1, k2, state->keysize); -- } --# endif - rpmlog(RPMLOG_DEBUG, -- _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"), -+ _("reflink: bsearch_r(key=%p, base=%p, nmemb=%d, size=%lu)\n"), - digest, state->table, state->keys, - state->keysize + sizeof(rpm_loff_t)); -- char *entry = bsearch(digest, state->table, state->keys, -- state->keysize + sizeof(rpm_loff_t), cmpdigest); -+ char *entry = bsearch_r(digest, state->table, state->keys, -+ state->keysize + sizeof(rpm_loff_t), cmpdigest, -+ &state->keysize); - if (entry == NULL) { - return NOT_FOUND; - } --- -2.35.1 - diff --git a/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch b/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch deleted file mode 100644 index f4bf8e3..0000000 --- a/0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 5753b178a08043316e6f3556754741cdd9cd19c5 Mon Sep 17 00:00:00 2001 -From: chantra -Date: Mon, 28 Mar 2022 14:00:13 -0700 -Subject: [PATCH 29/30] [extentsVerifySigs] Make it optional to print the - signature verification output - ---- - lib/rpmchecksig.c | 2 +- - lib/rpmextents.c | 39 ++++++++++++++++++++------------------- - lib/rpmextents_internal.h | 3 ++- - 3 files changed, 23 insertions(+), 21 deletions(-) - -diff --git a/lib/rpmchecksig.c b/lib/rpmchecksig.c -index c9fc3bbc9..7f856154e 100644 ---- a/lib/rpmchecksig.c -+++ b/lib/rpmchecksig.c -@@ -229,7 +229,7 @@ static int rpmpkgVerifySigs(rpmKeyring keyring, int vfylevel, rpmVSFlags flags, - - - if(isTranscodedRpm(fd) == RPMRC_OK){ -- return extentsVerifySigs(fd); -+ return extentsVerifySigs(fd, 1); - } - - struct rpmvs_s *vs = rpmvsCreate(vfylevel, flags, keyring); -diff --git a/lib/rpmextents.c b/lib/rpmextents.c -index 59ba427a4..ac43264af 100644 ---- a/lib/rpmextents.c -+++ b/lib/rpmextents.c -@@ -10,7 +10,7 @@ - #include "lib/rpmextents_internal.h" - - --int extentsVerifySigs(FD_t fd){ -+int extentsVerifySigs(FD_t fd, int print_content){ - rpm_loff_t current; - int32_t rc; - size_t len; -@@ -36,24 +36,26 @@ int extentsVerifySigs(FD_t fd){ - goto exit; - } - -- len = sizeof(content_len); -- if (Fread(&content_len, len, 1, fd) != len) { -- rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n")); -- goto exit; -- } -- -- content = rmalloc(content_len + 1); -- if(content == NULL) { -- rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n")); -- goto exit; -+ if(print_content) { -+ len = sizeof(content_len); -+ if (Fread(&content_len, len, 1, fd) != len) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content length\n")); -+ goto exit; -+ } -+ -+ content = rmalloc(content_len + 1); -+ if(content == NULL) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to allocate memory to read signature content\n")); -+ goto exit; -+ } -+ content[content_len] = 0; -+ if (Fread(content, content_len, 1, fd) != content_len) { -+ rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n")); -+ goto exit; -+ } -+ -+ rpmlog(RPMLOG_NOTICE, "%s", content); - } -- content[content_len] = 0; -- if (Fread(content, content_len, 1, fd) != content_len) { -- rpmlog(RPMLOG_ERR, _("extentsVerifySigs: Failed to read signature content\n")); -- goto exit; -- } -- -- rpmlog(RPMLOG_NOTICE, "%s", content); - exit: - if(content){ - rfree(content); -@@ -79,7 +81,6 @@ rpmRC extentsFooterFromFD(FD_t fd, struct extents_footer_t *footer) { - - len = sizeof(struct extents_footer_t); - if(Fseek(fd, -len, SEEK_END) < 0) { -- rpmlog(RPMLOG_ERR, _("isTranscodedRpm: failed to seek for footer: %s\n"), strerror(errno)); - rc = RPMRC_FAIL; - goto exit; - } -diff --git a/lib/rpmextents_internal.h b/lib/rpmextents_internal.h -index 380c08425..0a3318c8e 100644 ---- a/lib/rpmextents_internal.h -+++ b/lib/rpmextents_internal.h -@@ -32,9 +32,10 @@ struct __attribute__ ((__packed__)) extents_footer_t { - /** \ingroup rpmextents - * Checks the results of the signature verification ran during transcoding. - * @param fd The FD_t of the transcoded RPM -+ * @param print_content Whether or not to print the result from rpmsig - * @return The number of checks that `rpmvsVerify` failed during transcoding. - */ --int extentsVerifySigs(FD_t fd); -+int extentsVerifySigs(FD_t fd, int print_content); - - /** \ingroup rpmextents - * Read the RPM Extents footer from a file descriptor. --- -2.35.1 - diff --git a/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch b/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch deleted file mode 100644 index 4e19a52..0000000 --- a/0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch +++ /dev/null @@ -1,98 +0,0 @@ -From dc53b002bd3d03a21e9af406a9aff5e588710b5b Mon Sep 17 00:00:00 2001 -From: chantra -Date: Mon, 28 Mar 2022 19:42:39 -0700 -Subject: [PATCH 30/30] [rpmcow] Make rpm -i install package without the need - of --nodigest - -When using transcoded files, the logic to check signature is different -and was done while the file was transcoded. This change the code path -used by `rpm -{i,U}` to check if the file is transcoded, and in such -cases, assume it was already verified. ---- - lib/transaction.c | 29 ++++++++++++++++++----------- - tests/rpm2extents.at | 6 +++--- - 2 files changed, 21 insertions(+), 14 deletions(-) - -diff --git a/lib/transaction.c b/lib/transaction.c -index 36c2a7a64..703e4140c 100644 ---- a/lib/transaction.c -+++ b/lib/transaction.c -@@ -37,6 +37,7 @@ - #include "lib/rpmfi_internal.h" /* only internal apis */ - #include "lib/rpmte_internal.h" /* only internal apis */ - #include "lib/rpmts_internal.h" -+#include "lib/rpmextents_internal.h" - #include "lib/rpmvs.h" - #include "rpmio/rpmhook.h" - #include "lib/rpmtriggers.h" -@@ -1286,19 +1287,25 @@ static int verifyPackageFiles(rpmts ts, rpm_loff_t total) - - rpmtsNotify(ts, p, RPMCALLBACK_VERIFY_PROGRESS, oc++, total); - FD_t fd = rpmtsNotify(ts, p, RPMCALLBACK_INST_OPEN_FILE, 0, 0); -- if (fd != NULL) { -- prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg); -- rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0); -+ if(fd != NULL && isTranscodedRpm(fd) == RPMRC_OK) { -+ /* Transcoded RPMs are validated at transcoding time */ -+ prc = RPMRC_OK; -+ verified = 1; -+ } else { -+ if (fd != NULL) { -+ prc = rpmpkgRead(vs, fd, NULL, NULL, &vd.msg); -+ rpmtsNotify(ts, p, RPMCALLBACK_INST_CLOSE_FILE, 0, 0); -+ } -+ if (prc == RPMRC_OK) -+ prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); -+ -+ /* Record verify result */ -+ if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK) -+ verified |= RPMSIG_SIGNATURE_TYPE; -+ if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK) -+ verified |= RPMSIG_DIGEST_TYPE; - } - -- if (prc == RPMRC_OK) -- prc = rpmvsVerify(vs, RPMSIG_VERIFIABLE_TYPE, vfyCb, &vd); -- -- /* Record verify result */ -- if (vd.type[RPMSIG_SIGNATURE_TYPE] == RPMRC_OK) -- verified |= RPMSIG_SIGNATURE_TYPE; -- if (vd.type[RPMSIG_DIGEST_TYPE] == RPMRC_OK) -- verified |= RPMSIG_DIGEST_TYPE; - rpmteSetVerified(p, verified); - - if (prc) -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index 5c66de7f6..5135c9cf8 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -102,7 +102,7 @@ AT_CHECK([ - RPMDB_INIT - - runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64.rpm 2> /dev/null --runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm -+runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm - test -f ${RPMTEST}/usr/bin/hello - ], - [0], -@@ -115,7 +115,7 @@ AT_KEYWORDS([reflink]) - AT_CHECK([ - RPMDB_INIT - --runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $? -+runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /data/RPMS/hello-2.0-1.x86_64.rpm && exit $? - # Check that the file is properly installed in chroot - test -f ${RPMTEST}/usr/bin/hello - ], -@@ -132,7 +132,7 @@ RPMDB_INIT - - PKG=hlinktest-1.0-1.noarch.rpm - runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null --runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG} -+runroot_plugins rpm -i --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG} - ], - [0], - [], --- -2.35.1 - diff --git a/0031-rpmcow-denylist.patch b/0031-rpmcow-denylist.patch deleted file mode 100644 index 676d8be..0000000 --- a/0031-rpmcow-denylist.patch +++ /dev/null @@ -1,395 +0,0 @@ -From: Richard Phibel - -Subject: RPM with Copy on Write: add deny list mechanism - -commit 3431550e6c92ba4bc6d091cb244f70c158dfbbaa -Author: Richard Phibel -Date: Wed Oct 19 23:05:17 2022 +0200 - - RPM with Copy on Write: add deny list mechanism - - A couple of issues were encountered when using RPM CoW for some - packages. This change adds a deny list mechanism to disable RPM CoW for - specific packages. - -Signed-off-by: Richard Phibel ---- - 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 ---- a/build/pack.c -+++ b/build/pack.c -@@ -493,7 +493,7 @@ static rpmRC writeRPM(Package pkg, unsigned char ** pkgidp, - } - - /* Write the lead section into the package. */ -- if (rpmLeadWrite(fd, pkg->header)) { -+ if (rpmLeadWriteFromHeader(fd, pkg->header)) { - rpmlog(RPMLOG_ERR, _("Unable to write package: %s\n"), Fstrerror(fd)); - goto exit; - } -diff --git a/lib/package.c b/lib/package.c -index 90bd0d8a719353e8965c140b40e2dceef80a2ed1..fd41abbf6b4df07afa2caf1c47d9724765ee84e8 100644 ---- a/lib/package.c -+++ b/lib/package.c -@@ -410,11 +410,7 @@ rpmRC rpmReadPackageRaw(FD_t fd, Header * sigp, Header * hdrp) - Header h = NULL; - Header sigh = NULL; - -- rpmRC rc = rpmLeadRead(fd, &msg); -- if (rc != RPMRC_OK) -- goto exit; -- -- rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg); -+ rpmRC rc = hdrblobRead(fd, 1, 0, RPMTAG_HEADERSIGNATURES, sigblob, &msg); - if (rc != RPMRC_OK) - goto exit; - -diff --git a/lib/rpmlead.c b/lib/rpmlead.c -index 45b1c6f8edacb65549ba8d321de8f6ce8cef4503..82105122724a8efb071aecefdb278ef96ea5e70d 100644 ---- a/lib/rpmlead.c -+++ b/lib/rpmlead.c -@@ -24,24 +24,6 @@ static unsigned char const lead_magic[] = { - RPMLEAD_MAGIC0, RPMLEAD_MAGIC1, RPMLEAD_MAGIC2, RPMLEAD_MAGIC3 - }; - --/** \ingroup lead -- * The lead data structure. -- * The lead needs to be 8 byte aligned. -- * @deprecated The lead (except for signature_type) is legacy. -- * @todo Don't use any information from lead. -- */ --struct rpmlead_s { -- unsigned char magic[4]; -- unsigned char major; -- unsigned char minor; -- short type; -- short archnum; -- char name[66]; -- short osnum; -- short signature_type; /*!< Signature header type (RPMSIG_HEADERSIG) */ -- char reserved[16]; /*!< Pad to 96 bytes -- 8 byte aligned! */ --}; -- - static int rpmLeadFromHeader(Header h, struct rpmlead_s *l) - { - if (h != NULL) { -@@ -70,13 +52,23 @@ static int rpmLeadFromHeader(Header h, struct rpmlead_s *l) - } - - /* The lead needs to be 8 byte aligned */ --rpmRC rpmLeadWrite(FD_t fd, Header h) -+rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h) - { - rpmRC rc = RPMRC_FAIL; - struct rpmlead_s l; - -- if (rpmLeadFromHeader(h, &l)) { -- -+ if (rpmLeadFromHeader(h, &l)) { -+ rc = rpmLeadWrite(fd, l); -+ } -+ -+ return rc; -+} -+ -+/* The lead needs to be 8 byte aligned */ -+rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l) -+{ -+ rpmRC rc = RPMRC_FAIL; -+ - l.type = htons(l.type); - l.archnum = htons(l.archnum); - l.osnum = htons(l.osnum); -@@ -84,7 +76,6 @@ rpmRC rpmLeadWrite(FD_t fd, Header h) - - if (Fwrite(&l, 1, sizeof(l), fd) == sizeof(l)) - rc = RPMRC_OK; -- } - - return rc; - } -@@ -107,6 +98,11 @@ static rpmRC rpmLeadCheck(struct rpmlead_s *lead, char **msg) - } - - rpmRC rpmLeadRead(FD_t fd, char **emsg) -+{ -+ return rpmLeadReadAndReturn(fd, emsg, NULL); -+} -+ -+rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret) - { - rpmRC rc = RPMRC_OK; - struct rpmlead_s l; -@@ -136,5 +132,8 @@ rpmRC rpmLeadRead(FD_t fd, char **emsg) - free(err); - } - -+ if (ret) -+ *ret = l; -+ - return rc; - } -diff --git a/lib/rpmlead.h b/lib/rpmlead.h -index 9d86a8d73b3250d3c306b3a3ac4a33486e6920ec..8a592abc1d0e69822f438c4c7b248cce1cb5ee72 100644 ---- a/lib/rpmlead.h -+++ b/lib/rpmlead.h -@@ -19,13 +19,39 @@ extern "C" { - - #define RPMLEAD_SIZE 96 /*!< Don't rely on sizeof(struct) */ - -+/** \ingroup lead -+ * The lead data structure. -+ * The lead needs to be 8 byte aligned. -+ * @deprecated The lead (except for signature_type) is legacy. -+ * @todo Don't use any information from lead. -+ */ -+struct rpmlead_s { -+ unsigned char magic[4]; -+ unsigned char major; -+ unsigned char minor; -+ short type; -+ short archnum; -+ char name[66]; -+ short osnum; -+ short signature_type; /*!< Signature header type (RPMSIG_HEADERSIG) */ -+ char reserved[16]; /*!< Pad to 96 bytes -- 8 byte aligned! */ -+}; -+ - /** \ingroup lead - * Write lead to file handle. - * @param fd file handle - * @param h package header - * @return RPMRC_OK on success, RPMRC_FAIL on error - */ --rpmRC rpmLeadWrite(FD_t fd, Header h); -+rpmRC rpmLeadWriteFromHeader(FD_t fd, Header h); -+ -+/** \ingroup lead -+ * Write lead to file handle. -+ * @param fd file handle -+ * @param l lead -+ * @return RPMRC_OK on success, RPMRC_FAIL on error -+ */ -+rpmRC rpmLeadWrite(FD_t fd, struct rpmlead_s l); - - /** \ingroup lead - * Read lead from file handle. -@@ -35,6 +61,15 @@ rpmRC rpmLeadWrite(FD_t fd, Header h); - */ - rpmRC rpmLeadRead(FD_t fd, char **emsg); - -+/** \ingroup lead -+ * Read lead from file handle and return it. -+ * @param fd file handle -+ * @param[out] emsg failure message on error (malloced) -+ * @param[out] ret address of lead -+ * @return RPMRC_OK on success, RPMRC_FAIL/RPMRC_NOTFOUND on error -+ */ -+rpmRC rpmLeadReadAndReturn(FD_t fd, char **emsg, struct rpmlead_s * ret); -+ - #ifdef __cplusplus - } - #endif -diff --git a/rpm2extents.c b/rpm2extents.c -index 7dd5128decb03781411bd714339b3b6e9b805842..702d3765d76faf618992ca112011d2312d7fcdcc 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -134,6 +134,28 @@ exit: - return rc; - } - -+/** -+ * Check if package is in deny list. -+ * @param package_name package name -+ * @return true if package is in deny list -+ */ -+static inline int isInDenyList(char * package_name) -+{ -+ int is_in_deny_list = 0; -+ if (package_name) { -+ char *e_denylist = getenv("LIBREPO_TRANSCODE_RPMS_DENYLIST"); -+ char *denytlist_item = strtok(e_denylist, ","); -+ while (denytlist_item) { -+ if (strstr(package_name, denytlist_item)) { -+ is_in_deny_list = 1; -+ break; -+ } -+ denytlist_item = strtok(NULL, ","); -+ } -+ } -+ return is_in_deny_list; -+} -+ - static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) { - size_t len; - rpmRC rc = RPMRC_FAIL; -@@ -239,15 +261,41 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - uint32_t offset_ix = 0; - size_t len; - int next = 0; -+ struct rpmlead_s l; -+ rpmfiles files = NULL; -+ rpmfi fi = NULL; -+ char *msg = NULL; - - fdo = fdDup(STDOUT_FILENO); - -+ rc = rpmLeadReadAndReturn(fdi, &msg, &l); -+ if (rc != RPMRC_OK) -+ goto exit; -+ -+ /* Skip conversion if package is in deny list */ -+ if (isInDenyList(l.name)) { -+ if (rpmLeadWrite(fdo, l)) { -+ fprintf(stderr, _("Unable to write package lead: %s\n"), -+ Fstrerror(fdo)); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ -+ ssize_t fdilength = ufdCopy(fdi, fdo); -+ if (fdilength == -1) { -+ fprintf(stderr, _("process_package cat failed\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ -+ goto exit; -+ } else { - if (rpmReadPackageRaw(fdi, &sigh, &h)) { - rpmlog(RPMLOG_ERR, _("Error reading package\n")); - exit(EXIT_FAILURE); - } - -- if (rpmLeadWrite(fdo, h)) -+ if (rpmLeadWriteFromHeader(fdo, h)) - { - rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"), - Fstrerror(fdo)); -@@ -264,38 +312,41 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - exit(EXIT_FAILURE); - } - -- /* Retrieve payload size and compression type. */ -- { -- const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); -- rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); -- } -+ /* Retrieve payload size and compression type. */ -+ { -+ const char *compr = -+ headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); -+ rpmio_flags = -+ rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); -+ } - -- gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ -- free(rpmio_flags); -+ gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ -+ free(rpmio_flags); - - if (gzdi == NULL) { - rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); - exit(EXIT_FAILURE); - } - -- rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); -- rpmfi fi = rpmfiNewArchiveReader(gzdi, files, -- RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST); -+ files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); -+ fi = rpmfiNewArchiveReader(gzdi, files, -+ RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST); - -- /* this is encoded in the file format, so needs to be fixed size (for -- * now?) -- */ -- diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi)); -- digestSet ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, -- NULL); -- struct digestoffset offsets[rpmfiFC(fi)]; -- pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); -+ /* this is encoded in the file format, so needs to be fixed size (for -+ * now?) -+ */ -+ diglen = (uint32_t) rpmDigestLength(rpmfiDigestAlgo(fi)); -+ digestSet ds = -+ digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, -+ NULL); -+ struct digestoffset offsets[rpmfiFC(fi)]; -+ pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); - -- /* main headers are aligned to 8 byte boundry */ -- pos += pad_to(pos, 8); -- pos += headerSizeof(h, HEADER_MAGIC_YES); -+ /* main headers are aligned to 8 byte boundry */ -+ pos += pad_to(pos, 8); -+ pos += headerSizeof(h, HEADER_MAGIC_YES); - -- zeros = xcalloc(fundamental_block_size, 1); -+ zeros = xcalloc(fundamental_block_size, 1); - - while (next >= 0) { - next = rpmfiNext(fi); -@@ -342,8 +393,8 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - } - Fclose(gzdi); /* XXX gzdi == fdi */ - -- qsort(offsets, (size_t)offset_ix, sizeof(struct digestoffset), -- digestoffsetCmp); -+ qsort(offsets, (size_t) offset_ix, sizeof(struct digestoffset), -+ digestoffsetCmp); - - validation_pos = pos; - ssize_t validation_len = ufdCopy(validationi, fdo); -@@ -412,6 +463,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - rc = RPMRC_FAIL; - goto exit; - } -+ } - - exit: - rpmfilesFree(files); -diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c -index b4897f1de444080c8dc6c4913b5f33de20796822..d54e254ff41a0441d04fbcf27f26e4809f563b79 100644 ---- a/sign/rpmgensig.c -+++ b/sign/rpmgensig.c -@@ -610,7 +610,7 @@ static int rpmSign(const char *rpm, int deleting, int flags) - } - - /* Write the lead/signature of the output rpm */ -- rc = rpmLeadWrite(ofd, h); -+ rc = rpmLeadWriteFromHeader(ofd, h); - if (rc != RPMRC_OK) { - rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm, - Fstrerror(ofd)); -diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at -index 5135c9cf83d9e75e9d9bc0b84186ab10cc0cbcac..c9c79c5acd22b86704460f295712ce7ab5ee3259 100644 ---- a/tests/rpm2extents.at -+++ b/tests/rpm2extents.at -@@ -95,6 +95,17 @@ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64-signed.rpm; echo $? - []) - AT_CLEANUP - -+# check that package in denylist is not transcoded -+AT_SETUP([rpm2extents denylist]) -+AT_KEYWORDS([rpm2extents]) -+AT_CHECK([ -+export LIBREPO_TRANSCODE_RPMS_DENYLIST="vim,hello,cowsay" -+runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 | runroot_other cmp /data/RPMS/hello-2.0-1.x86_64.rpm -], -+[0], -+[], -+[ignore]) -+AT_CLEANUP -+ - AT_SETUP([rpm2extents install package]) - AT_KEYWORDS([rpm2extents reflink]) - AT_SKIP_IF([$REFLINK_DISABLED]) diff --git a/0032-rpmcow-workaround.patch b/0032-rpmcow-workaround.patch deleted file mode 100644 index 57e9f44..0000000 --- a/0032-rpmcow-workaround.patch +++ /dev/null @@ -1,386 +0,0 @@ -From: Richard Phibel - -commit 7976c921f60ec5d20c50c4c702ec5636b39210ba -Author: Richard Phibel -Date: Wed Oct 26 18:57:19 2022 +0200 - - RPM with Copy on Write: workaround for corrupt signature header - - Some packages have errors in the signature header. These errors do not - prevent installation of the package but cause issues in rpm2extents - conversion. This commit implements the same fix as in - unloadImmutableRegion. - -Signed-off-by: Richard Phibel ---- - rpm2extents.c | 281 +++++++++++++++++++++++++++----------------------- - 1 file changed, 153 insertions(+), 128 deletions(-) - -diff --git a/rpm2extents.c b/rpm2extents.c -index 702d3765d76faf618992ca112011d2312d7fcdcc..b641511fff884e3c8fb396f28acbd8e2c736e28a 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -139,7 +139,7 @@ exit: - * @param package_name package name - * @return true if package is in deny list - */ --static inline int isInDenyList(char * package_name) -+static inline int isInDenyList(char *package_name) - { - int is_in_deny_list = 0; - if (package_name) { -@@ -153,7 +153,7 @@ static inline int isInDenyList(char * package_name) - denytlist_item = strtok(NULL, ","); - } - } -- return is_in_deny_list; -+ return is_in_deny_list; - } - - static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) { -@@ -229,6 +229,22 @@ exit: - return rc; - } - -+static void sanitizeSignatureHeader(Header * sigh) -+{ -+ struct rpmtd_s td; -+ -+ /* This is inspired by the code in unloadImmutableRegion. See https://github.com/rpm-software-management/rpm/pull/1330 */ -+ if (!headerGet(*sigh, RPMTAG_HEADERSIGNATURES, &td, HEADERGET_DEFAULT)) { -+ /* Signature header corrupt/missing */ -+ rpmlog(RPMLOG_WARNING, _("Error verifying signature header\n")); -+ rpmtdFreeData(&td); -+ Header nh = headerCopy(*sigh); -+ headerFree(*sigh); -+ *sigh = headerLink(nh); -+ headerFree(nh); -+ } -+} -+ - static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - { - uint32_t diglen; -@@ -261,7 +277,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - uint32_t offset_ix = 0; - size_t len; - int next = 0; -- struct rpmlead_s l; -+ struct rpmlead_s l; - rpmfiles files = NULL; - rpmfi fi = NULL; - char *msg = NULL; -@@ -274,43 +290,47 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - - /* Skip conversion if package is in deny list */ - if (isInDenyList(l.name)) { -+ rpmlog(RPMLOG_WARNING, _("package %s is in deny list: conversion skipped\n"), l.name); - if (rpmLeadWrite(fdo, l)) { -- fprintf(stderr, _("Unable to write package lead: %s\n"), -- Fstrerror(fdo)); -+ rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"), -+ Fstrerror(fdo)); - rc = RPMRC_FAIL; - goto exit; - } - - ssize_t fdilength = ufdCopy(fdi, fdo); - if (fdilength == -1) { -- fprintf(stderr, _("process_package cat failed\n")); -+ rpmlog(RPMLOG_ERR, _("process_package cat failed\n")); - rc = RPMRC_FAIL; - goto exit; - } - - goto exit; - } else { -- if (rpmReadPackageRaw(fdi, &sigh, &h)) { -- rpmlog(RPMLOG_ERR, _("Error reading package\n")); -- exit(EXIT_FAILURE); -- } -+ if (rpmReadPackageRaw(fdi, &sigh, &h)) { -+ rpmlog(RPMLOG_ERR, _("Error reading package\n")); -+ exit(EXIT_FAILURE); -+ } - -- if (rpmLeadWriteFromHeader(fdo, h)) -- { -- rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"), -- Fstrerror(fdo)); -- exit(EXIT_FAILURE); -- } -+ sanitizeSignatureHeader(&sigh); - -- if (rpmWriteSignature(fdo, sigh)) { -- rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"), Fstrerror(fdo)); -- exit(EXIT_FAILURE); -- } -+ if (rpmLeadWriteFromHeader(fdo, h)) { -+ rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"), -+ Fstrerror(fdo)); -+ exit(EXIT_FAILURE); -+ } - -- if (headerWrite(fdo, h, HEADER_MAGIC_YES)) { -- rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"), Fstrerror(fdo)); -- exit(EXIT_FAILURE); -- } -+ if (rpmWriteSignature(fdo, sigh)) { -+ rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"), -+ Fstrerror(fdo)); -+ exit(EXIT_FAILURE); -+ } -+ -+ if (headerWrite(fdo, h, HEADER_MAGIC_YES)) { -+ rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"), -+ Fstrerror(fdo)); -+ exit(EXIT_FAILURE); -+ } - - /* Retrieve payload size and compression type. */ - { -@@ -323,10 +343,11 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - gzdi = Fdopen(fdi, rpmio_flags); /* XXX gzdi == fdi */ - free(rpmio_flags); - -- if (gzdi == NULL) { -- rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), Fstrerror(gzdi)); -- exit(EXIT_FAILURE); -- } -+ if (gzdi == NULL) { -+ rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), -+ Fstrerror(gzdi)); -+ exit(EXIT_FAILURE); -+ } - - files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER); - fi = rpmfiNewArchiveReader(gzdi, files, -@@ -348,124 +369,128 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - - zeros = xcalloc(fundamental_block_size, 1); - -- while (next >= 0) { -- next = rpmfiNext(fi); -- if (next == RPMERR_ITER_END) { -- rc = RPMRC_OK; -- break; -+ while (next >= 0) { -+ next = rpmfiNext(fi); -+ if (next == RPMERR_ITER_END) { -+ rc = RPMRC_OK; -+ break; -+ } -+ mode = rpmfiFMode(fi); -+ if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) { -+ /* not a regular file, or the archive doesn't contain any content -+ * for this entry. -+ */ -+ continue; -+ } -+ digest = rpmfiFDigest(fi, NULL, NULL); -+ if (digestSetGetEntry(ds, digest, NULL)) { -+ /* This specific digest has already been included, so skip it. */ -+ continue; -+ } -+ pad = pad_to(pos, fundamental_block_size); -+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -+ rpmlog(RPMLOG_ERR, _("Unable to write padding\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ /* round up to next fundamental_block_size */ -+ pos += pad; -+ digestSetAddEntry(ds, digest); -+ offsets[offset_ix].digest = digest; -+ offsets[offset_ix].pos = pos; -+ offset_ix++; -+ size = rpmfiFSize(fi); -+ rc = rpmfiArchiveReadToFile(fi, fdo, 0); -+ if (rc != RPMRC_OK) { -+ char *errstr = rpmfileStrerror(rc); -+ rpmlog(RPMLOG_ERR, -+ _("rpmfiArchiveReadToFile failed while extracting " -+ "\"%s\" with RC %d: %s\n"), -+ rpmfiFN(fi), rc, errstr); -+ free(errstr); -+ goto exit; -+ } -+ pos += size; - } -- mode = rpmfiFMode(fi); -- if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) { -- /* not a regular file, or the archive doesn't contain any content -- * for this entry. -- */ -- continue; -+ Fclose(gzdi); /* XXX gzdi == fdi */ -+ -+ qsort(offsets, (size_t) offset_ix, sizeof(struct digestoffset), -+ digestoffsetCmp); -+ -+ validation_pos = pos; -+ ssize_t validation_len = ufdCopy(validationi, fdo); -+ if (validation_len == -1) { -+ rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } -- digest = rpmfiFDigest(fi, NULL, NULL); -- if (digestSetGetEntry(ds, digest, NULL)) { -- /* This specific digest has already been included, so skip it. */ -- continue; -+ -+ digest_table_pos = validation_pos + validation_len; -+ -+ len = sizeof(offset_ix); -+ if (Fwrite(&offset_ix, len, 1, fdo) != len) { -+ rpmlog(RPMLOG_ERR, _("Unable to write length of table\n")); -+ rc = RPMRC_FAIL; -+ goto exit; - } -- pad = pad_to(pos, fundamental_block_size); -- if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -- rpmlog(RPMLOG_ERR, _("Unable to write padding\n")); -+ len = sizeof(diglen); -+ if (Fwrite(&diglen, len, 1, fdo) != len) { -+ rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n")); - rc = RPMRC_FAIL; - goto exit; - } -- /* round up to next fundamental_block_size */ -- pos += pad; -- digestSetAddEntry(ds, digest); -- offsets[offset_ix].digest = digest; -- offsets[offset_ix].pos = pos; -- offset_ix++; -- size = rpmfiFSize(fi); -- rc = rpmfiArchiveReadToFile(fi, fdo, 0); -- if (rc != RPMRC_OK) { -- char *errstr = rpmfileStrerror(rc); -- rpmlog(RPMLOG_ERR, -- _("rpmfiArchiveReadToFile failed while extracting "\ -- "\"%s\" with RC %d: %s\n"), -- rpmfiFN(fi), rc, errstr); -- free(errstr); -+ len = sizeof(rpm_loff_t); -+ for (int x = 0; x < offset_ix; x++) { -+ if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) { -+ rpmlog(RPMLOG_ERR, _("Unable to write digest\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) { -+ rpmlog(RPMLOG_ERR, _("Unable to write offset\n")); -+ rc = RPMRC_FAIL; -+ goto exit; -+ } -+ } -+ digest_pos = -+ (digest_table_pos + sizeof(offset_ix) + sizeof(diglen) + -+ offset_ix * (diglen + sizeof(rpm_loff_t)) -+ ); -+ -+ ssize_t digest_len = ufdCopy(digestori, fdo); -+ if (digest_len == -1) { -+ rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n")); -+ rc = RPMRC_FAIL; - goto exit; - } -- pos += size; -- } -- Fclose(gzdi); /* XXX gzdi == fdi */ -- -- qsort(offsets, (size_t) offset_ix, sizeof(struct digestoffset), -- digestoffsetCmp); - -- validation_pos = pos; -- ssize_t validation_len = ufdCopy(validationi, fdo); -- if (validation_len == -1) { -- rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- -- digest_table_pos = validation_pos + validation_len; -+ /* add more padding so the last file can be cloned. It doesn't matter that -+ * the table and validation etc are in this space. In fact, it's pretty -+ * efficient if it is. -+ */ - -- len = sizeof(offset_ix); -- if (Fwrite(&offset_ix, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write length of table\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- len = sizeof(diglen); -- if (Fwrite(&diglen, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- len = sizeof(rpm_loff_t); -- for (int x = 0; x < offset_ix; x++) { -- if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) { -- rpmlog(RPMLOG_ERR, _("Unable to write digest\n")); -+ pad = -+ pad_to((validation_pos + validation_len + -+ 2 * sizeof(rpm_loff_t) + sizeof(uint64_t)), -+ fundamental_block_size); -+ if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -+ rpmlog(RPMLOG_ERR, _("Unable to write final padding\n")); - rc = RPMRC_FAIL; - goto exit; - } -- if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write offset\n")); -+ zeros = _free(zeros); -+ struct extents_footer_t footer = {.offsets = -+ { validation_pos, digest_table_pos, digest_pos },.magic = -+ EXTENTS_MAGIC }; -+ len = sizeof(footer); -+ if (Fwrite(&footer, len, 1, fdo) != len) { -+ rpmlog(RPMLOG_ERR, _("Unable to write footer\n")); - rc = RPMRC_FAIL; - goto exit; - } - } -- digest_pos = ( -- digest_table_pos + sizeof(offset_ix) + sizeof(diglen) + -- offset_ix * (diglen + sizeof(rpm_loff_t)) -- ); -- -- ssize_t digest_len = ufdCopy(digestori, fdo); -- if (digest_len == -1) { -- rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- -- /* add more padding so the last file can be cloned. It doesn't matter that -- * the table and validation etc are in this space. In fact, it's pretty -- * efficient if it is. -- */ - -- pad = pad_to((validation_pos + validation_len + 2 * sizeof(rpm_loff_t) + -- sizeof(uint64_t)), fundamental_block_size); -- if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) { -- rpmlog(RPMLOG_ERR, _("Unable to write final padding\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- zeros = _free(zeros); -- struct extents_footer_t footer = {.offsets = {validation_pos, digest_table_pos, digest_pos}, .magic = EXTENTS_MAGIC}; -- len = sizeof(footer); -- if (Fwrite(&footer, len, 1, fdo) != len) { -- rpmlog(RPMLOG_ERR, _("Unable to write footer\n")); -- rc = RPMRC_FAIL; -- goto exit; -- } -- } -- --exit: -+ exit: - rpmfilesFree(files); - rpmfiFree(fi); - headerFree(h); diff --git a/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch b/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch deleted file mode 100644 index 2ea2066..0000000 --- a/0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 937f9bc67b905851c78719d8397926eaa97b174a Mon Sep 17 00:00:00 2001 -From: Richard Phibel -Date: Mon, 22 May 2023 05:16:51 +0200 -Subject: [PATCH] Fix stack overflow - -Creation of array struct digestoffset offsets[rpmfiFC(fi)] caused a -stack overflow because the total size is greater than 8M which is the -stack size limit on Linux. To fix the issue, the array is allocated on -the heap. - -I used AddressSanitizer to find the root cause of the issue. It found a -number of memory leaks so I fixed them as well. ---- - rpm2extents.c | 15 +++++++++++---- - 1 file changed, 11 insertions(+), 4 deletions(-) - -diff --git a/rpm2extents.c b/rpm2extents.c -index c2a373914..0ee8666fa 100644 ---- a/rpm2extents.c -+++ b/rpm2extents.c -@@ -226,6 +226,7 @@ exit: - if(msg) { - free(msg); - } -+ rpmtsFree(ts); - return rc; - } - -@@ -243,6 +244,7 @@ static void sanitizeSignatureHeader(Header * sigh) - *sigh = headerLink(nh); - headerFree(nh); - } -+ rpmtdFreeData(&td); - } - - static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) -@@ -281,6 +283,8 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - rpmfiles files = NULL; - rpmfi fi = NULL; - char *msg = NULL; -+ struct digestoffset *offsets = NULL; -+ digestSet ds = NULL; - - fdo = fdDup(STDOUT_FILENO); - -@@ -357,10 +361,8 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - * now?) - */ - diglen = (uint32_t) rpmDigestLength(rpmfiDigestAlgo(fi)); -- digestSet ds = -- digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, -- NULL); -- struct digestoffset offsets[rpmfiFC(fi)]; -+ ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp, NULL); -+ offsets = xcalloc(rpmfiFC(fi), sizeof(*offsets)); - pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES); - - /* main headers are aligned to 8 byte boundry */ -@@ -494,6 +496,10 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi) - rpmfilesFree(files); - rpmfiFree(fi); - headerFree(h); -+ headerFree(sigh); -+ free(offsets); -+ Fclose(fdo); -+ digestSetFree(ds); - return rc; - } - -@@ -693,6 +699,7 @@ int main(int argc, char *argv[]) { - - FD_t fdi = fdDup(STDIN_FILENO); - rc = teeRpm(fdi, algos, nb_algos); -+ Fclose(fdi); - if (rc != RPMRC_OK) { - /* translate rpmRC into generic failure return code. */ - return EXIT_FAILURE; --- -2.40.1 - diff --git a/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch b/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch deleted file mode 100644 index 709472d..0000000 --- a/0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch +++ /dev/null @@ -1,28 +0,0 @@ -From a3b6102b4d2e79a8b74b036c6a29272a7f6e5c6a Mon Sep 17 00:00:00 2001 -From: Richard Phibel -Date: Fri, 11 Aug 2023 00:43:21 +0200 -Subject: [PATCH] Fix issue for transaction with transcoded and non-transcoded - packages - -The flag saying whether a package is transcoded is not clean-up between -each packages. Because of that if a non-transcoded package is treated -after a transcoded one, the package is treated as transcoded ---- - plugins/reflink.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/plugins/reflink.c b/plugins/reflink.c -index 986cbd172..20d35eefd 100644 ---- a/plugins/reflink.c -+++ b/plugins/reflink.c -@@ -234,6 +234,7 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res) - inodeIndexHashFree(state->inodeIndexes); - state->inodeIndexes = NULL; - } -+ state->transcoded = 0; - return RPMRC_OK; - } - --- -2.40.1 - diff --git a/0035-rpmcow-fix-segfault-in-rpm2extents.patch b/0035-rpmcow-fix-segfault-in-rpm2extents.patch deleted file mode 100644 index 6ebf722..0000000 --- a/0035-rpmcow-fix-segfault-in-rpm2extents.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/rpm2extents.c 2024-07-03 07:13:36.195332381 -0700 -+++ b/rpm2extents.c 2024-07-03 07:13:43.606553540 -0700 -@@ -269,7 +269,7 @@ - - FD_t fdo; - FD_t gzdi; -- Header h, sigh; -+ Header h=NULL, sigh=NULL; - long fundamental_block_size = sysconf(_SC_PAGESIZE); - rpmRC rc = RPMRC_OK; - rpm_mode_t mode; diff --git a/0036-bsearchr_static.patch b/0036-bsearchr_static.patch deleted file mode 100644 index fe8e8fc..0000000 --- a/0036-bsearchr_static.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- 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 deleted file mode 100644 index 3ba625f..0000000 --- a/0037-plugin_path.patch +++ /dev/null @@ -1,35 +0,0 @@ ---- 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/0038-reflink-set-metadata-for-hardlinked-files.patch b/0038-reflink-set-metadata-for-hardlinked-files.patch deleted file mode 100644 index 1b7c595..0000000 --- a/0038-reflink-set-metadata-for-hardlinked-files.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 3310d203e0aa162428c7b9dc1e9d8e09da768608 Mon Sep 17 00:00:00 2001 -From: Matteo Croce -Date: Sat, 14 Sep 2024 09:32:48 -0700 -Subject: [PATCH] reflink: set metadata for hardlinked files - -RPM deduplicates identical files by creating them as hardlinks. -Since metadata is shared between copies, permissions are set when -extracting the last copy. -This breaks reflinks, where each copy has its own metadata. -Fix it by always set metadata when the file content is handled by a plugin. ---- - lib/fsm.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/fsm.c b/lib/fsm.c -index 05c5bcf..e562220 100644 ---- a/lib/fsm.c -+++ b/lib/fsm.c -@@ -1010,6 +1010,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files, - rc = plugin_rc; - } else if(plugin_rc == RPMRC_PLUGIN_CONTENTS){ - rc = RPMRC_OK; -+ /* The reflink plugins handles hardlink differently, metadata has to be set. */ -+ fp->setmeta = 1; - } else if (S_ISREG(fp->sb.st_mode)) { - if (rc == RPMERR_ENOENT) { - rc = fsmMkfile(di.dirfd, fi, fp, files, psm, nodigest, --- -2.43.5 - diff --git a/rpm.spec b/rpm.spec index 66496fc..372ddfd 100644 --- a/rpm.spec +++ b/rpm.spec @@ -149,43 +149,6 @@ Patch2000: rpm-4.16.1.3-backport-multithreaded-zstd.patch # Copy-on-Write Patch9901: 0001-RPM-with-Copy-on-Write.patch -Patch9902: 0002-Remove-use-of-bool-type-for-consistency.patch -Patch9903: 0003-Match-formatting-style-of-existing-code.patch -Patch9904: 0004-Fix-printf-formatting-in-reflink.c.patch -Patch9905: 0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch -Patch9906: 0006-rpm2extents-verify-package-signature-during-transcod.patch -Patch9907: 0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch -Patch9908: 0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch -Patch9909: 0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch -Patch9910: 0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch -Patch9911: 0011-rpm2extents-Perform-digest-computation-within-the-va.patch -Patch9912: 0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch -Patch9913: 0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch -Patch9914: 0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch -Patch9915: 0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch -Patch9916: 0016-test-new-runroot_plugins-function-to-run-command-in-.patch -Patch9917: 0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch -Patch9918: 0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch -Patch9919: 0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch -Patch9920: 0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch -Patch9921: 0021-tests-Fix-tests-AT_KEYWORDS-usage.patch -Patch9922: 0022-reflink-fix-support-for-hardlinks.patch -Patch9923: 0023-rpm2extents-Improve-logging.patch -Patch9924: 0024-rpm2extents-create-footer-struct-and-helpers.patch -Patch9925: 0025-extents-move-more-functions-helpers-behind-rpmextent.patch -Patch9926: 0026-fix-integer-underflow-in-vfyFDCb.patch -Patch9927: 0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch -Patch9928: 0028-reflink-remove-requirement-for-executable-stack-flag.patch -Patch9929: 0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch -Patch9930: 0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch -Patch9931: 0031-rpmcow-denylist.patch -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 -Patch9938: 0038-reflink-set-metadata-for-hardlinked-files.patch Provides: rpm(pr1470) Provides: rpm(pr1470_1)