1 /* 2 * Copyright (c) 2007, 2013, 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 import java.nio.file.Path; 25 import java.io.BufferedReader; 26 import java.io.ByteArrayOutputStream; 27 import java.io.Closeable; 28 import java.io.File; 29 import java.io.FileFilter; 30 import java.io.FileOutputStream; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.InputStreamReader; 34 import java.io.PrintStream; 35 import java.nio.charset.Charset; 36 import java.nio.file.Files; 37 import java.util.ArrayList; 38 import java.util.Arrays; 39 import java.util.Collections; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.jar.JarFile; 43 import java.util.jar.JarOutputStream; 44 import java.util.jar.Pack200; 45 import java.util.zip.ZipEntry; 46 import java.util.zip.ZipFile; 47 48 import static java.nio.file.StandardCopyOption.*; 49 import static java.nio.file.StandardOpenOption.*; 50 51 /** 52 * 53 * @author ksrini 54 */ 55 56 /* 57 * This class contains all the commonly used utilities used by various tests 58 * in this directory. 59 */ 60 class Utils { 61 static final String JavaHome = System.getProperty("test.java", 62 System.getProperty("java.home")); 63 static final boolean IsWindows = 64 System.getProperty("os.name").startsWith("Windows"); 65 static final boolean Is64Bit = 66 System.getProperty("sun.arch.data.model", "32").equals("64"); 67 static final File JavaSDK = new File(JavaHome).getParentFile(); 68 69 static final String PACK_FILE_EXT = ".pack"; 70 static final String JAVA_FILE_EXT = ".java"; 71 static final String CLASS_FILE_EXT = ".class"; 72 static final String JAR_FILE_EXT = ".jar"; 73 74 static final File TEST_SRC_DIR = new File(System.getProperty("test.src")); 75 static final File TEST_CLS_DIR = new File(System.getProperty("test.classes")); 76 static final String VERIFIER_DIR_NAME = "pack200-verifier"; 77 static final File VerifierJar = new File(VERIFIER_DIR_NAME + JAR_FILE_EXT); 78 static final File XCLASSES = new File("xclasses"); 79 80 private Utils() {} // all static 81 82 static { 83 if (!JavaHome.endsWith("jre")) { 84 throw new RuntimeException("Error: requires an SDK to run"); 85 } 86 } 87 88 private static void init() throws IOException { 89 if (VerifierJar.exists()) { 90 return; 91 } 92 File srcDir = new File(TEST_SRC_DIR, VERIFIER_DIR_NAME); 93 if (!srcDir.exists()) { 94 // if not available try one level above 95 srcDir = new File(TEST_SRC_DIR.getParentFile(), VERIFIER_DIR_NAME); 96 } 97 List<File> javaFileList = findFiles(srcDir, createFilter(JAVA_FILE_EXT)); 98 File tmpFile = File.createTempFile("javac", ".tmp"); 99 XCLASSES.mkdirs(); 100 FileOutputStream fos = null; 101 PrintStream ps = null; 102 try { 103 fos = new FileOutputStream(tmpFile); 104 ps = new PrintStream(fos); 105 for (File f : javaFileList) { 106 ps.println(f.getAbsolutePath()); 107 } 108 } finally { 109 close(ps); 110 close(fos); 111 } 112 113 compiler("-d", 114 XCLASSES.getName(), 115 "@" + tmpFile.getAbsolutePath()); 116 117 jar("cvfe", 118 VerifierJar.getName(), 119 "sun.tools.pack.verify.Main", 120 "-C", 121 XCLASSES.getName(), 122 "."); 123 } 124 125 static void dirlist(File dir) { 126 File[] files = dir.listFiles(); 127 System.out.println("--listing " + dir.getAbsolutePath() + "---"); 128 for (File f : files) { 129 StringBuffer sb = new StringBuffer(); 130 sb.append(f.isDirectory() ? "d " : "- "); 131 sb.append(f.getName()); 132 System.out.println(sb); 133 } 134 } 135 static void doCompareVerify(File reference, File specimen) throws IOException { 136 init(); 137 List<String> cmds = new ArrayList<String>(); 138 cmds.add(getJavaCmd()); 139 cmds.add("-cp"); 140 cmds.add(Utils.locateJar("tools.jar") + 141 System.getProperty("path.separator") + VerifierJar.getName()); 142 cmds.add("sun.tools.pack.verify.Main"); 143 cmds.add(reference.getAbsolutePath()); 144 cmds.add(specimen.getAbsolutePath()); 145 cmds.add("-O"); 146 runExec(cmds); 147 } 148 149 static void doCompareBitWise(File reference, File specimen) 150 throws IOException { 151 init(); 152 List<String> cmds = new ArrayList<String>(); 153 cmds.add(getJavaCmd()); 154 cmds.add("-cp"); 155 cmds.add(Utils.locateJar("tools.jar") 156 + System.getProperty("path.separator") + VerifierJar.getName()); 157 cmds.add("sun.tools.pack.verify.Main"); 158 cmds.add(reference.getName()); 159 cmds.add(specimen.getName()); 160 cmds.add("-O"); 161 cmds.add("-b"); 162 runExec(cmds); 163 } 164 165 static FileFilter createFilter(final String extension) { 166 return new FileFilter() { 167 @Override 168 public boolean accept(File pathname) { 169 String name = pathname.getName(); 170 if (name.endsWith(extension)) { 171 return true; 172 } 173 return false; 174 } 175 }; 176 } 177 178 /* 179 * clean up all the usual suspects 180 */ 181 static void cleanup() throws IOException { 182 recursiveDelete(XCLASSES); 183 List<File> toDelete = new ArrayList<>(); 184 toDelete.addAll(Utils.findFiles(new File("."), 185 Utils.createFilter(".out"))); 186 toDelete.addAll(Utils.findFiles(new File("."), 187 Utils.createFilter(".bak"))); 188 toDelete.addAll(Utils.findFiles(new File("."), 189 Utils.createFilter(".jar"))); 190 toDelete.addAll(Utils.findFiles(new File("."), 191 Utils.createFilter(".pack"))); 192 toDelete.addAll(Utils.findFiles(new File("."), 193 Utils.createFilter(".bnd"))); 194 toDelete.addAll(Utils.findFiles(new File("."), 195 Utils.createFilter(".txt"))); 196 toDelete.addAll(Utils.findFiles(new File("."), 197 Utils.createFilter(".idx"))); 198 toDelete.addAll(Utils.findFiles(new File("."), 199 Utils.createFilter(".gidx"))); 200 for (File f : toDelete) { 201 f.delete(); 202 } 203 } 204 205 static final FileFilter DIR_FILTER = new FileFilter() { 206 public boolean accept(File pathname) { 207 if (pathname.isDirectory()) { 208 return true; 209 } 210 return false; 211 } 212 }; 213 214 static final FileFilter FILE_FILTER = new FileFilter() { 215 public boolean accept(File pathname) { 216 if (pathname.isFile()) { 217 return true; 218 } 219 return false; 220 } 221 }; 222 223 static void copyFile(File src, File dst) throws IOException { 224 Path parent = dst.toPath().getParent(); 225 if (parent != null) { 226 Files.createDirectories(parent); 227 } 228 Files.copy(src.toPath(), dst.toPath(), COPY_ATTRIBUTES, REPLACE_EXISTING); 229 if (dst.isDirectory() && !dst.canWrite()) { 230 dst.setWritable(true); 231 } 232 } 233 234 static String baseName(File file, String extension) { 235 return baseName(file.getAbsolutePath(), extension); 236 } 237 238 static String baseName(String name, String extension) { 239 int cut = name.length() - extension.length(); 240 return name.lastIndexOf(extension) == cut 241 ? name.substring(0, cut) 242 : name; 243 244 } 245 static void createFile(File outFile, List<String> content) throws IOException { 246 Files.write(outFile.getAbsoluteFile().toPath(), content, 247 Charset.defaultCharset(), CREATE_NEW, TRUNCATE_EXISTING); 248 } 249 250 /* 251 * Suppose a path is provided which consists of a full path 252 * this method returns the sub path for a full path ex: /foo/bar/baz/foobar.z 253 * and the base path is /foo/bar it will will return baz/foobar.z. 254 */ 255 private static String getEntryPath(String basePath, String fullPath) { 256 if (!fullPath.startsWith(basePath)) { 257 return null; 258 } 259 return fullPath.substring(basePath.length()); 260 } 261 262 static String getEntryPath(File basePathFile, File fullPathFile) { 263 return getEntryPath(basePathFile.toString(), fullPathFile.toString()); 264 } 265 266 public static void recursiveCopy(File src, File dest) throws IOException { 267 if (!src.exists() || !src.canRead()) { 268 throw new IOException("file not found or readable: " + src); 269 } 270 if (dest.exists() && !dest.isDirectory() && !dest.canWrite()) { 271 throw new IOException("file not found or writeable: " + dest); 272 } 273 if (!dest.exists()) { 274 dest.mkdirs(); 275 } 276 List<File> a = directoryList(src); 277 for (File f : a) { 278 copyFile(f, new File(dest, getEntryPath(src, f))); 279 } 280 } 281 282 static List<File> directoryList(File dirname) { 283 List<File> dirList = new ArrayList<File>(); 284 return directoryList(dirname, dirList, null); 285 } 286 287 private static List<File> directoryList(File dirname, List<File> dirList, 288 File[] dirs) { 289 dirList.addAll(Arrays.asList(dirname.listFiles(FILE_FILTER))); 290 dirs = dirname.listFiles(DIR_FILTER); 291 for (File f : dirs) { 292 if (f.isDirectory() && !f.equals(dirname)) { 293 dirList.add(f); 294 directoryList(f, dirList, dirs); 295 } 296 } 297 return dirList; 298 } 299 300 static void recursiveDelete(File dir) throws IOException { 301 if (dir.isFile()) { 302 dir.delete(); 303 } else if (dir.isDirectory()) { 304 File[] entries = dir.listFiles(); 305 for (int i = 0; i < entries.length; i++) { 306 if (entries[i].isDirectory()) { 307 recursiveDelete(entries[i]); 308 } 309 entries[i].delete(); 310 } 311 dir.delete(); 312 } 313 } 314 315 static List<File> findFiles(File startDir, FileFilter filter) 316 throws IOException { 317 List<File> list = new ArrayList<File>(); 318 findFiles0(startDir, list, filter); 319 return list; 320 } 321 /* 322 * finds files in the start directory using the the filter, appends 323 * the files to the dirList. 324 */ 325 private static void findFiles0(File startDir, List<File> list, 326 FileFilter filter) throws IOException { 327 File[] foundFiles = startDir.listFiles(filter); 328 list.addAll(Arrays.asList(foundFiles)); 329 File[] dirs = startDir.listFiles(DIR_FILTER); 330 for (File dir : dirs) { 331 findFiles0(dir, list, filter); 332 } 333 } 334 335 static void close(Closeable c) { 336 if (c == null) { 337 return; 338 } 339 try { 340 c.close(); 341 } catch (IOException ignore) { 342 } 343 } 344 345 static void compiler(String... javacCmds) { 346 if (com.sun.tools.javac.Main.compile(javacCmds) != 0) { 347 throw new RuntimeException("compilation failed"); 348 } 349 } 350 351 static void jar(String... jargs) { 352 sun.tools.jar.Main jarTool = 353 new sun.tools.jar.Main(System.out, System.err, "jartool"); 354 if (!jarTool.run(jargs)) { 355 throw new RuntimeException("jar command failed"); 356 } 357 } 358 359 static void testWithRepack(File inFile, String... repackOpts) throws IOException { 360 File cwd = new File("."); 361 // pack using --repack in native mode 362 File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT); 363 repack(inFile, nativejarFile, false, repackOpts); 364 doCompareVerify(inFile, nativejarFile); 365 366 // ensure bit compatibility between the unpacker variants 367 File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT); 368 repack(inFile, javajarFile, true, repackOpts); 369 doCompareBitWise(javajarFile, nativejarFile); 370 } 371 372 static List<String> repack(File inFile, File outFile, 373 boolean disableNative, String... extraOpts) { 374 List<String> cmdList = new ArrayList<>(); 375 cmdList.clear(); 376 cmdList.add(Utils.getJavaCmd()); 377 cmdList.add("-ea"); 378 cmdList.add("-esa"); 379 if (disableNative) { 380 cmdList.add("-Dcom.sun.java.util.jar.pack.disable.native=true"); 381 } 382 cmdList.add("com.sun.java.util.jar.pack.Driver"); 383 cmdList.add("--repack"); 384 if (extraOpts != null) { 385 for (String opt: extraOpts) { 386 cmdList.add(opt); 387 } 388 } 389 cmdList.add(outFile.getName()); 390 cmdList.add(inFile.getName()); 391 return Utils.runExec(cmdList); 392 } 393 394 // given a jar file foo.jar will write to foo.pack 395 static void pack(JarFile jarFile, File packFile) throws IOException { 396 Pack200.Packer packer = Pack200.newPacker(); 397 Map<String, String> p = packer.properties(); 398 // Take the time optimization vs. space 399 p.put(packer.EFFORT, "1"); // CAUTION: do not use 0. 400 // Make the memory consumption as effective as possible 401 p.put(packer.SEGMENT_LIMIT, "10000"); 402 // ignore all JAR deflation requests to save time 403 p.put(packer.DEFLATE_HINT, packer.FALSE); 404 // save the file ordering of the original JAR 405 p.put(packer.KEEP_FILE_ORDER, packer.TRUE); 406 FileOutputStream fos = null; 407 try { 408 // Write out to a jtreg scratch area 409 fos = new FileOutputStream(packFile); 410 // Call the packer 411 packer.pack(jarFile, fos); 412 } finally { 413 close(fos); 414 } 415 } 416 417 // uses java unpacker, slow but useful to discover issues with the packer 418 static void unpackj(File inFile, JarOutputStream jarStream) 419 throws IOException { 420 unpack0(inFile, jarStream, true); 421 422 } 423 424 // uses native unpacker using the java APIs 425 static void unpackn(File inFile, JarOutputStream jarStream) 426 throws IOException { 427 unpack0(inFile, jarStream, false); 428 } 429 430 // given a packed file, create the jar file in the current directory. 431 private static void unpack0(File inFile, JarOutputStream jarStream, 432 boolean useJavaUnpack) throws IOException { 433 // Unpack the files 434 Pack200.Unpacker unpacker = Pack200.newUnpacker(); 435 Map<String, String> props = unpacker.properties(); 436 if (useJavaUnpack) { 437 props.put("com.sun.java.util.jar.pack.disable.native", "true"); 438 } 439 // Call the unpacker 440 unpacker.unpack(inFile, jarStream); 441 } 442 443 static byte[] getBuffer(ZipFile zf, ZipEntry ze) throws IOException { 444 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 445 byte buf[] = new byte[8192]; 446 InputStream is = null; 447 try { 448 is = zf.getInputStream(ze); 449 int n = is.read(buf); 450 while (n > 0) { 451 baos.write(buf, 0, n); 452 n = is.read(buf); 453 } 454 return baos.toByteArray(); 455 } finally { 456 close(is); 457 } 458 } 459 460 static ArrayList<String> getZipFileEntryNames(ZipFile z) { 461 ArrayList<String> out = new ArrayList<String>(); 462 for (ZipEntry ze : Collections.list(z.entries())) { 463 out.add(ze.getName()); 464 } 465 return out; 466 } 467 static List<String> runExec(List<String> cmdsList) { 468 return runExec(cmdsList, null); 469 } 470 static List<String> runExec(List<String> cmdsList, Map<String, String> penv) { 471 ArrayList<String> alist = new ArrayList<String>(); 472 ProcessBuilder pb = 473 new ProcessBuilder(cmdsList); 474 Map<String, String> env = pb.environment(); 475 if (penv != null && !penv.isEmpty()) { 476 env.putAll(penv); 477 } 478 pb.directory(new File(".")); 479 dirlist(new File(".")); 480 for (String x : cmdsList) { 481 System.out.print(x + " "); 482 } 483 System.out.println(""); 484 int retval = 0; 485 Process p = null; 486 InputStreamReader ir = null; 487 BufferedReader rd = null; 488 InputStream is = null; 489 try { 490 pb.redirectErrorStream(true); 491 p = pb.start(); 492 is = p.getInputStream(); 493 ir = new InputStreamReader(is); 494 rd = new BufferedReader(ir, 8192); 495 496 String in = rd.readLine(); 497 while (in != null) { 498 alist.add(in); 499 System.out.println(in); 500 in = rd.readLine(); 501 } 502 retval = p.waitFor(); 503 if (retval != 0) { 504 throw new RuntimeException("process failed with non-zero exit"); 505 } 506 } catch (Exception ex) { 507 throw new RuntimeException(ex.getMessage()); 508 } finally { 509 close(rd); 510 close(ir); 511 close(is); 512 if (p != null) { 513 p.destroy(); 514 } 515 } 516 return alist; 517 } 518 519 static String getUnpack200Cmd() { 520 return getAjavaCmd("unpack200"); 521 } 522 523 static String getPack200Cmd() { 524 return getAjavaCmd("pack200"); 525 } 526 527 static String getJavaCmd() { 528 return getAjavaCmd("java"); 529 } 530 531 static String getAjavaCmd(String cmdStr) { 532 File binDir = new File(JavaHome, "bin"); 533 File unpack200File = IsWindows 534 ? new File(binDir, cmdStr + ".exe") 535 : new File(binDir, cmdStr); 536 537 String cmd = unpack200File.getAbsolutePath(); 538 if (!unpack200File.canExecute()) { 539 throw new RuntimeException("please check" + 540 cmd + " exists and is executable"); 541 } 542 return cmd; 543 } 544 545 private static List<File> locaterCache = null; 546 // search the source dir and jdk dir for requested file and returns 547 // the first location it finds. 548 static File locateJar(String name) { 549 try { 550 if (locaterCache == null) { 551 locaterCache = new ArrayList<File>(); 552 locaterCache.addAll(findFiles(TEST_SRC_DIR, createFilter(JAR_FILE_EXT))); 553 locaterCache.addAll(findFiles(JavaSDK, createFilter(JAR_FILE_EXT))); 554 } 555 for (File f : locaterCache) { 556 if (f.getName().equals(name)) { 557 return f; 558 } 559 } 560 throw new IOException("file not found: " + name); 561 } catch (IOException e) { 562 throw new RuntimeException(e); 563 } 564 } 565 }