dcavalca / rpms / rpm

Forked from rpms/rpm a year ago
Clone
Richard Phibel ca8a44
From: Richard Phibel <richardphibel@meta.com>
Richard Phibel ca8a44
Richard Phibel ca8a44
Subject: RPM with Copy on Write: workaround for corrupt signature header
Richard Phibel ca8a44
Richard Phibel ca8a44
commit 7976c921f60ec5d20c50c4c702ec5636b39210ba
Richard Phibel ca8a44
Author: Richard Phibel <richardphibel@meta.com>
Richard Phibel ca8a44
Date:   Wed Oct 26 18:57:19 2022 +0200
Richard Phibel ca8a44
Richard Phibel ca8a44
    RPM with Copy on Write: workaround for corrupt signature header
Richard Phibel ca8a44
    
Richard Phibel ca8a44
    Some packages have errors in the signature header. These errors do not
Richard Phibel ca8a44
    prevent installation of the package but cause issues in rpm2extents
Richard Phibel ca8a44
    conversion. This commit implements the same fix as in
Richard Phibel ca8a44
    unloadImmutableRegion.
Richard Phibel ca8a44
Richard Phibel ca8a44
Signed-off-by: Richard Phibel <richardphibel@meta.com>
Richard Phibel ca8a44
Richard Phibel ca8a44
diff --git a/rpm2extents.c b/rpm2extents.c
Richard Phibel ca8a44
index 702d3765d76faf618992ca112011d2312d7fcdcc..b641511fff884e3c8fb396f28acbd8e2c736e28a 100644
Richard Phibel ca8a44
--- a/rpm2extents.c
Richard Phibel ca8a44
+++ b/rpm2extents.c
Richard Phibel ca8a44
@@ -139,7 +139,7 @@ exit:
Richard Phibel ca8a44
  * @param package_name	package name
Richard Phibel ca8a44
  * @return 		true if package is in deny list
Richard Phibel ca8a44
  */
Richard Phibel ca8a44
-static inline int isInDenyList(char * package_name)
Richard Phibel ca8a44
+static inline int isInDenyList(char *package_name)
Richard Phibel ca8a44
 {
Richard Phibel ca8a44
     int is_in_deny_list = 0;
Richard Phibel ca8a44
     if (package_name) {
Richard Phibel ca8a44
@@ -153,7 +153,7 @@ static inline int isInDenyList(char * package_name)
Richard Phibel ca8a44
 	    denytlist_item = strtok(NULL, ",");
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
     }
Richard Phibel ca8a44
-	return is_in_deny_list;
Richard Phibel ca8a44
+    return is_in_deny_list;
Richard Phibel ca8a44
 }
Richard Phibel ca8a44
 
Richard Phibel ca8a44
 static rpmRC FDWriteSignaturesValidation(FD_t fdo, int rpmvsrc, char *msg) {
Richard Phibel ca8a44
@@ -229,6 +229,22 @@ exit:
Richard Phibel ca8a44
     return rc;
Richard Phibel ca8a44
 }
Richard Phibel ca8a44
 
Richard Phibel ca8a44
+static void sanitizeSignatureHeader(Header * sigh)
Richard Phibel ca8a44
+{
Richard Phibel ca8a44
+    struct rpmtd_s td;
Richard Phibel ca8a44
+
Richard Phibel ca8a44
+    /* This is inspired by the code in unloadImmutableRegion. See https://github.com/rpm-software-management/rpm/pull/1330 */
Richard Phibel ca8a44
+    if (!headerGet(*sigh, RPMTAG_HEADERSIGNATURES, &td, HEADERGET_DEFAULT)) {
Richard Phibel ca8a44
+	/* Signature header corrupt/missing */
Richard Phibel ca8a44
+	rpmlog(RPMLOG_WARNING, _("Error verifying signature header\n"));
Richard Phibel ca8a44
+	rpmtdFreeData(&td);
Richard Phibel ca8a44
+	Header nh = headerCopy(*sigh);
Richard Phibel ca8a44
+	headerFree(*sigh);
Richard Phibel ca8a44
+	*sigh = headerLink(nh);
Richard Phibel ca8a44
+	headerFree(nh);
Richard Phibel ca8a44
+    }
Richard Phibel ca8a44
+}
Richard Phibel ca8a44
+
Richard Phibel ca8a44
 static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)
