#20 big patch squash
Merged 13 days ago by dcavalca. Opened 13 days ago by teknoraver.
rpms/ teknoraver/rpm c9s-sig-hyperscale  into  c9s-sig-hyperscale

file modified
+2128 -744
@@ -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 <malmond@fb.com>

  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 @@ 

  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 @@ 

   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 <inttypes.h>

-  #include <utime.h>

-  #include <errno.h>

- +#include <stdbool.h>

-  #include <fcntl.h>

-  #ifdef WITH_CAP

-  #include <sys/capability.h>

- @@ -17,6 +18,7 @@

-  #include <rpm/rpmts.h>

-  #include <rpm/rpmlog.h>

-  #include <rpm/rpmmacro.h>

- +#include <rpm/rpmlib.h>

-  

-  #include "rpmio/rpmio_internal.h"	/* fdInit/FiniDigest */

-  #include "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 @@ 

  +	    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 @@ 

  +    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 @@ 

  +    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 @@ 

  +    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 <rpm/rpmlog.h>

+ +#include <rpm/rpmio.h>

+ +#include <string.h>

+ +#include <errno.h>

+ +

+ +

+ +#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 <stdint.h>

+ +

+ +/** \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 @@ 

   /** \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 @@ 

   	}

       }

       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 @@ 

   {

       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 @@ 

    * 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 @@ 

   } 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 @@ 

   %__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 @@ 

   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 <errno.h>
@@ -481,6 +1284,7 @@ 

  +#include <rpm/rpmlog.h>

  +#include "lib/rpmlib.h"

  +#include "lib/rpmplugin.h"

+ +#include "lib/rpmextents_internal.h"

  +#include "lib/rpmte_internal.h"

  +#include <rpm/rpmfileutil.h>

  +#include "rpmio/rpmio_internal.h"
@@ -496,38 +1300,79 @@ 

  +#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 @@ 

  +}

  +

  +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 @@ 

  +    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 @@ 

  +    .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 <rpm/rpmcli.h>

  +#include <rpm/rpmlib.h>		/* rpmReadPackageFile .. */

+ +#include <rpm/rpmlog.h>

  +#include <rpm/rpmfi.h>

  +#include <rpm/rpmtag.h>

  +#include <rpm/rpmio.h>
@@ -824,8 +1690,10 @@ 

  +

  +#include <rpm/rpmts.h>

  +#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 <unistd.h>
@@ -838,7 +1706,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
@@ -848,9 +1716,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;
@@ -863,119 +1728,221 @@ 

  +    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 @@ 

  +    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]* <DIGESTALGO>");

+ +

+ +    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 @@ 

    * 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 @@ 

   /** \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 <chantr4@gmail.com>

+ +#

+ +#    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

  

@@ -1,64 +0,0 @@ 

- From 845b5c3882b1eecb31d712b61a4e91fe0eb70712 Mon Sep 17 00:00:00 2001

- From: Matthew Almond <malmond@fb.com>

- 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 <inttypes.h>

-  #include <utime.h>

-  #include <errno.h>

- -#include <stdbool.h>

-  #include <fcntl.h>

-  #ifdef WITH_CAP

-  #include <sys/capability.h>

- @@ -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

- 

@@ -0,0 +1,25 @@ 

+ From 8a95dda30c4237da2a4ef16f3dca76d6b4417bc7 Mon Sep 17 00:00:00 2001

+ From: Matteo Croce <teknoraver@meta.com>

+ Date: Fri, 22 Nov 2024 19:49:55 +0100

+ Subject: [PATCH 2/2] plugin absolute path

+ 

+ ---

+  lib/rpmplugins.c | 2 +-

+  1 file changed, 1 insertion(+), 1 deletion(-)

+ 

+ diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c

+ index 1e0c345..4b86320 100644

+ --- a/lib/rpmplugins.c

+ +++ b/lib/rpmplugins.c

+ @@ -371,7 +371,7 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,

+  	rpmPlugin plugin = plugins->plugins[i];

+  	RPMPLUGINS_SET_HOOK_FUNC(fsm_file_pre);

+  	if (hookFunc) {

+ -	    hook_rc = hookFunc(plugin, fi, path, file_mode, op);

+ +	    hook_rc = hookFunc(plugin, fi, apath, file_mode, op);

+  	    if (hook_rc == RPMRC_FAIL) {

+  		rpmlog(RPMLOG_ERR, "Plugin %s: hook fsm_file_pre failed\n", plugin->name);

+  		rc = RPMRC_FAIL;

+ -- 

+ 2.47.0

+ 

@@ -1,1231 +0,0 @@ 

- From aa31421bfe835dadd29da3aa46ee446038f80d02 Mon Sep 17 00:00:00 2001

- From: Matthew Almond <malmond@fb.com>

- 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

- 

@@ -1,27 +0,0 @@ 

- From 15127592f8cc3221129f61b79319d88c7727bec3 Mon Sep 17 00:00:00 2001

- From: Matthew Almond <malmond@fb.com>

- 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

- 

@@ -1,73 +0,0 @@ 

- From fd4060dcfbe4127fb0d19f1878d0d8b9f34c7b9a Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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 <chantr4@gmail.com>

- +#

- +#    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

- 

@@ -1,431 +0,0 @@ 

- From ea1177fcef609519f0c2377ebee236001d2a8fae Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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 <rpm/rpmcli.h>

-  #include <rpm/rpmlib.h>		/* rpmReadPackageFile .. */

