Skip to content

Commit

Permalink
Merge pull request #1206 from dwijnand/zip-merge-fix
Browse files Browse the repository at this point in the history
Fix writing zip64's offset
  • Loading branch information
eed3si9n authored Jun 18, 2023
2 parents 66fcbeb + b79cdd2 commit 0646b30
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public void dump(OutputStream os) throws IOException {
}
end.centot = elist.size();
end.cenlen = written;
end.write(os, written);
end.write(os, written + end.cenoff);
}

private List<Entry> readEntries() throws IOException {
Expand Down Expand Up @@ -242,6 +242,7 @@ private END findEND() throws IOException
end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g
end.endpos = end64pos;
}
log(end);
return end;
}
}
Expand Down Expand Up @@ -431,6 +432,8 @@ void write(OutputStream os, long offset) throws IOException {
writeShort(os, 0);
}
}

public String toString() { return String.format("END[@%07d #%05d %07dB]", cenoff, centot, cenlen); }
}

public static class Entry extends IndexNode {
Expand Down Expand Up @@ -739,4 +742,7 @@ void readExtra(ZipCentralDir zipfs) throws IOException {
}
}

private static void log(Object x) {
//System.out.println(x);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package sbt.internal.inc
package classfile

import java.nio.file._
import java.nio.file.spi.FileSystemProvider
import scala.collection.JavaConverters._

class IndexBasedZipFsOpsSpec extends UnitSpec {
private val XL = 0xffff // minimum size to be zip64, which I'm calling "XL"
private val L = XL - 1 // last size to be standard zip, which I'm calling "L"
private val tmpDir = Files.createTempDirectory("zinc-zipmergetest")
private lazy val zipFsProvider =
FileSystemProvider.installedProviders().stream().filter(_.getScheme == "jar").findAny().get()

it should "create XS jars" in assertSize(createJar(2), 2)
it should "merge XS jars" in assertMerge(2, 1)
it should "shrink XS jars" in assertShrink(3, 2)

it should "create L jars" in assertSize(createJar(L), L)
it should "merge L jars" in assertMerge(L, 1) // breach threshold
it should "shrink L jars" in assertShrink(L + 1, L) // breach threshold back

it should "create XL jars" in assertSize(createJar(XL), XL)
it should "merge XL jars" in assertMerge(XL, 1)
it should "shrink XL jars" in assertShrink(XL + 1, XL)

private def assertMerge(size1: Int, size2: Int) = {
val a = createJar(size1)
val b = createJar(size2, "b", size1)
safely(IndexBasedZipFsOps.mergeArchives(a, b))
assertSize(a, size1 + size2)
}

private def assertShrink(size1: Int, size2: Int) = {
val a = createJar(size1)
val files = for (i <- size2 until size1) yield classFileName(i)
safely(IndexBasedZipFsOps.removeEntries(a.toFile, files))
assertSize(a, size2)
}

private def assertSize(p: Path, size: Int) = {
val cen = safely(IndexBasedZipFsOps.readCentralDir(p.toFile))
assert(cen.getHeaders.size() == size)
Files.delete(p)
}

private def createJar(n: Int, name: String = "a", from: Int = 0) = {
val out = tmpDir.resolve(s"$name.jar")
val zipfs = zipFsProvider.newFileSystem(out, Map("create" -> "true").asJava)
val root = zipfs.getRootDirectories.iterator().next()
for (i <- from until (from + n)) {
val empty = root.resolve(classFileName(i))
Files.write(empty, Array.emptyByteArray)
}
zipfs.close()
out
}

private def classFileName(i: Int) = f"C$i%032d.class"

private def safely[A](op: => A) =
try op
catch { case ex: java.util.zip.ZipError => throw new ZipException(ex) }
}

// Avoid java.util.zip.ZipError, which is a VirtualMachineError!!?!
final class ZipException(val cause: Throwable) extends Exception
with scala.util.control.NoStackTrace {
override def toString: String = cause.toString
override def getCause: Throwable = cause.getCause
override def getMessage: String = cause.getMessage
override def getStackTrace: Array[StackTraceElement] = cause.getStackTrace
override def printStackTrace(s: java.io.PrintStream): Unit = cause.printStackTrace(s)
override def printStackTrace(s: java.io.PrintWriter): Unit = cause.printStackTrace(s)
}

0 comments on commit 0646b30

Please sign in to comment.