Richard Phibel ca8a44
 {
Richard Phibel ca8a44
     uint32_t diglen;
Richard Phibel ca8a44
@@ -261,7 +277,7 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)
Richard Phibel ca8a44
     uint32_t offset_ix = 0;
Richard Phibel ca8a44
     size_t len;
Richard Phibel ca8a44
     int next = 0;
Richard Phibel ca8a44
-	struct rpmlead_s l;
Richard Phibel ca8a44
+    struct rpmlead_s l;
Richard Phibel ca8a44
     rpmfiles files = NULL;
Richard Phibel ca8a44
     rpmfi fi = NULL;
Richard Phibel ca8a44
     char *msg = NULL;
Richard Phibel ca8a44
@@ -274,43 +290,47 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)
Richard Phibel ca8a44
 
Richard Phibel ca8a44
     /* Skip conversion if package is in deny list */
Richard Phibel ca8a44
     if (isInDenyList(l.name)) {
Richard Phibel ca8a44
+	rpmlog(RPMLOG_WARNING, _("package %s is in deny list: conversion skipped\n"), l.name);
Richard Phibel ca8a44
 	if (rpmLeadWrite(fdo, l)) {
Richard Phibel ca8a44
-		fprintf(stderr, _("Unable to write package lead: %s\n"),
Richard Phibel ca8a44
-		Fstrerror(fdo));
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),
Richard Phibel ca8a44
+		    Fstrerror(fdo));
Richard Phibel ca8a44
 	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
 	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
 
Richard Phibel ca8a44
 	ssize_t fdilength = ufdCopy(fdi, fdo);
Richard Phibel ca8a44
 	if (fdilength == -1) {
Richard Phibel ca8a44
-	    fprintf(stderr, _("process_package cat failed\n"));
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("process_package cat failed\n"));
Richard Phibel ca8a44
 	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
 	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
 
Richard Phibel ca8a44
 	goto exit;
Richard Phibel ca8a44
     } else {
Richard Phibel ca8a44
-    if (rpmReadPackageRaw(fdi, &sigh, &h)) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Error reading package\n"));
Richard Phibel ca8a44
-	exit(EXIT_FAILURE);
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
+	if (rpmReadPackageRaw(fdi, &sigh, &h)) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Error reading package\n"));
Richard Phibel ca8a44
+	    exit(EXIT_FAILURE);
Richard Phibel ca8a44
+	}
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    if (rpmLeadWriteFromHeader(fdo, h))
Richard Phibel ca8a44
-    {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),
Richard Phibel ca8a44
-		Fstrerror(fdo));
Richard Phibel ca8a44
-	exit(EXIT_FAILURE);
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
+	sanitizeSignatureHeader(&sigh;;
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    if (rpmWriteSignature(fdo, sigh)) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"), Fstrerror(fdo));
Richard Phibel ca8a44
-	exit(EXIT_FAILURE);
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
+	if (rpmLeadWriteFromHeader(fdo, h)) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write package lead: %s\n"),
Richard Phibel ca8a44
+		   Fstrerror(fdo));
Richard Phibel ca8a44
+	    exit(EXIT_FAILURE);
Richard Phibel ca8a44
+	}
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"), Fstrerror(fdo));
Richard Phibel ca8a44
-	exit(EXIT_FAILURE);
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
+	if (rpmWriteSignature(fdo, sigh)) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write signature: %s\n"),
Richard Phibel ca8a44
+		   Fstrerror(fdo));
Richard Phibel ca8a44
+	    exit(EXIT_FAILURE);
Richard Phibel ca8a44
+	}
Richard Phibel ca8a44
+
Richard Phibel ca8a44
+	if (headerWrite(fdo, h, HEADER_MAGIC_YES)) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write headers: %s\n"),
Richard Phibel ca8a44
+		   Fstrerror(fdo));
Richard Phibel ca8a44
+	    exit(EXIT_FAILURE);
Richard Phibel ca8a44
+	}
Richard Phibel ca8a44
 
