/* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* @test * @bug 4770745 6218846 6218848 6237956 * @summary test for correct detection and reporting of corrupted zip files * @author Martin Buchholz */ import java.util.*; import java.util.zip.*; import java.io.*; import static java.lang.System.*; import static java.util.zip.ZipFile.*; public class CorruptedZipFiles { static int passed = 0, failed = 0; static void fail(String msg) { failed++; err.println(msg); } static void unexpected(Throwable t) { failed++; t.printStackTrace(); } public static void main(String[] args) throws Exception { try (FileOutputStream fos = new FileOutputStream("x.zip"); ZipOutputStream zos = new ZipOutputStream(fos)) { ZipEntry e = new ZipEntry("x"); zos.putNextEntry(e); zos.write((int)'x'); } int len = (int)(new File("x.zip").length()); byte[] good = new byte[len]; try (FileInputStream fis = new FileInputStream("x.zip")) { fis.read(good); } new File("x.zip").delete(); int endpos = len - ENDHDR; int cenpos = u16(good, endpos+ENDOFF); int locpos = u16(good, cenpos+CENOFF); if (u32(good, endpos) != ENDSIG) fail("Where's ENDSIG?"); if (u32(good, cenpos) != CENSIG) fail("Where's CENSIG?"); if (u32(good, locpos) != LOCSIG) fail("Where's LOCSIG?"); if (u16(good, locpos+LOCNAM) != u16(good,cenpos+CENNAM)) fail("Name field length mismatch"); if (u16(good, locpos+LOCEXT) != u16(good,cenpos+CENEXT)) fail("Extra field length mismatch"); byte[] bad; err.println("corrupted ENDSIZ"); bad = good.clone(); bad[endpos+ENDSIZ]=(byte)0xff; checkZipException(bad, ".*bad central directory size.*"); err.println("corrupted ENDOFF"); bad = good.clone(); bad[endpos+ENDOFF]=(byte)0xff; checkZipException(bad, ".*bad central directory offset.*"); err.println("corrupted CENSIG"); bad = good.clone(); bad[cenpos]++; checkZipException(bad, ".*bad signature.*"); err.println("corrupted CENFLG"); bad = good.clone(); bad[cenpos+CENFLG] |= 1; checkZipException(bad, ".*encrypted entry.*"); err.println("corrupted CENNAM 1"); bad = good.clone(); bad[cenpos+CENNAM]++; checkZipException(bad, ".*bad header size.*"); err.println("corrupted CENNAM 2"); bad = good.clone(); bad[cenpos+CENNAM]--; checkZipException(bad, ".*bad header size.*"); err.println("corrupted CENNAM 3"); bad = good.clone(); bad[cenpos+CENNAM] = (byte)0xfd; bad[cenpos+CENNAM+1] = (byte)0xfd; checkZipException(bad, ".*bad header size.*"); err.println("corrupted CENEXT 1"); bad = good.clone(); bad[cenpos+CENEXT]++; checkZipException(bad, ".*bad header size.*"); err.println("corrupted CENEXT 2"); bad = good.clone(); bad[cenpos+CENEXT] = (byte)0xfd; bad[cenpos+CENEXT+1] = (byte)0xfd; checkZipException(bad, ".*bad header size.*"); err.println("corrupted CENCOM"); bad = good.clone(); bad[cenpos+CENCOM]++; checkZipException(bad, ".*bad header size.*"); err.println("corrupted CENHOW"); bad = good.clone(); bad[cenpos+CENHOW] = 2; checkZipException(bad, ".*bad compression method.*"); err.println("corrupted LOCSIG"); bad = good.clone(); bad[locpos]++; checkZipExceptionInGetInputStream(bad, ".*bad signature.*"); out.printf("passed = %d, failed = %d%n", passed, failed); if (failed > 0) throw new Exception("Some tests failed"); } static int uniquifier = 432; static void checkZipExceptionImpl(byte[] data, String msgPattern, boolean getInputStream) { String zipName = "bad" + (uniquifier++) + ".zip"; try { try (FileOutputStream fos = new FileOutputStream(zipName)) { fos.write(data); } try (ZipFile zf = new ZipFile(zipName)) { if (getInputStream) { InputStream is = zf.getInputStream(new ZipEntry("x")); is.read(); } } fail("Failed to throw expected ZipException"); } catch (ZipException e) { if (e.getMessage().matches(msgPattern)) passed++; else unexpected(e); } catch (Throwable t) { unexpected(t); } finally { new File(zipName).delete(); } } static void checkZipException(byte[] data, String msgPattern) { checkZipExceptionImpl(data, msgPattern, false); } static void checkZipExceptionInGetInputStream(byte[] data, String msgPattern) { checkZipExceptionImpl(data, msgPattern, true); } static int u8(byte[] data, int offset) { return data[offset]&0xff; } static int u16(byte[] data, int offset) { return u8(data,offset) + (u8(data,offset+1)<<8); } static int u32(byte[] data, int offset) { return u16(data,offset) + (u16(data,offset+2)<<16); } // The following can be deleted once this bug is fixed: // 6225935: "import static" accessibility rules for symbols different for no reason static final long LOCSIG = ZipFile.LOCSIG; static final long EXTSIG = ZipFile.EXTSIG; static final long CENSIG = ZipFile.CENSIG; static final long ENDSIG = ZipFile.ENDSIG; static final int LOCHDR = ZipFile.LOCHDR; static final int EXTHDR = ZipFile.EXTHDR; static final int CENHDR = ZipFile.CENHDR; static final int ENDHDR = ZipFile.ENDHDR; static final int LOCVER = ZipFile.LOCVER; static final int LOCFLG = ZipFile.LOCFLG; static final int LOCHOW = ZipFile.LOCHOW; static final int LOCTIM = ZipFile.LOCTIM; static final int LOCCRC = ZipFile.LOCCRC; static final int LOCSIZ = ZipFile.LOCSIZ; static final int LOCLEN = ZipFile.LOCLEN; static final int LOCNAM = ZipFile.LOCNAM; static final int LOCEXT = ZipFile.LOCEXT; static final int CENVEM = ZipFile.CENVEM; static final int CENVER = ZipFile.CENVER; static final int CENFLG = ZipFile.CENFLG; static final int CENHOW = ZipFile.CENHOW; static final int CENTIM = ZipFile.CENTIM; static final int CENCRC = ZipFile.CENCRC; static final int CENSIZ = ZipFile.CENSIZ; static final int CENLEN = ZipFile.CENLEN; static final int CENNAM = ZipFile.CENNAM; static final int CENEXT = ZipFile.CENEXT; static final int CENCOM = ZipFile.CENCOM; static final int CENDSK = ZipFile.CENDSK; static final int CENATT = ZipFile.CENATT; static final int CENATX = ZipFile.CENATX; static final int CENOFF = ZipFile.CENOFF; static final int ENDSUB = ZipFile.ENDSUB; static final int ENDTOT = ZipFile.ENDTOT; static final int ENDSIZ = ZipFile.ENDSIZ; static final int ENDOFF = ZipFile.ENDOFF; static final int ENDCOM = ZipFile.ENDCOM; }