2f13d7
From aa31421bfe835dadd29da3aa46ee446038f80d02 Mon Sep 17 00:00:00 2001
2f13d7
From: Matthew Almond <malmond@fb.com>
2f13d7
Date: Sun, 31 Jan 2021 13:51:16 -0800
2f13d7
Subject: [PATCH 03/30] Match formatting/style of existing code
2f13d7
2f13d7
The existing code contains some variability in formatting. I'm not sure
2f13d7
if { is meant to be on the end of the line, or on a new line, but I've
2f13d7
standardized on the former.
2f13d7
2f13d7
The indentation is intended to match the existing convention: 4 column
2f13d7
indent, but 8 column wide tab characters. This is easy to follow/use in
2f13d7
vim, but is surprisingly difficult to get right in vscode. I am doing
2f13d7
this reformat here and now, and future changes will be after this.
2f13d7
2f13d7
I'm keen to fold the patches together, but for now, I'm trying to keep
2f13d7
the history of #1470 linear so everyone can follow along.
2f13d7
---
2f13d7
 lib/rpmplugins.c  |   6 +-
2f13d7
 plugins/reflink.c | 407 ++++++++++++++++++---------------
2f13d7
 rpm2extents.c     | 562 ++++++++++++++++++++--------------------------
2f13d7
 3 files changed, 462 insertions(+), 513 deletions(-)
2f13d7
2f13d7
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
2f13d7
index c5084d398..3da3097af 100644
2f13d7
--- a/lib/rpmplugins.c
2f13d7
+++ b/lib/rpmplugins.c
2f13d7
@@ -368,9 +368,9 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
2f13d7
 		rc = RPMRC_FAIL;
2f13d7
 	    } else if (hook_rc == RPMRC_PLUGIN_CONTENTS && rc != RPMRC_FAIL) {
2f13d7
 		if (rc == RPMRC_PLUGIN_CONTENTS) {
2f13d7
-		    /*
2f13d7
-		    Another plugin already said it'd handle contents. It's undefined how
2f13d7
-		    these would combine, so treat this as a failure condition.
2f13d7
+		    /* Another plugin already said it'd handle contents. It's
2f13d7
+		     * undefined how these would combine, so treat this as a
2f13d7
+		     * failure condition.
2f13d7
 		    */
2f13d7
 		    rc = RPMRC_FAIL;
2f13d7
 		} else {
2f13d7
diff --git a/plugins/reflink.c b/plugins/reflink.c
2f13d7
index d7f19acd9..9eaa87094 100644
2f13d7
--- a/plugins/reflink.c
2f13d7
+++ b/plugins/reflink.c
2f13d7
@@ -32,31 +32,32 @@
2f13d7
 #include "lib/rpmhash.H"
2f13d7
 #include "lib/rpmhash.C"
2f13d7
 
2f13d7
-/*
2f13d7
-We use this in find to indicate a key wasn't found. This is an unrecoverable
2f13d7
-error, but we can at least show a decent error. 0 is never a valid offset
2f13d7
-because it's the offset of the start of the file.
2f13d7
-*/
2f13d7
+/* We use this in find to indicate a key wasn't found. This is an
2f13d7
+ * unrecoverable error, but we can at least show a decent error. 0 is never a
2f13d7
+ * valid offset because it's the offset of the start of the file.
2f13d7
+ */
2f13d7
 #define NOT_FOUND 0
2f13d7
 
2f13d7
 #define BUFFER_SIZE (1024 * 128)
2f13d7
 
2f13d7
-/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */
2f13d7
+/* magic value at end of file (64 bits) that indicates this is a transcoded
2f13d7
+ * rpm.
2f13d7
+ */
2f13d7
 #define MAGIC 3472329499408095051
2f13d7
 
2f13d7
 struct reflink_state_s {
2f13d7
-  /* Stuff that's used across rpms */
2f13d7
-  long fundamental_block_size;
2f13d7
-  char *buffer;
2f13d7
+    /* Stuff that's used across rpms */
2f13d7
+    long fundamental_block_size;
2f13d7
+    char *buffer;
2f13d7
 
2f13d7
-  /* stuff that's used/updated per psm */
2f13d7
-  uint32_t keys, keysize;
2f13d7
+    /* stuff that's used/updated per psm */
2f13d7
+    uint32_t keys, keysize;
2f13d7
 
2f13d7
-  // table for current rpm, keys * (keysize + sizeof(rpm_loff_t))
2f13d7
-  unsigned char *table;
2f13d7
-  FD_t fd;
2f13d7
-  rpmfiles files;
2f13d7
-  inodeIndexHash inodeIndexes;
2f13d7
+    /* table for current rpm, keys * (keysize + sizeof(rpm_loff_t)) */
2f13d7
+    unsigned char *table;
2f13d7
+    FD_t fd;
2f13d7
+    rpmfiles files;
2f13d7
+    inodeIndexHash inodeIndexes;
2f13d7
 };
2f13d7
 
2f13d7
 typedef struct reflink_state_s * reflink_state;
2f13d7
@@ -73,60 +74,62 @@ static unsigned int inodeId(rpm_ino_t a)
2f13d7
 }
2f13d7
 
2f13d7
 static rpmRC reflink_init(rpmPlugin plugin, rpmts ts) {
2f13d7
-  reflink_state state = rcalloc(1, sizeof(struct reflink_state_s));
2f13d7
+    reflink_state state = rcalloc(1, sizeof(struct reflink_state_s));
2f13d7
 
2f13d7
-  /*
2f13d7
-  IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset and
2f13d7
-  length arguments to be aligned to the fundamental block size.
2f13d7
+    /* IOCTL-FICLONERANGE(2): ...Disk filesystems generally require the offset
2f13d7
+     * and length arguments to be aligned to the fundamental block size.
2f13d7
+     *
2f13d7
+     * The value of "fundamental block size" is directly related to the
2f13d7
+     * system's page size, so we should use that.
2f13d7
+     */
2f13d7
+    state->fundamental_block_size = sysconf(_SC_PAGESIZE);
2f13d7
+    state->buffer = rcalloc(1, BUFFER_SIZE);
2f13d7
+    rpmPluginSetData(plugin, state);
2f13d7
 
2f13d7
-  The value of "fundamental block size" is directly related to the system's
2f13d7
-  page size, so we should use that.
2f13d7
-  */
2f13d7
-  state->fundamental_block_size = sysconf(_SC_PAGESIZE);
2f13d7
-  state->buffer = rcalloc(1, BUFFER_SIZE);
2f13d7
-  rpmPluginSetData(plugin, state);
2f13d7
-
2f13d7
-  return RPMRC_OK;
2f13d7
+    return RPMRC_OK;
2f13d7
 }
2f13d7
 
2f13d7
 static void reflink_cleanup(rpmPlugin plugin) {
2f13d7
-  reflink_state state = rpmPluginGetData(plugin);
2f13d7
-  free(state->buffer);
2f13d7
-  free(state);
2f13d7
+    reflink_state state = rpmPluginGetData(plugin);
2f13d7
+    free(state->buffer);
2f13d7
+    free(state);
2f13d7
 }
2f13d7
 
2f13d7
 static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {
2f13d7
     reflink_state state = rpmPluginGetData(plugin);
2f13d7
     state->fd = rpmteFd(te);
2f13d7
     if (state->fd == 0) {
2f13d7
-      rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n"));
2f13d7
-      return RPMRC_OK;
2f13d7
+	rpmlog(RPMLOG_DEBUG, _("reflink: fd = 0, no install\n"));
2f13d7
+	return RPMRC_OK;
2f13d7
     }
2f13d7
     rpm_loff_t current = Ftell(state->fd);
2f13d7
     uint64_t magic;
2f13d7
     if (Fseek(state->fd, -(sizeof(magic)), SEEK_END) < 0) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n"));
2f13d7
-      if (Fseek(state->fd, current, SEEK_SET) < 0) {
2f13d7
-        /* yes this gets a bit repetitive */
2f13d7
-        rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
2f13d7
-      }
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR, _("reflink: failed to seek for magic\n"));
2f13d7
+	if (Fseek(state->fd, current, SEEK_SET) < 0) {
2f13d7
+	    /* yes this gets a bit repetitive */
2f13d7
+	    rpmlog(RPMLOG_ERR,
2f13d7
+		 _("reflink: unable to seek back to original location\n"));
2f13d7
+	}
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
     size_t len = sizeof(magic);
2f13d7
     if (Fread(&magic, len, 1, state->fd) != len) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n"));
2f13d7
-      if (Fseek(state->fd, current, SEEK_SET) < 0) {
2f13d7
-        rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
2f13d7
-      }
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR, _("reflink: unable to read magic\n"));
2f13d7
+	if (Fseek(state->fd, current, SEEK_SET) < 0) {
2f13d7
+	    rpmlog(RPMLOG_ERR,
2f13d7
+		   _("reflink: unable to seek back to original location\n"));
2f13d7
+	}
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
     if (magic != MAGIC) {
2f13d7
-      rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n"));
2f13d7
-      if (Fseek(state->fd, current, SEEK_SET) < 0) {
2f13d7
-        rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
2f13d7
-        return RPMRC_FAIL;
2f13d7
-      }
2f13d7
-      return RPMRC_OK;
2f13d7
+	rpmlog(RPMLOG_DEBUG, _("reflink: not transcoded\n"));
2f13d7
+	if (Fseek(state->fd, current, SEEK_SET) < 0) {
2f13d7
+	    rpmlog(RPMLOG_ERR,
2f13d7
+		   _("reflink: unable to seek back to original location\n"));
2f13d7
+	    return RPMRC_FAIL;
2f13d7
+	}
2f13d7
+	return RPMRC_OK;
2f13d7
     }