Richard Phibel ca8a44
 	/* Retrieve payload size and compression type. */
Richard Phibel ca8a44
 	{
Richard Phibel ca8a44
@@ -323,10 +343,11 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)
Richard Phibel ca8a44
 	gzdi = Fdopen(fdi, rpmio_flags);	/* XXX gzdi == fdi */
Richard Phibel ca8a44
 	free(rpmio_flags);
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    if (gzdi == NULL) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"), Fstrerror(gzdi));
Richard Phibel ca8a44
-	exit(EXIT_FAILURE);
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
+	if (gzdi == NULL) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("cannot re-open payload: %s\n"),
Richard Phibel ca8a44
+		   Fstrerror(gzdi));
Richard Phibel ca8a44
+	    exit(EXIT_FAILURE);
Richard Phibel ca8a44
+	}
Richard Phibel ca8a44
 
Richard Phibel ca8a44
 	files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
Richard Phibel ca8a44
 	fi = rpmfiNewArchiveReader(gzdi, files,
Richard Phibel ca8a44
@@ -348,124 +369,128 @@ static rpmRC process_package(FD_t fdi, FD_t digestori, FD_t validationi)
Richard Phibel ca8a44
 
Richard Phibel ca8a44
 	zeros = xcalloc(fundamental_block_size, 1);
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    while (next >= 0) {
Richard Phibel ca8a44
-	next = rpmfiNext(fi);
Richard Phibel ca8a44
-	if (next == RPMERR_ITER_END) {
Richard Phibel ca8a44
-	    rc = RPMRC_OK;
Richard Phibel ca8a44
-	    break;
Richard Phibel ca8a44
+	while (next >= 0) {
Richard Phibel ca8a44
+	    next = rpmfiNext(fi);
Richard Phibel ca8a44
+	    if (next == RPMERR_ITER_END) {
Richard Phibel ca8a44
+		rc = RPMRC_OK;
Richard Phibel ca8a44
+		break;
Richard Phibel ca8a44
+	    }
Richard Phibel ca8a44
+	    mode = rpmfiFMode(fi);
Richard Phibel ca8a44
+	    if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) {
Richard Phibel ca8a44
+		/* not a regular file, or the archive doesn't contain any content
Richard Phibel ca8a44
+		 * for this entry.
Richard Phibel ca8a44
+		 */
Richard Phibel ca8a44
+		continue;
Richard Phibel ca8a44
+	    }
Richard Phibel ca8a44
+	    digest = rpmfiFDigest(fi, NULL, NULL);
Richard Phibel ca8a44
+	    if (digestSetGetEntry(ds, digest, NULL)) {
Richard Phibel ca8a44
+		/* This specific digest has already been included, so skip it. */
Richard Phibel ca8a44
+		continue;
Richard Phibel ca8a44
+	    }
Richard Phibel ca8a44
+	    pad = pad_to(pos, fundamental_block_size);
Richard Phibel ca8a44
+	    if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
Richard Phibel ca8a44
+		rpmlog(RPMLOG_ERR, _("Unable to write padding\n"));
Richard Phibel ca8a44
+		rc = RPMRC_FAIL;
Richard Phibel ca8a44
+		goto exit;
Richard Phibel ca8a44
+	    }
Richard Phibel ca8a44
+	    /* round up to next fundamental_block_size */
Richard Phibel ca8a44
+	    pos += pad;
Richard Phibel ca8a44
+	    digestSetAddEntry(ds, digest);
Richard Phibel ca8a44
+	    offsets[offset_ix].digest = digest;
Richard Phibel ca8a44
+	    offsets[offset_ix].pos = pos;
Richard Phibel ca8a44
+	    offset_ix++;
Richard Phibel ca8a44
+	    size = rpmfiFSize(fi);
Richard Phibel ca8a44
+	    rc = rpmfiArchiveReadToFile(fi, fdo, 0);
Richard Phibel ca8a44
+	    if (rc != RPMRC_OK) {
Richard Phibel ca8a44
+		char *errstr = rpmfileStrerror(rc);
Richard Phibel ca8a44
+		rpmlog(RPMLOG_ERR,
Richard Phibel ca8a44
+		       _("rpmfiArchiveReadToFile failed while extracting "
Richard Phibel ca8a44
+			 "\"%s\" with RC %d: %s\n"),
Richard Phibel ca8a44
+		       rpmfiFN(fi), rc, errstr);
Richard Phibel ca8a44
+		free(errstr);
Richard Phibel ca8a44
+		goto exit;
Richard Phibel ca8a44
+	    }
Richard Phibel ca8a44
+	    pos += size;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
-	mode = rpmfiFMode(fi);
Richard Phibel ca8a44
-	if (!S_ISREG(mode) || !rpmfiArchiveHasContent(fi)) {
Richard Phibel ca8a44
-	    /* not a regular file, or the archive doesn't contain any content
Richard Phibel ca8a44
-	     * for this entry.
Richard Phibel ca8a44
-	    */
Richard Phibel ca8a44
-	    continue;
Richard Phibel ca8a44
+	Fclose(gzdi);		/* XXX gzdi == fdi */
Richard Phibel ca8a44
+
Richard Phibel ca8a44
+	qsort(offsets, (size_t) offset_ix, sizeof(struct digestoffset),
Richard Phibel ca8a44
+	      digestoffsetCmp);
Richard Phibel ca8a44
+
Richard Phibel ca8a44
+	validation_pos = pos;
Richard Phibel ca8a44
+	ssize_t validation_len = ufdCopy(validationi, fdo);
Richard Phibel ca8a44
+	if (validation_len == -1) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n"));
Richard Phibel ca8a44
+	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
+	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
-	digest = rpmfiFDigest(fi, NULL, NULL);
Richard Phibel ca8a44
-	if (digestSetGetEntry(ds, digest, NULL)) {
Richard Phibel ca8a44
-	    /* This specific digest has already been included, so skip it. */
Richard Phibel ca8a44
-	    continue;
Richard Phibel ca8a44
+
Richard Phibel ca8a44
+	digest_table_pos = validation_pos + validation_len;
Richard Phibel ca8a44
+
Richard Phibel ca8a44
+	len = sizeof(offset_ix);
Richard Phibel ca8a44
+	if (Fwrite(&offset_ix, len, 1, fdo) != len) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write length of table\n"));
Richard Phibel ca8a44
+	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
+	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
-	pad = pad_to(pos, fundamental_block_size);
Richard Phibel ca8a44
-	if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
Richard Phibel ca8a44
-	    rpmlog(RPMLOG_ERR, _("Unable to write padding\n"));
Richard Phibel ca8a44
+	len = sizeof(diglen);
Richard Phibel ca8a44
+	if (Fwrite(&diglen, len, 1, fdo) != len) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n"));
Richard Phibel ca8a44
 	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
 	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
-	/* round up to next fundamental_block_size */
Richard Phibel ca8a44
-	pos += pad;
Richard Phibel ca8a44
-	digestSetAddEntry(ds, digest);
Richard Phibel ca8a44
-	offsets[offset_ix].digest = digest;
Richard Phibel ca8a44
-	offsets[offset_ix].pos = pos;
Richard Phibel ca8a44
-	offset_ix++;
Richard Phibel ca8a44
-	size = rpmfiFSize(fi);
Richard Phibel ca8a44
-	rc = rpmfiArchiveReadToFile(fi, fdo, 0);
Richard Phibel ca8a44
-	if (rc != RPMRC_OK) {
Richard Phibel ca8a44
-	    char *errstr = rpmfileStrerror(rc);
Richard Phibel ca8a44
-	    rpmlog(RPMLOG_ERR,
Richard Phibel ca8a44
-		   _("rpmfiArchiveReadToFile failed while extracting "\
Richard Phibel ca8a44
-		   "\"%s\" with RC %d: %s\n"),
Richard Phibel ca8a44
-		   rpmfiFN(fi), rc, errstr);
Richard Phibel ca8a44
-	    free(errstr);
Richard Phibel ca8a44
+	len = sizeof(rpm_loff_t);
Richard Phibel ca8a44
+	for (int x = 0; x < offset_ix; x++) {
Richard Phibel ca8a44
+	    if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) {
Richard Phibel ca8a44
+		rpmlog(RPMLOG_ERR, _("Unable to write digest\n"));
Richard Phibel ca8a44
+		rc = RPMRC_FAIL;
Richard Phibel ca8a44
+		goto exit;
Richard Phibel ca8a44
+	    }
Richard Phibel ca8a44
+	    if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {
Richard Phibel ca8a44
+		rpmlog(RPMLOG_ERR, _("Unable to write offset\n"));
Richard Phibel ca8a44
+		rc = RPMRC_FAIL;
Richard Phibel ca8a44
+		goto exit;
Richard Phibel ca8a44
+	    }
Richard Phibel ca8a44
+	}
Richard Phibel ca8a44
+	digest_pos =
Richard Phibel ca8a44
+	    (digest_table_pos + sizeof(offset_ix) + sizeof(diglen) +
Richard Phibel ca8a44
+	     offset_ix * (diglen + sizeof(rpm_loff_t))
Richard Phibel ca8a44
+	    );
Richard Phibel ca8a44
+
Richard Phibel ca8a44
+	ssize_t digest_len = ufdCopy(digestori, fdo);
Richard Phibel ca8a44
+	if (digest_len == -1) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n"));
Richard Phibel ca8a44
+	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
 	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
-	pos += size;
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
-    Fclose(gzdi);	/* XXX gzdi == fdi */
Richard Phibel ca8a44
-
Richard Phibel ca8a44
-	qsort(offsets, (size_t) offset_ix, sizeof(struct digestoffset),
Richard Phibel ca8a44
-	      digestoffsetCmp);
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    validation_pos = pos;
Richard Phibel ca8a44
-    ssize_t validation_len = ufdCopy(validationi, fdo);
Richard Phibel ca8a44
-    if (validation_len == -1) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("validation output ufdCopy failed\n"));
Richard Phibel ca8a44
-	rc = RPMRC_FAIL;
Richard Phibel ca8a44
-	goto exit;
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
-
Richard Phibel ca8a44
-    digest_table_pos = validation_pos + validation_len;
Richard Phibel ca8a44
+	/* add more padding so the last file can be cloned. It doesn't matter that
Richard Phibel ca8a44
+	 * the table and validation etc are in this space. In fact, it's pretty
Richard Phibel ca8a44
+	 * efficient if it is.
Richard Phibel ca8a44
+	 */
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    len = sizeof(offset_ix);
Richard Phibel ca8a44
-    if (Fwrite(&offset_ix, len, 1, fdo) != len) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Unable to write length of table\n"));
Richard Phibel ca8a44
-	rc = RPMRC_FAIL;
Richard Phibel ca8a44
-	goto exit;
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
-    len = sizeof(diglen);
Richard Phibel ca8a44
-    if (Fwrite(&diglen, len, 1, fdo) != len) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Unable to write length of digest\n"));
Richard Phibel ca8a44
-	rc = RPMRC_FAIL;
Richard Phibel ca8a44
-	goto exit;
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
-    len = sizeof(rpm_loff_t);
Richard Phibel ca8a44
-    for (int x = 0; x < offset_ix; x++) {
Richard Phibel ca8a44
-	if (Fwrite(offsets[x].digest, diglen, 1, fdo) != diglen) {
Richard Phibel ca8a44
-	    rpmlog(RPMLOG_ERR, _("Unable to write digest\n"));
Richard Phibel ca8a44
+	pad =
Richard Phibel ca8a44
+	    pad_to((validation_pos + validation_len +
Richard Phibel ca8a44
+		    2 * sizeof(rpm_loff_t) + sizeof(uint64_t)),
Richard Phibel ca8a44
+		   fundamental_block_size);
Richard Phibel ca8a44
+	if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write final padding\n"));
Richard Phibel ca8a44
 	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
 	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
-	if (Fwrite(&offsets[x].pos, len, 1, fdo) != len) {
Richard Phibel ca8a44
-	    rpmlog(RPMLOG_ERR, _("Unable to write offset\n"));
Richard Phibel ca8a44
+	zeros = _free(zeros);
Richard Phibel ca8a44
+	struct extents_footer_t footer = {.offsets =
Richard Phibel ca8a44
+		{ validation_pos, digest_table_pos, digest_pos },.magic =
Richard Phibel ca8a44
+	    EXTENTS_MAGIC };
Richard Phibel ca8a44
+	len = sizeof(footer);
Richard Phibel ca8a44
+	if (Fwrite(&footer, len, 1, fdo) != len) {
Richard Phibel ca8a44
+	    rpmlog(RPMLOG_ERR, _("Unable to write footer\n"));
Richard Phibel ca8a44
 	    rc = RPMRC_FAIL;
Richard Phibel ca8a44
 	    goto exit;
Richard Phibel ca8a44
 	}
Richard Phibel ca8a44
     }
Richard Phibel ca8a44
-    digest_pos = (
Richard Phibel ca8a44
-	digest_table_pos + sizeof(offset_ix) + sizeof(diglen) +
Richard Phibel ca8a44
-	offset_ix * (diglen + sizeof(rpm_loff_t))
Richard Phibel ca8a44
-    );
Richard Phibel ca8a44
-
Richard Phibel ca8a44
-    ssize_t digest_len = ufdCopy(digestori, fdo);
Richard Phibel ca8a44
-    if (digest_len == -1) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("digest table ufdCopy failed\n"));
Richard Phibel ca8a44
-	rc = RPMRC_FAIL;
Richard Phibel ca8a44
-	goto exit;
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
-
Richard Phibel ca8a44
-    /* add more padding so the last file can be cloned. It doesn't matter that
Richard Phibel ca8a44
-     * the table and validation etc are in this space. In fact, it's pretty
Richard Phibel ca8a44
-     * efficient if it is.
Richard Phibel ca8a44
-    */
Richard Phibel ca8a44
 
Richard Phibel ca8a44
-    pad = pad_to((validation_pos + validation_len + 2 * sizeof(rpm_loff_t) +
Richard Phibel ca8a44
-		 sizeof(uint64_t)), fundamental_block_size);
Richard Phibel ca8a44
-    if (Fwrite(zeros, sizeof(char), pad, fdo) != pad) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Unable to write final padding\n"));
Richard Phibel ca8a44
-	rc = RPMRC_FAIL;
Richard Phibel ca8a44
-	goto exit;
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
-    zeros = _free(zeros);
Richard Phibel ca8a44
-    struct extents_footer_t footer = {.offsets = {validation_pos, digest_table_pos, digest_pos}, .magic = EXTENTS_MAGIC};
Richard Phibel ca8a44
-    len = sizeof(footer);
Richard Phibel ca8a44
-    if (Fwrite(&footer, len, 1, fdo) != len) {
Richard Phibel ca8a44
-	rpmlog(RPMLOG_ERR, _("Unable to write footer\n"));
Richard Phibel ca8a44
-	rc = RPMRC_FAIL;
Richard Phibel ca8a44
-	goto exit;
Richard Phibel ca8a44
-    }
Richard Phibel ca8a44
-	}
Richard Phibel ca8a44
-
Richard Phibel ca8a44
-exit:
Richard Phibel ca8a44
+  exit:
Richard Phibel ca8a44
     rpmfilesFree(files);
Richard Phibel ca8a44
     rpmfiFree(fi);
Richard Phibel ca8a44
     headerFree(h);