src/share/classes/org/openjdk/jigsaw/ModuleFile.java

Print this page




  41         switch (type) {
  42         case MODULE_INFO:
  43         case SIGNATURE:
  44             return ".";
  45         case CLASSES:
  46         case RESOURCES:
  47             return "classes";
  48         case NATIVE_LIBS:
  49             return "lib";
  50         case NATIVE_CMDS:
  51             return "bin";
  52         case CONFIG:
  53             return "etc";
  54         default:
  55             throw new AssertionError(type);
  56         }
  57     }
  58 
  59     public final static class Reader implements Closeable {
  60 



  61         private DataInputStream stream;
  62         private File destination;
  63         private boolean deflate;
  64         private HashType hashtype;
  65 
  66         private static class CountingInputStream extends FilterInputStream {
  67             int count;
  68             public CountingInputStream(InputStream stream, int count) {
  69                 super(stream);
  70                 this.count = count;
  71             }
  72 
  73             public int available() throws IOException {
  74                 return count;
  75             }
  76 
  77             public boolean markSupported() {
  78                 return false;
  79             }
  80 


 106                     return -1;
 107                 n = Math.min(n, count);
 108                 long skipped = super.skip(n);
 109                 if (n > 0)
 110                     count-=skipped;
 111                 return skipped;
 112             }
 113         }
 114 
 115         public Reader(DataInputStream stream) {
 116             hashtype = HashType.SHA256;
 117             // Ensure that mark/reset is supported
 118             if (stream.markSupported()) {
 119                 this.stream = stream;
 120             } else {
 121                 this.stream =
 122                     new DataInputStream(new BufferedInputStream(stream));
 123             }
 124         }
 125 





 126         private void checkHashMatch(byte[] expected, byte[] computed)
 127             throws IOException
 128         {
 129             if (!MessageDigest.isEqual(expected, computed))
 130                 throw new IOException("Expected hash "
 131                                       + hashHexString(expected)
 132                                       + " instead of "
 133                                       + hashHexString(computed));
 134         }
 135 
 136         private ModuleFileHeader fileHeader = null;
 137         private MessageDigest fileDigest = null;
 138         private MessageDigest sectionDigest = null;
 139         private DataInputStream fileIn = null;
 140         private byte[] moduleInfoBytes = null;
 141         private Integer moduleSignatureType = null;
 142         private byte[] moduleSignatureBytes = null;
 143         private final int MAX_SECTION_HEADER_LENGTH = 128;
 144         private List<byte[]> calculatedHashes = new ArrayList<>();
 145         private boolean extract = true;


 243         }
 244 
 245         private JarOutputStream contentStream = null;
 246 
 247         private JarOutputStream contentStream() throws IOException {
 248             if (contentStream == null) {
 249                 if (extract) {
 250                     FileOutputStream fos
 251                         = new FileOutputStream(computeRealPath("classes"));
 252                     contentStream
 253                         = new JarOutputStream(new BufferedOutputStream(fos));
 254                 } else {
 255                     contentStream = new JarOutputStream(new NullOutputStream());
 256                 }
 257             }
 258             return contentStream;
 259         }
 260 
 261         public void close() throws IOException {
 262             try {

 263                 if (contentStream != null) {
 264                     contentStream.close();
 265                     contentStream = null;
 266                 }
 267             } finally {
 268                 if (fileIn != null) {
 269                     fileIn.close();
 270                     fileIn = null;
 271                 }
 272             }




 273         }


 274 

 275         public void readModule() throws IOException {
 276             extract = false;
 277             readStart();
 278             readRest();
 279         }
 280 
 281         public void readModule(File dst) throws IOException {
 282             readStart();
 283             readRest(dst, false);
 284         }
 285 
 286         private void readSignatureSection(DataInputStream stream,
 287                                           DigestInputStream dis)
 288             throws IOException
 289         {
 290 
 291             // Turn off digest computation before reading Signature Section
 292             dis.on(false);
 293 
 294             // Mark the starting position


 366                 }
 367                 break;
 368             case GZIP:
 369                 readGZIPCompressedFile(in, type);
 370                 break;
 371             case PACK200_GZIP:
 372                 readClasses(
 373                     new DataInputStream(new CountingInputStream(in, csize)));
 374                 break;
 375             default:
 376                 throw new IOException("Unsupported Compressor for files: " +
 377                                       compressor);
 378             }
 379         }
 380 
 381         public void readClasses(DataInputStream in) throws IOException {
 382             unpack200gzip(in);
 383         }
 384 
 385         private File currentPath = null;


 386 
 387         private OutputStream openOutputStream(SectionType type,
 388                                               String path)
 389             throws IOException
 390         {
 391             if (!extract)
 392                 return new NullOutputStream();
 393             currentPath = null;
 394             assert type != SectionType.CLASSES;
 395             if (type == SectionType.RESOURCES)
 396                 return Files.newOutputStream(contentStream(), path);
 397             currentPath = computeRealPath(type, path);
 398             File parent = currentPath.getParentFile();
 399             if (!parent.exists())
 400                 Files.mkdirs(parent, currentPath.getName());
 401             return new BufferedOutputStream(new FileOutputStream(currentPath));
 402         }
 403 
 404         private static class NullOutputStream extends OutputStream {
 405             @Override


 412 
 413         public void readGZIPCompressedFile(DataInputStream in,
 414                                            SectionType type)
 415             throws IOException
 416         {
 417             SubSectionFileHeader header = SubSectionFileHeader.read(in);
 418             int csize = header.getCSize();
 419 
 420             // Splice off the compressed file from input stream
 421             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 422             copyStream(new CountingInputStream(in, csize), baos, csize);
 423 
 424             byte[] compressedfile = baos.toByteArray();
 425             ByteArrayInputStream bain
 426                 = new ByteArrayInputStream(compressedfile);
 427             try (GZIPInputStream gin = new GZIPInputStream(bain);
 428                  OutputStream out = openOutputStream(type, header.getPath())) {
 429                 copyStream(gin, out);
 430             }
 431 
 432             if (extract)
 433                 markNativeCodeExecutable(type, currentPath);


 434         }

 435 
 436         public void readUncompressedFile(DataInputStream in,
 437                                          SectionType type,
 438                                          int csize)
 439             throws IOException
 440         {
 441             assert type != SectionType.MODULE_INFO;
 442             SubSectionFileHeader header = SubSectionFileHeader.read(in);
 443             csize = header.getCSize();
 444             try (OutputStream out = openOutputStream(type, header.getPath())) {
 445                 CountingInputStream cin = new CountingInputStream(in, csize);
 446                 byte[] buf = new byte[8192];
 447                 int n;
 448                 while ((n = cin.read(buf)) >= 0)
 449                     out.write(buf, 0, n);
 450             }

 451             markNativeCodeExecutable(type, currentPath);


 452          }

 453 
 454         public byte[] readModuleInfo(DataInputStream in, int csize)
 455             throws IOException
 456         {
 457             CountingInputStream cin = new CountingInputStream(in, csize);
 458             ByteArrayOutputStream out = new ByteArrayOutputStream();
 459             byte[] buf = new byte[8192];
 460             int n;
 461             while ((n = cin.read(buf)) >= 0)
 462                 out.write(buf, 0, n);
 463             return out.toByteArray();
 464         }
 465 
 466         public byte[] readModuleSignature(DataInputStream in, int csize)
 467             throws IOException
 468         {
 469             return readModuleInfo(in, csize); // signature has the same format
 470         }
 471 


















































 472         private File computeRealPath(String storedpath) throws IOException {
 473 
 474             String convertedpath = storedpath.replace('/', File.separatorChar);
 475             File path = new File(convertedpath);
 476 
 477             // Absolute path names are not permitted.
 478             ensureNonAbsolute(path);
 479             path = resolveAndNormalize(destination, convertedpath);
 480             // Create the parent directories if necessary
 481             File parent = path.getParentFile();
 482             if (!parent.exists())
 483                 Files.mkdirs(parent, path.getName());
 484 
 485             return path;
 486         }
 487 
 488         private File computeRealPath(SectionType type,
 489                                      String storedpath)
 490             throws IOException
 491         {





















 492             String dir = getSubdirOfSection(type);
 493             return computeRealPath(dir + File.separatorChar + storedpath);
 494         }
 495 
 496         private static void markNativeCodeExecutable(SectionType type,
 497                                                      File file)
 498         {
 499             if (type == SectionType.NATIVE_CMDS
 500                 || (type == SectionType.NATIVE_LIBS
 501                     && System.getProperty("os.name").startsWith("Windows")))
 502                 {
 503                     file.setExecutable(true);
 504                 }
 505         }
 506 
 507         private void unpack200gzip(DataInputStream in) throws IOException {
 508             GZIPInputStream gis = new GZIPInputStream(in) {
 509                     public void close() throws IOException {}
 510                 };
 511             Pack200.Unpacker unpacker = Pack200.newUnpacker();




  41         switch (type) {
  42         case MODULE_INFO:
  43         case SIGNATURE:
  44             return ".";
  45         case CLASSES:
  46         case RESOURCES:
  47             return "classes";
  48         case NATIVE_LIBS:
  49             return "lib";
  50         case NATIVE_CMDS:
  51             return "bin";
  52         case CONFIG:
  53             return "etc";
  54         default:
  55             throw new AssertionError(type);
  56         }
  57     }
  58 
  59     public final static class Reader implements Closeable {
  60 
  61         // The library where this module is to be installed, or null if
  62         // simply extracting ( jmod Extract, or jsign )
  63         private SimpleLibrary lib;
  64         private DataInputStream stream;
  65         private File destination;
  66         private boolean deflate;
  67         private HashType hashtype;
  68 
  69         private static class CountingInputStream extends FilterInputStream {
  70             int count;
  71             public CountingInputStream(InputStream stream, int count) {
  72                 super(stream);
  73                 this.count = count;
  74             }
  75 
  76             public int available() throws IOException {
  77                 return count;
  78             }
  79 
  80             public boolean markSupported() {
  81                 return false;
  82             }
  83 


 109                     return -1;
 110                 n = Math.min(n, count);
 111                 long skipped = super.skip(n);
 112                 if (n > 0)
 113                     count-=skipped;
 114                 return skipped;
 115             }
 116         }
 117 
 118         public Reader(DataInputStream stream) {
 119             hashtype = HashType.SHA256;
 120             // Ensure that mark/reset is supported
 121             if (stream.markSupported()) {
 122                 this.stream = stream;
 123             } else {
 124                 this.stream =
 125                     new DataInputStream(new BufferedInputStream(stream));
 126             }
 127         }
 128 
 129         public Reader(DataInputStream stream, SimpleLibrary lib) {
 130             this(stream);
 131             this.lib = lib;
 132         }
 133 
 134         private void checkHashMatch(byte[] expected, byte[] computed)
 135             throws IOException
 136         {
 137             if (!MessageDigest.isEqual(expected, computed))
 138                 throw new IOException("Expected hash "
 139                                       + hashHexString(expected)
 140                                       + " instead of "
 141                                       + hashHexString(computed));
 142         }
 143 
 144         private ModuleFileHeader fileHeader = null;
 145         private MessageDigest fileDigest = null;
 146         private MessageDigest sectionDigest = null;
 147         private DataInputStream fileIn = null;
 148         private byte[] moduleInfoBytes = null;
 149         private Integer moduleSignatureType = null;
 150         private byte[] moduleSignatureBytes = null;
 151         private final int MAX_SECTION_HEADER_LENGTH = 128;
 152         private List<byte[]> calculatedHashes = new ArrayList<>();
 153         private boolean extract = true;


 251         }
 252 
 253         private JarOutputStream contentStream = null;
 254 
 255         private JarOutputStream contentStream() throws IOException {
 256             if (contentStream == null) {
 257                 if (extract) {
 258                     FileOutputStream fos
 259                         = new FileOutputStream(computeRealPath("classes"));
 260                     contentStream
 261                         = new JarOutputStream(new BufferedOutputStream(fos));
 262                 } else {
 263                     contentStream = new JarOutputStream(new NullOutputStream());
 264                 }
 265             }
 266             return contentStream;
 267         }
 268 
 269         public void close() throws IOException {
 270             try {
 271                 try {
 272                     if (contentStream != null) {
 273                         contentStream.close();
 274                         contentStream = null;
 275                     }
 276                 } finally {
 277                     if (fileIn != null) {
 278                         fileIn.close();
 279                         fileIn = null;
 280                     }
 281                 }
 282             } finally {
 283                 if (oomFilesWriter != null) {
 284                     oomFilesWriter.close();
 285                     oomFilesWriter = null;
 286                 }
 287             }
 288         }
 289 
 290 
 291         public void readModule() throws IOException {
 292             extract = false;
 293             readStart();
 294             readRest();
 295         }
 296 
 297         public void readModule(File dst) throws IOException {
 298             readStart();
 299             readRest(dst, false);
 300         }
 301 
 302         private void readSignatureSection(DataInputStream stream,
 303                                           DigestInputStream dis)
 304             throws IOException
 305         {
 306 
 307             // Turn off digest computation before reading Signature Section
 308             dis.on(false);
 309 
 310             // Mark the starting position


 382                 }
 383                 break;
 384             case GZIP:
 385                 readGZIPCompressedFile(in, type);
 386                 break;
 387             case PACK200_GZIP:
 388                 readClasses(
 389                     new DataInputStream(new CountingInputStream(in, csize)));
 390                 break;
 391             default:
 392                 throw new IOException("Unsupported Compressor for files: " +
 393                                       compressor);
 394             }
 395         }
 396 
 397         public void readClasses(DataInputStream in) throws IOException {
 398             unpack200gzip(in);
 399         }
 400 
 401         private File currentPath = null;
 402         // true if currentPath points a path outside the module directory
 403         private boolean oomPath;   // false
 404 
 405         private OutputStream openOutputStream(SectionType type,
 406                                               String path)
 407             throws IOException
 408         {
 409             if (!extract)
 410                 return new NullOutputStream();
 411             currentPath = null;
 412             assert type != SectionType.CLASSES;
 413             if (type == SectionType.RESOURCES)
 414                 return Files.newOutputStream(contentStream(), path);
 415             currentPath = computeRealPath(type, path);
 416             File parent = currentPath.getParentFile();
 417             if (!parent.exists())
 418                 Files.mkdirs(parent, currentPath.getName());
 419             return new BufferedOutputStream(new FileOutputStream(currentPath));
 420         }
 421 
 422         private static class NullOutputStream extends OutputStream {
 423             @Override


 430 
 431         public void readGZIPCompressedFile(DataInputStream in,
 432                                            SectionType type)
 433             throws IOException
 434         {
 435             SubSectionFileHeader header = SubSectionFileHeader.read(in);
 436             int csize = header.getCSize();
 437 
 438             // Splice off the compressed file from input stream
 439             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 440             copyStream(new CountingInputStream(in, csize), baos, csize);
 441 
 442             byte[] compressedfile = baos.toByteArray();
 443             ByteArrayInputStream bain
 444                 = new ByteArrayInputStream(compressedfile);
 445             try (GZIPInputStream gin = new GZIPInputStream(bain);
 446                  OutputStream out = openOutputStream(type, header.getPath())) {
 447                 copyStream(gin, out);
 448             }
 449 
 450             if (extract) {
 451                 markNativeCodeExecutable(type, currentPath);
 452                 if (oomPath)
 453                     trackOutOfModuleContent(currentPath);
 454             }
 455         }
 456 
 457         public void readUncompressedFile(DataInputStream in,
 458                                          SectionType type,
 459                                          int csize)
 460             throws IOException
 461         {
 462             assert type != SectionType.MODULE_INFO;
 463             SubSectionFileHeader header = SubSectionFileHeader.read(in);
 464             csize = header.getCSize();
 465             try (OutputStream out = openOutputStream(type, header.getPath())) {
 466                 CountingInputStream cin = new CountingInputStream(in, csize);
 467                 byte[] buf = new byte[8192];
 468                 int n;
 469                 while ((n = cin.read(buf)) >= 0)
 470                     out.write(buf, 0, n);
 471             }
 472             if (extract) {
 473                 markNativeCodeExecutable(type, currentPath);
 474                 if (oomPath)
 475                     trackOutOfModuleContent(currentPath);
 476             }
 477          }
 478 
 479         public byte[] readModuleInfo(DataInputStream in, int csize)
 480             throws IOException
 481         {
 482             CountingInputStream cin = new CountingInputStream(in, csize);
 483             ByteArrayOutputStream out = new ByteArrayOutputStream();
 484             byte[] buf = new byte[8192];
 485             int n;
 486             while ((n = cin.read(buf)) >= 0)
 487                 out.write(buf, 0, n);
 488             return out.toByteArray();
 489         }
 490 
 491         public byte[] readModuleSignature(DataInputStream in, int csize)
 492             throws IOException
 493         {
 494             return readModuleInfo(in, csize); // signature has the same format
 495         }
 496 
 497         // Returns the path for the section type, if the library
 498         // has one configured.
 499         private File librarySectionPath(SectionType type) {
 500             if (lib != null && type == SectionType.NATIVE_LIBS
 501                 && lib.natlibs() != null)
 502                 return lib.natlibs();
 503             if (lib != null && type == SectionType.NATIVE_CMDS
 504                 && lib.natcmds() != null)
 505                 return lib.natcmds();
 506 
 507             return null;
 508         }
 509 
 510         // Track files installed outside the module library. For later removal.
 511         private PrintWriter oomFilesWriter;
 512 
 513         private void trackOutOfModuleContent(File file)
 514             throws IOException
 515         {
 516             if (file == null)
 517                 return;
 518 
 519             // Lazy construction, not all modules will need this.
 520             if (oomFilesWriter == null) {
 521                 oomFilesWriter = new PrintWriter(computeRealPath("oomfiles"));
 522             }
 523             oomFilesWriter.println(file);
 524             oomFilesWriter.flush();
 525         }
 526 
 527         void remove() throws IOException {
 528             ModuleFile.Reader.remove(destination);
 529         }
 530 
 531         // Removes a module, given its module install directory
 532         static void remove(File moduleDir) throws IOException {
 533             // Firstly remove any files installed outside of the module dir
 534             File oomfiles = new File(moduleDir, "oomfiles");
 535             if (oomfiles.exists()) {
 536                 try (FileInputStream fis = new FileInputStream(oomfiles);
 537                      BufferedReader in = new BufferedReader(new InputStreamReader(fis))) {
 538                     String filename;
 539                     while ((filename = in.readLine()) != null)
 540                         Files.delete(new File(filename));
 541                 }
 542             }
 543 
 544             Files.deleteTree(moduleDir);
 545         }
 546 
 547         private File computeRealPath(String storedpath) throws IOException {
 548 
 549             String convertedpath = storedpath.replace('/', File.separatorChar);
 550             File path = new File(convertedpath);
 551 
 552             // Absolute path names are not permitted.
 553             ensureNonAbsolute(path);
 554             path = resolveAndNormalize(destination, convertedpath);
 555             // Create the parent directories if necessary
 556             File parent = path.getParentFile();
 557             if (!parent.exists())
 558                 Files.mkdirs(parent, path.getName());
 559 
 560             return path;
 561         }
 562 
 563         private File computeRealPath(SectionType type,
 564                                      String storedpath)
 565             throws IOException
 566         {
 567             File lsp = librarySectionPath(type);
 568             if (lsp != null) {
 569                 // The library has a configured path for this section
 570                 File realpath = new File(lsp, storedpath);
 571 
 572                 if (realpath.exists()) {
 573                     // conflict, for now just fail
 574                     throw new IOException("File " + realpath + " already exists");
 575                 }
 576 
 577                 // Create the parent directories if necessary
 578                 File parent = realpath.getParentFile();
 579                 if (!parent.exists())
 580                     Files.mkdirs(parent, realpath.getName());
 581 
 582                 oomPath = true;
 583                 return realpath;
 584             }
 585 
 586             // reset since the path must be within the module directory
 587             oomPath = false;
 588             String dir = getSubdirOfSection(type);
 589             return computeRealPath(dir + File.separatorChar + storedpath);
 590         }
 591 
 592         private static void markNativeCodeExecutable(SectionType type,
 593                                                      File file)
 594         {
 595             if (type == SectionType.NATIVE_CMDS
 596                 || (type == SectionType.NATIVE_LIBS
 597                     && System.getProperty("os.name").startsWith("Windows")))
 598                 {
 599                     file.setExecutable(true);
 600                 }
 601         }
 602 
 603         private void unpack200gzip(DataInputStream in) throws IOException {
 604             GZIPInputStream gis = new GZIPInputStream(in) {
 605                     public void close() throws IOException {}
 606                 };
 607             Pack200.Unpacker unpacker = Pack200.newUnpacker();