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

Print this page




  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 
  81             public int read() throws IOException {
  82                 if (count == 0)
  83                     return -1;
  84                 int read = super.read();


 163                 calculatedHashes.add(sectionDigest.digest());
 164 
 165                 fileIn = new DataInputStream(dis);
 166                 if (readSection(fileIn) != SectionType.MODULE_INFO)
 167                     throw new IOException("First module-file section"
 168                                           + " is not MODULE_INFO");
 169                 assert moduleInfoBytes != null;
 170 
 171                 // Read the Signature Section, if present
 172                 readSignatureSection(fileIn, dis);
 173 
 174                 return moduleInfoBytes.clone();
 175             } catch (IOException x) {
 176                 close();
 177                 throw x;
 178             }
 179         }
 180 
 181         public void readRest() throws IOException {
 182             extract = false;
 183             readRest(null, false);
 184         }
 185 
 186         public void readRest(File dst, boolean deflate) throws IOException {
 187             this.destination = dst;






 188             this.deflate = deflate;




 189             try {
 190                 if (extract)
 191                     Files.store(moduleInfoBytes, computeRealPath("info"));
 192                 // Module-Info and Signature, if present, have been consumed
 193 
 194                 // Read rest of file until all sections have been read
 195                 stream.mark(1);
 196                 while (-1 != stream.read()) {
 197                     stream.reset();
 198                     readSection(fileIn);
 199                     stream.mark(1);
 200                 }
 201 
 202                 close();
 203                 byte[] fileHeaderHash = fileHeader.getHashNoClone();
 204                 checkHashMatch(fileHeaderHash, fileDigest.digest());
 205                 calculatedHashes.add(fileHeaderHash);
 206             } finally {
 207                 close();
 208             }


 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 


 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();
 512             if (deflate) {
 513                 Map<String,String> p = unpacker.properties();
 514                 p.put(Pack200.Unpacker.DEFLATE_HINT, Pack200.Unpacker.TRUE);
 515             }
 516             unpacker.unpack(gis, contentStream());
 517         }
 518 
 519     }
 520 
 521     private static void checkCompressor(SectionType type,
 522                                         Compressor compressor) {
 523 
 524         if ((SectionType.MODULE_INFO == type &&
 525              Compressor.NONE != compressor)
 526             || (SectionType.CLASSES == type &&


 562         throws IOException
 563     {
 564         byte[] buffer = new byte[1024 * 8];
 565 
 566         while(count > 0) {
 567             int b_read = in.read(buffer, 0, Math.min(count, buffer.length));
 568             if (-1 == b_read)
 569                 return;
 570             out.write(buffer, 0, b_read);
 571             count-=b_read;
 572         }
 573     }
 574 
 575     private static void copyStream(InputStream in, OutputStream out,
 576                                    int count)
 577         throws IOException
 578     {
 579         copyStream(in, (DataOutput) new DataOutputStream(out), count);
 580     }
 581 
 582     private static void ensureNonAbsolute(File path) throws IOException {
 583         if (path.isAbsolute())
 584             throw new IOException("Abolute path instead of relative: " + path);
 585     }
 586 
 587     private static void ensureNonNegativity(long size, String parameter) {
 588         if (size < 0)
 589             throw new IllegalArgumentException(parameter + "<0: " + size);
 590     }
 591 
 592     private static void ensureNonNull(Object reference, String parameter) {
 593         if (null == reference)
 594             throw new IllegalArgumentException(parameter + " == null");
 595     }
 596 
 597     private static void ensureMatch(int found, int expected, String field)
 598         throws IOException
 599     {
 600         if (found != expected)
 601             throw new IOException(field + " expected : "
 602                 + Integer.toHexString(expected) + " found: "
 603                 + Integer.toHexString(found));
 604     }
 605 
 606     private static void ensureShortNativePath(File path, String name)


 659         for (int i = 0; i < hash.length; i++) {
 660             int val = (hash[i] & 0xFF);
 661             if (val <= 16)
 662                 hex.append("0");
 663             hex.append(Integer.toHexString(val));
 664         }
 665         return hex.toString();
 666     }
 667 
 668     private static File resolveAndNormalize(File directory, String path)
 669         throws IOException
 670     {
 671         File realpath = new File(directory, path);
 672         if (directory != null &&
 673             ! realpath.toPath().startsWith(directory.toPath()))
 674             throw new IOException("Bogus relative path: " + path);
 675 
 676         return realpath;
 677     }
 678 
















 679     private static short readHashLength(DataInputStream in) throws IOException {
 680         final short hashLength = in.readShort();
 681         ensureNonNegativity(hashLength, "hashLength");
 682 
 683         return hashLength;
 684     }
 685 
 686     private static byte[] readHashBytes(DataInputStream in, short hashLength)
 687         throws IOException
 688     {
 689 
 690         final byte[] hash = new byte[hashLength];
 691         in.readFully(hash);
 692 
 693         return hash;
 694     }
 695 
 696     private static byte[] readHash(DataInputStream in) throws IOException {
 697         return readHashBytes(in, readHashLength(in));
 698     }




  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         private File natlibs;
  66         private File natcmds;
  67         private File configs;
  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 
  84             public int read() throws IOException {
  85                 if (count == 0)
  86                     return -1;
  87                 int read = super.read();


 166                 calculatedHashes.add(sectionDigest.digest());
 167 
 168                 fileIn = new DataInputStream(dis);
 169                 if (readSection(fileIn) != SectionType.MODULE_INFO)
 170                     throw new IOException("First module-file section"
 171                                           + " is not MODULE_INFO");
 172                 assert moduleInfoBytes != null;
 173 
 174                 // Read the Signature Section, if present
 175                 readSignatureSection(fileIn, dis);
 176 
 177                 return moduleInfoBytes.clone();
 178             } catch (IOException x) {
 179                 close();
 180                 throw x;
 181             }
 182         }
 183 
 184         public void readRest() throws IOException {
 185             extract = false;
 186             readRest(null, false, null, null, null);
 187         }
 188 
 189         public void readRest(File dst, boolean deflate) throws IOException {
 190             readRest(dst, deflate, null, null, null);
 191         }
 192 
 193         public void readRest(File dst, boolean deflate, File natlibs,
 194                              File natcmds, File configs)
 195                 throws IOException
 196         {
 197             this.deflate = deflate;
 198             this.destination = dst != null ? dst.getCanonicalFile() : null;
 199             this.natlibs = natlibs != null ? natlibs : new File(destination, "lib");
 200             this.natcmds = natcmds != null ? natcmds : new File(destination, "bin");
 201             this.configs = configs != null ? configs : new File(destination, "etc");
 202             try {
 203                 if (extract)
 204                     Files.store(moduleInfoBytes, computeRealPath("info"));
 205                 // Module-Info and Signature, if present, have been consumed
 206 
 207                 // Read rest of file until all sections have been read
 208                 stream.mark(1);
 209                 while (-1 != stream.read()) {
 210                     stream.reset();
 211                     readSection(fileIn);
 212                     stream.mark(1);
 213                 }
 214 
 215                 close();
 216                 byte[] fileHeaderHash = fileHeader.getHashNoClone();
 217                 checkHashMatch(fileHeaderHash, fileDigest.digest());
 218                 calculatedHashes.add(fileHeaderHash);
 219             } finally {
 220                 close();
 221             }


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


 433         public void readGZIPCompressedFile(DataInputStream in,
 434                                            SectionType type)
 435             throws IOException
 436         {
 437             SubSectionFileHeader header = SubSectionFileHeader.read(in);
 438             int csize = header.getCSize();
 439 
 440             // Splice off the compressed file from input stream
 441             ByteArrayOutputStream baos = new ByteArrayOutputStream();
 442             copyStream(new CountingInputStream(in, csize), baos, csize);
 443 
 444             byte[] compressedfile = baos.toByteArray();
 445             ByteArrayInputStream bain
 446                 = new ByteArrayInputStream(compressedfile);
 447             try (GZIPInputStream gin = new GZIPInputStream(bain);
 448                  OutputStream out = openOutputStream(type, header.getPath())) {
 449                 copyStream(gin, out);
 450             }
 451 
 452             if (extract)
 453                 postExtract(type, currentPath);
 454         }
 455 
 456         public void readUncompressedFile(DataInputStream in,
 457                                          SectionType type,
 458                                          int csize)
 459             throws IOException
 460         {
 461             assert type != SectionType.MODULE_INFO;
 462             SubSectionFileHeader header = SubSectionFileHeader.read(in);
 463             csize = header.getCSize();
 464             try (OutputStream out = openOutputStream(type, header.getPath())) {
 465                 CountingInputStream cin = new CountingInputStream(in, csize);
 466                 byte[] buf = new byte[8192];
 467                 int n;
 468                 while ((n = cin.read(buf)) >= 0)
 469                     out.write(buf, 0, n);
 470             }
 471             if (extract) {
 472                 postExtract(type, currentPath);
 473             }
 474          }
 475 
 476         public byte[] readModuleInfo(DataInputStream in, int csize)
 477             throws IOException
 478         {
 479             CountingInputStream cin = new CountingInputStream(in, csize);
 480             ByteArrayOutputStream out = new ByteArrayOutputStream();
 481             byte[] buf = new byte[8192];
 482             int n;
 483             while ((n = cin.read(buf)) >= 0)
 484                 out.write(buf, 0, n);
 485             return out.toByteArray();
 486         }
 487 
 488         public byte[] readModuleSignature(DataInputStream in, int csize)
 489             throws IOException
 490         {
 491             return readModuleInfo(in, csize); // signature has the same format
 492         }
 493 
 494         // Track files installed outside the module library. For later removal.
 495         // files are relative to the modules directory.
 496         private PrintWriter filesWriter;
 497 
 498         private void trackFiles(SectionType type, File file)
 499             throws IOException
 500         {
 501             if (file == null || file.toPath().startsWith(destination.toPath()))
 502                 return;
 503 
 504             // Lazy construction, not all modules will need this.
 505             if (filesWriter == null)
 506                 filesWriter = new PrintWriter(computeRealPath("files"), "UTF-8");




 507 
 508             filesWriter.println(Files.convertSeparator(relativize(destination, file)));
 509             filesWriter.flush();
 510         }
 511 
 512         void remove() throws IOException {
 513             ModuleFile.Reader.remove(destination);
 514         }
 515 
 516         // Removes a module, given its module install directory
 517         static void remove(File moduleDir) throws IOException {
 518             // Firstly remove any files installed outside of the module dir
 519             File files = new File(moduleDir, "files");
 520             if (files.exists()) {
 521                 try (FileInputStream fis = new FileInputStream(files);
 522                      InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
 523                      BufferedReader in = new BufferedReader(isr)) {
 524                     String filename;
 525                     while ((filename = in.readLine()) != null)
 526                         Files.delete(new File(moduleDir,
 527                                               Files.platformSeparator(filename)));
 528                 }
 529             }
 530 
 531             Files.deleteTree(moduleDir);
 532         }
 533 
 534         // Returns the absolute path of the given section type.
 535         private File getDirOfSection(SectionType type) {
 536             if (type == SectionType.NATIVE_LIBS)
 537                 return natlibs; 
 538             else if (type == SectionType.NATIVE_CMDS)
 539                 return natcmds;
 540             else if (type == SectionType.CONFIG)
 541                 return configs;
 542 
 543             // resolve sub dir section paths against the modules directory
 544             return new File(destination, ModuleFile.getSubdirOfSection(type));
 545         }
 546 
 547         private File computeRealPath(String path) throws IOException {
 548             return resolveAndNormalize(destination, path);
 549         }
 550 
 551         private File computeRealPath(SectionType type, String storedpath)
 552             throws IOException
 553         {
 554             File sectionPath = getDirOfSection(type);
 555             File realpath = new File(sectionPath,
 556                  Files.ensureNonAbsolute(Files.platformSeparator(storedpath)));
 557 
 558             validatePath(sectionPath, realpath);
 559 
 560             // Create the parent directories if necessary
 561             File parent = realpath.getParentFile();
 562             if (!parent.exists())
 563                 Files.mkdirs(parent, realpath.getName());
 564 
 565             return realpath;
 566         }
 567 
 568         private static void markNativeCodeExecutable(SectionType type,
 569                                                      File file)
 570         {
 571             if (type == SectionType.NATIVE_CMDS
 572                 || (type == SectionType.NATIVE_LIBS
 573                     && System.getProperty("os.name").startsWith("Windows")))
 574                 {
 575                     file.setExecutable(true);
 576                 }
 577         }
 578 
 579         private void postExtract(SectionType type, File path)
 580             throws IOException
 581         {
 582             markNativeCodeExecutable(type, path);
 583             trackFiles(type, path);
 584         }
 585 
 586         private void unpack200gzip(DataInputStream in) throws IOException {
 587             GZIPInputStream gis = new GZIPInputStream(in) {
 588                     public void close() throws IOException {}
 589                 };
 590             Pack200.Unpacker unpacker = Pack200.newUnpacker();
 591             if (deflate) {
 592                 Map<String,String> p = unpacker.properties();
 593                 p.put(Pack200.Unpacker.DEFLATE_HINT, Pack200.Unpacker.TRUE);
 594             }
 595             unpacker.unpack(gis, contentStream());
 596         }
 597 
 598     }
 599 
 600     private static void checkCompressor(SectionType type,
 601                                         Compressor compressor) {
 602 
 603         if ((SectionType.MODULE_INFO == type &&
 604              Compressor.NONE != compressor)
 605             || (SectionType.CLASSES == type &&


 641         throws IOException
 642     {
 643         byte[] buffer = new byte[1024 * 8];
 644 
 645         while(count > 0) {
 646             int b_read = in.read(buffer, 0, Math.min(count, buffer.length));
 647             if (-1 == b_read)
 648                 return;
 649             out.write(buffer, 0, b_read);
 650             count-=b_read;
 651         }
 652     }
 653 
 654     private static void copyStream(InputStream in, OutputStream out,
 655                                    int count)
 656         throws IOException
 657     {
 658         copyStream(in, (DataOutput) new DataOutputStream(out), count);
 659     }
 660 





 661     private static void ensureNonNegativity(long size, String parameter) {
 662         if (size < 0)
 663             throw new IllegalArgumentException(parameter + "<0: " + size);
 664     }
 665 
 666     private static void ensureNonNull(Object reference, String parameter) {
 667         if (null == reference)
 668             throw new IllegalArgumentException(parameter + " == null");
 669     }
 670 
 671     private static void ensureMatch(int found, int expected, String field)
 672         throws IOException
 673     {
 674         if (found != expected)
 675             throw new IOException(field + " expected : "
 676                 + Integer.toHexString(expected) + " found: "
 677                 + Integer.toHexString(found));
 678     }
 679 
 680     private static void ensureShortNativePath(File path, String name)


 733         for (int i = 0; i < hash.length; i++) {
 734             int val = (hash[i] & 0xFF);
 735             if (val <= 16)
 736                 hex.append("0");
 737             hex.append(Integer.toHexString(val));
 738         }
 739         return hex.toString();
 740     }
 741 
 742     private static File resolveAndNormalize(File directory, String path)
 743         throws IOException
 744     {
 745         File realpath = new File(directory, path);
 746         if (directory != null &&
 747             ! realpath.toPath().startsWith(directory.toPath()))
 748             throw new IOException("Bogus relative path: " + path);
 749 
 750         return realpath;
 751     }
 752 
 753 
 754     private static String relativize(File directory, File path) throws IOException {
 755         return (directory.toPath().relativize(path.toPath().toRealPath())).toString();
 756     }
 757 
 758     private static void validatePath(File parent, File child)
 759         throws IOException
 760     {
 761         if (!child.toPath().startsWith(parent.toPath()) )
 762             throw new IOException("Bogus relative path: " + child);
 763         if (child.exists()) {
 764             // conflict, for now just fail
 765             throw new IOException("File " + child + " already exists");
 766         }
 767     }
 768 
 769     private static short readHashLength(DataInputStream in) throws IOException {
 770         final short hashLength = in.readShort();
 771         ensureNonNegativity(hashLength, "hashLength");
 772 
 773         return hashLength;
 774     }
 775 
 776     private static byte[] readHashBytes(DataInputStream in, short hashLength)
 777         throws IOException
 778     {
 779 
 780         final byte[] hash = new byte[hashLength];
 781         in.readFully(hash);
 782 
 783         return hash;
 784     }
 785 
 786     private static byte[] readHash(DataInputStream in) throws IOException {
 787         return readHashBytes(in, readHashLength(in));
 788     }