diff options
author | Dominik Stadler <centic@apache.org> | 2024-07-15 05:40:56 +0000 |
---|---|---|
committer | Dominik Stadler <centic@apache.org> | 2024-07-15 05:40:56 +0000 |
commit | 5085e3d1b2af1ac20e6158b0a00797a0d3b6f2ba (patch) | |
tree | af1c26dbd052c082f6e55eedad2cd4634ce17492 /poi-ooxml | |
parent | 1a07ee8d6a41a410c7567b3d58f9b1ee7815c941 (diff) | |
download | poi-5085e3d1b2af1ac20e6158b0a00797a0d3b6f2ba.tar.gz poi-5085e3d1b2af1ac20e6158b0a00797a0d3b6f2ba.zip |
Add initial support for SOURCE_DATE_EPOCH
This allows to create reproducible binary files without creation/modification-timestamp
being set when environment variable SOURCE_DATE_EPOCH is set.
See https://reproducible-builds.org/docs/source-date-epoch/ for the related specification.
For now, we ensure that Zip-file entries set the modification time to 1970-01-01,
which seems to be enough to make simple OOXML files reproducible.
There are likely some other places where resulting files are not reproducible, some
more testing will be necessary to identify other areas that should take this into
account as well.
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1919236 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'poi-ooxml')
5 files changed, 31 insertions, 9 deletions
diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java index cbdd46efdc..c87d5f061a 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java +++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java @@ -61,6 +61,8 @@ public class ZipContentTypeManager extends ContentTypeManager { ZipArchiveEntry partEntry = new ZipArchiveEntry(CONTENT_TYPES_PART_NAME); try { + ZipHelper.adjustEntryTime(partEntry); + // Referenced in ZIP zos.putArchiveEntry(partEntry); try { diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java index 5fb580530e..81fd80aae9 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java +++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/ZipHelper.java @@ -18,7 +18,6 @@ package org.apache.poi.openxml4j.opc.internal; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -38,6 +37,7 @@ import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream; import org.apache.poi.openxml4j.util.ZipSecureFile; import org.apache.poi.poifs.filesystem.FileMagic; import org.apache.poi.util.Internal; +import org.apache.poi.util.Reproducibility; @Internal public final class ZipHelper { @@ -69,7 +69,9 @@ public final class ZipHelper { return null; } - return new ZipArchiveEntry(corePropsRel.getTargetURI().getPath()); + ZipArchiveEntry entry = new ZipArchiveEntry(corePropsRel.getTargetURI().getPath()); + ZipHelper.adjustEntryTime(entry); + return entry; } /** @@ -133,10 +135,10 @@ public final class ZipHelper { return null; } } - + /** * Verifies that the given stream starts with a Zip structure. - * + * * Warning - this will consume the first few bytes of the stream, * you should push-back or reset the stream after use! */ @@ -195,7 +197,7 @@ public final class ZipHelper { } /** - * Opens the specified file as a secure zip, or returns null if no + * Opens the specified file as a secure zip, or returns null if no * such file exists * * @param file @@ -211,7 +213,7 @@ public final class ZipHelper { if (file.isDirectory()) { throw new IOException("File is a directory"); } - + // Peek at the first few bytes to sanity check try (InputStream input = Files.newInputStream(file.toPath())) { verifyZipHeader(input); @@ -231,4 +233,17 @@ public final class ZipHelper { public static ZipSecureFile openZipFile(String path) throws IOException { return openZipFile(new File(path)); } + + /** + * If environment-variable SOURCE_DATE_EPOCH is set, we use "0" for the + * time of the entry. + * + * @param entry The zip-entry to adjust + */ + public static void adjustEntryTime(ZipArchiveEntry entry) { + // if SOURCE_DATE_EPOCH is set, we set the time-field to zero + if (Reproducibility.isSourceDateEpoch()) { + entry.setTime(0); + } + } } diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java index f3ad53cda7..82d5d0a3cc 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java +++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPackagePropertiesMarshaller.java @@ -45,6 +45,8 @@ public final class ZipPackagePropertiesMarshaller extends PackagePropertiesMarsh .getZipItemNameFromOPCName(part.getPartName().getURI() .toString())); try { + ZipHelper.adjustEntryTime(ctEntry); + // Save in ZIP zos.putArchiveEntry(ctEntry); // Add entry in ZIP try { diff --git a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java index d4d363c1f3..61eb8a9b55 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java +++ b/poi-ooxml/src/main/java/org/apache/poi/openxml4j/opc/internal/marshallers/ZipPartMarshaller.java @@ -83,6 +83,8 @@ public final class ZipPartMarshaller implements PartMarshaller { .getZipItemNameFromOPCName(part.getPartName().getURI() .getPath())); try { + ZipHelper.adjustEntryTime(partEntry); + // Create next zip entry zos.putArchiveEntry(partEntry); @@ -187,6 +189,8 @@ public final class ZipPartMarshaller implements PartMarshaller { ZipArchiveEntry ctEntry = new ZipArchiveEntry(ZipHelper.getZipURIFromOPCName( relPartName.getURI().toASCIIString()).getPath()); try { + ZipHelper.adjustEntryTime(ctEntry); + zos.putArchiveEntry(ctEntry); try { return StreamHelper.saveXmlInStream(xmlOutDoc, zos); diff --git a/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java index 401529839b..d4f8b7f817 100644 --- a/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java +++ b/poi-ooxml/src/main/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java @@ -35,7 +35,6 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Spliterator; -import org.apache.commons.compress.archivers.ArchiveOutputStream; import org.apache.commons.compress.archivers.zip.Zip64Mode; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; @@ -424,7 +423,7 @@ public class SXSSFWorkbook implements Workbook { } protected void injectData(ZipEntrySource zipEntrySource, OutputStream out) throws IOException { - ArchiveOutputStream zos = createArchiveOutputStream(out); + ZipArchiveOutputStream zos = createArchiveOutputStream(out); try { Enumeration<? extends ZipArchiveEntry> en = zipEntrySource.getEntries(); while (en.hasMoreElements()) { @@ -785,7 +784,7 @@ public class SXSSFWorkbook implements Workbook { * has been created. Support for the remove method may be added in the future * if someone can figure out a reliable implementation. * - * @throws UnsupportedOperationException + * @throws UnsupportedOperationException Always thrown in this implementation */ @Override public void remove() throws IllegalStateException { |