1 /* 2 * Copyright (c) 2012, 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 /* 25 * @test 26 * @bug 7194005 27 * @summary launcher handling of zip64 archives (Scenario A and B) 28 * @modules jdk.compiler 29 * jdk.zipfs 30 * @compile -XDignore.symbol.file BigJar.java 31 * @run main/timeout=600 BigJar 32 */ 33 /* 34 * This test consists of two scenarios: 35 * 36 * Scenario A: create a jar with entries exceeding 64K, add a main class and 37 * see if the launcher can handle it. 38 * 39 * Scenario A1: create a jar as in A, but add a zipfile comment as well. 40 * 41 * Scenario B: create a jar with a large enough file exceeding 4GB, and 42 * similarly test the launcher. This test can be run optionally by using the 43 * following jtreg option: 44 * "-javaoptions:-DBigJar_testScenarioB=true" 45 * or set 46 * "BigJar_testScenarioB" environment variable. 47 * 48 * Note this test will only run iff all the disk requirements are met at runtime. 49 */ 50 import java.io.BufferedInputStream; 51 import java.io.BufferedOutputStream; 52 import java.io.File; 53 import java.io.FileInputStream; 54 import java.io.FileOutputStream; 55 import java.io.IOException; 56 import java.io.OutputStream; 57 import java.nio.file.Files; 58 import java.nio.file.Path; 59 import java.util.ArrayList; 60 import java.util.List; 61 import java.util.jar.Attributes; 62 import java.util.jar.JarEntry; 63 import java.util.jar.JarOutputStream; 64 import java.util.jar.Manifest; 65 import java.util.zip.CRC32; 66 import java.util.zip.ZipEntry; 67 import java.util.zip.ZipOutputStream; 68 69 public class BigJar extends TestHelper { 70 71 private static final long GIGA = 1024 * 1024 * 1024; 72 private static final int BUFFER_LEN = Short.MAX_VALUE * 2; 73 74 long getCount(long minlength) { 75 return (minlength / BUFFER_LEN) + 1; 76 } 77 78 long computeCRC(long minlength) { 79 CRC32 crc = new CRC32(); 80 byte[] buffer = new byte[BUFFER_LEN]; 81 long count = getCount(minlength); 82 for (long i = 0; i < count; i++) { 83 crc.update(buffer); 84 } 85 return crc.getValue(); 86 } 87 88 long computeCRC(File inFile) throws IOException { 89 byte[] buffer = new byte[8192]; 90 CRC32 crc = new CRC32(); 91 try (FileInputStream fis = new FileInputStream(inFile); 92 BufferedInputStream bis = new BufferedInputStream(fis)) { 93 int n = bis.read(buffer); 94 while (n > 0) { 95 crc.update(buffer, 0, n); 96 n = bis.read(buffer); 97 } 98 } 99 return crc.getValue(); 100 } 101 102 void createLargeFile(OutputStream os, long minlength) throws IOException { 103 byte[] buffer = new byte[BUFFER_LEN]; 104 long count = getCount(minlength); 105 for (long i = 0; i < count; i++) { 106 os.write(buffer); 107 } 108 os.flush(); 109 } 110 111 Manifest createMainClass(File javaFile) throws IOException { 112 javaFile.delete(); 113 List<String> content = new ArrayList<>(); 114 content.add("public class " + baseName(javaFile) + "{"); 115 content.add("public static void main(String... args) {"); 116 content.add("System.out.println(\"Hello World\\n\");"); 117 content.add("System.exit(0);"); 118 content.add("}"); 119 content.add("}"); 120 createFile(javaFile, content); 121 compile(javaFile.getName()); 122 Manifest manifest = new Manifest(); 123 manifest.clear(); 124 manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); 125 manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, baseName(javaFile)); 126 System.out.println(manifest.getMainAttributes().keySet()); 127 System.out.println(manifest.getMainAttributes().values()); 128 return manifest; 129 } 130 131 void createJarWithLargeFile(File jarFile, long minlength) throws IOException { 132 File javaFile = new File("Foo.java"); 133 Manifest manifest = createMainClass(javaFile); 134 File classFile = getClassFile(javaFile); 135 try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), manifest); 136 BufferedOutputStream bos = new BufferedOutputStream(jos); 137 FileInputStream fis = new FileInputStream(classFile);) { 138 jos.setLevel(ZipOutputStream.STORED); 139 jos.setMethod(0); 140 141 JarEntry je = new JarEntry("large.data"); 142 je.setCompressedSize(getCount(minlength) * BUFFER_LEN); 143 je.setSize(getCount(minlength) * BUFFER_LEN); 144 je.setCrc(computeCRC(minlength)); 145 je.setMethod(ZipEntry.STORED); 146 jos.putNextEntry(je); 147 createLargeFile(bos, minlength); 148 149 je = new JarEntry(classFile.getName()); 150 je.setCompressedSize(classFile.length()); 151 je.setSize(classFile.length()); 152 je.setCrc(computeCRC(classFile)); 153 je.setMethod(ZipEntry.STORED); 154 jos.putNextEntry(je); 155 copyStream(fis, bos); 156 bos.flush(); 157 jos.closeEntry(); 158 } 159 } 160 161 void createLargeJar(File jarFile, String comment) throws IOException { 162 final int MAX = Short.MAX_VALUE * 2 + 10; 163 JarEntry je = null; 164 File javaFile = new File("Foo.java"); 165 File classFile = getClassFile(javaFile); 166 Manifest manifest = createMainClass(javaFile); 167 try (JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), manifest); 168 FileInputStream fis = new FileInputStream(classFile)) { 169 jos.setLevel(JarOutputStream.STORED); 170 jos.setMethod(JarOutputStream.STORED); 171 for (int i = 0; i < MAX; i++) { 172 je = new JarEntry("X" + i + ".txt"); 173 je.setSize(0); 174 je.setCompressedSize(0); 175 je.setCrc(0); 176 jos.putNextEntry(je); 177 } 178 179 // add a class file 180 je = new JarEntry(classFile.getName()); 181 je.setCompressedSize(classFile.length()); 182 je.setSize(classFile.length()); 183 je.setCrc(computeCRC(classFile)); 184 jos.putNextEntry(je); 185 copyStream(fis, jos); 186 jos.closeEntry(); 187 if (comment != null) { 188 jos.setComment(comment); 189 } 190 } 191 } 192 193 void testTheJar(File theJar) throws Exception { 194 try { 195 TestResult tr = doExec(javaCmd, "-jar", theJar.getName()); 196 tr.checkPositive(); 197 if (!tr.testStatus) { 198 System.out.println(tr); 199 throw new Exception("Failed"); 200 } 201 } finally { 202 theJar.delete(); 203 } 204 } 205 206 // a jar with entries exceeding 64k + a class file for the existential test 207 @Test 208 void testScenarioA() throws Exception { 209 File largeJar = new File("large.jar"); 210 createLargeJar(largeJar, null); 211 testTheJar(largeJar); 212 } 213 214 // a jar with entries exceeding 64k and zip comment 215 @Test 216 void testScenarioA1() throws Exception { 217 File largeJar = new File("largewithcomment.jar"); 218 createLargeJar(largeJar, "A really large jar with a comment"); 219 testTheJar(largeJar); 220 } 221 222 // a jar with an enormous file + a class file for the existential test 223 @Test 224 void testScenarioB() throws Exception { 225 final String testString = "BigJar_testScenarioB"; 226 if (Boolean.getBoolean(testString) == false && 227 System.getenv(testString) == null) { 228 System.out.println("Warning: testScenarioB passes vacuously"); 229 return; 230 } 231 final File largeJar = new File("huge.jar"); 232 233 final Path path = largeJar.getAbsoluteFile().getParentFile().toPath(); 234 final long available = Files.getFileStore(path).getUsableSpace(); 235 final long MAX_VALUE = 0xFFFF_FFFFL; 236 237 final long absolute = MAX_VALUE + 1L; 238 final long required = (long) (absolute * 1.1); // pad for sundries 239 System.out.println("\tavailable: " + available / GIGA + " GB"); 240 System.out.println("\trequired: " + required / GIGA + " GB"); 241 242 if (available > required) { 243 createJarWithLargeFile(largeJar, absolute); 244 testTheJar(largeJar); 245 } else { 246 System.out.println("Warning: testScenarioB passes vacuously," 247 + " requirements exceeds available space"); 248 } 249 } 250 251 public static void main(String... args) throws Exception { 252 BigJar bj = new BigJar(); 253 bj.run(args); 254 if (testExitValue > 0) { 255 System.out.println("Total of " + testExitValue + " failed"); 256 System.exit(1); 257 } else { 258 System.out.println("All tests pass"); 259 } 260 } 261 }