2f13d7
     rpmlog(RPMLOG_DEBUG, _("reflink: *is* transcoded\n"));
2f13d7
     Header h = rpmteHeader(te);
2f13d7
@@ -136,53 +139,60 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {
2f13d7
     headerPutString(h, RPMTAG_PAYLOADFORMAT, "clon");
2f13d7
     headerFree(h);
2f13d7
     state->files = rpmteFiles(te);
2f13d7
-    /* tail of file contains offset_table, offset_checksums
2f13d7
-       then magic
2f13d7
-    */
2f13d7
+    /* tail of file contains offset_table, offset_checksums then magic */
2f13d7
     if (Fseek(state->fd, -(sizeof(rpm_loff_t) * 2 + sizeof(magic)), SEEK_END) < 0) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd);
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"),
2f13d7
+	       state->fd);
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
     rpm_loff_t table_start;
2f13d7
     len = sizeof(table_start);
2f13d7
     if (Fread(&table_start, len, 1, state->fd) != len) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n"));
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR, _("reflink: unable to read table_start\n"));
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
     if (Fseek(state->fd, table_start, SEEK_SET) < 0) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n"));
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR, _("reflink: unable to seek to table_start\n"));
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
     len = sizeof(state->keys);
2f13d7
     if (Fread(&state->keys, len, 1, state->fd) != len) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n"));
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR, _("reflink: unable to read number of keys\n"));
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
     len = sizeof(state->keysize);
2f13d7
     if (Fread(&state->keysize, len, 1, state->fd) != len) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n"));
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR, _("reflink: unable to read keysize\n"));
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
-    rpmlog(RPMLOG_DEBUG, _("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"), table_start, state->keys, state->keysize);
2f13d7
-    // now get digest table if there is a reason to have one.
2f13d7
+    rpmlog(
2f13d7
+	RPMLOG_DEBUG,
2f13d7
+	_("reflink: table_start=0x%lx, keys=%d, keysize=%d\n"),
2f13d7
+	table_start, state->keys, state->keysize
2f13d7
+    );
2f13d7
+    /* now get digest table if there is a reason to have one. */
2f13d7
     if (state->keys == 0 || state->keysize == 0) {
2f13d7
-      // no files (or no digests(!))
2f13d7
-      state->table = NULL;
2f13d7
+	/* no files (or no digests(!)) */
2f13d7
+	state->table = NULL;
2f13d7
     } else {
2f13d7
-      int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t));
2f13d7
-      state->table = rcalloc(1, table_size);
2f13d7
-      if (Fread(state->table, table_size, 1, state->fd) != table_size) {
2f13d7
-        rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n"));
2f13d7
-        return RPMRC_FAIL;
2f13d7
-      }
2f13d7
-      state->inodeIndexes = inodeIndexHashCreate(state->keys, inodeId, inodeCmp, NULL, NULL);
2f13d7
+	int table_size = state->keys * (state->keysize + sizeof(rpm_loff_t));
2f13d7
+	state->table = rcalloc(1, table_size);
2f13d7
+	if (Fread(state->table, table_size, 1, state->fd) != table_size) {
2f13d7
+	    rpmlog(RPMLOG_ERR, _("reflink: unable to read table\n"));
2f13d7
+	    return RPMRC_FAIL;
2f13d7
+	}
2f13d7
+	state->inodeIndexes = inodeIndexHashCreate(
2f13d7
+	    state->keys, inodeId, inodeCmp, NULL, NULL
2f13d7
+	);
2f13d7
     }
2f13d7
 
2f13d7
-    // seek back to original location
2f13d7
-    // might not be needed if we seek to offset immediately
2f13d7
+    /* Seek back to original location.
2f13d7
+     * Might not be needed if we seek to offset immediately
2f13d7
+     */
2f13d7
     if (Fseek(state->fd, current, SEEK_SET) < 0) {
2f13d7
-      rpmlog(RPMLOG_ERR, _("reflink: unable to seek back to original location\n"));
2f13d7
-      return RPMRC_FAIL;
2f13d7
+	rpmlog(RPMLOG_ERR,
2f13d7
+	       _("reflink: unable to seek back to original location\n"));
2f13d7
+	return RPMRC_FAIL;
2f13d7
     }
2f13d7
     return RPMRC_OK;
2f13d7
 }
2f13d7
@@ -192,40 +202,45 @@ static rpmRC reflink_psm_post(rpmPlugin plugin, rpmte te, int res)
2f13d7
     reflink_state state = rpmPluginGetData(plugin);
2f13d7
     state->files = rpmfilesFree(state->files);
2f13d7
     if (state->table) {
2f13d7
-      free(state->table);
2f13d7
-      state->table = NULL;
2f13d7
+	free(state->table);
2f13d7
+	state->table = NULL;
2f13d7
     }
2f13d7
     if (state->inodeIndexes) {
2f13d7
-      inodeIndexHashFree(state->inodeIndexes);
2f13d7
-      state->inodeIndexes = NULL;
2f13d7
+	inodeIndexHashFree(state->inodeIndexes);
2f13d7
+	state->inodeIndexes = NULL;
2f13d7
     }
2f13d7
     return RPMRC_OK;
2f13d7
 }
2f13d7
 
2f13d7
 
2f13d7
-// have a prototype, warnings system
2f13d7
+/* have a prototype, warnings system */
2f13d7
 rpm_loff_t find(const unsigned char *digest, reflink_state state);
2f13d7
 
