teknoraver / rpms / rpm

Forked from rpms/rpm 4 months ago
Clone

Blame 0032-rpmcow-workaround.patch

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