[platform] fixes symlink resolve in Windows file access helper (platform part, binaries, tests)

This commit is contained in:
Roman Shevchenko
2018-07-06 09:40:21 +02:00
parent f802d0c8c6
commit 16f59f289b
4 changed files with 58 additions and 13 deletions
Binary file not shown.
Binary file not shown.
@@ -15,6 +15,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
@@ -164,7 +165,7 @@ public class FileSystemUtil {
else {
realPath = ourMediator.resolveSymLink(path);
}
if (realPath != null && new File(realPath).exists()) {
if (realPath != null && (SystemInfo.isWindows && realPath.startsWith("\\\\") || new File(realPath).exists())) {
return realPath;
}
}
@@ -364,18 +365,39 @@ public class FileSystemUtil {
private final IdeaWin32 myInstance = IdeaWin32.getInstance();
@Override
protected FileAttributes getAttributes(@NotNull final String path) {
final FileInfo fileInfo = myInstance.getInfo(path);
protected FileAttributes getAttributes(@NotNull String path) {
FileInfo fileInfo = myInstance.getInfo(path);
return fileInfo != null ? fileInfo.toFileAttributes() : null;
}
@Override
protected String resolveSymLink(@NotNull final String path) {
return myInstance.resolveSymLink(path);
protected String resolveSymLink(@NotNull String path) throws FileNotFoundException {
path = new File(path).getAbsolutePath();
char drive = Character.toUpperCase(path.charAt(0));
if (!(path.length() > 3 && drive >= 'A' && drive <= 'Z' && path.charAt(1) == ':' && path.charAt(2) == '\\')) {
return path; // unknown format
}
int remainder = 4;
while (remainder < path.length()) {
int next = path.indexOf('\\', remainder);
String subPath = next > 0 ? path.substring(0, next) : path;
FileAttributes attributes = getAttributes(subPath);
if (attributes == null) {
throw new FileNotFoundException(subPath);
}
if (attributes.isSymLink()) {
return myInstance.resolveSymLink(path);
}
remainder = next > 0 ? next + 1 : path.length();
}
return path;
}
}
// thanks to SVNKit for the idea of platform-specific offsets
private static class JnaUnixMediatorImpl extends Mediator {
@SuppressWarnings({"OctalInteger", "SpellCheckingInspection"})
@@ -433,7 +455,7 @@ public class FileSystemUtil {
private final boolean myCoarseTs = SystemProperties.getBooleanProperty(COARSE_TIMESTAMP_KEY, false);
private JnaUnixMediatorImpl() {
if ("linux-x86".equals(Platform.RESOURCE_PREFIX)) myOffsets = LINUX_32;
if ("linux-x86".equals(Platform.RESOURCE_PREFIX)) myOffsets = LINUX_32;
else if ("linux-x86-64".equals(Platform.RESOURCE_PREFIX)) myOffsets = LINUX_64;
else if ("linux-arm".equals(Platform.RESOURCE_PREFIX)) myOffsets = LNX_ARM32;
else if ("linux-ppc".equals(Platform.RESOURCE_PREFIX)) myOffsets = LNX_PPC32;
@@ -60,7 +60,9 @@ public abstract class FileAttributesReadingTest {
@Override public void linkToDirectory() { }
@Override public void missingLink() { }
@Override public void selfLink() { }
@Override public void innerSymlinkResolve() { }
@Override public void junction() { }
@Override public void innerJunctionResolve() { }
@Override public void permissionsCloning() { }
}
@@ -292,13 +294,22 @@ public abstract class FileAttributesReadingTest {
assertEquals(dir.getPath(), target);
}
@Test
public void innerSymlinkResolve() throws IOException {
File file = tempDir.newFile("dir/file.txt");
File link = new File(tempDir.getRoot(), "link");
Files.createSymbolicLink(link.toPath(), file.getParentFile().toPath());
String target = FileSystemUtil.resolveSymLink(link.getPath() + '/' + file.getName());
assertEquals(file.getPath(), target);
}
@Test
public void junction() throws IOException {
assumeTrue(SystemInfo.isWinVistaOrNewer);
File target = tempDir.newFolder("dir");
File path = new File(tempDir.getRoot(), "junction.dir");
File junction = IoTestUtil.createJunction(target.getPath(), path.getAbsolutePath());
File junction = IoTestUtil.createJunction(target.getPath(), tempDir.getRoot() + "/junction.dir");
try {
FileAttributes attributes = getAttributes(junction);
@@ -324,6 +335,18 @@ public abstract class FileAttributesReadingTest {
}
}
@Test
public void innerJunctionResolve() throws IOException {
assumeTrue(SystemInfo.isWinVistaOrNewer);
File file = tempDir.newFile("dir/file.txt");
File junction = new File(tempDir.getRoot(), "junction");
IoTestUtil.createJunction(file.getParent(), junction.getPath());
String target = FileSystemUtil.resolveSymLink(junction.getPath() + '/' + file.getName());
assertEquals(file.getPath(), target);
}
@Test
public void hiddenDir() throws IOException {
assumeTrue(SystemInfo.isWindows);
@@ -535,7 +558,7 @@ public abstract class FileAttributesReadingTest {
}
@Test
public void testUnicodeName() throws IOException {
public void unicodeName() throws IOException {
String name = IoTestUtil.getUnicodeName();
assumeTrue(name != null);
File file = tempDir.newFile(name + ".txt");
@@ -560,9 +583,9 @@ public abstract class FileAttributesReadingTest {
if (SystemInfo.isWindows && checkList) {
String parent = file.getParent();
if (parent != null) {
FileInfo[] infos = IdeaWin32.getInstance().listChildren(parent);
assertNotNull(infos);
for (FileInfo info : infos) {
FileInfo[] children = IdeaWin32.getInstance().listChildren(parent);
assertNotNull(children);
for (FileInfo info : children) {
if (file.getName().equals(info.getName())) {
assertEquals(attributes, info.toFileAttributes());
return attributes;