2f13d7
 rpm_loff_t find(const unsigned char *digest, reflink_state state) {
2f13d7
 # if defined(__GNUC__)
2f13d7
-  /* GCC nested function because bsearch's comparison function can't access
2f13d7
-     state-keysize otherwise
2f13d7
-  */
2f13d7
-  int cmpdigest(const void *k1, const void *k2) {
2f13d7
-    rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
2f13d7
-    return memcmp(k1, k2, state->keysize);
2f13d7
-  }
2f13d7
+    /* GCC nested function because bsearch's comparison function can't access
2f13d7
+     * state-keysize otherwise
2f13d7
+     */
2f13d7
+    int cmpdigest(const void *k1, const void *k2) {
2f13d7
+	rpmlog(RPMLOG_DEBUG, _("reflink: cmpdigest k1=%p k2=%p\n"), k1, k2);
2f13d7
+	return memcmp(k1, k2, state->keysize);
2f13d7
+    }
2f13d7
 # endif
2f13d7
-  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));
2f13d7
-  char *entry = bsearch(digest, state->table, state->keys, state->keysize + sizeof(rpm_loff_t), cmpdigest);
2f13d7
-  if (entry == NULL) {
2f13d7
-    return NOT_FOUND;
2f13d7
-  }
2f13d7
-  rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize);
2f13d7
-  return offset;
2f13d7
+    rpmlog(RPMLOG_DEBUG,
2f13d7
+	   _("reflink: bsearch(key=%p, base=%p, nmemb=%d, size=%lu)\n"),
2f13d7
+	   digest, state->table, state->keys,
2f13d7
+	   state->keysize + sizeof(rpm_loff_t));
2f13d7
+    char *entry = bsearch(digest, state->table, state->keys,
2f13d7
+			  state->keysize + sizeof(rpm_loff_t), cmpdigest);
2f13d7
+    if (entry == NULL) {
2f13d7
+	return NOT_FOUND;
2f13d7
+    }
2f13d7
+    rpm_loff_t offset = *(rpm_loff_t *)(entry + state->keysize);
2f13d7
+    return offset;
2f13d7
 }
2f13d7
 
