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();
}
}
}