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