2f13d7
-static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, mode_t file_mode, rpmFsmOp op)
2f13d7
+static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path,
2f13d7
+                                  mode_t file_mode, rpmFsmOp op)
2f13d7
 {
2f13d7
     struct file_clone_range fcr;
2f13d7
     rpm_loff_t size;
2f13d7
@@ -234,99 +249,119 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path,
2f13d7
 
2f13d7
     reflink_state state = rpmPluginGetData(plugin);
2f13d7
     if (state->table == NULL) {
2f13d7
-        // no table means rpm is not in reflink format, so leave. Now.
2f13d7
-        return RPMRC_OK;
2f13d7
+	/* no table means rpm is not in reflink format, so leave. Now. */
2f13d7
+	return RPMRC_OK;
2f13d7
     }
2f13d7
     if (op == FA_TOUCH) {
2f13d7
-        // we're not overwriting an existing file
2f13d7
-        return RPMRC_OK;
2f13d7
+	/* we're not overwriting an existing file. */
2f13d7
+	return RPMRC_OK;
2f13d7
     }
2f13d7
     fcr.dest_offset = 0;
2f13d7
     if (S_ISREG(file_mode) && !(rpmfiFFlags(fi) & RPMFILE_GHOST)) {
2f13d7
-      rpm_ino_t inode = rpmfiFInode(fi);
2f13d7
-      /* check for hard link entry in table. GetEntry overwrites hlix with the address of the first match */
2f13d7
-      if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, NULL)) {
2f13d7
-        // entry is in table, use hard link
2f13d7
-        char *fn = rpmfilesFN(state->files, hlix[0]);
2f13d7
-        if (link(fn, path) != 0) {
2f13d7
-          rpmlog(RPMLOG_ERR, _("reflink: Unable to hard link %s -> %s due to %s\n"), fn, path, strerror(errno));
2f13d7
-          free(fn);
2f13d7
-          return RPMRC_FAIL;
2f13d7
-        }
2f13d7
-        free(fn);
2f13d7
-        return RPMRC_PLUGIN_CONTENTS;
2f13d7
-      }
2f13d7
-      /* if we didn't hard link, then we'll track this inode as being created soon */
2f13d7
-      if (rpmfiFNlink(fi) > 1) {
2f13d7
-        /* minor optimization: only store files with more than one link */
2f13d7
-        inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi));
2f13d7
-      }
2f13d7
-      /* derived from wfd_open in fsm.c */
2f13d7
-      mode_t old_umask = umask(0577);
2f13d7
-      dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
2f13d7
-      umask(old_umask);
2f13d7
-      if (dst == -1) {
2f13d7
-          rpmlog(RPMLOG_ERR, _("reflink: Unable to open %s for writing due to %s, flags = %x\n"), path, strerror(errno), rpmfiFFlags(fi));
2f13d7
-          return RPMRC_FAIL;
2f13d7
-      }
2f13d7
-      size = rpmfiFSize(fi);
2f13d7
-      if (size > 0) {
2f13d7
-          /* round src_length down to fundamental_block_size multiple */
2f13d7
-          fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size;
2f13d7
-          if ((size % state->fundamental_block_size) > 0) {
2f13d7
-              /* round up to next fundamental_block_size. We expect the data in the rpm to be similarly padded */
2f13d7
-              fcr.src_length += state->fundamental_block_size;
2f13d7
-          }
2f13d7
-          fcr.src_fd = Fileno(state->fd);
2f13d7
-          if (fcr.src_fd == -1) {
2f13d7
-            close(dst);
2f13d7
-            rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n"));
2f13d7
-            return RPMRC_FAIL;
2f13d7
-          }
2f13d7
-          fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state);
2f13d7
-          if (fcr.src_offset == NOT_FOUND) {
2f13d7
-            close(dst);
2f13d7
-            rpmlog(RPMLOG_ERR, _("reflink: digest not found\n"));
2f13d7
-            return RPMRC_FAIL;
2f13d7
-          }
2f13d7
-          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);
2f13d7
-          rc = ioctl(dst, FICLONERANGE, &fcr;;
2f13d7
-          if (rc) {
2f13d7
-            rpmlog(RPMLOG_WARNING, _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"), path, rc, errno, strerror(errno));
2f13d7
-            if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) {
2f13d7
-                close(dst);
2f13d7
-                rpmlog(RPMLOG_ERR, _("reflink: unable to seek on copying bits\n"));
2f13d7
-                return RPMRC_FAIL;
2f13d7
-            }
2f13d7
-            rpm_loff_t left = size;
2f13d7
-            size_t len, read, written;
2f13d7
-            while (left) {
2f13d7
-              len = (left > BUFFER_SIZE ? BUFFER_SIZE : left);
2f13d7
-              read = Fread(state->buffer, len, 1, state->fd);
2f13d7
-              if (read != len) {
2f13d7
-                close(dst);
2f13d7
-                rpmlog(RPMLOG_ERR, _("reflink: short read on copying bits\n"));
2f13d7
-                return RPMRC_FAIL;
2f13d7
-              }
2f13d7
-              written = write(dst, state->buffer, len);
2f13d7
-              if (read != written) {
2f13d7
-                close(dst);
2f13d7
-                rpmlog(RPMLOG_ERR, _("reflink: short write on copying bits\n"));
2f13d7
-                return RPMRC_FAIL;
2f13d7
-              }
2f13d7
-              left -= len;
2f13d7
-            }
2f13d7
-          } else {
2f13d7
-            /* reflink worked, so truncate */
2f13d7
-            rc = ftruncate(dst, size);
2f13d7
-            if (rc) {
2f13d7
-                rpmlog(RPMLOG_ERR, _("reflink: Unable to truncate %s to %ld due to %s\n"), path, size, strerror(errno));
2f13d7
-                return RPMRC_FAIL;
2f13d7
-            }
2f13d7
-          }
2f13d7
-      }
2f13d7
-      close(dst);
2f13d7
-      return RPMRC_PLUGIN_CONTENTS;
2f13d7
+	rpm_ino_t inode = rpmfiFInode(fi);
2f13d7
+	/* check for hard link entry in table. GetEntry overwrites hlix with
2f13d7
+	 * the address of the first match.
2f13d7
+	 */
2f13d7
+	if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL,
2f13d7
+	                           NULL)) {
2f13d7
+	    /* entry is in table, use hard link */
2f13d7
+	    char *fn = rpmfilesFN(state->files, hlix[0]);
2f13d7
+	    if (link(fn, path) != 0) {
2f13d7
+		rpmlog(RPMLOG_ERR,
2f13d7
+		       _("reflink: Unable to hard link %s -> %s due to %s\n"),
2f13d7
+		       fn, path, strerror(errno));
2f13d7
+		free(fn);
2f13d7
+		return RPMRC_FAIL;
2f13d7
+	    }
2f13d7
+	    free(fn);
2f13d7
+	    return RPMRC_PLUGIN_CONTENTS;
2f13d7
+	}
2f13d7
+	/* if we didn't hard link, then we'll track this inode as being
2f13d7
+	 * created soon
2f13d7
+	 */
2f13d7
+	if (rpmfiFNlink(fi) > 1) {
2f13d7
+	    /* minor optimization: only store files with more than one link */
2f13d7
+	    inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi));
2f13d7
+	}
2f13d7
+	/* derived from wfd_open in fsm.c */
2f13d7
+	mode_t old_umask = umask(0577);
2f13d7
+	dst = open(path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
2f13d7
+	umask(old_umask);
2f13d7
+	if (dst == -1) {
2f13d7
+	    rpmlog(RPMLOG_ERR,
2f13d7
+		   _("reflink: Unable to open %s for writing due to %s, flags = %x\n"),
2f13d7
+		   path, strerror(errno), rpmfiFFlags(fi));
2f13d7
+	    return RPMRC_FAIL;
2f13d7
+	}
2f13d7
+	size = rpmfiFSize(fi);
2f13d7
+	if (size > 0) {
2f13d7
+	    /* round src_length down to fundamental_block_size multiple */
2f13d7
+	    fcr.src_length = size / state->fundamental_block_size * state->fundamental_block_size;
2f13d7
+	    if ((size % state->fundamental_block_size) > 0) {
2f13d7
+		/* round up to next fundamental_block_size. We expect the data
2f13d7
+		 * in the rpm to be similarly padded.
2f13d7
+		 */
2f13d7
+		fcr.src_length += state->fundamental_block_size;
2f13d7
+	    }
2f13d7
+	    fcr.src_fd = Fileno(state->fd);
2f13d7
+	    if (fcr.src_fd == -1) {
2f13d7
+		close(dst);
2f13d7
+		rpmlog(RPMLOG_ERR, _("reflink: src fd lookup failed\n"));
2f13d7
+		return RPMRC_FAIL;
2f13d7
+	    }
2f13d7
+	    fcr.src_offset = find(rpmfiFDigest(fi, NULL, NULL), state);
2f13d7
+	    if (fcr.src_offset == NOT_FOUND) {
2f13d7
+		close(dst);
2f13d7
+		rpmlog(RPMLOG_ERR, _("reflink: digest not found\n"));
2f13d7
+		return RPMRC_FAIL;
2f13d7
+	    }
2f13d7
+	    rpmlog(RPMLOG_DEBUG,
2f13d7
+	           _("reflink: Reflinking %lu bytes at %lu to %s orig size=%lu, file=%ld\n"),
2f13d7
+		   fcr.src_length, fcr.src_offset, path, size, fcr.src_fd);
2f13d7
+	    rc = ioctl(dst, FICLONERANGE, &fcr;;
2f13d7
+	    if (rc) {
2f13d7
+		rpmlog(RPMLOG_WARNING,
2f13d7
+		       _("reflink: falling back to copying bits for %s due to %d, %d = %s\n"),
2f13d7
+		       path, rc, errno, strerror(errno));
2f13d7
+		if (Fseek(state->fd, fcr.src_offset, SEEK_SET) < 0) {
2f13d7
+		    close(dst);
2f13d7
+		    rpmlog(RPMLOG_ERR,
2f13d7
+			   _("reflink: unable to seek on copying bits\n"));
2f13d7
+		    return RPMRC_FAIL;
2f13d7
+		}
2f13d7
+		rpm_loff_t left = size;
2f13d7
+		size_t len, read, written;
2f13d7
+		while (left) {
2f13d7
+		    len = (left > BUFFER_SIZE ? BUFFER_SIZE : left);
2f13d7
+		    read = Fread(state->buffer, len, 1, state->fd);
2f13d7
+		    if (read != len) {
2f13d7
+			close(dst);
2f13d7
+			rpmlog(RPMLOG_ERR,
2f13d7
+			       _("reflink: short read on copying bits\n"));
2f13d7
+			return RPMRC_FAIL;
2f13d7
+		    }
2f13d7
+		    written = write(dst, state->buffer, len);
2f13d7
+		    if (read != written) {
2f13d7
+			close(dst);
2f13d7
+			rpmlog(RPMLOG_ERR,
2f13d7
+			       _("reflink: short write on copying bits\n"));
2f13d7
+			return RPMRC_FAIL;
2f13d7
+		    }
2f13d7
+		    left -= len;
2f13d7
+		}
2f13d7
+	    } else {
2f13d7
+		/* reflink worked, so truncate */
2f13d7
+		rc = ftruncate(dst, size);
2f13d7
+		if (rc) {
2f13d7
+		    rpmlog(RPMLOG_ERR,
2f13d7
+			   _("reflink: Unable to truncate %s to %ld due to %s\n"),
2f13d7
+			   path, size, strerror(errno));
2f13d7
+		     return RPMRC_FAIL;
2f13d7
+		}
2f13d7
+	    }
2f13d7
+	}
2f13d7
+	close(dst);
2f13d7
+	return RPMRC_PLUGIN_CONTENTS;
2f13d7
     }
2f13d7
     return RPMRC_OK;
2f13d7
 }
2f13d7
diff --git a/rpm2extents.c b/rpm2extents.c
2f13d7
index 5662b86a6..c111be0a2 100644
2f13d7
--- a/rpm2extents.c
2f13d7
+++ b/rpm2extents.c
2f13d7
@@ -24,7 +24,7 @@
2f13d7
 #include "debug.h"
2f13d7
 
2f13d7
 /* hash of void * (pointers) to file digests to offsets within output.
2f13d7
-   The length of the key depends on what the FILEDIGESTALGO is.
2f13d7
+ * The length of the key depends on what the FILEDIGESTALGO is.
2f13d7
  */
2f13d7
 #undef HASHTYPE
2f13d7
 #undef HTKEYTYPE
2f13d7
@@ -34,7 +34,9 @@
2f13d7
 #include "lib/rpmhash.H"
2f13d7
 #include "lib/rpmhash.C"
2f13d7
 
2f13d7
-/* magic value at end of file (64 bits) that indicates this is a transcoded rpm */
2f13d7
+/* magic value at end of file (64 bits) that indicates this is a transcoded
2f13d7
+ * rpm.
2f13d7
+ */
2f13d7
 #define MAGIC 3472329499408095051
