@Nullable private VirtualFileSystemEntry findChild(@NotNull String name, boolean doRefresh, boolean ensureCanonicalName, @NotNull NewVirtualFileSystem delegate) { boolean ignoreCase = !delegate.isCaseSensitive(); VirtualFileSystemEntry result = doFindChild(name, ensureCanonicalName, delegate, ignoreCase); //noinspection UseVirtualFileEquals if (result == NULL_VIRTUAL_FILE) { result = doRefresh ? createAndFindChildWithEventFire(name, delegate) : null; } else if (result != null && doRefresh && delegate.isDirectory(result) != result.isDirectory()) { RefreshQueue.getInstance().refresh(false, false, null, result); result = findChild(name, false, ensureCanonicalName, delegate); } return result; }
@Override @NotNull public Iterable<VirtualFile> iterInDbChildren() { if (!ourPersistence.wereChildrenAccessed(this)) { return Collections.emptyList(); } if (!ourPersistence.areChildrenLoaded(this)) { final String[] names = ourPersistence.listPersisted(this); final NewVirtualFileSystem delegate = PersistentFS.replaceWithNativeFS(getFileSystem()); for (String name : names) { findChild(name, false, false, delegate); } } return getCachedChildren(); }
public void scan() { NewVirtualFile root = myRefreshQueue.pullFirst().first; boolean rootDirty = root.isDirty(); debug(LOG, "root=%s dirty=%b", root, rootDirty); if (!rootDirty) return; NewVirtualFileSystem fs = root.getFileSystem(); FileAttributes rootAttributes = fs.getAttributes(root); if (rootAttributes == null) { scheduleDeletion(root); root.markClean(); return; } else if (rootAttributes.isDirectory()) { fs = PersistentFS.replaceWithNativeFS(fs); } myRefreshQueue.addLast(pair(root, rootAttributes)); try { processQueue(fs, PersistentFS.getInstance()); } catch (RefreshCancelledException e) { LOG.debug("refresh cancelled"); } }
@Nullable private VirtualFileSystemEntry findChild(@NotNull String name, final boolean doRefresh, boolean ensureCanonicalName, @NotNull NewVirtualFileSystem delegate) { boolean ignoreCase = !delegate.isCaseSensitive(); Comparator comparator = getComparator(name, ignoreCase); VirtualFileSystemEntry result = doFindChild(name, ensureCanonicalName, delegate, comparator); if (result == NULL_VIRTUAL_FILE) { result = doRefresh ? createAndFindChildWithEventFire(name, delegate) : null; } else if (result != null) { if (doRefresh && delegate.isDirectory(result) != result.isDirectory()) { RefreshQueue.getInstance().refresh(false, false, null, result); result = findChild(name, false, ensureCanonicalName, delegate); } } if (result == null) { addToAdoptedChildren(name, !delegate.isCaseSensitive(), comparator); } return result; }
@NotNull public VirtualFileSystemEntry createChild(@NotNull String name, int id, @NotNull NewVirtualFileSystem delegate) { VirtualFileSystemEntry child; final int attributes = ourPersistence.getFileAttributes(id); if (PersistentFS.isDirectory(attributes)) { child = new VirtualDirectoryImpl(name, this, delegate, id, attributes); } else { child = new VirtualFileImpl(name, this, id, attributes); //noinspection TestOnlyProblems assertAccessInTests(child, delegate); } if (delegate.markNewFilesAsDirty()) { child.markDirty(); } return child; }
private boolean checkAndScheduleSymLinkTargetChange(@NotNull VirtualFile parent, @NotNull VirtualFile child, @NotNull FileAttributes childAttributes, @NotNull NewVirtualFileSystem fs) { if (childAttributes.isSymLink()) { String currentTarget = child.getCanonicalPath(); String upToDateTarget = fs.resolveSymLink(child); String upToDateVfsTarget = upToDateTarget != null ? FileUtil.toSystemIndependentName(upToDateTarget) : null; if (!Comparing.equal(currentTarget, upToDateVfsTarget)) { scheduleDeletion(child); scheduleReCreation(parent, child.getName(), childAttributes.isDirectory()); return true; } } return false; }
public void testFindRootWithDenormalizedPath() { File tempDir = new WriteAction<File>() { @Override protected void run(Result<File> result) throws Throwable { File res = createTempDirectory(); new File(res, "x.jar").createNewFile(); result.setResult(res); } }.execute().getResultObject(); VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempDir); VirtualFile jar = vDir.findChild("x.jar"); assertNotNull(jar); NewVirtualFile root1 = ManagingFS.getInstance().findRoot(jar.getPath()+"!/", (NewVirtualFileSystem)StandardFileSystems.jar()); NewVirtualFile root2 = ManagingFS.getInstance().findRoot(jar.getParent().getPath() + "//"+ jar.getName()+"!/", (NewVirtualFileSystem)StandardFileSystems.jar()); assertNotNull(root1); assertSame(root1, root2); }
public void testFindRootShouldNotBeFooledByRelativePath() throws IOException { File tmp = createTempDirectory(); File x = new File(tmp, "x.jar"); x.createNewFile(); LocalFileSystem lfs = LocalFileSystem.getInstance(); VirtualFile vx = lfs.refreshAndFindFileByIoFile(x); assertNotNull(vx); ArchiveFileSystem jfs = (ArchiveFileSystem)StandardFileSystems.jar(); VirtualFile root = ArchiveVfsUtil.getArchiveRootForLocalFile(vx); PersistentFS fs = PersistentFS.getInstance(); String path = vx.getPath() + "/../" + vx.getName() + ArchiveFileSystem.ARCHIVE_SEPARATOR; NewVirtualFile root1 = fs.findRoot(path, (NewVirtualFileSystem)jfs); assertSame(root1, root); }
@Nullable private VirtualFileSystemEntry findChild(@Nonnull String name, boolean doRefresh, boolean ensureCanonicalName, @Nonnull NewVirtualFileSystem delegate) { boolean ignoreCase = !delegate.isCaseSensitive(); VirtualFileSystemEntry result = doFindChild(name, ensureCanonicalName, delegate, ignoreCase); //noinspection UseVirtualFileEquals if (result == NULL_VIRTUAL_FILE) { result = doRefresh ? createAndFindChildWithEventFire(name, delegate) : null; } else if (result != null && doRefresh && delegate.isDirectory(result) != result.isDirectory()) { RefreshQueue.getInstance().refresh(false, false, null, result); result = findChild(name, false, ensureCanonicalName, delegate); } return result; }
@Override @Nonnull public Iterable<VirtualFile> iterInDbChildren() { if (!ourPersistence.wereChildrenAccessed(this)) { return Collections.emptyList(); } if (!ourPersistence.areChildrenLoaded(this)) { final String[] names = ourPersistence.listPersisted(this); final NewVirtualFileSystem delegate = PersistentFS.replaceWithNativeFS(getFileSystem()); for (String name : names) { findChild(name, false, false, delegate); } } return getCachedChildren(); }
public void scan() { NewVirtualFile root = myRefreshQueue.pullFirst().first; boolean rootDirty = root.isDirty(); if (LOG.isDebugEnabled()) LOG.debug("root=" + root + " dirty=" + rootDirty); if (!rootDirty) return; NewVirtualFileSystem fs = root.getFileSystem(); FileAttributes rootAttributes = fs.getAttributes(root); if (rootAttributes == null) { scheduleDeletion(root); root.markClean(); return; } else if (rootAttributes.isDirectory()) { fs = PersistentFS.replaceWithNativeFS(fs); } myRefreshQueue.addLast(pair(root, rootAttributes)); try { processQueue(fs, PersistentFS.getInstance()); } catch (RefreshCancelledException e) { LOG.debug("refresh cancelled"); } }
@NotNull private VirtualFileSystemEntry createChild(int nameId, int id, @NotNull NewVirtualFileSystem delegate) { final int attributes = ourPersistence.getFileAttributes(id); VfsData.Segment segment = VfsData.getSegment(id, true); try { VfsData.initFile(id, segment, nameId, PersistentFS.isDirectory(attributes) ? new VfsData.DirectoryData() : KeyFMap.EMPTY_MAP); } catch (VfsData.FileAlreadyCreatedException e) { throw new RuntimeException("dir=" + myId + "; dir.children=" + Arrays.toString(FSRecords.listAll(myId)), e); } LOG.assertTrue(!(getFileSystem() instanceof Win32LocalFileSystem)); VirtualFileSystemEntry child = VfsData.getFileById(id, this); assert child != null; segment.setFlag(id, IS_SYMLINK_FLAG, PersistentFS.isSymLink(attributes)); segment.setFlag(id, IS_SPECIAL_FLAG, PersistentFS.isSpecialFile(attributes)); segment.setFlag(id, IS_WRITABLE_FLAG, PersistentFS.isWritable(attributes)); segment.setFlag(id, IS_HIDDEN_FLAG, PersistentFS.isHidden(attributes)); child.updateLinkStatus(); if (delegate.markNewFilesAsDirty()) { child.markDirty(); } return child; }
@Nullable private VirtualFileSystemEntry createAndFindChildWithEventFire(@NotNull String name, @NotNull NewVirtualFileSystem delegate) { final VirtualFile fake = new FakeVirtualFile(this, name); final FileAttributes attributes = delegate.getAttributes(fake); if (attributes == null) return null; final String realName = delegate.getCanonicallyCasedName(fake); final VFileCreateEvent event = new VFileCreateEvent(null, this, realName, attributes.isDirectory(), true); RefreshQueue.getInstance().processSingleEvent(event); return findChild(realName); }
@Override @NotNull public NewVirtualFileSystem getFileSystem() { final VirtualFileSystemEntry parent = getParent(); assert parent != null; return parent.getFileSystem(); }
@NotNull public static NewVirtualFileSystem replaceWithNativeFS(@NotNull final NewVirtualFileSystem fs) { if (SystemInfo.isWindows && !(fs instanceof Win32LocalFileSystem) && fs.getProtocol().equals(LocalFileSystem.PROTOCOL) && Win32LocalFileSystem.isAvailable()) { return Win32LocalFileSystem.getWin32Instance(); } return fs; }
public VirtualDirectoryImpl(@NonNls @NotNull final String name, @Nullable final VirtualDirectoryImpl parent, @NotNull final NewVirtualFileSystem fs, final int id, @PersistentFS.Attributes final int attributes) { super(name, parent, id, attributes); myFS = fs; }
@TestOnly private static void assertAccessInTests(@NotNull VirtualFileSystemEntry child, @NotNull NewVirtualFileSystem delegate) { final Application application = ApplicationManager.getApplication(); if (IS_UNDER_TEAMCITY && SHOULD_PERFORM_ACCESS_CHECK && application.isUnitTestMode() && application instanceof ApplicationImpl && ((ApplicationImpl)application).isComponentsCreated()) { if (delegate != LocalFileSystem.getInstance() && delegate != JarFileSystem.getInstance()) { return; } // root' children are loaded always if (child.getParent() == null || child.getParent().getParent() == null) return; Set<String> allowed = allowedRoots(); boolean isUnder = allowed == null; if (!isUnder) { String childPath = child.getPath(); if (delegate == JarFileSystem.getInstance()) { VirtualFile local = JarFileSystem.getInstance().getVirtualFileForJar(child); assert local != null : child; childPath = local.getPath(); } for (String root : allowed) { if (FileUtil.startsWith(childPath, root)) { isUnder = true; break; } if (root.startsWith(JarFileSystem.PROTOCOL_PREFIX)) { String rootLocalPath = FileUtil.toSystemIndependentName(PathUtil.toPresentableUrl(root)); isUnder = FileUtil.startsWith(childPath, rootLocalPath); if (isUnder) break; } } } assert isUnder || allowed.isEmpty() : "File accessed outside allowed roots: " + child + ";\nAllowed roots: " + new ArrayList<String>(allowed); } }
public void testWindowsHiddenDirectory() throws Exception { if (!SystemInfo.isWindows) { System.err.println(getName() + " skipped: " + SystemInfo.OS_NAME); return; } File file = new File("C:\\Documents and Settings\\desktop.ini"); if (!file.exists()) { System.err.println(getName() + " skipped: missing " + file); return; } String parent = FileUtil.toSystemIndependentName(file.getParent()); VirtualDirectoryImpl.allowRootAccess(parent); try { VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file); assertNotNull(virtualFile); NewVirtualFileSystem fs = (NewVirtualFileSystem)virtualFile.getFileSystem(); FileAttributes attributes = fs.getAttributes(virtualFile); assertNotNull(attributes); assertEquals(FileAttributes.Type.FILE, attributes.type); assertEquals(FileAttributes.HIDDEN, attributes.flags); } finally { VirtualDirectoryImpl.disallowRootAccess(parent); } }
@Nullable @Override public NewVirtualFile findRoot(@Nonnull String basePath, @Nonnull NewVirtualFileSystem fs) { String p = PathUtil.toPresentableUrl(basePath); VirtualFile fileByPath = LocalFileSystem.getInstance().findFileByPath(p); if (fileByPath != null) { if (fs instanceof ArchiveFileSystem) { return new ArchiveNewVirtualFile(fileByPath, (ArchiveFileSystemBase) fs); } return new CompilerServerNewVirtualFileImpl(fileByPath, fs); } return null; }
public void testFindRootPerformance() { File tempDir = new WriteAction<File>() { @Override protected void run(Result<File> result) throws Throwable { File res = createTempDirectory(); new File(res, "x.jar").createNewFile(); result.setResult(res); } }.execute().getResultObject(); final VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(tempDir); final VirtualFile jar = vDir.findChild("x.jar"); assertNotNull(jar); final NewVirtualFile root = ManagingFS.getInstance().findRoot(jar.getPath()+"!/", (NewVirtualFileSystem)StandardFileSystems.jar()); PlatformTestUtil.startPerformanceTest("find root is slow", 500, new ThrowableRunnable() { @Override public void run() throws Throwable { final String path = jar.getPath() + "!/"; final NewVirtualFileSystem fileSystem = (NewVirtualFileSystem)StandardFileSystems.jar(); JobLauncher.getInstance().invokeConcurrentlyUnderProgress(Collections.nCopies(500, null), null, false, new Processor<Object>() { @Override public boolean process(Object o) { for (int i = 0; i < 1000; i++) { NewVirtualFile rootJar = ManagingFS.getInstance().findRoot(path, fileSystem); assertNotNull(rootJar); assertSame(root, rootJar); } return true; } }); } }).assertTiming(); }
@Nonnull private VirtualFileSystemEntry createChild(int nameId, int id, @Nonnull NewVirtualFileSystem delegate) { final int attributes = ourPersistence.getFileAttributes(id); VfsData.Segment segment = VfsData.getSegment(id, true); try { VfsData.initFile(id, segment, nameId, PersistentFS.isDirectory(attributes) ? new VfsData.DirectoryData() : KeyFMap.EMPTY_MAP); } catch (VfsData.FileAlreadyCreatedException e) { throw new RuntimeException("dir=" + myId + "; dir.children=" + Arrays.toString(FSRecords.listAll(myId)), e); } LOG.assertTrue(!(getFileSystem() instanceof Win32LocalFileSystem)); VirtualFileSystemEntry child = VfsData.getFileById(id, this); assert child != null; segment.setFlag(id, IS_SYMLINK_FLAG, PersistentFS.isSymLink(attributes)); segment.setFlag(id, IS_SPECIAL_FLAG, PersistentFS.isSpecialFile(attributes)); segment.setFlag(id, IS_WRITABLE_FLAG, PersistentFS.isWritable(attributes)); segment.setFlag(id, IS_HIDDEN_FLAG, PersistentFS.isHidden(attributes)); child.updateLinkStatus(); if (delegate.markNewFilesAsDirty()) { child.markDirty(); } return child; }
@Nullable private VirtualFileSystemEntry createAndFindChildWithEventFire(@Nonnull String name, @Nonnull NewVirtualFileSystem delegate) { final VirtualFile fake = new FakeVirtualFile(this, name); final FileAttributes attributes = delegate.getAttributes(fake); if (attributes == null) return null; final String realName = delegate.getCanonicallyCasedName(fake); final VFileCreateEvent event = new VFileCreateEvent(null, this, realName, attributes.isDirectory(), true); RefreshQueue.getInstance().processSingleEvent(event); return findChild(realName); }
@Override @Nonnull public NewVirtualFileSystem getFileSystem() { final VirtualFileSystemEntry parent = getParent(); assert parent != null; return parent.getFileSystem(); }
@Nonnull public static NewVirtualFileSystem replaceWithNativeFS(@Nonnull final NewVirtualFileSystem fs) { if (SystemInfo.isWindows && !(fs instanceof Win32LocalFileSystem) && fs.getProtocol().equals(LocalFileSystem.PROTOCOL) && Win32LocalFileSystem.isAvailable()) { return Win32LocalFileSystem.getWin32Instance(); } return fs; }
private static boolean needsRefresh(final VirtualFile file) { final VirtualFileSystem fs = file.getFileSystem(); return fs instanceof NewVirtualFileSystem && file.getTimeStamp() != ((NewVirtualFileSystem)fs).getTimeStamp(file); }
public VirtualDirectoryImpl(int id, VfsData.Segment segment, VfsData.DirectoryData data, VirtualDirectoryImpl parent, NewVirtualFileSystem fs) { super(id, segment, parent); myData = data; myFs = fs; }
@Override @NotNull public NewVirtualFileSystem getFileSystem() { return myFs; }
@Nullable // null if there can't be a child with this name, NULL_VIRTUAL_FILE if cached as absent, the file if found private VirtualFileSystemEntry doFindChild(@NotNull String name, boolean ensureCanonicalName, @NotNull NewVirtualFileSystem delegate, boolean ignoreCase) { if (name.isEmpty()) { return null; } VirtualFileSystemEntry found = doFindChildInArray(name, ignoreCase); if (found != null) return found; if (allChildrenLoaded()) { return NULL_VIRTUAL_FILE; } if (ensureCanonicalName) { name = UriUtil.trimTrailingSlashes(UriUtil.trimLeadingSlashes(FileUtilRt.toSystemIndependentName(name))); if (name.indexOf('/') != -1) return null; // name must not contain slashes in the middle VirtualFile fake = new FakeVirtualFile(this, name); name = delegate.getCanonicallyCasedName(fake); if (name.isEmpty()) return null; } VirtualFileSystemEntry child; synchronized (myData) { // maybe another doFindChild() sneaked in the middle if (myData.isAdoptedName(name)) return NULL_VIRTUAL_FILE; int[] array = myData.myChildrenIds; int indexInReal = findIndex(array, name, ignoreCase); // double check if (indexInReal >= 0) { return VfsData.getFileById(array[indexInReal], this); } if (allChildrenLoaded()) { return null; } // do not extract getId outside the synchronized block since it will cause a concurrency problem. int id = ourPersistence.getId(this, name, delegate); if (id <= 0) { myData.addAdoptedName(name, !ignoreCase); return null; } child = createChild(FileNameCache.storeName(name), id, delegate); int[] after = myData.myChildrenIds; if (after != array) { // in tests when we call assertAccessInTests it can load a huge number of files which lead to children modification // so fall back to slow path addChild(child); } else { insertChildAt(child, indexInReal); assertConsistency(!delegate.isCaseSensitive(), name); } } if (!child.isDirectory()) { // access check should only be called when child is actually added to the parent, otherwise it may break VirtualFilePointers validity //noinspection TestOnlyProblems VfsRootAccess.assertAccessInTests(child, getFileSystem()); } return child; }
@NotNull public VirtualFileSystemEntry createChild(String name, int id, @NotNull NewVirtualFileSystem delegate) { synchronized (myData) { return createChild(FileNameCache.storeName(name), id, delegate); } }
@TestOnly static void assertAccessInTests(@NotNull VirtualFileSystemEntry child, @NotNull NewVirtualFileSystem delegate) { final Application application = ApplicationManager.getApplication(); if (SHOULD_PERFORM_ACCESS_CHECK && application.isUnitTestMode() && application instanceof ApplicationImpl && ((ApplicationImpl)application).isComponentsCreated()) { if (delegate != LocalFileSystem.getInstance() && delegate != JarFileSystem.getInstance()) { return; } // root' children are loaded always if (child.getParent() == null || child.getParent().getParent() == null) { return; } Set<String> allowed = ApplicationManager.getApplication().runReadAction(new Computable<Set<String>>() { @Override public Set<String> compute() { return allowedRoots(); } }); boolean isUnder = allowed == null || allowed.isEmpty(); if (!isUnder) { String childPath = child.getPath(); if (delegate == JarFileSystem.getInstance()) { VirtualFile local = JarFileSystem.getInstance().getVirtualFileForJar(child); assert local != null : child; childPath = local.getPath(); } for (String root : allowed) { if (FileUtil.startsWith(childPath, root)) { isUnder = true; break; } if (root.startsWith(JarFileSystem.PROTOCOL_PREFIX)) { String rootLocalPath = FileUtil.toSystemIndependentName(PathUtil.toPresentableUrl(root)); isUnder = FileUtil.startsWith(childPath, rootLocalPath); if (isUnder) break; } } } assert isUnder : "File accessed outside allowed roots: " + child + ";\nAllowed roots: " + new ArrayList<String>(allowed); } }
private void processQueue(NewVirtualFileSystem fs, PersistentFS persistence) throws RefreshCancelledException { TObjectHashingStrategy<String> strategy = FilePathHashingStrategy.create(fs.isCaseSensitive()); while (!myRefreshQueue.isEmpty()) { Pair<NewVirtualFile, FileAttributes> pair = myRefreshQueue.pullFirst(); NewVirtualFile file = pair.first; boolean fileDirty = file.isDirty(); debug(LOG, "file=%s dirty=%b", file, fileDirty); if (!fileDirty) continue; checkCancelled(file); FileAttributes attributes = pair.second != null ? pair.second : fs.getAttributes(file); if (attributes == null) { scheduleDeletion(file); continue; } NewVirtualFile parent = file.getParent(); if (parent != null && checkAndScheduleFileTypeChange(parent, file, attributes)) { // ignore everything else file.markClean(); continue ; } if (file.isDirectory()) { boolean fullSync = ((VirtualDirectoryImpl)file).allChildrenLoaded(); if (fullSync) { fullDirRefresh(fs, persistence, strategy, (VirtualDirectoryImpl)file); } else { partialDirRefresh(fs, strategy, (VirtualDirectoryImpl)file); } } else { long currentTimestamp = persistence.getTimeStamp(file); long upToDateTimestamp = attributes.lastModified; long currentLength = persistence.getLastRecordedLength(file); long upToDateLength = attributes.length; if (currentTimestamp != upToDateTimestamp || currentLength != upToDateLength) { scheduleUpdateContent(file); } } boolean currentWritable = persistence.isWritable(file); boolean upToDateWritable = attributes.isWritable(); if (LOG_ATTRIBUTES.isDebugEnabled()) { LOG_ATTRIBUTES.debug("file=" + file + " writable vfs=" + file.isWritable() + " persistence=" + currentWritable + " real=" + upToDateWritable); } if (currentWritable != upToDateWritable) { scheduleAttributeChange(file, VirtualFile.PROP_WRITABLE, currentWritable, upToDateWritable); } if (SystemInfo.isWindows) { boolean currentHidden = file.is(VFileProperty.HIDDEN); boolean upToDateHidden = attributes.isHidden(); if (currentHidden != upToDateHidden) { scheduleAttributeChange(file, VirtualFile.PROP_HIDDEN, currentHidden, upToDateHidden); } } if (attributes.isSymLink()) { String currentTarget = file.getCanonicalPath(); String upToDateTarget = fs.resolveSymLink(file); String upToDateVfsTarget = upToDateTarget != null ? FileUtil.toSystemIndependentName(upToDateTarget) : null; if (!Comparing.equal(currentTarget, upToDateVfsTarget)) { scheduleAttributeChange(file, VirtualFile.PROP_SYMLINK_TARGET, currentTarget, upToDateVfsTarget); } } if (myIsRecursive || !file.isDirectory()) { file.markClean(); } } }
@Override @NotNull public NewVirtualFileSystem getFileSystem() { return myFS; }
@Nullable // null if there can't be a child with this name, NULL_VIRTUAL_FILE if cached as absent, the file if found private VirtualFileSystemEntry doFindChild(@NotNull String name, boolean ensureCanonicalName, @NotNull NewVirtualFileSystem delegate, @NotNull Comparator comparator) { if (name.isEmpty()) { return null; } VirtualFileSystemEntry found = doFindChildInArray(comparator); if (found != null) return found; if (allChildrenLoaded()) { return NULL_VIRTUAL_FILE; } if (ensureCanonicalName) { VirtualFile fake = new FakeVirtualFile(this, name); name = delegate.getCanonicallyCasedName(fake); if (name.isEmpty()) return null; } synchronized (this) { // do not extract getId outside the synchronized block since it will cause a concurrency problem. int id = ourPersistence.getId(this, name, delegate); if (id <= 0) { return null; } // maybe another doFindChild() sneaked in the middle VirtualFileSystemEntry[] array = myChildren; long r = findIndexInBoth(array, comparator); int indexInReal = (int)(r >> 32); int indexInAdopted = (int)r; if (indexInAdopted >= 0) return NULL_VIRTUAL_FILE; // double check if (indexInReal >= 0) { return array[indexInReal]; } String shorty = new String(name); VirtualFileSystemEntry child = createChild(shorty, id, delegate); // So we don't hold whole char[] buffer of a lengthy path VirtualFileSystemEntry[] after = myChildren; if (after != array) { // in tests when we call assertAccessInTests it can load a huge number of files which lead to children modification // so fall back to slow path addChild(child); } else { insertChildAt(child, indexInReal); assertConsistency(myChildren, !delegate.isCaseSensitive(), name); } return child; } }
@Override @NotNull public synchronized VirtualFile[] getChildren() { VirtualFileSystemEntry[] children = myChildren; NewVirtualFileSystem delegate = getFileSystem(); final boolean ignoreCase = !delegate.isCaseSensitive(); if (allChildrenLoaded()) { assertConsistency(children, ignoreCase); return children; } FSRecords.NameId[] childrenIds = ourPersistence.listAll(this); VirtualFileSystemEntry[] result; if (childrenIds.length == 0) { result = EMPTY_ARRAY; } else { Arrays.sort(childrenIds, new java.util.Comparator<FSRecords.NameId>() { @Override public int compare(FSRecords.NameId o1, FSRecords.NameId o2) { String name1 = o1.name; String name2 = o2.name; return compareNames(name1, name2, ignoreCase); } }); result = new VirtualFileSystemEntry[childrenIds.length]; int delegateI = 0; int i = 0; int cachedEnd = getAdoptedChildrenStart(); // merge (sorted) children[0..cachedEnd) and childrenIds into the result array. // file that is already in children array must be copied into the result as is // for the file name that is new in childrenIds the file must be created and copied into result while (delegateI < childrenIds.length) { FSRecords.NameId nameId = childrenIds[delegateI]; while (i < cachedEnd && children[i].compareNameTo(nameId.name, ignoreCase) < 0) i++; // skip files that are not in childrenIds VirtualFileSystemEntry resultFile; if (i < cachedEnd && children[i].compareNameTo(nameId.name, ignoreCase) == 0) { resultFile = children[i++]; } else { resultFile = createChild(nameId.name, nameId.id, delegate); } result[delegateI++] = resultFile; } assertConsistency(result, ignoreCase, children, cachedEnd, childrenIds); } if (getId() > 0) { myChildren = result; setChildrenLoaded(); } return result; }
@Nonnull @Override public NewVirtualFileSystem getFileSystem() { return (NewVirtualFileSystem)myFileSystem; }