JDK-4406823 : Dup entry in Zip/JarOutputStream causes corrupt file to be produced (cf#112217)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 1.3.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_98,windows_nt
  • CPU: x86
  • Submitted: 2001-01-22
  • Updated: 2002-07-08
  • Resolved: 2001-06-22
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0 beta2Fixed
Description

Name: boT120536			Date: 01/22/2001


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)


If I construct a jar file using the JarOutputStream, and using putNextEntry(),
I add a duplicate entry, a corrupt jar file is produced. I get this error
message when doing a "jar tvf mybad.jar"

java.util.zip.ZipException: invalid stored block lengths
        at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:140)
        at java.util.zip.ZipInputStream.read(ZipInputStream.java:138)
         ...(didn't include the rest)...

If I trap duplicates and don't try adding them, the file is OK.

I noticed in the source for ZipOutputStream in the putNextEntry() method, a
check is done for duplicate entries, but it is after the writeLOC(e) call which
puts the local file header into the zip stream even though the file won't be
written.
(Review ID: 110419) 
======================================================================

Name: boT120536			Date: 01/22/2001


java version "1.2.2"
Classic VM (build JDK-1.2.2-001, native threads, symcjit)

and

java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)




Due to our build process, we create multiple jar files with multiple
manifests.  I wrote a JARAggregator class which combines multiple jar files
into one jar file and combines the contents of the manifest.  When doing it,
the jar output file can be used on the classpath line correctly; however the
output file cannot be accessed using the jar tool.

There are two problems
If you try to add a duplicate entry, the jar file becomes corrupted

Here is a test case.  The problem occurs when copying from one jar file to
another using JarInputStream and JarOutputStream.  Invoke it by "JarTest
inJar.jar outJar.jar"  where inJar is any jar of size.

Then run

tar tf outJar.jar

And ad after the first file you'll get...

java.util.zip.ZipException: invalid stored block lengths
        at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:140)
        at java.util.zip.ZipInputStream.read(ZipInputStream.java:138)
        at java.util.zip.ZipInputStream.closeEntry(ZipInputStream.java:96)
        at sun.tools.jar.Main.list(Main.java:705)
        at sun.tools.jar.Main.run(Main.java:192)
        at sun.tools.jar.Main.main(Main.java:778)

This seems as if it is caused by writeLOC being executed before the testing of
the entry being a duplicate in ZipOutputStream.putNextEntry()


import java.io.*;
import java.util.*;
import java.util.jar.*;
import java.util.zip.*;

public class JarTest {
    public static void main(String[] args) throws java.io.IOException {
	File inFile = new File(args[0]);
	File outFile = new File(args[1]);
	JarFile inJar = new JarFile(inFile);
	OutputStream fout = new FileOutputStream(outFile);
	JarOutputStream out = new JarOutputStream(fout);
     
	byte[] buf = new byte[1024];
	int available;
	for (Enumeration entries = inJar.entries(); entries.hasMoreElements();){
	    JarEntry entry = (JarEntry) entries.nextElement();
	    InputStream in = inJar.getInputStream(entry);
	    try {
		JarEntry newEntry = (JarEntry) entry.clone();
		newEntry.setCompressedSize(-1);
		out.putNextEntry(newEntry);
		while ((available = in.read(buf)) != -1) {
		    out.write(buf, 0, available);
		}
		out.closeEntry();
	    }
	    catch (ZipException ex) {
		ex.printStackTrace();
		return;
	    }
	    finally {
		out.closeEntry();
	    }
	    try {
		out.putNextEntry(new JarEntry(entry.getName()));
	    }
	    catch (ZipException ex) {
		// supposed to be here
	    }

	}
	out.close();
    }
}
(Review ID: 112217)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta2 FIXED IN: merlin-beta2 INTEGRATED IN: merlin-beta2 VERIFIED IN: hopper-rc merlin-beta3
14-06-2004

EVALUATION to be fixed
11-06-2004

WORK AROUND Name: boT120536 Date: 01/22/2001 I don't add duplicates... ======================================================================
11-06-2004

PUBLIC COMMENTS Now we check for dup before calling writeLOC
10-06-2004