Ensure that entry is completely configured before putting to the stream
Previously, BootZipCopyAction would put the next entry to the stream and then, in the case of a stored entry, configure its size, CRC32 etc. This had the benefit of being able to copy the entry into the zip once, capturing its bytes for the calculation of the CRC32 as it was copied. Unfortunately, while this produced zip files that could be read by the JVM, other zip tools failed. For example, Go's zip support that's used by CloudFoundry could not unzip the archive. This commit updates BootZipCopy action to completely configure the entry before putting it to the stream. This has the downside of copying the file twice (once for the CRC32 and once to actually write it to the zip stream) but this appears to be unavoidable as we have to produce archives that can be unzipped without problems on all platforms. Closes gh-8816
This commit is contained in:
parent
2f64cdfa98
commit
ab18901ad0
|
@ -18,7 +18,6 @@ package org.springframework.boot.gradle.tasks.bundling;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.function.Function;
|
||||
|
@ -221,26 +220,29 @@ class BootZipCopyAction implements CopyAction {
|
|||
String relativePath = details.getRelativePath().getPathString();
|
||||
ZipEntry archiveEntry = new ZipEntry(relativePath);
|
||||
archiveEntry.setTime(getTime(details));
|
||||
this.zipStream.putNextEntry(archiveEntry);
|
||||
ZipCompression compression = this.compressionType.apply(details);
|
||||
if (compression == ZipCompression.STORED) {
|
||||
archiveEntry.setMethod(ZipEntry.STORED);
|
||||
archiveEntry.setSize(details.getSize());
|
||||
archiveEntry.setCompressedSize(details.getSize());
|
||||
Crc32OutputStream crcStream = new Crc32OutputStream(this.zipStream);
|
||||
details.copyTo(crcStream);
|
||||
archiveEntry.setCrc(crcStream.getCrc());
|
||||
if (this.requiresUnpack.isSatisfiedBy(details)) {
|
||||
archiveEntry.setComment(
|
||||
"UNPACK:" + FileUtils.sha1Hash(details.getFile()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
details.copyTo(this.zipStream);
|
||||
prepareStoredEntry(details, archiveEntry);
|
||||
}
|
||||
this.zipStream.putNextEntry(archiveEntry);
|
||||
details.copyTo(this.zipStream);
|
||||
this.zipStream.closeEntry();
|
||||
}
|
||||
|
||||
private void prepareStoredEntry(FileCopyDetailsInternal details,
|
||||
ZipEntry archiveEntry) throws IOException {
|
||||
archiveEntry.setMethod(ZipEntry.STORED);
|
||||
archiveEntry.setSize(details.getSize());
|
||||
archiveEntry.setCompressedSize(details.getSize());
|
||||
Crc32OutputStream crcStream = new Crc32OutputStream();
|
||||
details.copyTo(crcStream);
|
||||
archiveEntry.setCrc(crcStream.getCrc());
|
||||
if (this.requiresUnpack.isSatisfiedBy(details)) {
|
||||
archiveEntry
|
||||
.setComment("UNPACK:" + FileUtils.sha1Hash(details.getFile()));
|
||||
}
|
||||
}
|
||||
|
||||
private long getTime(FileCopyDetails details) {
|
||||
return this.preserveFileTimestamps ? details.getLastModified()
|
||||
: GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES;
|
||||
|
@ -249,33 +251,25 @@ class BootZipCopyAction implements CopyAction {
|
|||
}
|
||||
|
||||
/**
|
||||
* A {@code FilterOutputStream} that provides a CRC-32 of the data that is written to
|
||||
* it.
|
||||
* An {@code OutputStream} that provides a CRC-32 of the data that is written to it.
|
||||
*/
|
||||
private static final class Crc32OutputStream extends FilterOutputStream {
|
||||
private static final class Crc32OutputStream extends OutputStream {
|
||||
|
||||
private final CRC32 crc32 = new CRC32();
|
||||
|
||||
private Crc32OutputStream(OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
this.crc32.update(b);
|
||||
this.out.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException {
|
||||
this.crc32.update(b);
|
||||
this.out.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
this.crc32.update(b, off, len);
|
||||
this.out.write(b, off, len);
|
||||
}
|
||||
|
||||
private long getCrc() {
|
||||
|
|
Loading…
Reference in New Issue