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