Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8258117: jar tool sets the time stamp of module-info.class entries to the current time #5486

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 67 additions & 22 deletions src/jdk.jartool/share/classes/sun/tools/jar/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -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()));
}
}
}
Expand Down Expand Up @@ -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)))
Expand All @@ -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()));
}
}

Expand Down
Loading