Skip to content
Permalink
Browse files
8258117: jar tool sets the time stamp of module-info.class entries to…
… the current time

Reviewed-by: lancea, ihse, alanb
  • Loading branch information
jaikiran committed Nov 25, 2021
1 parent 26472bd commit a81e4fc07b654a3cc954921981d9d3c0cfd8bcec
Showing 2 changed files with 285 additions and 22 deletions.
@@ -44,6 +44,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.FileTime;
import java.text.MessageFormat;
import java.util.*;
import java.util.function.Consumer;
@@ -120,7 +121,7 @@ public int hashCode() {
Set<Entry> entries = new LinkedHashSet<>();

// module-info.class entries need to be added/updated.
Map<String,byte[]> moduleInfos = new HashMap<>();
Map<String, ModuleInfoEntry> moduleInfos = new HashMap<>();

// A paths Set for each version, where each Set contains directories
// specified by the "-C" operation.
@@ -806,7 +807,10 @@ private void expand(File dir, String[] files, Set<String> cpaths, int version)
if (f.isFile()) {
Entry e = new Entry(f, name, false);
if (isModuleInfoEntry(name)) {
moduleInfos.putIfAbsent(name, Files.readAllBytes(f.toPath()));
Path path = f.toPath();
byte[] fileContent = Files.readAllBytes(path);
ModuleInfoEntry mie = new StreamedModuleInfoEntry(name, fileContent, Files.getLastModifiedTime(path));
moduleInfos.putIfAbsent(name, mie);
if (uflag) {
entryMap.put(name, e);
}
@@ -907,7 +911,7 @@ private boolean equalsIgnoreCase(String s, String upper) {
*/
boolean update(InputStream in, OutputStream out,
InputStream newManifest,
Map<String,byte[]> moduleInfos,
Map<String, ModuleInfoEntry> moduleInfos,
JarIndex jarIndex) throws IOException
{
ZipInputStream zis = new ZipInputStream(in);
@@ -956,7 +960,7 @@ boolean update(InputStream in, OutputStream out,
return false;
}
} else if (moduleInfos != null && isModuleInfoEntry) {
moduleInfos.putIfAbsent(name, zis.readAllBytes());
moduleInfos.putIfAbsent(name, new StreamedModuleInfoEntry(name, zis.readAllBytes(), e.getLastModifiedTime()));
} else {
boolean isDir = e.isDirectory();
if (!entryMap.containsKey(name)) { // copy the old stuff
@@ -1040,15 +1044,21 @@ private void addIndex(JarIndex index, ZipOutputStream zos)
zos.closeEntry();
}

private void updateModuleInfo(Map<String,byte[]> moduleInfos, ZipOutputStream zos)
private void updateModuleInfo(Map<String, ModuleInfoEntry> moduleInfos, ZipOutputStream zos)
throws IOException
{
String fmt = uflag ? "out.update.module-info": "out.added.module-info";
for (Map.Entry<String,byte[]> mi : moduleInfos.entrySet()) {
for (Map.Entry<String, ModuleInfoEntry> mi : moduleInfos.entrySet()) {
String name = mi.getKey();
byte[] bytes = mi.getValue();
ModuleInfoEntry mie = mi.getValue();
byte[] bytes = mie.readAllBytes();
ZipEntry e = new ZipEntry(name);
e.setTime(System.currentTimeMillis());
FileTime lastModified = mie.getLastModifiedTime();
if (lastModified != null) {
e.setLastModifiedTime(lastModified);
} else {
e.setLastModifiedTime(FileTime.fromMillis(System.currentTimeMillis()));
}
if (flag0) {
crc32ModuleInfo(e, bytes);
}
@@ -1743,12 +1753,23 @@ private File createTemporaryFile(String tmpbase, String suffix) {

/**
* Associates a module descriptor's zip entry name along with its
* bytes and an optional URI. Used when describing modules.
* bytes and an optional URI.
*/
interface ModuleInfoEntry {
String name();
Optional<String> uriString();
InputStream bytes() throws IOException;
String name();
Optional<String> uriString();
InputStream bytes() throws IOException;
/**
* @return Returns the last modified time of the module-info.class.
* Returns null if the last modified time is unknown or cannot be
* determined.
*/
FileTime getLastModifiedTime();
default byte[] readAllBytes() throws IOException {
try (InputStream is = bytes()) {
return is.readAllBytes();
}
}
}

static class ZipFileModuleInfoEntry implements ModuleInfoEntry {
@@ -1762,6 +1783,12 @@ static class ZipFileModuleInfoEntry implements ModuleInfoEntry {
@Override public InputStream bytes() throws IOException {
return zipFile.getInputStream(entry);
}

@Override
public FileTime getLastModifiedTime() {
return entry.getLastModifiedTime();
}

/** Returns an optional containing the effective URI. */
@Override public Optional<String> uriString() {
String uri = (Paths.get(zipFile.getName())).toUri().toString();
@@ -1773,14 +1800,28 @@ static class ZipFileModuleInfoEntry implements ModuleInfoEntry {
static class StreamedModuleInfoEntry implements ModuleInfoEntry {
private final String name;
private final byte[] bytes;
StreamedModuleInfoEntry(String name, byte[] bytes) {
private final FileTime lastModifiedTime;

StreamedModuleInfoEntry(String name, byte[] bytes, FileTime lastModifiedTime) {
this.name = name;
this.bytes = bytes;
this.lastModifiedTime = lastModifiedTime;
}
@Override public String name() { return name; }
@Override public InputStream bytes() throws IOException {
return new ByteArrayInputStream(bytes);
}

@Override
public byte[] readAllBytes() throws IOException {
return bytes;
}

@Override
public FileTime getLastModifiedTime() {
return lastModifiedTime;
}

/** Returns an empty optional. */
@Override public Optional<String> uriString() {
return Optional.empty(); // no URI can be derived
@@ -1832,7 +1873,7 @@ private boolean describeModuleFromStream(FileInputStream fis)
while ((e = zis.getNextEntry()) != null) {
String ename = e.getName();
if (isModuleInfoEntry(ename)) {
infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes()));
infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes(), e.getLastModifiedTime()));
}
}
}
@@ -2045,14 +2086,14 @@ static String toBinaryName(String classname) {
return (classname.replace('.', '/')) + ".class";
}

private boolean checkModuleInfo(byte[] moduleInfoBytes, Set<String> entries)
private boolean checkModuleInfo(ModuleInfoEntry moduleInfoEntry, Set<String> entries)
throws IOException
{
boolean ok = true;
if (moduleInfoBytes != null) { // no root module-info.class if null
if (moduleInfoEntry != null) { // no root module-info.class if null
try {
// ModuleDescriptor.read() checks open/exported pkgs vs packages
ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
ModuleDescriptor md = ModuleDescriptor.read(moduleInfoEntry.bytes());
// A module must have the implementation class of the services it 'provides'.
if (md.provides().stream().map(Provides::providers).flatMap(List::stream)
.filter(p -> !entries.contains(toBinaryName(p)))
@@ -2070,15 +2111,19 @@ private boolean checkModuleInfo(byte[] moduleInfoBytes, Set<String> entries)

/**
* Adds extended modules attributes to the given module-info's. The given
* Map values are updated in-place. Returns false if an error occurs.
* Map values are updated in-place.
*/
private void addExtendedModuleAttributes(Map<String,byte[]> moduleInfos,
private void addExtendedModuleAttributes(Map<String, ModuleInfoEntry> moduleInfos,
Set<String> packages)
throws IOException
{
for (Map.Entry<String,byte[]> e: moduleInfos.entrySet()) {
ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue()));
e.setValue(extendedInfoBytes(md, e.getValue(), packages));
for (Map.Entry<String, ModuleInfoEntry> e: moduleInfos.entrySet()) {
ModuleInfoEntry mie = e.getValue();
byte[] bytes = mie.readAllBytes();
ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(bytes));
byte[] extended = extendedInfoBytes(md, bytes, packages);
// replace the entry value with the extended bytes
e.setValue(new StreamedModuleInfoEntry(mie.name(), extended, mie.getLastModifiedTime()));
}
}

1 comment on commit a81e4fc

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on a81e4fc Nov 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.