IDEA-82554 (find file by symlink traversal path)

This commit is contained in:
Roman Shevchenko
2012-03-15 17:58:46 +01:00
parent d7401912a9
commit 644286b86f
3 changed files with 59 additions and 16 deletions
@@ -341,7 +341,13 @@ public abstract class VirtualFile extends UserDataHolderBase implements Modifica
child = this;
}
else if (name.equals("..")) {
child = getParent();
if (isSymLink()) {
final VirtualFile canonicalFile = getCanonicalFile();
child = canonicalFile != null ? canonicalFile.getParent() : null;
}
else {
child = getParent();
}
}
else {
child = findChild(name);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 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.
@@ -17,7 +17,6 @@ package com.intellij.openapi.vfs.newvfs;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -25,29 +24,31 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
public class VfsImplUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vfs.newvfs.VfsImplUtil");
@NonNls private static final String FILE_SEPARATORS = "/" + File.separator;
private VfsImplUtil() {
}
private VfsImplUtil() { }
@Nullable
public static VirtualFile findFileByPath(NewVirtualFileSystem vfs, @NotNull @NonNls final String path) {
public static NewVirtualFile findFileByPath(@NotNull final NewVirtualFileSystem vfs, @NotNull @NonNls final String path) {
final String normalizedPath = vfs.normalize(path);
if (normalizedPath == null) return null;
final String basePath = vfs.extractRootPath(normalizedPath);
NewVirtualFile file = ManagingFS.getInstance().findRoot(basePath, vfs);
if (file == null || !file.exists()) return null;
if (normalizedPath.length() < basePath.length()) return null;
if (normalizedPath.length() < basePath.length()) {
return null;
}
for (String pathElement : StringUtil.tokenize(normalizedPath.substring(basePath.length()), FILE_SEPARATORS)) {
if (pathElement.isEmpty() || ".".equals(pathElement)) continue;
if ("..".equals(pathElement)) {
file = file.getParent();
if (file.isSymLink()) {
final NewVirtualFile canonicalFile = file.getCanonicalFile();
file = canonicalFile != null ? canonicalFile.getParent() : null;
}
else {
file = file.getParent();
}
}
else {
file = file.findChild(pathElement);
@@ -60,7 +61,7 @@ public class VfsImplUtil {
}
@Nullable
public static VirtualFile findFileByPathIfCached(NewVirtualFileSystem vfs, @NotNull @NonNls String path) {
public static NewVirtualFile findFileByPathIfCached(@NotNull final NewVirtualFileSystem vfs, @NotNull @NonNls final String path) {
final String normalizedPath = vfs.normalize(path);
if (normalizedPath == null) return null;
final String basePath = vfs.extractRootPath(normalizedPath);
@@ -70,7 +71,14 @@ public class VfsImplUtil {
for (String pathElement : StringUtil.tokenize(normalizedPath.substring(basePath.length()), FILE_SEPARATORS)) {
if (pathElement.isEmpty() || ".".equals(pathElement)) continue;
if ("..".equals(pathElement)) {
file = file.getParent();
if (file.isSymLink()) {
final String canonicalPath = file.getCanonicalPath();
final NewVirtualFile canonicalFile = canonicalPath != null ? findFileByPathIfCached(vfs, canonicalPath) : null;
file = canonicalFile != null ? canonicalFile.getParent() : null;
}
else {
file = file.getParent();
}
}
else {
file = file.findChildIfCached(pathElement);
@@ -83,18 +91,27 @@ public class VfsImplUtil {
}
@Nullable
public static VirtualFile refreshAndFindFileByPath(NewVirtualFileSystem vfs, @NotNull final String path) {
public static NewVirtualFile refreshAndFindFileByPath(@NotNull final NewVirtualFileSystem vfs, @NotNull @NonNls final String path) {
final String normalizedPath = vfs.normalize(path);
if (normalizedPath == null) return null;
final String basePath = vfs.extractRootPath(normalizedPath);
NewVirtualFile file = ManagingFS.getInstance().findRoot(basePath, vfs);
if (file == null || !file.exists()) return null;
LOG.assertTrue(basePath.length() <= normalizedPath.length(), vfs + " failed to extract root path: " + basePath + " from " + normalizedPath);
LOG.assertTrue(basePath.length() <= normalizedPath.length(),
vfs + " failed to extract root path '" + basePath + "' from '" + normalizedPath + "'");
for (String pathElement : StringUtil.tokenize(normalizedPath.substring(basePath.length()), FILE_SEPARATORS)) {
if (pathElement.isEmpty() || ".".equals(pathElement)) continue;
if ("..".equals(pathElement)) {
file = file.getParent();
if (file.isSymLink()) {
final String canonicalPath = file.getCanonicalPath();
final NewVirtualFile canonicalFile = canonicalPath != null ? refreshAndFindFileByPath(vfs, canonicalPath) : null;
file = canonicalFile != null ? canonicalFile.getParent() : null;
}
else {
file = file.getParent();
}
}
else {
file = file.refreshAndFindChild(pathElement);
@@ -245,6 +245,26 @@ public class SymlinkHandlingTest extends LightPlatformLangTestCase {
assertEquals(linkContent, fileContent);
}
public void testFindByLinkParentPath() throws Exception {
final File topDir = FileUtil.createTempDirectory("topDir.", null);
final File subDir1 = FileUtil.createTempDirectory(topDir, "subDir1.", null);
final File link = createTempLink(subDir1.getAbsolutePath(), "link");
final VirtualFile vLink = refreshAndFind(link);
assertNotNull(link.getPath(), vLink);
final File subDir2 = FileUtil.createTempDirectory(topDir, "subDir2.", null);
final File subChild = FileUtil.createTempFile(subDir2, "subChild.", ".txt", true);
final VirtualFile vSubChild = refreshAndFind(subChild);
assertNotNull(subChild.getPath(), vSubChild);
final String relPath = "../" + subDir2.getName() + "/" + subChild.getName();
VirtualFile vSubChildRel;
vSubChildRel = vLink.findFileByRelativePath(relPath);
assertEquals(vSubChild, vSubChildRel);
vSubChildRel = LocalFileSystem.getInstance().findFileByPath(vLink.getPath() + "/" + relPath);
assertEquals(vSubChild, vSubChildRel);
}
// todo[r.sh] use NIO2 API after migration to JDK 7
private static File createTempLink(final String target, final String link) throws InterruptedException, ExecutionException {
final boolean isAbsolute = SystemInfo.isUnix && StringUtil.startsWithChar(link, '/') ||