From 001e5de8dc5a197d4c725545a4892ced9b217d79 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 31 Mar 2014 19:04:29 +0200 Subject: [PATCH] IDEA-122931, EA-52281 (better handling for corrupted .jar files) --- .../testData/vfs/maven-toolchain-1.0.jar | Bin 0 -> 32911 bytes .../openapi/vfs/JarFileSystemTest.java | 11 + .../openapi/vfs/impl/jar/JarHandlerBase.java | 237 ++++++++++-------- 3 files changed, 138 insertions(+), 110 deletions(-) create mode 100644 java/java-tests/testData/vfs/maven-toolchain-1.0.jar diff --git a/java/java-tests/testData/vfs/maven-toolchain-1.0.jar b/java/java-tests/testData/vfs/maven-toolchain-1.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..ace00cfb44fb114685b06657dda8e56825e8682c GIT binary patch literal 32911 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 literal 0 HcmV?d00001 diff --git a/java/java-tests/testSrc/com/intellij/openapi/vfs/JarFileSystemTest.java b/java/java-tests/testSrc/com/intellij/openapi/vfs/JarFileSystemTest.java index 000942a51ae1..5f658292895a 100644 --- a/java/java-tests/testSrc/com/intellij/openapi/vfs/JarFileSystemTest.java +++ b/java/java-tests/testSrc/com/intellij/openapi/vfs/JarFileSystemTest.java @@ -16,6 +16,7 @@ package com.intellij.openapi.vfs; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Ref; @@ -100,6 +101,16 @@ public class JarFileSystemTest extends IdeaTestCase { assertContent(entry, "update"); } + public void testInvalidJar() throws Exception { + String jarPath = PathManagerEx.getTestDataPath() + "/vfs/maven-toolchain-1.0.jar"; + VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(jarPath); + assertNotNull(vFile); + VirtualFile manifest = findByPath(jarPath + JarFileSystem.JAR_SEPARATOR + java.util.jar.JarFile.MANIFEST_NAME); + assertNotNull(manifest); + VirtualFile classFile = findByPath(jarPath + JarFileSystem.JAR_SEPARATOR + "org/apache/maven/toolchain/java/JavaToolChain.class"); + assertNotNull(classFile); + } + private String getJdkRtPath(String relativePath) { Sdk jdk = ModuleRootManager.getInstance(myModule).getSdk(); assertNotNull(jdk); diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java index 0648e3d319e1..26509f2d3652 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandlerBase.java @@ -51,15 +51,18 @@ public class JarHandlerBase { protected final String myBasePath; protected static class EntryInfo { - protected final boolean isDirectory; - @NotNull - protected final String shortName; protected final EntryInfo parent; + protected final String shortName; + protected final boolean isDirectory; + protected final long length; + protected final long timestamp; - public EntryInfo(@NotNull String shortName, final EntryInfo parent, final boolean directory) { - this.shortName = shortName; + public EntryInfo(EntryInfo parent, @NotNull String shortName, boolean isDirectory, long length, long timestamp) { this.parent = parent; - isDirectory = directory; + this.shortName = shortName; + this.isDirectory = isDirectory; + this.length = length; + this.timestamp = timestamp; } } @@ -108,10 +111,6 @@ public class JarHandlerBase { myEntry = entry; } - public ZipEntry getEntry() { - return myEntry; - } - @Override public String getName() { return myEntry.getName(); @@ -197,23 +196,7 @@ public class JarHandlerBase { } @NotNull - private static EntryInfo getOrCreate(@NotNull String entryName, boolean isDirectory, @NotNull Map map) { - EntryInfo info = map.get(entryName); - if (info == null) { - int idx = entryName.lastIndexOf('/'); - final String parentEntryName = idx > 0 ? entryName.substring(0, idx) : ""; - String shortName = idx > 0 ? entryName.substring(idx + 1) : entryName; - if (".".equals(shortName)) return getOrCreate(parentEntryName, true, map); - - info = new EntryInfo(shortName, getOrCreate(parentEntryName, true, map), isDirectory); - map.put(entryName, info); - } - - return info; - } - - @NotNull - public String[] list(@NotNull final VirtualFile file) { + public String[] list(@NotNull VirtualFile file) { synchronized (lock) { EntryInfo parentEntry = getEntryInfo(file); @@ -229,10 +212,12 @@ public class JarHandlerBase { } protected EntryInfo getEntryInfo(@NotNull VirtualFile file) { - synchronized (lock) { - String parentPath = getRelativePath(file); - return getEntryInfo(parentPath); - } + return getEntryInfo(getRelativePath(file)); + } + + private String getRelativePath(VirtualFile file) { + String path = file.getPath().substring(myBasePath.length() + 1); + return StringUtil.startsWithChar(path, '/') ? path.substring(1) : path; } public EntryInfo getEntryInfo(@NotNull String parentPath) { @@ -245,18 +230,18 @@ public class JarHandlerBase { Map map = SoftReference.dereference(myRelPathsToEntries); if (map == null) { - final JarFile zip = getJar(); + JarFile zip = getJar(); if (zip != null) { LogUtil.debug(LOG, "mapping %s", myBasePath); map = new THashMap(); - map.put("", new EntryInfo("", null, true)); - final Enumeration entries = zip.entries(); + map.put("", new EntryInfo(null, "", true, DEFAULT_LENGTH, DEFAULT_TIMESTAMP)); + + Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { - final JarFile.JarEntry entry = entries.nextElement(); - final String name = entry.getName(); - final boolean isDirectory = StringUtil.endsWithChar(name, '/'); - getOrCreate(isDirectory ? name.substring(0, name.length() - 1) : name, isDirectory, map); + JarFile.JarEntry entry = entries.nextElement(); + if (entry == null) break; // corrupted .jar + getOrCreate(entry, map, zip); } myRelPathsToEntries = new SoftReference>(map); @@ -271,87 +256,119 @@ public class JarHandlerBase { } @NotNull - private String getRelativePath(@NotNull VirtualFile file) { - final String path = file.getPath().substring(myBasePath.length() + 1); - return StringUtil.startsWithChar(path, '/') ? path.substring(1) : path; - } - - @Nullable - private JarFile.JarEntry convertToEntry(@NotNull VirtualFile file) { - String path = getRelativePath(file); - final JarFile jar = getJar(); - return jar == null ? null : jar.getEntry(path); - } - - public long getLength(@NotNull final VirtualFile file) { - final JarFile.JarEntry entry = convertToEntry(file); - synchronized (lock) { - return entry == null ? DEFAULT_LENGTH : entry.getSize(); + private static EntryInfo getOrCreate(JarFile.JarEntry entry, Map map, JarFile zip) { + boolean isDirectory = entry.isDirectory(); + String entryName = entry.getName(); + if (StringUtil.endsWithChar(entryName, '/')) { + entryName = entryName.substring(0, entryName.length() - 1); + isDirectory = true; } + + EntryInfo info = map.get(entryName); + if (info != null) return info; + + int idx = entryName.lastIndexOf('/'); + String parentName = idx > 0 ? entryName.substring(0, idx) : ""; + String shortName = idx > 0 ? entryName.substring(idx + 1) : entryName; + + EntryInfo parentInfo = getOrCreate(parentName, map, zip); + + if (".".equals(shortName)) { + return parentInfo; + } + + info = new EntryInfo(parentInfo, shortName, isDirectory, entry.getSize(), entry.getTime()); + map.put(entryName, info); + return info; } @NotNull - public InputStream getInputStream(@NotNull final VirtualFile file) throws IOException { + private static EntryInfo getOrCreate(String entryName, Map map, JarFile zip) { + EntryInfo info = map.get(entryName); + + if (info == null) { + JarFile.JarEntry entry = zip.getEntry(entryName + "/"); + if (entry != null) { + return getOrCreate(entry, map, zip); + } + + int idx = entryName.lastIndexOf('/'); + String parentName = idx > 0 ? entryName.substring(0, idx) : ""; + String shortName = idx > 0 ? entryName.substring(idx + 1) : entryName; + + EntryInfo parentInfo = getOrCreate(parentName, map, zip); + info = new EntryInfo(parentInfo, shortName, true, DEFAULT_LENGTH, DEFAULT_TIMESTAMP); + map.put(entryName, info); + } + + if (!info.isDirectory) { + //noinspection ConstantConditions + LOG.info(zip.getZipFile().getName() + ": " + entryName + " should be a directory"); + info = new EntryInfo(info.parent, info.shortName, true, info.length, info.timestamp); + map.put(entryName, info); + } + + return info; + } + + public long getLength(@NotNull VirtualFile file) { + if (file.getParent() == null) return DEFAULT_LENGTH; + EntryInfo entry = getEntryInfo(file); + return entry == null ? DEFAULT_LENGTH : entry.length; + } + + public long getTimeStamp(@NotNull VirtualFile file) { + if (file.getParent() == null) return getOriginalFile().lastModified(); + EntryInfo entry = getEntryInfo(file); + return entry == null ? DEFAULT_TIMESTAMP : entry.timestamp; + } + + public boolean isDirectory(@NotNull VirtualFile file) { + if (file.getParent() == null) return true; + EntryInfo info = getEntryInfo(file); + return info == null || info.isDirectory; + } + + public boolean exists(@NotNull VirtualFile file) { + if (file.getParent() == null) { + return myJarFile.get() != null || getOriginalFile().exists(); + } + + return getEntryInfo(file) != null; + } + + @Nullable + public FileAttributes getAttributes(@NotNull VirtualFile file) { + if (file.getParent() == null) { + return new FileAttributes(true, false, false, false, DEFAULT_LENGTH, getOriginalFile().lastModified(), false); + } + + EntryInfo entry = getEntryInfo(file); + return entry == null ? null : new FileAttributes(entry.isDirectory, false, false, false, entry.length, entry.timestamp, false); + } + + @NotNull + public InputStream getInputStream(@NotNull VirtualFile file) throws IOException { return new BufferExposingByteArrayInputStream(contentsToByteArray(file)); } @NotNull - public byte[] contentsToByteArray(@NotNull final VirtualFile file) throws IOException { - final JarFile.JarEntry entry = convertToEntry(file); - if (entry == null) { - return ArrayUtil.EMPTY_BYTE_ARRAY; - } - synchronized (lock) { - final JarFile jar = getJar(); - assert jar != null : file; - - final InputStream stream = jar.getInputStream(entry); - assert stream != null : file; - - try { - return FileUtil.loadBytes(stream, (int)entry.getSize()); - } - finally { - stream.close(); + public byte[] contentsToByteArray(@NotNull VirtualFile file) throws IOException { + JarFile jar = getJar(); + if (jar != null) { + JarFile.JarEntry entry = jar.getEntry(getRelativePath(file)); + if (entry != null) { + InputStream stream = jar.getInputStream(entry); + if (stream != null) { + try { + return FileUtil.loadBytes(stream, (int)entry.getSize()); + } + finally { + stream.close(); + } + } } } - } - - public long getTimeStamp(@NotNull final VirtualFile file) { - if (file.getParent() == null) return getOriginalFile().lastModified(); // Optimization - final JarFile.JarEntry entry = convertToEntry(file); - synchronized (lock) { - return entry == null ? DEFAULT_TIMESTAMP : entry.getTime(); - } - } - - public boolean isDirectory(@NotNull final VirtualFile file) { - if (file.getParent() == null) return true; // Optimization - synchronized (lock) { - final String path = getRelativePath(file); - final EntryInfo info = getEntryInfo(path); - return info == null || info.isDirectory; - } - } - - public boolean exists(@NotNull final VirtualFile fileOrDirectory) { - if (fileOrDirectory.getParent() == null) { - // Optimization. Do not build entries if asked for jar root existence. - return myJarFile.get() != null || getOriginalFile().exists(); - } - - return getEntryInfo(fileOrDirectory) != null; - } - - @Nullable - public FileAttributes getAttributes(@NotNull final VirtualFile file) { - final JarFile.JarEntry entry = convertToEntry(file); - synchronized (lock) { - final EntryInfo entryInfo = getEntryInfo(getRelativePath(file)); - if (entryInfo == null) return null; - final long length = entry != null ? entry.getSize() : DEFAULT_LENGTH; - final long timeStamp = entry != null ? entry.getTime() : DEFAULT_TIMESTAMP; - return new FileAttributes(entryInfo.isDirectory, false, false, false, length, timeStamp, false); - } + return ArrayUtil.EMPTY_BYTE_ARRAY; } }