From 4d37e5ad95d72b2d01a263219e05db41e4537d59 Mon Sep 17 00:00:00 2001 From: Dmitry Avdeev Date: Mon, 31 Oct 2011 19:39:29 +0400 Subject: [PATCH] symlink support in vfs & SOE protection --- .../com/intellij/openapi/vfs/VfsUtilCore.java | 31 ++- .../com/intellij/openapi/vfs/VirtualFile.java | 5 + .../openapi/vfs/VirtualFileVisitor.java | 27 +++ .../roots/impl/DirectoryIndexImpl.java | 194 +++++++++++------- .../openapi/roots/impl/FileIndexImplUtil.java | 28 ++- .../vfs/newvfs/FileSystemInterface.java | 2 + .../vfs/newvfs/NewVirtualFileSystem.java | 5 + .../openapi/vfs/impl/jar/JarHandler.java | 5 + .../vfs/impl/local/LocalFileSystemBase.java | 5 + .../vfs/newvfs/impl/SymlinkDirectory.java | 44 ++++ .../vfs/newvfs/impl/VirtualDirectoryImpl.java | 4 +- .../vfs/newvfs/persistent/PersistentFS.java | 14 +- 12 files changed, 279 insertions(+), 85 deletions(-) create mode 100644 platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java create mode 100644 platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/SymlinkDirectory.java diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java index 2377eb3a45dd..5d40326f4de8 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VfsUtilCore.java @@ -20,7 +20,11 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Set; public class VfsUtilCore { /** @@ -151,4 +155,29 @@ public class VfsUtilCore { } return stream; } + + public static void visitChildrenRecursively(@NotNull VirtualFile file, VirtualFileVisitor visitor) { + visitChildrenRecursively(file, visitor, null); + } + + private static void visitChildrenRecursively(@NotNull VirtualFile file, + VirtualFileVisitor visitor, + @Nullable Set visitedSymlinks) { + + if (!visitor.visitFile(file)) return; + if (file.isSymLink()) { + if (visitedSymlinks == null) { + visitedSymlinks = new HashSet(); + } + if (!visitedSymlinks.add(file)) { + visitor.afterChildrenVisited(file); + return; + } + } + VirtualFile[] children = file.getChildren(); + for (VirtualFile child : children) { + visitChildrenRecursively(child, visitor, visitedSymlinks); + } + visitor.afterChildrenVisited(file); + } } diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java index 572daa417ab5..365e4c6fb73f 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFile.java @@ -212,6 +212,11 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica return false; } + @Nullable + public String resolveSymLink() { + return null; + } + /** * Checks whether this file is a special (e.g. FIFO or device) file. * diff --git a/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java new file mode 100644 index 000000000000..9e9d0ab555c4 --- /dev/null +++ b/platform/core-api/src/com/intellij/openapi/vfs/VirtualFileVisitor.java @@ -0,0 +1,27 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.vfs; + +/** + * @author Dmitry Avdeev + * Date: 10/31/11 + */ +public abstract class VirtualFileVisitor { + + public abstract boolean visitFile(VirtualFile file); + + public void afterChildrenVisited(VirtualFile file) {} +} diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java index 63bea30fdc53..78a20effa8ad 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/DirectoryIndexImpl.java @@ -353,7 +353,7 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone } if (!parentInfo.getOrderEntries().isEmpty()) { - state.fillMapWithOrderEntries(file, parentInfo.getOrderEntries(), null, null, null, parentInfo, null); + state.fillMapWithOrderEntries(file, parentInfo.getOrderEntries(), null, null, null, parentInfo); } return state; } @@ -427,29 +427,59 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone return info; } - private void fillMapWithModuleContent(VirtualFile dir, Module module, VirtualFile contentRoot) { - if (isExcluded(contentRoot, dir)) return; - if (isIgnored(dir)) return; + private void fillMapWithModuleContent(VirtualFile root, final Module module, final VirtualFile contentRoot) { - DirectoryInfo info = getOrCreateDirInfo(dir); + VfsUtilCore.visitChildrenRecursively(root, new DirectoryVisitor() { + + @Override + protected DirectoryInfo updateInfo(VirtualFile file) { + if (isExcluded(contentRoot, file)) return null; + if (isIgnored(file)) return null; - if (info.module != null) { // module contents overlap - DirectoryInfo parentInfo = myDirToInfoMap.get(dir.getParent()); - if (parentInfo == null || !info.module.equals(parentInfo.module)) return; // content of another module is below this module's content - } + DirectoryInfo info = getOrCreateDirInfo(file); - VirtualFile[] children = dir.getChildren(); - for (VirtualFile child : children) { - if (child.isDirectory()) { - fillMapWithModuleContent(child, module, contentRoot); + if (info.module != null) { // module contents overlap + DirectoryInfo parentInfo = myDirToInfoMap.get(file.getParent()); + if (parentInfo == null || !info.module.equals(parentInfo.module)) return null; + } + + return info; } - } - // important to change module AFTER processing children - to handle overlapping modules - info.module = module; - info.contentRoot = contentRoot; + @Override + protected void afterChildrenVisited(DirectoryInfo info) { + info.module = module; + info.contentRoot = contentRoot; + } + }); } + private abstract class DirectoryVisitor extends VirtualFileVisitor { + + private Stack myDirectoryInfoStack = new Stack(); + + @Override + public boolean visitFile(VirtualFile file) { + if (!file.isDirectory()) return false; + DirectoryInfo info = updateInfo(file); + if (info != null) { + myDirectoryInfoStack.push(info); + return true; + } + return false; + } + + @Override + public void afterChildrenVisited(VirtualFile file) { + afterChildrenVisited(myDirectoryInfoStack.pop()); + } + + @Nullable + protected abstract DirectoryInfo updateInfo(VirtualFile file); + + protected void afterChildrenVisited(DirectoryInfo info) {} + } + private boolean isExcluded(VirtualFile root, VirtualFile dir) { Set excludes = myExcludeRootsMap.get(root); return excludes != null && excludes.contains(dir.getUrl()); @@ -494,28 +524,45 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone } } - private void fillMapWithModuleSource(VirtualFile dir, Module module, String packageName, VirtualFile sourceRoot, boolean isTestSource) { - DirectoryInfo info = myDirToInfoMap.get(dir); - if (info == null) return; - if (!module.equals(info.module)) return; + private void fillMapWithModuleSource(final VirtualFile dir, final Module module, final String packageName, final VirtualFile sourceRoot, final boolean isTestSource) { + + VfsUtilCore.visitChildrenRecursively(dir, new DirectoryVisitor() { + + private Stack myPackages = new Stack(); - if (info.isInModuleSource) { // module sources overlap - String definedPackage = myDirToPackageName.get(dir); - if (definedPackage != null && definedPackage.length() == 0) return; // another source root starts here - } + @Override + protected DirectoryInfo updateInfo(VirtualFile file) { + DirectoryInfo info = myDirToInfoMap.get(file); + if (info == null) return null; + if (!module.equals(info.module)) return null; - info.isInModuleSource = true; - info.isTestSource = isTestSource; - info.sourceRoot = sourceRoot; - setPackageName(dir, packageName); + if (info.isInModuleSource) { // module sources overlap + String definedPackage = myDirToPackageName.get(file); + if (definedPackage != null && definedPackage.length() == 0) return null; // another source root starts here + } - VirtualFile[] children = dir.getChildren(); - for (VirtualFile child : children) { - if (child.isDirectory()) { - String childPackageName = getPackageNameForSubdir(packageName, child.getName()); - fillMapWithModuleSource(child, module, childPackageName, sourceRoot, isTestSource); + info.isInModuleSource = true; + info.isTestSource = isTestSource; + info.sourceRoot = sourceRoot; + + String currentPackage; + if (myPackages.isEmpty()) { + currentPackage = packageName; + } + else { + currentPackage = getPackageNameForSubdir(myPackages.peek(), file.getName()); + } + myPackages.push(currentPackage); + setPackageName(file, currentPackage); + return info; } - } + + @Override + protected void afterChildrenVisited(DirectoryInfo info) { + super.afterChildrenVisited(info); + myPackages.pop(); + } + }); } private void initLibrarySources(Module module, ProgressIndicator progress) { @@ -623,7 +670,7 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone VirtualFile[] sourceRoots = orderEntry.getFiles(OrderRootType.SOURCES); for (VirtualFile sourceRoot : sourceRoots) { - fillMapWithOrderEntries(sourceRoot, oneEntryList, entryModule, null, null, null, null); + fillMapWithOrderEntries(sourceRoot, oneEntryList, entryModule, null, null, null); } } else if (orderEntry instanceof LibraryOrderEntry || orderEntry instanceof JdkOrderEntry) { @@ -645,19 +692,19 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone for (Map.Entry> mapEntry : depEntries.entrySet()) { final VirtualFile vRoot = mapEntry.getKey(); final Collection entries = mapEntry.getValue(); - fillMapWithOrderEntries(vRoot, entries, null, null, null, null, null); + fillMapWithOrderEntries(vRoot, entries, null, null, null, null); } for (Map.Entry> mapEntry : libClassRootEntries.entrySet()) { final VirtualFile vRoot = mapEntry.getKey(); final Collection entries = mapEntry.getValue(); - fillMapWithOrderEntries(vRoot, entries, null, vRoot, null, null, null); + fillMapWithOrderEntries(vRoot, entries, null, vRoot, null, null); } for (Map.Entry> mapEntry : libSourceRootEntries.entrySet()) { final VirtualFile vRoot = mapEntry.getKey(); final Collection entries = mapEntry.getValue(); - fillMapWithOrderEntries(vRoot, entries, null, null, vRoot, null, null); + fillMapWithOrderEntries(vRoot, entries, null, null, vRoot, null); } } @@ -690,41 +737,50 @@ public class DirectoryIndexImpl extends DirectoryIndex implements ProjectCompone } } - private void fillMapWithOrderEntries(VirtualFile dir, - Collection orderEntries, - Module module, - VirtualFile libraryClassRoot, - VirtualFile librarySourceRoot, - DirectoryInfo parentInfo, - final List oldParentEntries) { - if (isIgnored(dir)) return; + private void fillMapWithOrderEntries(final VirtualFile root, + final Collection orderEntries, + final Module module, + final VirtualFile libraryClassRoot, + final VirtualFile librarySourceRoot, + final DirectoryInfo parentInfo) { + + VfsUtilCore.visitChildrenRecursively(root, new DirectoryVisitor() { - DirectoryInfo info = myDirToInfoMap.get(dir); // do not create it here! - if (info == null) return; + private Stack> myEntries = new Stack>(); - if (module != null) { - if (info.module != module) return; - if (!info.isInModuleSource) return; - } - else if (libraryClassRoot != null) { - if (info.libraryClassRoot != libraryClassRoot) return; - if (info.isInModuleSource) return; - } - else if (librarySourceRoot != null) { - if (!info.isInLibrarySource) return; - if (info.sourceRoot != librarySourceRoot) return; - if (info.libraryClassRoot != null) return; - } + @Override + protected DirectoryInfo updateInfo(VirtualFile dir) { + if (isIgnored(dir)) return null; - final List oldEntries = info.getOrderEntries(); - info.addOrderEntries(orderEntries, parentInfo, oldParentEntries); + DirectoryInfo info = myDirToInfoMap.get(dir); // do not create it here! + if (info == null) return null; - final VirtualFile[] children = dir.getChildren(); - for (VirtualFile child : children) { - if (child.isDirectory()) { - fillMapWithOrderEntries(child, orderEntries, module, libraryClassRoot, librarySourceRoot, info, oldEntries); + if (module != null) { + if (info.module != module) return null; + if (!info.isInModuleSource) return null; + } + else if (libraryClassRoot != null) { + if (info.libraryClassRoot != libraryClassRoot) return null; + if (info.isInModuleSource) return null; + } + else if (librarySourceRoot != null) { + if (!info.isInLibrarySource) return null; + if (info.sourceRoot != librarySourceRoot) return null; + if (info.libraryClassRoot != null) return null; + } + + List oldParentEntries = myEntries.isEmpty() ? null : myEntries.peek(); + final List oldEntries = info.getOrderEntries(); + myEntries.push(oldEntries); + info.addOrderEntries(orderEntries, parentInfo, oldParentEntries); + return info; } - } + + @Override + protected void afterChildrenVisited(DirectoryInfo info) { + myEntries.pop(); + } + }); } private void doInitialize(boolean reverseAllSets/* for testing order independence*/) { diff --git a/platform/platform-api/src/com/intellij/openapi/roots/impl/FileIndexImplUtil.java b/platform/platform-api/src/com/intellij/openapi/roots/impl/FileIndexImplUtil.java index d8e734a47ec4..94c2485a5f38 100644 --- a/platform/platform-api/src/com/intellij/openapi/roots/impl/FileIndexImplUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/roots/impl/FileIndexImplUtil.java @@ -17,26 +17,34 @@ package com.intellij.openapi.roots.impl; import com.intellij.openapi.roots.ContentIterator; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileFilter; +import com.intellij.openapi.vfs.VirtualFileVisitor; import org.jetbrains.annotations.NotNull; public class FileIndexImplUtil { private FileIndexImplUtil() { } - public static boolean iterateRecursively(@NotNull VirtualFile root, @NotNull VirtualFileFilter filter, @NotNull ContentIterator iterator){ - if (!root.isValid() || !filter.accept(root)) return true; + public static boolean iterateRecursively(@NotNull final VirtualFile root, @NotNull final VirtualFileFilter filter, @NotNull final ContentIterator iterator){ - if (!iterator.processFile(root)) return false; + try { + VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() { + @Override + public boolean visitFile(VirtualFile file) { + if (!file.isValid() || !filter.accept(file)) return true; - if (root.isDirectory()){ - VirtualFile[] children = root.getChildren(); - for (VirtualFile child : children) { - if (!iterateRecursively(child, filter, iterator)) return false; - } + if (!iterator.processFile(file)) throw new StopItException(); + return true; + } + }); + return true; + } + catch (StopItException e) { + return false; } - - return true; } + + private static class StopItException extends RuntimeException {} } diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileSystemInterface.java b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileSystemInterface.java index ec94931ecef6..bb16fae1ee50 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileSystemInterface.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileSystemInterface.java @@ -42,6 +42,8 @@ public interface FileSystemInterface { void setWritable(@NotNull VirtualFile file, boolean writableFlag) throws IOException; boolean isSymLink(@NotNull VirtualFile file); + @Nullable + String resolveSymLink(@NotNull VirtualFile file); boolean isSpecialFile(@NotNull VirtualFile file); diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFileSystem.java b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFileSystem.java index 7f33084d393c..dd10ab7e41bb 100644 --- a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFileSystem.java +++ b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/NewVirtualFileSystem.java @@ -57,6 +57,11 @@ public abstract class NewVirtualFileSystem extends VirtualFileSystem implements return false; } + @Override + public String resolveSymLink(@NotNull VirtualFile file) { + return null; + } + @Override public boolean isSpecialFile(@NotNull final VirtualFile file) { return false; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java index 67ddec2cae7e..8c19444a3686 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarHandler.java @@ -185,6 +185,11 @@ public class JarHandler extends JarHandlerBase implements FileSystemInterface { return false; } + @Override + public String resolveSymLink(@NotNull VirtualFile file) { + return null; + } + @Override public boolean isSpecialFile(@NotNull VirtualFile file) { return false; diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java index 934ac3b69a97..c7b639d162db 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/local/LocalFileSystemBase.java @@ -178,6 +178,11 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { return SymLinkUtil.isSymLink(file.getPath()); } + @Override + public String resolveSymLink(@NotNull VirtualFile file) { + return SymLinkUtil.resolveSymLink(file.getPath()); + } + @Override public boolean isSpecialFile(@NotNull final VirtualFile file) { final File ioFile = convertToIOFile(file); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/SymlinkDirectory.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/SymlinkDirectory.java new file mode 100644 index 000000000000..c177c2358ffb --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/SymlinkDirectory.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.vfs.newvfs.impl; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem; +import com.intellij.openapi.vfs.newvfs.VfsImplUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Dmitry Avdeev + * Date: 10/31/11 + */ +public class SymlinkDirectory extends VirtualDirectoryImpl { + + @Nullable + private final VirtualFile myTarget; + + public SymlinkDirectory(@NotNull String name, final VirtualDirectoryImpl parent, @NotNull NewVirtualFileSystem fs, final int id) { + super(name, parent, fs, id); + String path = fs.resolveSymLink(this); + myTarget = path == null ? null : VfsImplUtil.findFileByPath(fs, path); + } + + @NotNull + @Override + public VirtualFile[] getChildren() { + return myTarget == null ? VirtualFile.EMPTY_ARRAY : myTarget.getChildren(); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 5c3ed62b7218..e7e14fa11444 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -68,7 +68,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { private final NewVirtualFileSystem myFS; // guarded by this - private Object myChildren; // Either HashMap or VFile[] + protected Object myChildren; // Either HashMap or VFile[] public VirtualDirectoryImpl(@NotNull String name, final VirtualDirectoryImpl parent, @NotNull NewVirtualFileSystem fs, final int id) { super(name, parent, id); @@ -165,7 +165,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { final VirtualFileSystemEntry child; final NewVirtualFileSystem fs = getFileSystem(); if (PersistentFS.isDirectory(id)) { - child = new VirtualDirectoryImpl(name, this, fs, id); + child = PersistentFS.isSymLink(id) ? new SymlinkDirectory(name, this, fs, id) : new VirtualDirectoryImpl(name, this, fs, id); } else { child = new VirtualFileImpl(name, this, id); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java index c54355519196..cd30a88ab262 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java @@ -24,9 +24,7 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ex.ApplicationEx; import com.intellij.openapi.components.ApplicationComponent; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.ShutDownTracker; -import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream; import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream; import com.intellij.openapi.util.io.ByteSequence; @@ -322,6 +320,11 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { return (FSRecords.getFlags(id) & IS_DIRECTORY_FLAG) != 0; } + public static boolean isSymLink(final int id) { + assert id > 0; + return (FSRecords.getFlags(id) & IS_SYMLINK) != 0; + } + private static int getParent(final int id) { assert id > 0; return FSRecords.getParent(id); @@ -363,6 +366,11 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { return (FSRecords.getFlags(getFileId(file)) & IS_SYMLINK) != 0; } + @Override + public String resolveSymLink(@NotNull VirtualFile file) { + throw new UnsupportedOperationException(); + } + @Override public boolean isSpecialFile(@NotNull VirtualFile file) { return (FSRecords.getFlags(getFileId(file)) & IS_SPECIAL) != 0;