2f13d7
 
2f13d7
 struct digestoffset {
2f13d7
@@ -64,77 +66,54 @@ static int digestor(
2f13d7
     int algo;
2f13d7
     rpmRC rc = RPMRC_FAIL;
2f13d7
 
2f13d7
-    for (algo = 0; algo < algos_len; algo++)
2f13d7
-    {
2f13d7
-        fdInitDigest(fdi, algos[algo], 0);
2f13d7
+    for (algo = 0; algo < algos_len; algo++) {
2f13d7
+	fdInitDigest(fdi, algos[algo], 0);
2f13d7
     }
2f13d7
     fdilength = ufdCopy(fdi, fdo);
2f13d7
-    if (fdilength == -1)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("digest cat failed\n"));
2f13d7
-        goto exit;
2f13d7
+    if (fdilength == -1) {
2f13d7
+	fprintf(stderr, _("digest cat failed\n"));
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
 
2f13d7
     len = sizeof(fdilength);
2f13d7
-    if (Fwrite(&fdilength, len, 1, validationo) != len)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write input length %zd\n"), fdilength);
2f13d7
-        goto exit;
2f13d7
+    if (Fwrite(&fdilength, len, 1, validationo) != len) {
2f13d7
+	fprintf(stderr, _("Unable to write input length %zd\n"), fdilength);
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
     len = sizeof(algos_len);
2f13d7
-    if (Fwrite(&algos_len, len, 1, validationo) != len)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write number of validation digests\n"));
2f13d7
-        goto exit;
2f13d7
+    if (Fwrite(&algos_len, len, 1, validationo) != len) {
2f13d7
+	fprintf(stderr, _("Unable to write number of validation digests\n"));
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
-    for (algo = 0; algo < algos_len; algo++)
2f13d7
-    {
2f13d7
-        fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0);
2f13d7
-
2f13d7
-        algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]);
2f13d7
-        algo_name_len = (uint32_t)strlen(algo_name);
2f13d7
-        algo_digest_len = (uint32_t)filedigest_len;
2f13d7
-
2f13d7
-        len = sizeof(algo_name_len);
2f13d7
-        if (Fwrite(&algo_name_len, len, 1, validationo) != len)
2f13d7
-        {
2f13d7
-            fprintf(
2f13d7
-                stderr,
2f13d7
-                _("Unable to write validation algo name length\n")
2f13d7
-            );
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
-        len = sizeof(algo_digest_len);
2f13d7
-        if (Fwrite(&algo_digest_len, len, 1, validationo) != len)
2f13d7
-        {
2f13d7
-            fprintf(
2f13d7
-                stderr,
2f13d7
-                _("Unable to write number of bytes for validation digest\n")
2f13d7
-            );
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
-        if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len)
2f13d7
-        {
2f13d7
-            fprintf(stderr, _("Unable to write validation algo name\n"));
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
-        if (
2f13d7
-            Fwrite(
2f13d7
-                filedigest,
2f13d7
-                algo_digest_len,
2f13d7
-                1,
2f13d7
-                validationo
2f13d7
-            ) != algo_digest_len
2f13d7
-        )
2f13d7
-        {
2f13d7
-            fprintf(
2f13d7
-                stderr,
2f13d7
-                _("Unable to write validation digest value %u, %zu\n"),
2f13d7
-                algo_digest_len,
2f13d7
-                filedigest_len
2f13d7
-            );
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
+    for (algo = 0; algo < algos_len; algo++) {
2f13d7
+	fdFiniDigest(fdi, algos[algo], (void **)&filedigest, &filedigest_len, 0);
2f13d7
+
2f13d7
+	algo_name = pgpValString(PGPVAL_HASHALGO, algos[algo]);
2f13d7
+	algo_name_len = (uint32_t)strlen(algo_name);
2f13d7
+	algo_digest_len = (uint32_t)filedigest_len;
2f13d7
+
2f13d7
+	len = sizeof(algo_name_len);
2f13d7
+	if (Fwrite(&algo_name_len, len, 1, validationo) != len) {
2f13d7
+	    fprintf(stderr,
2f13d7
+		    _("Unable to write validation algo name length\n"));
2f13d7
+	    goto exit;
2f13d7
+	}
2f13d7
+	len = sizeof(algo_digest_len);
2f13d7
+	if (Fwrite(&algo_digest_len, len, 1, validationo) != len) {
2f13d7
+	    fprintf(stderr,
2f13d7
+		    _("Unable to write number of bytes for validation digest\n"));
2f13d7
+	     goto exit;
2f13d7
+	}
2f13d7
+	if (Fwrite(algo_name, algo_name_len, 1, validationo) != algo_name_len) {
2f13d7
+	    fprintf(stderr, _("Unable to write validation algo name\n"));
2f13d7
+	    goto exit;
2f13d7
+	}
2f13d7
+	if (Fwrite(filedigest, algo_digest_len, 1, validationo ) != algo_digest_len) {
2f13d7
+	    fprintf(stderr,
2f13d7
+		    _("Unable to write validation digest value %u, %zu\n"),
2f13d7
+		    algo_digest_len, filedigest_len);
2f13d7
+	    goto exit;
2f13d7
+	}
2f13d7
     }
2f13d7
     rc = RPMRC_OK;
2f13d7
 exit:
2f13d7
@@ -145,23 +124,20 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
2f13d7
 {
2f13d7
     uint32_t diglen;
2f13d7
     /* GNU C extension: can use diglen from outer context */
2f13d7
-    int digestSetCmp(const unsigned char * a, const unsigned char * b)
2f13d7
-    {
2f13d7
-        return memcmp(a, b, diglen);
2f13d7
+    int digestSetCmp(const unsigned char * a, const unsigned char * b) {
2f13d7
+	return memcmp(a, b, diglen);
2f13d7
     }
2f13d7
 
2f13d7
-    unsigned int digestSetHash(const unsigned char * digest)
2f13d7
-    {
2f13d7
+    unsigned int digestSetHash(const unsigned char * digest) {
2f13d7
         /* assumes sizeof(unsigned int) < diglen */
2f13d7
         return *(unsigned int *)digest;
2f13d7
     }
2f13d7
 
2f13d7
-    int digestoffsetCmp(const void * a, const void * b)
2f13d7
-    {
2f13d7
-        return digestSetCmp(
2f13d7
-            ((struct digestoffset *)a)->digest,
2f13d7
-            ((struct digestoffset *)b)->digest
2f13d7
-        );
2f13d7
+    int digestoffsetCmp(const void * a, const void * b) {
2f13d7
+	return digestSetCmp(
2f13d7
+	    ((struct digestoffset *)a)->digest,
2f13d7
+	    ((struct digestoffset *)b)->digest
2f13d7
+	);
2f13d7
     }
2f13d7
 
2f13d7
     FD_t fdo;
2f13d7
@@ -179,65 +155,52 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
2f13d7
 
2f13d7
     fdo = fdDup(STDOUT_FILENO);
2f13d7
 
2f13d7
-    if (rpmReadPackageRaw(fdi, &sigh, &h))
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Error reading package\n"));
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (rpmReadPackageRaw(fdi, &sigh, &h)) {
2f13d7
+	fprintf(stderr, _("Error reading package\n"));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
 
2f13d7
     if (rpmLeadWrite(fdo, h))
2f13d7
     {
2f13d7
-        fprintf(
2f13d7
-            stderr,
2f13d7
-            _("Unable to write package lead: %s\n"),
2f13d7
-            Fstrerror(fdo)
2f13d7
-        );
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+	fprintf(stderr, _("Unable to write package lead: %s\n"),
2f13d7
+		Fstrerror(fdo));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
 
2f13d7
-    if (rpmWriteSignature(fdo, sigh))
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo));
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (rpmWriteSignature(fdo, sigh)) {
2f13d7
+	fprintf(stderr, _("Unable to write signature: %s\n"), Fstrerror(fdo));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
 
2f13d7
-    if (headerWrite(fdo, h, HEADER_MAGIC_YES))
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo));
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {
2f13d7
+	fprintf(stderr, _("Unable to write headers: %s\n"), Fstrerror(fdo));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
 
2f13d7
     /* Retrieve payload size and compression type. */
2f13d7
-    {	const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
2f13d7
-        rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
2f13d7
+    {
2f13d7
+	const char *compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
2f13d7
+	rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
2f13d7
     }
2f13d7
 
2f13d7
     gzdi = Fdopen(fdi, rpmio_flags);	/* XXX gzdi == fdi */
2f13d7
     free(rpmio_flags);
2f13d7
 
2f13d7
-    if (gzdi == NULL)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (gzdi == NULL) {
2f13d7
+	fprintf(stderr, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
 
2f13d7
     rpmfiles files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
2f13d7
-    rpmfi fi = rpmfiNewArchiveReader(
2f13d7
-        gzdi,
2f13d7
-        files,
2f13d7
-        RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST
2f13d7
-    );
2f13d7
+    rpmfi fi = rpmfiNewArchiveReader(gzdi, files,
2f13d7
+				     RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);
2f13d7
 
2f13d7
     /* this is encoded in the file format, so needs to be fixed size (for
2f13d7
-        now?)
2f13d7
-    */
2f13d7
+     * now?)
2f13d7
+     */
2f13d7
     diglen = (uint32_t)rpmDigestLength(rpmfiDigestAlgo(fi));
2f13d7
-    digestSet ds = digestSetCreate(
2f13d7
-        rpmfiFC(fi),
2f13d7
-        digestSetHash,
2f13d7
-        digestSetCmp,
2f13d7
-        NULL
2f13d7
-    );
2f13d7
+    digestSet ds = digestSetCreate(rpmfiFC(fi), digestSetHash, digestSetCmp,
2f13d7
+				   NULL);
2f13d7
     struct digestoffset offsets[rpmfiFC(fi)];
2f13d7
     pos = RPMLEAD_SIZE + headerSizeof(sigh, HEADER_MAGIC_YES);
2f13d7
 
2f13d7
@@ -247,139 +210,114 @@ static rpmRC process_package(FD_t fdi, FD_t validationi)
2f13d7
 
2f13d7
     zeros = xcalloc(fundamental_block_size, 1);
2f13d7
 
2f13d7
-    while (next >= 0)
2f13d7
-    {
2f13d7
-        next = rpmfiNext(fi);
2f13d7
-        if (next == RPMERR_ITER_END)
2f13d7
-        {
2f13d7
-            rc = RPMRC_OK;
2f13d7
-            break;
2f13d7
-        }
2f13d7
-        mode = rpmfiFMode(fi);
2f13d7
-        if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi))
2f13d7
-        {
2f13d7
-            /* not a regular file, or the archive doesn't contain any content for
2f13d7
-               this entry
2f13d7
-            */
2f13d7
-            continue;
2f13d7
-        }
2f13d7
-        digest = rpmfiFDigest(fi, NULL, NULL);
2f13d7
-        if (digestSetGetEntry(ds, digest, NULL))
2f13d7
-        {
2f13d7
-            /* This specific digest has already been included, so skip it */
2f13d7
-            continue;
2f13d7
-        }
2f13d7
-        pad = pad_to(pos, fundamental_block_size);
2f13d7
-        if (Fwrite(zeros, sizeof(char), pad, fdo) != pad)
2f13d7
-        {
2f13d7
-            fprintf(stderr, _("Unable to write padding\n"));
2f13d7
-            rc = RPMRC_FAIL;
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
-        /* round up to next fundamental_block_size */
2f13d7
-        pos += pad;
2f13d7
-        digestSetAddEntry(ds, digest);
2f13d7
-        offsets[offset_ix].digest = digest;
2f13d7
-        offsets[offset_ix].pos = pos;
2f13d7
-        offset_ix++;
2f13d7
-        size = rpmfiFSize(fi);
2f13d7
-        rc = rpmfiArchiveReadToFile(fi, fdo, 0);
2f13d7
-        if (rc != RPMRC_OK)
2f13d7
-        {
2f13d7
-            fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc);
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
-        pos += size;
2f13d7
+    while (next >= 0) {
2f13d7
+	next = rpmfiNext(fi);
2f13d7
+	if (next == RPMERR_ITER_END) {
2f13d7
+	    rc = RPMRC_OK;
2f13d7
+	    break;
2f13d7
+	}
2f13d7
+	mode = rpmfiFMode(fi);
2f13d7
+	if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) {
2f13d7
+	    /* not a regular file, or the archive doesn't contain any content
2f13d7
+	     * for this entry.
2f13d7
+	    */
2f13d7
+	    continue;
2f13d7
+	}
2f13d7
+	digest = rpmfiFDigest(fi, NULL, NULL);
2f13d7
+	if (digestSetGetEntry(ds, digest, NULL)) {
2f13d7
+	    /* This specific digest has already been included, so skip it. */
2f13d7
+	    continue;
2f13d7
+	}
2f13d7
+	pad = pad_to(pos, fundamental_block_size);
2f13d7
+	if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
2f13d7
+	    fprintf(stderr, _("Unable to write padding\n"));
2f13d7
+	    rc = RPMRC_FAIL;
2f13d7
+	    goto exit;
2f13d7
+	}
2f13d7
+	/* round up to next fundamental_block_size */
2f13d7
+	pos += pad;
2f13d7
+	digestSetAddEntry(ds, digest);
2f13d7
+	offsets[offset_ix].digest = digest;
2f13d7
+	offsets[offset_ix].pos = pos;
2f13d7
+	offset_ix++;
2f13d7
+	size = rpmfiFSize(fi);
2f13d7
+	rc = rpmfiArchiveReadToFile(fi, fdo, 0);
2f13d7
+	if (rc != RPMRC_OK) {
2f13d7
+	    fprintf(stderr, _("rpmfiArchiveReadToFile failed with %d\n"), rc);
2f13d7
+	    goto exit;
2f13d7
+	}
2f13d7
+	pos += size;
2f13d7
     }
2f13d7
     Fclose(gzdi);	/* XXX gzdi == fdi */
2f13d7
 
2f13d7
-    qsort(
2f13d7
-        offsets,
2f13d7
-        (size_t)offset_ix,
2f13d7
-        sizeof(struct digestoffset),
2f13d7
-        digestoffsetCmp
2f13d7
-    );
2f13d7
+    qsort(offsets, (size_t)offset_ix, sizeof(struct digestoffset),
2f13d7
+	  digestoffsetCmp);
2f13d7
 
2f13d7
     len = sizeof(offset_ix);
2f13d7
-    if (Fwrite(&offset_ix, len, 1, fdo) != len)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write length of table\n"));
2f13d7
-        rc = RPMRC_FAIL;
2f13d7
-        goto exit;
2f13d7
+    if (Fwrite(&offset_ix, len, 1, fdo) != len) {
2f13d7
+	fprintf(stderr, _("Unable to write length of table\n"));
2f13d7
+	rc = RPMRC_FAIL;
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
     len = sizeof(diglen);
2f13d7
-    if (Fwrite(&diglen, len, 1, fdo) != len)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write length of digest\n"));
2f13d7
-        rc = RPMRC_FAIL;
2f13d7
-        goto exit;
2f13d7
+    if (Fwrite(&diglen, len, 1, fdo) != len) {
2f13d7
+	fprintf(stderr, _("Unable to write length of digest\n"));
2f13d7
+	rc = RPMRC_FAIL;
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
     len = sizeof(rpm_loff_t);
2f13d7
-    for (int x = 0; x < offset_ix; x++)
2f13d7
-    {
2f13d7
-        if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen)
2f13d7
-        {
2f13d7
-            fprintf(stderr, _("Unable to write digest\n"));
2f13d7
-            rc = RPMRC_FAIL;
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
-        if (Fwrite(&offsets[x].pos, len, 1, fdo) != len)
2f13d7
-        {
2f13d7
-            fprintf(stderr, _("Unable to write offset\n"));
2f13d7
-            rc = RPMRC_FAIL;
2f13d7
-            goto exit;
2f13d7
-        }
2f13d7
+    for (int x = 0; x < offset_ix; x++) {
2f13d7
+	if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) {
2f13d7
+	    fprintf(stderr, _("Unable to write digest\n"));
2f13d7
+	    rc = RPMRC_FAIL;
2f13d7
+	    goto exit;
2f13d7
+	}
2f13d7
+	if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {
2f13d7
+	    fprintf(stderr, _("Unable to write offset\n"));
2f13d7
+	    rc = RPMRC_FAIL;
2f13d7
+	    goto exit;
2f13d7
+	}
2f13d7
     }
2f13d7
     validation_pos = (
2f13d7
-        pos + sizeof(offset_ix) + sizeof(diglen) +
2f13d7
-        offset_ix * (diglen + sizeof(rpm_loff_t))
2f13d7
+	pos + sizeof(offset_ix) + sizeof(diglen) +
2f13d7
+	offset_ix * (diglen + sizeof(rpm_loff_t))
2f13d7
     );
2f13d7
 
2f13d7
     ssize_t validation_len = ufdCopy(validationi, fdo);
2f13d7
-    if (validation_len == -1)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("digest table ufdCopy failed\n"));
2f13d7
-        rc = RPMRC_FAIL;
2f13d7
-        goto exit;
2f13d7
+    if (validation_len == -1) {
2f13d7
+	fprintf(stderr, _("digest table ufdCopy failed\n"));
2f13d7
+	rc = RPMRC_FAIL;
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
     /* add more padding so the last file can be cloned. It doesn't matter that
2f13d7
-       the table and validation etc are in this space. In fact, it's pretty
2f13d7
-       efficient if it is
2f13d7
+     * the table and validation etc are in this space. In fact, it's pretty
2f13d7
+     * efficient if it is.
2f13d7
     */
2f13d7
 
2f13d7
-    pad = pad_to(
2f13d7
-        (
2f13d7
-            validation_pos + validation_len + 2 * sizeof(rpm_loff_t) +
2f13d7
-            sizeof(uint64_t)
2f13d7
-        ),
2f13d7
-        fundamental_block_size
2f13d7
-    );
2f13d7
-    if (Fwrite(zeros, sizeof(char), pad, fdo) != pad)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write final padding\n"));
2f13d7
-        rc = RPMRC_FAIL;
2f13d7
-        goto exit;
2f13d7
+    pad = pad_to((validation_pos + validation_len + 2 * sizeof(rpm_loff_t) +
2f13d7
+		 sizeof(uint64_t)), fundamental_block_size);
2f13d7
+    if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
2f13d7
+	fprintf(stderr, _("Unable to write final padding\n"));
2f13d7
+	rc = RPMRC_FAIL;
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
     zeros = _free(zeros);
2f13d7
-    if (Fwrite(&pos, len, 1, fdo) != len)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write offset of digest table\n"));
2f13d7
-        rc = RPMRC_FAIL;
2f13d7
-        goto exit;
2f13d7
+    if (Fwrite(&pos, len, 1, fdo) != len) {
2f13d7
+	fprintf(stderr, _("Unable to write offset of digest table\n"));
2f13d7
+	rc = RPMRC_FAIL;
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
-    if (Fwrite(&validation_pos, len, 1, fdo) != len)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write offset of validation table\n"));
2f13d7
-        rc = RPMRC_FAIL;
2f13d7
-        goto exit;
2f13d7
+    if (Fwrite(&validation_pos, len, 1, fdo) != len) {
2f13d7
+	fprintf(stderr, _("Unable to write offset of validation table\n"));
2f13d7
+	rc = RPMRC_FAIL;
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
     uint64_t magic = MAGIC;
2f13d7
     len = sizeof(magic);
2f13d7
-    if (Fwrite(&magic, len, 1, fdo) != len)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Unable to write magic\n"));
2f13d7
-        rc = RPMRC_FAIL;
2f13d7
-        goto exit;
2f13d7
+    if (Fwrite(&magic, len, 1, fdo) != len) {
2f13d7
+	fprintf(stderr, _("Unable to write magic\n"));
2f13d7
+	rc = RPMRC_FAIL;
2f13d7
+	goto exit;
2f13d7
     }
2f13d7
 
2f13d7
 exit:
2f13d7
@@ -389,8 +327,7 @@ exit:
2f13d7
     return rc;
2f13d7
 }
2f13d7
 
2f13d7
-int main(int argc, char *argv[])
2f13d7
-{
2f13d7
+int main(int argc, char *argv[]) {
2f13d7
     rpmRC rc;
2f13d7
     int cprc = 0;
2f13d7
     uint8_t algos[argc - 1];
2f13d7
@@ -402,118 +339,95 @@ int main(int argc, char *argv[])
2f13d7
     xsetprogname(argv[0]);	/* Portability call -- see system.h */
2f13d7
     rpmReadConfigFiles(NULL, NULL);
2f13d7
 
2f13d7
-    if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help")))
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]);
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (argc > 1 && (rstreq(argv[1], "-h") || rstreq(argv[1], "--help"))) {
2f13d7
+	fprintf(stderr, _("Usage: %s [DIGESTALGO]...\n"), argv[0]);
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
 
2f13d7
-    if (argc == 1)
2f13d7
-    {
2f13d7
-        fprintf(
2f13d7
-            stderr,
2f13d7
-            _("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n")
2f13d7
-        );
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (argc == 1) {
2f13d7
+	fprintf(stderr,
2f13d7
+		_("Need at least one DIGESTALGO parameter, e.g. 'SHA256'\n"));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
 
2f13d7
-    for (int x = 0; x < (argc - 1); x++)
2f13d7
-    {
2f13d7
-        if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0)
2f13d7
-        {
2f13d7
-            fprintf(
2f13d7
-                stderr,
2f13d7
-                _("Unable to resolve '%s' as a digest algorithm, exiting\n"),
2f13d7
-                argv[x + 1]
2f13d7
-            );
2f13d7
-            exit(EXIT_FAILURE);
2f13d7
-        }
2f13d7
+    for (int x = 0; x < (argc - 1); x++) {
2f13d7
+	if (pgpStringVal(PGPVAL_HASHALGO, argv[x + 1], &algos[x]) != 0)
2f13d7
+	{
2f13d7
+	    fprintf(stderr,
2f13d7
+		    _("Unable to resolve '%s' as a digest algorithm, exiting\n"),
2f13d7
+		    argv[x + 1]);
2f13d7
+	    exit(EXIT_FAILURE);
2f13d7
+	}
2f13d7
     }
2f13d7
 
2f13d7
 
2f13d7
-    if (pipe(mainpipefd) == -1)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Main pipe failure\n"));
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (pipe(mainpipefd) == -1) {
2f13d7
+	fprintf(stderr, _("Main pipe failure\n"));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
-    if (pipe(metapipefd) == -1)
2f13d7
-    {
2f13d7
-        fprintf(stderr, _("Meta pipe failure\n"));
2f13d7
-        exit(EXIT_FAILURE);
2f13d7
+    if (pipe(metapipefd) == -1) {
2f13d7
+	fprintf(stderr, _("Meta pipe failure\n"));
2f13d7
+	exit(EXIT_FAILURE);
2f13d7
     }
2f13d7
     cpid = fork();
2f13d7
-    if (cpid == 0)
2f13d7
-    {
2f13d7
-        /* child: digestor */
2f13d7
-        close(mainpipefd[0]);
2f13d7
-        close(metapipefd[0]);
2f13d7
-        FD_t fdi = fdDup(STDIN_FILENO);
2f13d7
-        FD_t fdo = fdDup(mainpipefd[1]);
2f13d7
-        FD_t validationo = fdDup(metapipefd[1]);
2f13d7
-        rc = digestor(fdi, fdo, validationo, algos, argc - 1);
2f13d7
-        Fclose(validationo);
2f13d7
-        Fclose(fdo);
2f13d7
-        Fclose(fdi);
2f13d7
+    if (cpid == 0) {
2f13d7
+	/* child: digestor */
2f13d7
+	close(mainpipefd[0]);
2f13d7
+	close(metapipefd[0]);
2f13d7
+	FD_t fdi = fdDup(STDIN_FILENO);
2f13d7
+	FD_t fdo = fdDup(mainpipefd[1]);
2f13d7
+	FD_t validationo = fdDup(metapipefd[1]);
2f13d7
+	rc = digestor(fdi, fdo, validationo, algos, argc - 1);
2f13d7
+	Fclose(validationo);
2f13d7
+	Fclose(fdo);
2f13d7
+	Fclose(fdi);
2f13d7
     } else {
2f13d7
-        /* parent: main program */
2f13d7
-        close(mainpipefd[1]);
2f13d7
-        close(metapipefd[1]);
2f13d7
-        FD_t fdi = fdDup(mainpipefd[0]);
2f13d7
-        FD_t validationi = fdDup(metapipefd[0]);
2f13d7
-        rc = process_package(fdi, validationi);
2f13d7
-        Fclose(validationi);
2f13d7
-        /* fdi is normally closed through the stacked file gzdi in the function. */
2f13d7
-        /* wait for child process (digestor for stdin) to complete. */
2f13d7
-        if (rc != RPMRC_OK)
2f13d7
-        {
2f13d7
-            if (kill(cpid, SIGTERM) != 0)
2f13d7
-            {
2f13d7
-                fprintf(
2f13d7
-                    stderr,
2f13d7
-                    _("Failed to kill digest process when main process failed: %s\n"),
2f13d7
-                    strerror(errno)
2f13d7
-                );
2f13d7
-            }
2f13d7
-        }
2f13d7
-        w = waitpid(cpid, &wstatus, 0);
2f13d7
-        if (w == -1)
2f13d7
-        {
2f13d7
-            fprintf(stderr, _("waitpid failed\n"));
2f13d7
-            cprc = EXIT_FAILURE;
2f13d7
-        } else if (WIFEXITED(wstatus))
2f13d7
-        {
2f13d7
-            cprc = WEXITSTATUS(wstatus);
2f13d7
-            if (cprc != 0)
2f13d7
-            {
2f13d7
-                fprintf(
2f13d7
-                    stderr,
2f13d7
-                    _("Digest process non-zero exit code %d\n"),
2f13d7
-                    cprc
2f13d7
-                );
2f13d7
-            }
2f13d7
-        } else if (WIFSIGNALED(wstatus))
2f13d7
-        {
2f13d7
-            fprintf(
2f13d7
-                stderr,
2f13d7
-                _("Digest process was terminated with a signal: %d\n"),
2f13d7
-                WTERMSIG(wstatus)
2f13d7
-            );
2f13d7
-            cprc = EXIT_FAILURE;
2f13d7
-        } else
2f13d7
-        {
2f13d7
-            /* don't think this can happen, but covering all bases */
2f13d7
-            fprintf(stderr, _("Unhandled circumstance in waitpid\n"));
2f13d7
-            cprc = EXIT_FAILURE;
2f13d7
-        }
2f13d7
-        if (cprc != EXIT_SUCCESS)
2f13d7
-        {
2f13d7
-            rc = RPMRC_FAIL;
2f13d7
-        }
2f13d7
+	/* parent: main program */
2f13d7
+	close(mainpipefd[1]);
2f13d7
+	close(metapipefd[1]);
2f13d7
+	FD_t fdi = fdDup(mainpipefd[0]);
2f13d7
+	FD_t validationi = fdDup(metapipefd[0]);
2f13d7
+	rc = process_package(fdi, validationi);
2f13d7
+	Fclose(validationi);
2f13d7
+	/* fdi is normally closed through the stacked file gzdi in the
2f13d7
+	 * function.
2f13d7
+	 * Wait for child process (digestor for stdin) to complete.
2f13d7
+	 */
2f13d7
+	if (rc != RPMRC_OK) {
2f13d7
+	    if (kill(cpid, SIGTERM) != 0) {
2f13d7
+		fprintf(stderr,
2f13d7
+		        _("Failed to kill digest process when main process failed: %s\n"),
2f13d7
+			strerror(errno));
2f13d7
+	    }
2f13d7
+	}
2f13d7
+	w = waitpid(cpid, &wstatus, 0);
2f13d7
+	if (w == -1) {
2f13d7
+	    fprintf(stderr, _("waitpid failed\n"));
2f13d7
+	    cprc = EXIT_FAILURE;
2f13d7
+	} else if (WIFEXITED(wstatus)) {
2f13d7
+	    cprc = WEXITSTATUS(wstatus);
2f13d7
+	    if (cprc != 0) {
2f13d7
+		fprintf(stderr,
2f13d7
+			_("Digest process non-zero exit code %d\n"),
2f13d7
+			cprc);
2f13d7
+	    }
2f13d7
+	} else if (WIFSIGNALED(wstatus)) {
2f13d7
+	    fprintf(stderr,
2f13d7
+		    _("Digest process was terminated with a signal: %d\n"),
2f13d7
+		    WTERMSIG(wstatus));
2f13d7
+	    cprc = EXIT_FAILURE;
2f13d7
+	} else {
2f13d7
+	    /* Don't think this can happen, but covering all bases */
2f13d7
+	    fprintf(stderr, _("Unhandled circumstance in waitpid\n"));
2f13d7
+	    cprc = EXIT_FAILURE;
2f13d7
+	}
2f13d7
+	if (cprc != EXIT_SUCCESS) {
2f13d7
+	    rc = RPMRC_FAIL;
2f13d7
+	}
2f13d7
     }
2f13d7
-    if (rc != RPMRC_OK)
2f13d7
-    {
2f13d7
-        /* translate rpmRC into generic failure return code. */
2f13d7
-        return EXIT_FAILURE;
2f13d7
+    if (rc != RPMRC_OK) {
2f13d7
+	/* translate rpmRC into generic failure return code. */
2f13d7
+	return EXIT_FAILURE;
2f13d7
     }
2f13d7
     return EXIT_SUCCESS;
2f13d7
 }
2f13d7
-- 
2f13d7
2.35.1
2f13d7