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 0e249c5d6089..a4136a37a384 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 @@ -74,8 +74,8 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { @Override public VirtualFile findFileByIoFile(@NotNull File file) { - String path = file.getAbsolutePath(); - return findFileByPath(path.replace(File.separatorChar, '/')); + String path = FileUtil.toSystemIndependentName(file.getAbsolutePath()); + return findFileByPath(path); } @NotNull @@ -197,13 +197,11 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { path = path.substring(1); // hack over new File(path).toURI().toURL().getFile() } - if (path.contains("~")) { - try { - path = new File(FileUtil.toSystemDependentName(path)).getCanonicalPath(); - } - catch (IOException e) { - return null; - } + try { + path = FileUtil.resolveShortWindowsName(path); + } + catch (IOException e) { + return null; } } @@ -227,8 +225,8 @@ public abstract class LocalFileSystemBase extends LocalFileSystem { @Override public VirtualFile refreshAndFindFileByIoFile(@NotNull File file) { - String path = file.getAbsolutePath(); - return refreshAndFindFileByPath(path.replace(File.separatorChar, '/')); + String path = FileUtil.toSystemIndependentName(file.getAbsolutePath()); + return refreshAndFindFileByPath(path); } @Override 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 89da3d1c7f31..4ee0f9be1b9d 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -1016,6 +1016,7 @@ public class FileUtil extends FileUtilRt { * Use {@link FileUtilRt#getExtension(String)} instead to get the unchanged extension. * If you need to check whether a file has a specified extension use {@link FileUtilRt#extensionEquals(String, String)} */ + @SuppressWarnings("StringToUpperCaseOrToLowerCaseWithoutLocale") @NotNull public static String getExtension(@NotNull String fileName) { return FileUtilRt.getExtension(fileName).toLowerCase(); @@ -1023,7 +1024,31 @@ public class FileUtil extends FileUtilRt { @NotNull public static String resolveShortWindowsName(@NotNull String path) throws IOException { - return SystemInfo.isWindows && StringUtil.containsChar(path, '~') ? new File(path).getCanonicalPath() : path; + return SystemInfo.isWindows && containsWindowsShortName(path) ? new File(path).getCanonicalPath() : path; + } + + public static boolean containsWindowsShortName(@NotNull String path) { + if (StringUtil.containsChar(path, '~')) { + path = toSystemIndependentName(path); + + int start = 0; + while (start < path.length()) { + int end = path.indexOf('/', start); + if (end < 0) end = path.length(); + + // "How Windows Generates 8.3 File Names from Long File Names", https://support.microsoft.com/en-us/kb/142982 + int dot = path.lastIndexOf('.', end); + if (dot < start) dot = end; + if (dot - start > 2 && dot - start <= 8 && end - dot - 1 <= 3 && + path.charAt(dot - 2) == '~' && Character.isDigit(path.charAt(dot - 1))) { + return true; + } + + start = end + 1; + } + } + + return false; } public static void collectMatchedFiles(@NotNull File root, @NotNull Pattern pattern, @NotNull List outFiles) { @@ -1672,4 +1697,8 @@ public class FileUtil extends FileUtilRt { FileAttributes lower = FileSystemUtil.getAttributes(path.toLowerCase(Locale.ENGLISH)); return !(attributes.equals(upper) && attributes.equals(lower)); } + + public static boolean isWindowsShortName(@NotNull String fileName) { + return false; + } } diff --git a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilLightTest.java b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilLightTest.java index 747c5c79a129..820d1f328669 100644 --- a/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilLightTest.java +++ b/platform/util/testSrc/com/intellij/openapi/util/io/FileUtilLightTest.java @@ -214,4 +214,21 @@ public class FileUtilLightTest { assertThat(FileUtil.sanitizeFileName("a+b+c")).isEqualTo("a_b_c"); } + + @Test + public void windowsShortName() { + assertTrue(FileUtil.containsWindowsShortName("C:\\dir~1")); + assertTrue(FileUtil.containsWindowsShortName("C:\\dir~1\\")); + assertTrue(FileUtil.containsWindowsShortName("C:\\dir~1\\file.txt")); + assertTrue(FileUtil.containsWindowsShortName("C:/dir/file~1")); + assertTrue(FileUtil.containsWindowsShortName("C:/dir/file~1.txt")); + assertTrue(FileUtil.containsWindowsShortName("C:/dir/file~1.1")); + + assertFalse(FileUtil.containsWindowsShortName("~")); + assertFalse(FileUtil.containsWindowsShortName("C:\\some~dir")); + assertFalse(FileUtil.containsWindowsShortName("C:\\some-dir~1")); + assertFalse(FileUtil.containsWindowsShortName("C:/dir/file~1.extension")); + assertFalse(FileUtil.containsWindowsShortName("C:/dir/file.~1")); + assertFalse(FileUtil.containsWindowsShortName("C:/dir/file.ext~1")); + } }