1 /* 2 * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 6334171 26 * @summary Test that zip file's data descriptor is written correctly. 27 */ 28 29 import java.io.*; 30 import java.util.*; 31 import java.util.zip.*; 32 33 /** 34 * Bug 6252735 ZipEntry contains wasteful "temporary storage" fields introduced 35 * a regression. The value of the general purpose flag bit in a LOC header is 36 * written incorrectly, because it is computed on stale data. 37 * <p> 38 * With the bug present, zipbytes2 is written incorrectly: when the LOC 39 * header is written, (flag(e) & 8) == 8. This is correct: the data will be 40 * compressed, so we don't have data length, etc. yet; that should be written 41 * in the DataDescriptor after the data itself is written. However, when the 42 * ZipOutputStream that wraps zipbytes2 is closed, the data length _is_ 43 * available, therefore (flag(e) & 8) = 0), therefore the DataDescriptor is 44 * not written. This is why, with the bug, zipbytes1.length == sizeof(ext 45 * header) + zipbytes2.length. 46 * <p> 47 * The result is an invalid LOC header in zipbytes2. So when we again use 48 * copyZip, we attempt to read a data length not from the LOC header but from 49 * the non-existent EXT header, and at that position in the file is some 50 * arbitrary and incorrect value. 51 */ 52 public class DataDescriptor { copyZip(ZipInputStream in, ZipOutputStream out)53 static void copyZip(ZipInputStream in, ZipOutputStream out) throws IOException { 54 byte[] buffer = new byte[1 << 14]; 55 for (ZipEntry ze; (ze = in.getNextEntry()) != null; ) { 56 out.putNextEntry(ze); 57 // When the bug is present, it shows up here. The second call to 58 // copyZip will throw an exception while reading data. 59 for (int nr; 0 < (nr = in.read(buffer)); ) { 60 out.write(buffer, 0, nr); 61 } 62 } 63 in.close(); 64 } 65 realMain(String[] args)66 private static void realMain(String[] args) throws Throwable { 67 // Create zip output in byte array zipbytes 68 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 69 ZipOutputStream zos = new ZipOutputStream(baos); 70 ZipEntry e = new ZipEntry("testdir/foo"); 71 byte[] data = "entry data".getBytes("ASCII"); 72 zos.putNextEntry(e); 73 zos.write(data); 74 zos.close(); 75 byte[] zipbytes1 = baos.toByteArray(); 76 int length1 = zipbytes1.length; 77 System.out.println("zip bytes pre-copy length=" + length1); 78 79 // Make a ZipInputStream around zipbytes, and use 80 // copyZip to get a new byte array. 81 ZipInputStream zis = 82 new ZipInputStream( 83 new ByteArrayInputStream(zipbytes1)); 84 baos.reset(); 85 zos = new ZipOutputStream(baos); 86 copyZip(zis, zos); 87 zos.close(); 88 byte[] zipbytes2 = baos.toByteArray(); 89 int length2 = zipbytes2.length; 90 // When the bug is present, pre- and post-copy lengths are different! 91 System.out.println("zip bytes post-copy length=" + length2); 92 93 equal(length1, length2); 94 check(Arrays.equals(zipbytes1, zipbytes2)); 95 96 // Now use copyZip again on the bytes resulting from the previous 97 // copy. When the bug is present, copyZip will get an exception this 98 // time. 99 baos.reset(); 100 zos = new ZipOutputStream(baos); 101 copyZip(new ZipInputStream(new ByteArrayInputStream(zipbytes2)), zos); 102 zos.close(); 103 byte[] zipbytes3 = baos.toByteArray(); 104 int length3 = zipbytes3.length; 105 System.out.println("zip bytes post-copy length=" + length3); 106 107 equal(length1, length3); 108 check(Arrays.equals(zipbytes1, zipbytes3)); 109 } 110 111 //--------------------- Infrastructure --------------------------- 112 static volatile int passed = 0, failed = 0; pass()113 static void pass() {passed++;} fail()114 static void fail() {failed++; Thread.dumpStack();} fail(String msg)115 static void fail(String msg) {System.out.println(msg); fail();} unexpected(Throwable t)116 static void unexpected(Throwable t) {failed++; t.printStackTrace();} check(boolean cond)117 static void check(boolean cond) {if (cond) pass(); else fail();} equal(Object x, Object y)118 static void equal(Object x, Object y) { 119 if (x == null ? y == null : x.equals(y)) pass(); 120 else fail(x + " not equal to " + y);} main(String[] args)121 public static void main(String[] args) throws Throwable { 122 try {realMain(args);} catch (Throwable t) {unexpected(t);} 123 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 124 if (failed > 0) throw new AssertionError("Some tests failed");} 125 } 126