- +#include <rpm/rpmlog.h>

-  #include <rpm/rpmfi.h>

-  #include <rpm/rpmtag.h>

-  #include <rpm/rpmio.h>

- @@ -10,6 +12,7 @@

-  

-  #include <rpm/rpmts.h>

-  #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]* <DIGESTALGO>");

-  

- -    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

- 

@@ -1,282 +0,0 @@ 

- From a4755a5ed793ca439bb23b804ba7a8ab080ff110 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,116 +0,0 @@ 

- From c705a6287f8c7fb5e37dad0ac87257731a41fa69 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,70 +0,0 @@ 

- From 44b86112136e4804eb606636cbcb4ae847cad773 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,204 +0,0 @@ 

- From 7da1e826ccb08fdd404524146736b3f12a473e31 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,389 +0,0 @@ 

- From 86776bf17f1644c76fdf8b87042645cf77bd3873 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,299 +0,0 @@ 

- From ecab80b80e3917d3acf0f909c9cc84691a207fc0 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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 <rpm/rpmlog.h>

- +#include <rpm/rpmio.h>

- +

- +#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 <stdint.h>

- +

- +/* 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 <rpm/rpmlog.h>

-  #include "lib/rpmlib.h"

-  #include "lib/rpmplugin.h"

- +#include "lib/rpmextents_internal.h"

-  #include "lib/rpmte_internal.h"

-  #include <rpm/rpmfileutil.h>

-  #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 <unistd.h>

- @@ -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

- 

@@ -1,214 +0,0 @@ 

- From 5c97d7f83f56015d6a37934cee4e55ed8d747890 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,89 +0,0 @@ 

- From ad46eb4132cbd2c4ee23686a1c52f2fc57afffc5 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,33 +0,0 @@ 

- From b2fc576828af873a1993bdaa2fcb7c860b94df3e Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,33 +0,0 @@ 

- From e04b5d20a6d8c64dba7416edba8e435145a5d7d3 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,63 +0,0 @@ 

- From e86207d3395e0963f19363b047551100569900df Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,97 +0,0 @@ 

- From 048db395b6de8544dc88231f0afebee8570daee6 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,175 +0,0 @@ 

- From 5f762af17c6e72e86e4710975dcdfd71fc5d1b07 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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 <rpm/rpmts.h>

-  #include <rpm/rpmlog.h>

-  #include <rpm/rpmmacro.h>

- -#include <rpm/rpmlib.h>

-  

-  #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

- 

@@ -1,35 +0,0 @@ 

- From 13aea986ada3ed7d26182d81d8878bcc807a6ab5 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,43 +0,0 @@ 

- From 3e363f853a4379e0199db81f777f4b610e158eae Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,132 +0,0 @@ 

- From fd8ffffced543e248847d63e9375fb95584f998d Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,393 +0,0 @@ 

- From a2c959085250d186c54130b78af076095c3d3cd3 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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]* <DIGESTALGO>");

-  

-      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

- 

@@ -1,200 +0,0 @@ 

- From aabaa6c6587c37b84a1b9cfd98bff31f1b69345e Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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 <rpm/rpmlog.h>

-  #include <rpm/rpmio.h>

- +#include <string.h>

- +#include <errno.h>

- +

-  

-  #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 <stdint.h>

-  

- +/** \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

- 

@@ -1,176 +0,0 @@ 

- From 8235711d92d8783abe63d6e4f29afd495fc4b22e Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,25 +0,0 @@ 

- From 3372e6c917e54b3a84c04ca4274000da04a98e86 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,169 +0,0 @@ 

- From 1e0850cf7649578e1d7da815751efaa8101773e7 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,117 +0,0 @@ 

- From 57aa660de4d1b8375cd56f7b8b5fcaf8ad9a5af7 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,109 +0,0 @@ 

- From 5753b178a08043316e6f3556754741cdd9cd19c5 Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,98 +0,0 @@ 

- From dc53b002bd3d03a21e9af406a9aff5e588710b5b Mon Sep 17 00:00:00 2001

- From: chantra <chantr4@gmail.com>

- 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

- 

@@ -1,395 +0,0 @@ 

- From: Richard Phibel <richardphibel@meta.com>

- 

- Subject: RPM with Copy on Write: add deny list mechanism

- 

- commit 3431550e6c92ba4bc6d091cb244f70c158dfbbaa

- Author: Richard Phibel <richardphibel@meta.com>

- 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 <richardphibel@meta.com>

- ---

-  build/pack.c         |   2 +-

-  lib/package.c        |   6 +--

-  lib/rpmlead.c        |  43 +++++++++---------

-  lib/rpmlead.h        |  37 +++++++++++++++-

-  rpm2extents.c        | 102 ++++++++++++++++++++++++++++++++-----------

-  sign/rpmgensig.c     |   2 +-

-  tests/rpm2extents.at |  11 +++++

-  7 files changed, 148 insertions(+), 55 deletions(-)

- 

- diff --git a/build/pack.c b/build/pack.c

- index 8d6f74935ebb8a4d65aa2bcb666825a99162be9c..e2f05b6412d3e0d814a1160a0dcdfad5c323a8f8 100644

- --- 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])

@@ -1,386 +0,0 @@ 

- From: Richard Phibel <richardphibel@meta.com>

- 

- commit 7976c921f60ec5d20c50c4c702ec5636b39210ba

- Author: Richard Phibel <richardphibel@meta.com>

- 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 <richardphibel@meta.com>

- ---

-  rpm2extents.c | 281 +++++++++++++++++++++++++++-----------------------

-  1 file changed, 153 insertions(+), 128 deletions(-)

- 

- diff --git a/rpm2extents.c b/rpm2extents.c

- index 702d3765d76faf618992ca112011d2312d7fcdcc..b641511fff884e3c8fb396f28acbd8e2c736e28a 100644

- --- 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);

@@ -1,80 +0,0 @@ 

- From 937f9bc67b905851c78719d8397926eaa97b174a Mon Sep 17 00:00:00 2001

- From: Richard Phibel <richardphibel@meta.com>

- 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

- 

@@ -1,28 +0,0 @@ 

- From a3b6102b4d2e79a8b74b036c6a29272a7f6e5c6a Mon Sep 17 00:00:00 2001

- From: Richard Phibel <richardphibel@meta.com>

- 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

- 

@@ -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;

@@ -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)

-  {

file removed
-35
@@ -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,

@@ -1,30 +0,0 @@ 

- From 3310d203e0aa162428c7b9dc1e9d8e09da768608 Mon Sep 17 00:00:00 2001

- From: Matteo Croce <teknoraver@meta.com>

- 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

- 

file modified
+6 -38
@@ -32,7 +32,7 @@ 

  

  %global rpmver 4.16.1.3

  #global snapver rc1

- %global rel 34.2

+ %global rel 34.3

  %global sover 9

  

  %global srcver %{rpmver}%{?snapver:-%{snapver}}
@@ -149,43 +149,7 @@ 

  

  # 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

+ Patch9902: 0002-plugin-absolute-path.patch

  Provides: rpm(pr1470)

  Provides: rpm(pr1470_1)

  
@@ -764,6 +728,10 @@ 

  %doc doc/librpm/html/*

  

  %changelog

+ * Fri Nov 22 2024 Matteo Croce <teknoraver@meta.com> - 4.16.1.3-34.3

+ - Squash all CoW patches

+ - Fix a path issue with plugins

+ 

  * Sat Sep 14 2024 Matteo Croce <teknoraver@meta.com> - 4.16.1.3-34.2

  - Fix deduplication error in RPM CoW

  

Squash all 35 patches in one, and fix a potential problem when interacting with other plugins

Pull-Request has been merged by dcavalca

13 days ago
Metadata
Changes Summary 40
+2128 -744
file changed
0001-RPM-with-Copy-on-Write.patch
-64
file removed
0002-Remove-use-of-bool-type-for-consistency.patch
+25
file added
0002-plugin-absolute-path.patch
-1231
file removed
0003-Match-formatting-style-of-existing-code.patch
-27
file removed
0004-Fix-printf-formatting-in-reflink.c.patch
-73
file removed
0005-tests-rpm2extents-Add-basic-tests-for-rpm2extents.patch
-431
file removed
0006-rpm2extents-verify-package-signature-during-transcod.patch
-282
file removed
0007-rpm2extents-write-RC-and-output-to-transcodedfile-me.patch
-116
file removed
0008-rpm2extents-Add-script-to-troubleshoot-transcoded-fi.patch
-70
file removed
0009-rpm2extents-Add-test-verifying-RC-code-and-signature.patch
-204
file removed
0010-rpm2extents-Make-rpmkeys-support-reading-metadata-fr.patch
-389
file removed
0011-rpm2extents-Perform-digest-computation-within-the-va.patch
-299
file removed
0012-rpmextents-Create-an-internal-library-to-make-rpmext.patch
-214
file removed
0013-plugin-add-plugin_fsm_file_install_func-plugin-hook.patch
-89
file removed
0014-fsm-Call-new-rpmpluginsCallFsmFileInstall-in-rpmPack.patch
-33
file removed
0015-reflink-use-reflink_fsm_file_install-hook-instead-of.patch
-33
file removed
0016-test-new-runroot_plugins-function-to-run-command-in-.patch
-63
file removed
0017-test-Add-test-installing-an-RPM-with-reflink-plugin.patch
-97
file removed
0018-plugin-add-rpmpluginsCallFsmFileArchiveReader.patch
-175
file removed
0019-reflink-use-rpmpluginsCallFsmFileArchiveReader-to-pr.patch
-35
file removed
0020-reflink-tests-Can-install-standard-RPM-with-reflink.patch
-43
file removed
0021-tests-Fix-tests-AT_KEYWORDS-usage.patch
-132
file removed
0022-reflink-fix-support-for-hardlinks.patch
-393
file removed
0023-rpm2extents-Improve-logging.patch
-200
file removed
0024-rpm2extents-create-footer-struct-and-helpers.patch
-176
file removed
0025-extents-move-more-functions-helpers-behind-rpmextent.patch
-25
file removed
0026-fix-integer-underflow-in-vfyFDCb.patch
-169
file removed
0027-rpmchecksig-Refactor-rpmpkgVerifySigs-with-custom-ve.patch
-117
file removed
0028-reflink-remove-requirement-for-executable-stack-flag.patch
-109
file removed
0029-extentsVerifySigs-Make-it-optional-to-print-the-sign.patch
-98
file removed
0030-rpmcow-Make-rpm-i-install-package-without-the-need-o.patch
-395
file removed
0031-rpmcow-denylist.patch
-386
file removed
0032-rpmcow-workaround.patch
-80
file removed
0033-rpmcow-fix-stack-overflow-in-rpm2extents.patch
-28
file removed
0034-rpmcow-fix-issue-for-transaction-with-transcoded-and-untranscoded-packages.patch
-11
file removed
0035-rpmcow-fix-segfault-in-rpm2extents.patch
-11
file removed
0036-bsearchr_static.patch
-35
file removed
0037-plugin_path.patch
-30
file removed
0038-reflink-set-metadata-for-hardlinked-files.patch
+6 -38
file changed
rpm.spec