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

Print this page

        

*** 33,42 **** --- 33,43 ---- import java.nio.file.Files; import java.security.MessageDigest; import java.util.*; import java.util.jar.*; import java.util.zip.*; + import org.openjdk.jigsaw.ModuleFileParser.Event; import static org.openjdk.jigsaw.FileConstants.ModuleFile.*; import static org.openjdk.jigsaw.ModuleFile.*; /**
*** 47,56 **** --- 48,58 ---- private final File outfile; private final HashType hashtype; private final boolean fastestCompression; private long usize; + private int headerLength; public ModuleFileWriter(File outfile) { this(outfile, false); }
*** 61,74 **** } /** * Generates an unsigned module file. */ ! public void writeModule(File mdir, ! File nativelibs, ! File nativecmds, ! File config) throws IOException { if (!mdir.isDirectory()) { throw new IOException("Not a directory: " + mdir); } --- 63,74 ---- } /** * Generates an unsigned module file. */ ! public void writeModule(File mdir, File nativelibs, File nativecmds, ! File config, ModuleArchitecture modArch) throws IOException { if (!mdir.isDirectory()) { throw new IOException("Not a directory: " + mdir); }
*** 75,95 **** try (RandomAccessFile file = new RandomAccessFile(outfile, "rw")) { // Truncate the file if it already exists file.setLength(0); // Reset module file to right after module header ! file.seek(ModuleFileHeader.LENGTH); - // TODO: Why was this after the module info??? - long remainderStart = file.getFilePointer(); - // Write out the Module-Info Section File miclass = new File(mdir, "module-info.class"); ! if (!miclass.exists()) { throw new IOException(miclass + " does not exist"); ! } writeSection(file, SectionType.MODULE_INFO, mdir, Collections.singletonList(miclass.toPath()), Compressor.NONE); --- 75,99 ---- try (RandomAccessFile file = new RandomAccessFile(outfile, "rw")) { // Truncate the file if it already exists file.setLength(0); + // set appropriate fields in the header before determining the length + ModuleFileHeader dummyHeader = ModuleFileHeader.newBuilder() + .setArchitecture(modArch) + .setHashType(hashtype) + .setHash(new byte[hashtype.length()]) + .build(); + // Reset module file to right after module header ! file.seek(headerLength = dummyHeader.getLength()); // Write out the Module-Info Section File miclass = new File(mdir, "module-info.class"); ! if (!miclass.exists()) throw new IOException(miclass + " does not exist"); ! writeSection(file, SectionType.MODULE_INFO, mdir, Collections.singletonList(miclass.toPath()), Compressor.NONE);
*** 96,106 **** // Write out the optional file sections writeOptionalSections(file, mdir, nativelibs, nativecmds, config); // Write out the module file header ! writeModuleFileHeader(file, remainderStart); } } /* * Write a section to the given module file. --- 100,110 ---- // Write out the optional file sections writeOptionalSections(file, mdir, nativelibs, nativecmds, config); // Write out the module file header ! writeModuleFileHeader(file, headerLength, modArch); } } /* * Write a section to the given module file.
*** 113,123 **** */ private void writeSection(RandomAccessFile file, SectionType type, File sourcedir, List<Path> files, ! Compressor compressor) throws IOException { // Start of section header final long start = file.getFilePointer(); // Start of section content final long cstart = start + SectionHeader.LENGTH; --- 117,129 ---- */ private void writeSection(RandomAccessFile file, SectionType type, File sourcedir, List<Path> files, ! Compressor compressor) ! throws IOException ! { // Start of section header final long start = file.getFilePointer(); // Start of section content final long cstart = start + SectionHeader.LENGTH;
*** 140,151 **** private void writeSectionContent(RandomAccessFile file, SectionType type, File sourcedir, List<Path> files, ! Compressor compressor) throws IOException { ! if (type.hasFiles()) { for (Path p : files) { writeSubSection(file, sourcedir, p, compressor); } } else if (type == SectionType.CLASSES) { --- 146,158 ---- private void writeSectionContent(RandomAccessFile file, SectionType type, File sourcedir, List<Path> files, ! Compressor compressor) ! throws IOException ! { if (type.hasFiles()) { for (Path p : files) { writeSubSection(file, sourcedir, p, compressor); } } else if (type == SectionType.CLASSES) {
*** 160,171 **** private void writeSectionHeader(RandomAccessFile file, SectionType type, Compressor compressor, long start, int csize, ! short subsections) throws IOException { ! // Compute hash of content MessageDigest md = getHashInstance(hashtype); FileChannel channel = file.getChannel(); ByteBuffer content = ByteBuffer.allocate(csize); --- 167,179 ---- private void writeSectionHeader(RandomAccessFile file, SectionType type, Compressor compressor, long start, int csize, ! short subsections) ! throws IOException ! { // Compute hash of content MessageDigest md = getHashInstance(hashtype); FileChannel channel = file.getChannel(); ByteBuffer content = ByteBuffer.allocate(csize);
*** 188,198 **** } private void writeClassesContent(DataOutput out, File sourcedir, List<Path> files, ! Compressor compressor) throws IOException { CompressedClassOutputStream cos = CompressedClassOutputStream.newInstance(sourcedir.toPath(), files, compressor, fastestCompression); --- 196,208 ---- } private void writeClassesContent(DataOutput out, File sourcedir, List<Path> files, ! Compressor compressor) ! throws IOException ! { CompressedClassOutputStream cos = CompressedClassOutputStream.newInstance(sourcedir.toPath(), files, compressor, fastestCompression);
*** 200,210 **** cos.writeTo(out); } private void writeFileContent(DataOutput out, Path p, ! Compressor compressor) throws IOException { CompressedOutputStream cos = CompressedOutputStream.newInstance(p, compressor); usize += cos.getUSize(); cos.writeTo(out); } --- 210,222 ---- cos.writeTo(out); } private void writeFileContent(DataOutput out, Path p, ! Compressor compressor) ! throws IOException ! { CompressedOutputStream cos = CompressedOutputStream.newInstance(p, compressor); usize += cos.getUSize(); cos.writeTo(out); }
*** 217,227 **** * @params compressor compression type */ private void writeSubSection(RandomAccessFile file, File sourcedir, Path p, ! Compressor compressor) throws IOException { CompressedOutputStream cos = CompressedOutputStream.newInstance(p, compressor); usize += cos.getUSize(); String storedpath = relativePath(sourcedir.toPath(), p); SubSectionFileHeader header = new SubSectionFileHeader((int)cos.getCSize(), storedpath); --- 229,241 ---- * @params compressor compression type */ private void writeSubSection(RandomAccessFile file, File sourcedir, Path p, ! Compressor compressor) ! throws IOException ! { CompressedOutputStream cos = CompressedOutputStream.newInstance(p, compressor); usize += cos.getUSize(); String storedpath = relativePath(sourcedir.toPath(), p); SubSectionFileHeader header = new SubSectionFileHeader((int)cos.getCSize(), storedpath);
*** 284,323 **** /* * Writes out the module file header. */ private void writeModuleFileHeader(RandomAccessFile file, ! long remainderStart) throws IOException { - long csize = file.length() - remainderStart; - // Header Step 1 // Write out the module file header (using a dummy file hash value) ! ModuleFileHeader header = ! new ModuleFileHeader(csize, usize, hashtype, ! new byte[hashtype.length()]); file.seek(0); ! header.write(file); ! // Generate the module file hash ! byte[] fileHash = generateFileHash(file); // Header Step 2 // Write out the module file header (using correct file hash value) ! header = new ModuleFileHeader(csize, usize, hashtype, fileHash); file.seek(0); ! header.write(file); } private void listClassesResources(Path dir, final List<Path> classes, final List<Path> resources) throws IOException { - Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (!file.endsWith("module-info.class")) { --- 298,351 ---- /* * Writes out the module file header. */ private void writeModuleFileHeader(RandomAccessFile file, ! long headerLength, ! ModuleArchitecture modArch) throws IOException { + long csize = file.length() - headerLength; // Header Step 1 // Write out the module file header (using a dummy file hash value) ! ModuleFileHeader.Builder hBuilder = ModuleFileHeader.newBuilder() ! .setCSize(csize) ! .setUSize(usize) ! .setArchitecture(modArch) ! .setHashType(hashtype) ! .setHash(new byte[hashtype.length()]); ! ModuleFileHeader fileHeader = hBuilder.build(); ! assert (fileHeader.getLength() == headerLength); ! file.seek(0); ! fileHeader.write(file); ! // Calculate the correct module file hash, using a non-validating parser ! file.seek(0); ! byte[] fileHash = null; ! ModuleFileParser parser = ! ModuleFile.newParser(Channels.newInputStream(file.getChannel())); ! while (parser.hasNext()) { ! if (parser.next().equals(Event.END_FILE)) ! fileHash = parser.getHash(); ! } // Header Step 2 // Write out the module file header (using correct file hash value) ! hBuilder.setHash(fileHash); file.seek(0); ! fileHeader = hBuilder.build(); ! assert (fileHeader.getLength() == headerLength); ! fileHeader.write(file); } private void listClassesResources(Path dir, final List<Path> classes, final List<Path> resources) throws IOException { Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (!file.endsWith("module-info.class")) {
*** 425,435 **** p.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.FALSE); p.put(Pack200.Packer.MODIFICATION_TIME, Pack200.Packer.LATEST); p.put(Pack200.Packer.DEFLATE_HINT, Pack200.Packer.FALSE); } ! void compress(Path sourcepath, List<Path> classes) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); try (JarOutputStream jos = new JarOutputStream(os)) { jos.setLevel(0); for (Path file : classes) { // write to the JarInputStream for later pack200 compression --- 453,465 ---- p.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.FALSE); p.put(Pack200.Packer.MODIFICATION_TIME, Pack200.Packer.LATEST); p.put(Pack200.Packer.DEFLATE_HINT, Pack200.Packer.FALSE); } ! void compress(Path sourcepath, List<Path> classes) ! throws IOException ! { ByteArrayOutputStream os = new ByteArrayOutputStream(); try (JarOutputStream jos = new JarOutputStream(os)) { jos.setLevel(0); for (Path file : classes) { // write to the JarInputStream for later pack200 compression
*** 453,463 **** } } } } ! private String relativePath(Path sourcepath, Path path) throws IOException { Path relativepath = sourcepath.relativize(path); // The '/' character separates nested directories in path names. String pathseparator = relativepath.getFileSystem().getSeparator(); String stored = relativepath.toString().replace(pathseparator, "/"); --- 483,495 ---- } } } } ! private String relativePath(Path sourcepath, Path path) ! throws IOException ! { Path relativepath = sourcepath.relativize(path); // The '/' character separates nested directories in path names. String pathseparator = relativepath.getFileSystem().getSeparator(); String stored = relativepath.toString().replace(pathseparator, "/");
*** 468,481 **** // ## the native libraries in jdk modules are changed // ensureShortNativePath(realpath, stored); return stored; } ! private List<Path> listFiles(Path path) throws IOException { final List<Path> list = new ArrayList<>(); Files.walkFileTree(path, new SimpleFileVisitor<Path>() { - @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { list.add(file); return FileVisitResult.CONTINUE; --- 500,514 ---- // ## the native libraries in jdk modules are changed // ensureShortNativePath(realpath, stored); return stored; } ! private List<Path> listFiles(Path path) ! throws IOException ! { final List<Path> list = new ArrayList<>(); Files.walkFileTree(path, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { list.add(file); return FileVisitResult.CONTINUE;
*** 483,534 **** }); return list; } /* - * Generates the hash value for a module file. - * Excludes itself (the hash bytes in the module file header). - */ - private byte[] generateFileHash(RandomAccessFile file) - throws IOException - { - MessageDigest md = getHashInstance(hashtype); - - long remainderSize = file.length() - ModuleFileHeader.LENGTH; - FileChannel channel = file.getChannel(); - - // Module file header without the hash bytes - ByteBuffer content = ByteBuffer.allocate(ModuleFileHeader.LENGTH_WITHOUT_HASH); - int n = channel.read(content, 0); - if (n != ModuleFileHeader.LENGTH_WITHOUT_HASH) { - throw new IOException("too few bytes read"); - } - content.position(0); - md.update(content); - - // Remainder of file (read in chunks) - content = ByteBuffer.allocate(8192); - channel.position(ModuleFileHeader.LENGTH); - n = channel.read(content); - while (n != -1) { - content.limit(n); - content.position(0); - md.update(content); - content = ByteBuffer.allocate(8192); - n = channel.read(content); - } - - return md.digest(); - } - - /* * Check if a given directory is not empty. */ private static boolean directoryIsNotEmpty(File dir) ! throws IOException { ! try (DirectoryStream<Path> ds = ! Files.newDirectoryStream(dir.toPath())) { return ds.iterator().hasNext(); } } - } --- 516,530 ---- }); return list; } /* * Check if a given directory is not empty. */ private static boolean directoryIsNotEmpty(File dir) ! throws IOException ! { ! try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir.toPath())) { return ds.iterator().hasNext(); } } }