diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java index 4a8e7f0a0e07..c64a109153a7 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/file/PsiDirectoryImpl.java @@ -215,11 +215,12 @@ public class PsiDirectoryImpl extends PsiElementBase implements PsiDirectory, Qu ProgressIndicatorProvider.checkCanceled(); for (VirtualFile vFile : myFile.getChildren()) { + boolean isDir = vFile.isDirectory(); if (processor instanceof PsiFileSystemItemProcessor && - !((PsiFileSystemItemProcessor)processor).acceptItem(vFile.getName(), vFile.isDirectory())) { + !((PsiFileSystemItemProcessor)processor).acceptItem(vFile.getName(), isDir)) { continue; } - if (vFile.isDirectory()) { + if (isDir) { PsiDirectory dir = myManager.findDirectory(vFile); if (dir != null) { if (!processor.execute(dir)) return false; 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 d0ebd6f159fb..f2ba97153912 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 @@ -23,6 +23,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileListener; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.VirtualFileSystem; +import org.intellij.lang.annotations.MagicConstant; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -103,4 +104,48 @@ public abstract class NewVirtualFileSystem extends VirtualFileSystem implements public String getCanonicallyCasedName(@NotNull VirtualFile file) { return file.getName(); } + + public static final int BA_EXISTS = 0x01; + public static final int BA_REGULAR = 0x02; + public static final int BA_DIRECTORY = 0x04; + public static final int BA_HIDDEN = 0x08; + + @MagicConstant(flags = {BA_EXISTS, BA_REGULAR, BA_DIRECTORY, BA_HIDDEN}) + public @interface FileBooleanAttributes {} + + /** + * Queries the file about several attributes at once, and returns them ORed together. + * This method is typically faster than several methods calls querying corresponding file attributes one by one. + * + * @param file to query. + * @param flags Attributes to query the file for. + * Each attribute is an int constant from this class. + * Following attributes are defined: + * + * Attributes can be bitwise ORed together to query several file attributes at once. + * -1 as an argument value will query all attributes. + * @return Attributes mask for the file, where the bit is set if the corresponding attribute for the file is true. + * That is, the return value is
{@code
+   *           (file.exists() ? BA_EXISTS : 0) |
+   *           (file.isDirectory()() ? BA_DIRECTORY : 0) |
+   *           (file.isRegular()() ? BA_REGULAR : 0) |
+   *           (file.isHidden()() ? BA_HIDDEN : 0)
+   *           }
+ * Except that the bit in the return value is undefined if the corresponding bit in the flags parameter is not set. + *

+ * Example usage: + *

{@code
+   *  int attributes = getBooleanAttributes(file, BA_EXISTS | BA_DIRECTORY);
+   *  if ((attributes & BA_EXISTS) != 0) {
+   *    // file exists
+   *    boolean isDirectory = (attributes & BA_DIRECTORY) != 0;
+   *  }}
+ */ + @FileBooleanAttributes + public abstract int getBooleanAttributes(@NotNull final VirtualFile file, @FileBooleanAttributes int flags); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java index b2688f67df36..7f35b77eba8c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/temp/TempFileSystem.java @@ -270,7 +270,7 @@ public class TempFileSystem extends NewVirtualFileSystem { } } - private static abstract class FSItem { + private abstract static class FSItem { private final FSDir myParent; private String myName; private long myTimestamp; @@ -365,4 +365,13 @@ public class TempFileSystem extends NewVirtualFileSystem { return false; } } + + @Override + public int getBooleanAttributes(@NotNull VirtualFile file, int flags) { + FSItem item = convert(file); + int isDir = item instanceof FSDir ? BA_DIRECTORY : 0; + int exists = item == null ? 0 : BA_EXISTS; + int regular = isDir == 0 ? BA_REGULAR : 0; + return isDir | exists | regular; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java index 66d5eb272da9..abaac61050f4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/jar/JarFileSystemImpl.java @@ -365,4 +365,22 @@ public class JarFileSystemImpl extends JarFileSystem implements ApplicationCompo public VirtualFile refreshAndFindFileByPath(@NotNull String path) { return VfsImplUtil.refreshAndFindFileByPath(this, path); } + + @Override + public int getBooleanAttributes(@NotNull VirtualFile file, int flags) { + int exists = 0; + JarHandler handler = getHandler(file); + if ((flags & BA_EXISTS) != 0) { + exists = handler.exists(file) ? BA_EXISTS : 0; + } + int isDir = 0; + if ((flags & BA_DIRECTORY) != 0) { + isDir = handler.isDirectory(file) ? BA_DIRECTORY : 0; + } + int regular = 0; + if ((flags & BA_REGULAR) != 0) { + regular = isDir == 0 ? BA_REGULAR : 0; + } + return exists | isDir | regular; + } } 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 915ca59e82b8..f727a8e7278f 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 @@ -25,10 +25,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.openapi.vfs.ex.VirtualFileManagerEx; -import com.intellij.openapi.vfs.newvfs.ManagingFS; -import com.intellij.openapi.vfs.newvfs.NewVirtualFile; -import com.intellij.openapi.vfs.newvfs.RefreshQueue; -import com.intellij.openapi.vfs.newvfs.VfsImplUtil; +import com.intellij.openapi.vfs.newvfs.*; import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.Processor; @@ -140,10 +137,6 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { private static final Method JAVA_IO_FILESYSTEM_GET_BOOLEAN_ATTRIBUTES_METHOD; private static final Object/* java.io.FileSystem */ JAVA_IO_FILESYSTEM; // copied from FileSystem - private static final int BA_EXISTS = 0x01; - private static final int BA_REGULAR = 0x02; - private static final int BA_DIRECTORY = 0x04; - private static final int BA_HIDDEN = 0x08; static { Object fs; @@ -170,6 +163,8 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { JAVA_IO_FILESYSTEM_GET_BOOLEAN_ATTRIBUTES_METHOD = getBooleanAttributes; } + + @NotNull private static File convertToIOFileAndCheck(@NotNull final VirtualFile file) throws FileNotFoundException { final File ioFile = convertToIOFile(file); @@ -769,6 +764,17 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { } } + @Override + public int getBooleanAttributes(@NotNull VirtualFile file, int flags) { + int attributes = getBooleanAttributes(convertToIOFile(file)); + if (attributes != -1) return attributes & flags; + return ((flags & BA_EXISTS) != 0 && exists(file) ? BA_EXISTS : 0) | + ((flags & BA_DIRECTORY) != 0 && isDirectory(file) ? BA_DIRECTORY : 0) | + ((flags & BA_REGULAR) != 0 && !isSpecialFile(file) ? BA_REGULAR : 0) | + ((flags & BA_HIDDEN) != 0 && convertToIOFile(file).isHidden() ? BA_HIDDEN : 0) + ; + } + @Override public void refresh(final boolean asynchronous) { RefreshQueue.getInstance().refresh(asynchronous, true, null, ManagingFS.getInstance().getRoots(this)); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/FileInfo.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/FileInfo.java index ea85f580259f..52cdc416ac7f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/FileInfo.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/FileInfo.java @@ -15,23 +15,28 @@ */ package com.intellij.openapi.vfs.impl.win32; +import org.intellij.lang.annotations.MagicConstant; + /** * @author Dmitry Avdeev */ public class FileInfo { - static { - initIDs(); - } + static { + initIDs(); + } - private static native void initIDs(); - - public String name; - public int attributes; - public long timestamp; - public long length; + private static native void initIDs(); - public String toString() { - return name; - } + public String name; + + @MagicConstant(flagsFromClass = Win32Kernel.class) + public int attributes; + + public long timestamp; + public long length; + + public String toString() { + return name; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32Kernel.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32Kernel.java index c7fe8b9b2706..18450eb9ea6c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32Kernel.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32Kernel.java @@ -15,7 +15,10 @@ */ package com.intellij.openapi.vfs.impl.win32; +import com.intellij.openapi.vfs.newvfs.NewVirtualFileSystem; import com.intellij.util.ArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.FileNotFoundException; import java.util.ArrayList; @@ -27,7 +30,10 @@ import java.util.Map; */ public class Win32Kernel { public static final int FILE_ATTRIBUTE_READONLY = 0x0001; + public static final int FILE_ATTRIBUTE_HIDDEN = 0x0002; public static final int FILE_ATTRIBUTE_DIRECTORY = 0x0010; + public static final int FILE_ATTRIBUTE_DEVICE = 0x0040; + public static final int FILE_ATTRIBUTE_REPARSE_POINT = 0x0400; private final IdeaWin32 myKernel = new IdeaWin32(); @@ -43,13 +49,12 @@ public class Win32Kernel { return ArrayUtil.EMPTY_STRING_ARRAY; } ArrayList names = new ArrayList(fileInfos.length); - for (int i = 0, fileInfosLength = fileInfos.length; i < fileInfosLength; i++) { - FileInfo info = fileInfos[i]; + for (FileInfo info : fileInfos) { if (info.name.equals(".")) { myCache.put(absolutePath, info); continue; } - else if (info.name.equals("..")) { + if (info.name.equals("..")) { continue; } myCache.put(absolutePath + "/" + info.name, info); @@ -59,8 +64,8 @@ public class Win32Kernel { return ArrayUtil.toStringArray(names); } - public void exists(String path) throws FileNotFoundException { - getInfo(path); + public boolean exists(String path) { + return doGetInfo(path) != null; } public boolean isDirectory(String path) throws FileNotFoundException { @@ -84,14 +89,42 @@ public class Win32Kernel { } private FileInfo getInfo(String path) throws FileNotFoundException { + FileInfo info = doGetInfo(path); + if (info == null) { + throw new FileNotFoundException(path); + } + return info; + } + + @Nullable + private FileInfo doGetInfo(String path) { FileInfo info = myCache.get(path); if (info == null) { info = myKernel.getInfo(path.replace('/', '\\')); if (info == null) { - throw new FileNotFoundException(path); + return null; } myCache.put(path, info); } return info; } + + @NewVirtualFileSystem.FileBooleanAttributes + public int getBooleanAttributes(@NotNull String path, @NewVirtualFileSystem.FileBooleanAttributes int flags) { + FileInfo info = doGetInfo(path); + int result = 0; + if ((flags & NewVirtualFileSystem.BA_EXISTS) != 0) { + result |= info == null ? 0 : NewVirtualFileSystem.BA_EXISTS; + } + if ((flags & NewVirtualFileSystem.BA_DIRECTORY) != 0) { + result |= info == null || (info.attributes & FILE_ATTRIBUTE_DIRECTORY) == 0 ? 0 : NewVirtualFileSystem.BA_DIRECTORY; + } + if ((flags & NewVirtualFileSystem.BA_REGULAR) != 0) { + result |= info == null || (info.attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE | FILE_ATTRIBUTE_REPARSE_POINT)) != 0 ? 0 : NewVirtualFileSystem.BA_REGULAR; + } + if ((flags & NewVirtualFileSystem.BA_HIDDEN) != 0) { + result |= info == null || (info.attributes & FILE_ATTRIBUTE_HIDDEN) == 0 ? 0 : NewVirtualFileSystem.BA_HIDDEN; + } + return result; + } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32LocalFileSystem.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32LocalFileSystem.java index 126b8505ebe4..c69ca7f5379c 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32LocalFileSystem.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32LocalFileSystem.java @@ -33,33 +33,34 @@ import java.util.Set; public class Win32LocalFileSystem extends LocalFileSystemBase { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.impl.win32.Win32LocalFileSystem"); - private static boolean ourIsAvailable; + private static final boolean ourIsAvailable; static { + boolean available = false; if (SystemInfo.isWindows) { String libName = SystemInfo.is64Bit ? "IdeaWin64" : "IdeaWin32"; try { System.load(PathManager.getHomePath() + "/community/bin/win/" + libName + ".dll"); - ourIsAvailable = true; + available = true; } catch (Throwable t0) { try { System.load(PathManager.getHomePath() + "/bin/win/" + libName + ".dll"); - ourIsAvailable = true; + available = true; } catch (Throwable t1) { try { System.loadLibrary(libName); - ourIsAvailable = true; + available = true; } catch (Throwable t2) { LOG.warn("Failed to load native filesystem for Windows", t2); - ourIsAvailable = false; } } } } - if (ourIsAvailable) { + ourIsAvailable = available; + if (available) { LOG.info("Native filesystem for Windows is operational"); } } @@ -108,16 +109,11 @@ public class Win32LocalFileSystem extends LocalFileSystemBase { @Override public boolean exists(@NotNull VirtualFile fileOrDirectory) { if (fileOrDirectory.getParent() == null) return true; - try { - myKernel.exists(fileOrDirectory.getPath()); - if (checkMe && !super.exists(fileOrDirectory)) { - LOG.error(fileOrDirectory.getPath()); - } - return true; - } - catch (FileNotFoundException e) { - return super.exists(fileOrDirectory); + boolean b = myKernel.exists(fileOrDirectory.getPath()); + if (checkMe && b != super.exists(fileOrDirectory)) { + LOG.error(fileOrDirectory.getPath()); } + return b; } @Override @@ -196,4 +192,9 @@ public class Win32LocalFileSystem extends LocalFileSystemBase { public void removeWatchedRoot(@NotNull WatchRequest watchRequest) { throw new UnsupportedOperationException(); } + + @Override + public int getBooleanAttributes(@NotNull VirtualFile file, int flags) { + return myKernel.getBooleanAttributes(file.getPath(), flags); + } } 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 4e8508153bed..6ff87f199cb1 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 @@ -42,6 +42,7 @@ import com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent; import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; import com.intellij.util.ArrayUtil; import com.intellij.util.PathUtil; +import com.intellij.util.SmartList; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.text.CaseInsensitiveStringHashingStrategy; @@ -312,14 +313,15 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { return VfsUtil.toVirtualFileArray(roots); } - @Nullable private VirtualFileSystemEntry createAndFindChildWithEventFire(@NotNull String name) { final NewVirtualFileSystem delegate = getFileSystem(); VirtualFile fake = new FakeVirtualFile(this, name); - if (delegate.exists(fake)) { + int attributes = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY); + if ((attributes & NewVirtualFileSystem.BA_EXISTS) != 0) { final String realName = delegate.getCanonicallyCasedName(fake); - VFileCreateEvent event = new VFileCreateEvent(null, this, realName, delegate.isDirectory(fake), true); + boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0; + VFileCreateEvent event = new VFileCreateEvent(null, this, realName, isDir, true); RefreshQueue.getInstance().processSingleEvent(event); return findChild(realName); } @@ -526,14 +528,16 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry { final Map map = asMap(); if (map == null) return Collections.emptyList(); - List names = new ArrayList(); + List names = null; + for (Map.Entry entry : map.entrySet()) { if (entry.getValue() == NULL_VIRTUAL_FILE) { + if (names == null) names = new SmartList(); names.add(entry.getKey()); } } - return names; + return names == null ? Collections.emptyList() : names; } @Override 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 9a2de59babeb..0d387162d9fc 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 @@ -48,6 +48,7 @@ import gnu.trove.TIntObjectHashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import java.io.*; import java.util.*; @@ -189,7 +190,8 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { childrenIds[i] = currentIds[idx]; } else { - int childId = createAndCopyRecord(delegate, new FakeVirtualFile(file, name), id); + FakeVirtualFile child = new FakeVirtualFile(file, name); + int childId = createAndCopyRecord(delegate, child, id, delegate.isDirectory(child)); childrenIds[i] = childId; } } @@ -283,12 +285,16 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { return FSRecords.getModCount(); } - private static boolean copyRecordFromDelegateFS(final int id, final int parentId, final VirtualFile file, NewVirtualFileSystem delegate) { + private static boolean copyRecordFromDelegateFS(final int id, + final int parentId, + final VirtualFile file, + NewVirtualFileSystem delegate, + boolean isDir) { String name = file.getName(); - if (name.length() > 0 && namesEqual(delegate, name, FSRecords.getName(id))) return false; // TODO: Handle root attributes change. + if (!name.isEmpty() && namesEqual(delegate, name, FSRecords.getName(id))) return false; // TODO: Handle root attributes change. - if (name.length() == 0) { // TODO: hack + if (name.isEmpty()) { // TODO: hack if (areChildrenLoaded(id)) return false; } @@ -299,11 +305,9 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { FSRecords.setTimestamp(id, delegate.getTimeStamp(file)); - boolean directory = delegate.isDirectory(file); + FSRecords.setLength(id, isDir ? -1L : delegate.getLength(file)); - FSRecords.setLength(id, directory ? -1L : delegate.getLength(file)); - - FSRecords.setFlags(id, (directory ? IS_DIRECTORY_FLAG : 0) | + FSRecords.setFlags(id, (isDir ? IS_DIRECTORY_FLAG : 0) | (delegate.isWritable(file) ? 0 : IS_READ_ONLY) | (delegate.isSymLink(file) ? IS_SYMLINK : 0) | (delegate.isSpecialFile(file) ? IS_SPECIAL : 0), true); @@ -398,8 +402,10 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { } VirtualFile fake = new FakeVirtualFile(parent, childName); - if (delegate.exists(fake)) { - int child = createAndCopyRecord(delegate, fake, parentId); + int attributes = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY); + if ((attributes & NewVirtualFileSystem.BA_EXISTS) != 0) { + boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0; + int child = createAndCopyRecord(delegate, fake, parentId, isDir); FSRecords.updateList(parentId, ArrayUtil.append(children, child)); return child; } @@ -722,13 +728,13 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { synchronized (LOCK) { final String rootUrl = fs.getProtocol() + "://" + basePath; VirtualFileSystemEntry root = myRoots.get(rootUrl); - if (root == null && basePath.length() == 0) { + if (root == null && basePath.isEmpty()) { root = myFakeRoot; } if (root == null) { try { final int rootId = FSRecords.findRootRecord(rootUrl); - if (basePath.length() > 0) { + if (!basePath.isEmpty()) { root = new VirtualDirectoryImpl(basePath, null, fs, rootId) { @NotNull @Override @@ -756,14 +762,14 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { @Override public VirtualFileSystemEntry findChild(@NotNull String name) { - if (name.length() == 0) return null; + if (name.isEmpty()) return null; return findRoot(name, fs); } }; } if (!fs.exists(root)) return null; - boolean newRoot = copyRecordFromDelegateFS(rootId, 0, root, fs); + boolean newRoot = copyRecordFromDelegateFS(rootId, 0, root, fs, true); if (!newRoot) { if (fs.getTimeStamp(root) != FSRecords.getTimestamp(rootId)) { root.markDirtyRecursively(); @@ -774,7 +780,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { throw new RuntimeException(e); } - if (basePath.length() > 0) { + if (!basePath.isEmpty()) { myRoots.put(rootUrl, root); myRootsById.put(root.getId(), root); } @@ -949,10 +955,12 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { private static void executeCreateChild(final VirtualFile parent, final String name) { final NewVirtualFileSystem delegate = getDelegate(parent); - VirtualFile fakeFile = new FakeVirtualFile(parent, name); - if (delegate.exists(fakeFile)) { + VirtualFile fake = new FakeVirtualFile(parent, name); + int attributes = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY); + if ((attributes & NewVirtualFileSystem.BA_EXISTS) != 0) { final int parentId = getFileId(parent); - int childId = createAndCopyRecord(delegate, fakeFile, parentId); + boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0; + int childId = createAndCopyRecord(delegate, fake, parentId, isDir); appendIdToParentList(parentId, childId); final VirtualDirectoryImpl dir = (VirtualDirectoryImpl)parent; @@ -960,9 +968,9 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { } } - private static int createAndCopyRecord(NewVirtualFileSystem delegateSystem, VirtualFile delegateFile, int parentId) { + private static int createAndCopyRecord(NewVirtualFileSystem delegateSystem, VirtualFile delegateFile, int parentId, boolean isDir) { int childId = FSRecords.createRecord(); - copyRecordFromDelegateFS(childId, parentId, delegateFile, delegateSystem); + copyRecordFromDelegateFS(childId, parentId, delegateFile, delegateSystem, isDir); return childId; } @@ -1067,7 +1075,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { FSRecords.setLength(getFileId(file), delegate.getLength(file)); FSRecords.setTimestamp(getFileId(file), delegate.getTimeStamp(file)); - ((NewVirtualFile)file).setModificationStamp(newModificationStamp); + ((VirtualFileSystemEntry)file).setModificationStamp(newModificationStamp); } @SuppressWarnings({"UnusedDeclaration"}) @@ -1092,6 +1100,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { return FSRecords.getName(id); } + @TestOnly public void cleanPersistedContents() { try { final int[] roots = FSRecords.listRoots(); @@ -1104,6 +1113,7 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { } } + @TestOnly private static void cleanPersistedContentsRecursively(int id) { if (isDirectory(id)) { for (int child : FSRecords.list(id)) { @@ -1116,11 +1126,12 @@ public class PersistentFS extends ManagingFS implements ApplicationComponent { } public static NewVirtualFileSystem replaceWithNativeFS(NewVirtualFileSystem delegate) { - if (delegate.getProtocol().equals(LocalFileSystem.PROTOCOL) && Registry.is("filesystem.useNative")) { - if (SystemInfo.isWindows && Win32LocalFileSystem.isAvailable()) { - delegate = Win32LocalFileSystem.getWin32Instance(); - } - } + if (delegate.getProtocol().equals(LocalFileSystem.PROTOCOL) && + Registry.is("filesystem.useNative") && + SystemInfo.isWindows && + Win32LocalFileSystem.isAvailable()) { + delegate = Win32LocalFileSystem.getWin32Instance(); + } return delegate; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java index 39f9da022ab9..9360c401f53d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/RefreshWorker.java @@ -25,6 +25,7 @@ import com.intellij.openapi.vfs.newvfs.impl.FakeVirtualFile; import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl; import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry; import com.intellij.util.containers.Queue; +import org.jetbrains.annotations.NotNull; import java.util.*; @@ -47,12 +48,15 @@ public class RefreshWorker { public void scan() { final NewVirtualFile root = (NewVirtualFile)myRefreshRoot; NewVirtualFileSystem delegate = root.getFileSystem(); - if (root.isDirty() && !delegate.exists(root)) { + int attributes = delegate.getBooleanAttributes(root, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY); + + if (root.isDirty() && (attributes & NewVirtualFileSystem.BA_EXISTS) == 0) { scheduleDeletion(root); root.markClean(); } else { - if (root.isDirectory()) { + boolean isDir = (attributes & NewVirtualFileSystem.BA_DIRECTORY) != 0; + if (isDir) { delegate = PersistentFS.replaceWithNativeFS(delegate); } @@ -86,14 +90,16 @@ public class RefreshWorker { for (VirtualFile child : file.getChildren()) { if (!deletedNames.contains(child.getName())) { - scheduleChildRefresh(file, child, delegate); + int childAttributes = delegate.getBooleanAttributes(child, -1); + scheduleChildRefresh(file, child, delegate, childAttributes); } } } else { for (VirtualFile child : file.getCachedChildren()) { - if (delegate.exists(child)) { - scheduleChildRefresh(file, child, delegate); + int childAttributes = delegate.getBooleanAttributes(child, -1); + if ((childAttributes & NewVirtualFileSystem.BA_EXISTS) != 0) { + scheduleChildRefresh(file, child, delegate, childAttributes); } else { scheduleDeletion(child); @@ -102,11 +108,13 @@ public class RefreshWorker { final List names = dir.getSuspiciousNames(); for (String name : names) { - if (name.length() == 0) continue; + if (name.isEmpty()) continue; final VirtualFile fake = new FakeVirtualFile(file, name); - if (delegate.exists(fake)) { - scheduleCreation(file, name, delegate.isDirectory(fake)); + int attrs = delegate.getBooleanAttributes(fake, NewVirtualFileSystem.BA_EXISTS | NewVirtualFileSystem.BA_DIRECTORY); + if ((attrs & NewVirtualFileSystem.BA_EXISTS) != 0) { + boolean isDira = (attrs & NewVirtualFileSystem.BA_DIRECTORY) != 0; + scheduleCreation(file, name, isDira); } } } @@ -132,13 +140,16 @@ public class RefreshWorker { } } - private void scheduleChildRefresh(final VirtualFileSystemEntry file, final VirtualFile child, final NewVirtualFileSystem delegate) { + private void scheduleChildRefresh(@NotNull VirtualFileSystemEntry file, + @NotNull VirtualFile child, + @NotNull NewVirtualFileSystem delegate, + @NewVirtualFileSystem.FileBooleanAttributes int childAttributes) { final boolean currentIsDirectory = child.isDirectory(); final boolean currentIsSymlink = child.isSymLink(); final boolean currentIsSpecial = child.isSpecialFile(); - final boolean upToDateIsDirectory = delegate.isDirectory(child); + final boolean upToDateIsDirectory = (childAttributes & NewVirtualFileSystem.BA_DIRECTORY) != 0; final boolean upToDateIsSymlink = delegate.isSymLink(child); - final boolean upToDateIsSpecial = delegate.isSpecialFile(child); + final boolean upToDateIsSpecial = (childAttributes & (NewVirtualFileSystem.BA_REGULAR | NewVirtualFileSystem.BA_DIRECTORY | NewVirtualFileSystem.BA_EXISTS)) == NewVirtualFileSystem.BA_EXISTS; if (currentIsDirectory != upToDateIsDirectory || currentIsSymlink != upToDateIsSymlink || currentIsSpecial != upToDateIsSpecial) { scheduleDeletion(child); scheduleReCreation(file, child.getName(), upToDateIsDirectory); diff --git a/platform/testFramework/src/com/intellij/mock/MockLocalFileSystem.java b/platform/testFramework/src/com/intellij/mock/MockLocalFileSystem.java index 4fb4e5937362..59be016ec53c 100644 --- a/platform/testFramework/src/com/intellij/mock/MockLocalFileSystem.java +++ b/platform/testFramework/src/com/intellij/mock/MockLocalFileSystem.java @@ -251,4 +251,9 @@ public class MockLocalFileSystem extends LocalFileSystem { public int getRank() { return 1; } + + @Override + public int getBooleanAttributes(@NotNull VirtualFile file, int flags) { + return 0; + } } diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index 3ed50898fc01..c48b53e30bdc 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -41,7 +41,7 @@ import java.util.regex.Pattern; @SuppressWarnings({"UtilityClassWithoutPrivateConstructor"}) public class FileUtil { public static final int MEGABYTE = 1024 * 1024; - public static final String ASYNC_DELETE_EXTENSION = ".__del__"; + @NonNls public static final String ASYNC_DELETE_EXTENSION = ".__del__"; private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.FileUtil"); @@ -681,7 +681,7 @@ public class FileUtil { final int oldPermissions = FileSystemUtil.getPermissions(fromFile); final int newPermissions = FileSystemUtil.getPermissions(toFile); if (oldPermissions != -1 && newPermissions != -1) { - FileSystemUtil.setPermissions(toFile, (oldPermissions | newPermissions)); + FileSystemUtil.setPermissions(toFile, oldPermissions | newPermissions); } } } @@ -713,7 +713,7 @@ public class FileUtil { public static void copyDir(@NotNull File fromDir, @NotNull File toDir, boolean copySystemFiles) throws IOException { copyDir(fromDir, toDir, copySystemFiles ? null : new FileFilter() { public boolean accept(File file) { - return !file.getName().startsWith("."); + return !StringUtil.startsWithChar(file.getName(), '.'); } }); } @@ -939,7 +939,7 @@ public class FileUtil { final StringBuilder builder = new StringBuilder(antPattern.length()); int asteriskCount = 0; boolean recursive = true; - final int start = ignoreStartingSlash && (antPattern.startsWith("/") || antPattern.startsWith("\\")) ? 1 : 0; + final int start = ignoreStartingSlash && (StringUtil.startsWithChar(antPattern, '/') || StringUtil.startsWithChar(antPattern, '\\')) ? 1 : 0; for (int idx = start; idx < antPattern.length(); idx++) { final char ch = antPattern.charAt(idx);