diff --git a/bin/win/IdeaWin32.dll b/bin/win/IdeaWin32.dll index 16c7b25be82f..b08710b6bb8d 100644 Binary files a/bin/win/IdeaWin32.dll and b/bin/win/IdeaWin32.dll differ diff --git a/bin/win/IdeaWin64.dll b/bin/win/IdeaWin64.dll index e5e8896b4550..ecc9ae3d52ae 100644 Binary files a/bin/win/IdeaWin64.dll and b/bin/win/IdeaWin64.dll differ diff --git a/native/IdeaWin32/IdeaWin32.cpp b/native/IdeaWin32/IdeaWin32.cpp index 276e50329d38..c629e4553ff8 100644 --- a/native/IdeaWin32/IdeaWin32.cpp +++ b/native/IdeaWin32/IdeaWin32.cpp @@ -25,104 +25,22 @@ static jfieldID attributesID = NULL; static jfieldID timestampID = NULL; static jfieldID lengthID = NULL; +#define FILE_INFO_CLASS "com/intellij/openapi/util/io/win32/FileInfo" #define BROKEN_SYMLINK_ATTR -1 - -static jclass getFileInfoClass(JNIEnv *env) { - return env->FindClass("com/intellij/openapi/util/io/win32/FileInfo"); -} - -static bool CopyObjectArray(JNIEnv *env, jobjectArray dst, jobjectArray src, jint count) { - for (int i = 0; i < count; i++) { - jobject p = env->GetObjectArrayElement(src, i); - env->SetObjectArrayElement(dst, i, p); - env->DeleteLocalRef(p); - } - return true; -} - -static inline LONGLONG pairToInt64(DWORD lowPart, DWORD highPart) { - ULARGE_INTEGER large; - large.LowPart = lowPart; - large.HighPart = highPart; - return large.QuadPart; -} - #define IS_SET(flags, flag) ((flags & flag) == flag) #define FILE_SHARE_ATTRIBUTES (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) -static jobject CreateFileInfo(JNIEnv *env, jstring path, bool append, LPWIN32_FIND_DATA lpData, jclass fileInfoClass) { - DWORD attributes = lpData->dwFileAttributes; - LONGLONG timestamp = pairToInt64(lpData->ftLastWriteTime.dwLowDateTime, lpData->ftLastWriteTime.dwHighDateTime); - LONGLONG length = pairToInt64(lpData->nFileSizeLow, lpData->nFileSizeHigh); - - if (IS_SET(attributes, FILE_ATTRIBUTE_REPARSE_POINT)) { - if (IS_SET(lpData->dwReserved0, IO_REPARSE_TAG_SYMLINK)) { - attributes = BROKEN_SYMLINK_ATTR; - timestamp = 0; - length = 0; - - const jchar *dirName = env->GetStringChars(path, 0); - wchar_t *fullPath = (wchar_t *)dirName; - - if (append) { - size_t nameLen = env->GetStringLength(path) + wcslen(lpData->cFileName) + 2; - fullPath = (wchar_t *)malloc(nameLen * sizeof(wchar_t)); - if (fullPath != NULL) { - wcscpy_s(fullPath, nameLen, (LPCWSTR)dirName); - wcscat_s(fullPath, nameLen, L"\\"); - wcscat_s(fullPath, nameLen, lpData->cFileName); - } - } - - if (fullPath != NULL) { - // read symlink target attributes - HANDLE h = CreateFile(fullPath, 0, FILE_SHARE_ATTRIBUTES, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (h != INVALID_HANDLE_VALUE) { - BY_HANDLE_FILE_INFORMATION targetData; - if (GetFileInformationByHandle(h, &targetData)) { - attributes = targetData.dwFileAttributes | FILE_ATTRIBUTE_REPARSE_POINT; - timestamp = pairToInt64(targetData.ftLastWriteTime.dwLowDateTime, targetData.ftLastWriteTime.dwHighDateTime); - length = pairToInt64(targetData.nFileSizeLow, targetData.nFileSizeHigh); - } - CloseHandle(h); - } - - if (append) { - free(fullPath); - } - } - - env->ReleaseStringChars(path, dirName); - } - else { - attributes &= (~ FILE_ATTRIBUTE_REPARSE_POINT); // keep reparse flag only for symlinks - } - } - - jobject o = env->AllocObject(fileInfoClass); - if (o == NULL) { - return NULL; - } - - jstring fileName = env->NewString((jchar*)lpData->cFileName, (jsize)wcslen(lpData->cFileName)); - if (fileName == NULL) { - return NULL; - } - env->SetObjectField(o, nameID, fileName); - - env->SetIntField(o, attributesID, attributes); - env->SetLongField(o, timestampID, timestamp); - env->SetLongField(o, lengthID, length); - - return o; -} +static wchar_t* ToWinPath(JNIEnv* env, jstring path, bool dirSuffix); +static jobject CreateFileInfo(JNIEnv* env, wchar_t* path, bool isDirectory, LPWIN32_FIND_DATA lpData, jclass aClass); +static jobjectArray CopyObjectArray(JNIEnv* env, jobjectArray src, jclass aClass, jsize count, jsize newSize); -JNIEXPORT void JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_initIDs(JNIEnv *env, jclass cls) { - __GetFinalPathNameByHandle = - (GetFinalPathNameByHandlePtr)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetFinalPathNameByHandleW"); +// interface methods - jclass fileInfoClass = getFileInfoClass(env); +JNIEXPORT void JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_initIDs(JNIEnv* env, jclass cls) { + __GetFinalPathNameByHandle = (GetFinalPathNameByHandlePtr)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "GetFinalPathNameByHandleW"); + + jclass fileInfoClass = env->FindClass(FILE_INFO_CLASS); if (fileInfoClass == NULL) { return; } @@ -133,155 +51,250 @@ JNIEXPORT void JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_initIDs lengthID = env->GetFieldID(fileInfoClass, "length", "J"); } - -JNIEXPORT jobject JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_getInfo0(JNIEnv *env, jobject method, jstring path) { - const jchar* pathStr = env->GetStringChars(path, 0); - - WIN32_FILE_ATTRIBUTE_DATA attrData; - BOOL res = GetFileAttributesEx((LPCWSTR)pathStr, GetFileExInfoStandard, &attrData); - if (!res) { - env->ReleaseStringChars(path, pathStr); +JNIEXPORT jobject JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_getInfo0(JNIEnv* env, jobject method, jstring path) { + wchar_t* winPath = ToWinPath(env, path, false); + if (winPath == NULL) { return NULL; } - WIN32_FIND_DATA data; - data.dwFileAttributes = attrData.dwFileAttributes; - data.dwReserved0 = 0; - data.ftLastWriteTime = attrData.ftLastWriteTime; - data.nFileSizeLow = attrData.nFileSizeLow; - data.nFileSizeHigh = attrData.nFileSizeHigh; - - if (IS_SET(attrData.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) { - WIN32_FIND_DATA findData; - HANDLE h = FindFirstFile((LPCWSTR)pathStr, &findData); - if (h != INVALID_HANDLE_VALUE) { - FindClose(h); - data.dwFileAttributes = findData.dwFileAttributes; - data.dwReserved0 = findData.dwReserved0; - data.ftLastWriteTime = findData.ftLastWriteTime; - data.nFileSizeLow = findData.nFileSizeLow; - data.nFileSizeHigh = findData.nFileSizeHigh; - } + WIN32_FILE_ATTRIBUTE_DATA attrData; + BOOL res = GetFileAttributesExW(winPath, GetFileExInfoStandard, &attrData); + if (!res) { + free(winPath); + return NULL; } - env->ReleaseStringChars(path, pathStr); - - jclass fileInfoClass = getFileInfoClass(env); + jclass fileInfoClass = env->FindClass(FILE_INFO_CLASS); if (fileInfoClass == NULL) { return NULL; } - return CreateFileInfo(env, path, false, &data, fileInfoClass); -} - - -JNIEXPORT jstring JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_resolveSymLink0(JNIEnv *env, jobject method, jstring path) { - if (__GetFinalPathNameByHandle == NULL) { - return NULL; // XP + jobject result = NULL; + if (IS_SET(attrData.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) { + // may be symlink + WIN32_FIND_DATA data; + HANDLE h = FindFirstFileW(winPath, &data); + if (h != INVALID_HANDLE_VALUE) { + FindClose(h); + result = CreateFileInfo(env, winPath, false, &data, fileInfoClass); + } + } + if (result == NULL) { + // either not a symlink or FindFirstFile() failed + WIN32_FIND_DATA data; + data.dwFileAttributes = attrData.dwFileAttributes; + data.dwReserved0 = 0; + data.ftLastWriteTime = attrData.ftLastWriteTime; + data.nFileSizeLow = attrData.nFileSizeLow; + data.nFileSizeHigh = attrData.nFileSizeHigh; + data.cFileName[0] = L'\0'; + result = CreateFileInfo(env, winPath, false, &data, fileInfoClass); } - const jchar* pathStr = env->GetStringChars(path, 0); + free(winPath); + return result; +} + +JNIEXPORT jstring JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_resolveSymLink0(JNIEnv* env, jobject method, jstring path) { + if (__GetFinalPathNameByHandle == NULL) { + return NULL; // links not supported + } + + wchar_t* winPath = ToWinPath(env, path, false); jstring result = NULL; WIN32_FIND_DATA data; - HANDLE h = FindFirstFile((LPCWSTR)pathStr, &data); + HANDLE h = FindFirstFileW(winPath, &data); if (h != INVALID_HANDLE_VALUE) { FindClose(h); if (IS_SET(data.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) && IS_SET(data.dwReserved0, IO_REPARSE_TAG_SYMLINK)) { - HANDLE th = CreateFile((LPCWSTR)pathStr, 0, FILE_SHARE_ATTRIBUTES, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + HANDLE th = CreateFileW(winPath, 0, FILE_SHARE_ATTRIBUTES, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (th != INVALID_HANDLE_VALUE) { - TCHAR name[MAX_PATH]; - DWORD len = __GetFinalPathNameByHandle(th, name, MAX_PATH, 0); + wchar_t buff[MAX_PATH], * finalPath = buff; + DWORD len = __GetFinalPathNameByHandle(th, buff, MAX_PATH, 0); + if (len >= MAX_PATH) { + finalPath = (wchar_t*)malloc((len + 1) * sizeof(wchar_t)); + len = finalPath != NULL ? __GetFinalPathNameByHandle(th, finalPath, len, 0) : 0; + } if (len > 0) { - if (len < MAX_PATH) { - result = env->NewString((jchar *)name, len); - } - else { - TCHAR *name = (TCHAR *)malloc(sizeof(TCHAR) * (len + 1)); - if (name != NULL) { - len = __GetFinalPathNameByHandle(th, name, len, 0); - if (len > 0) { - result = env->NewString((jchar *)name, len); - } - free(name); - } + int prefix = (len > 4 && finalPath[0] == L'\\' && finalPath[1] == L'\\' && finalPath[2] == L'?' && finalPath[3] == L'\\') ? 4 : 0; + result = env->NewString((jchar*)finalPath + prefix, len - prefix); + if (finalPath != buff) { + free(finalPath); } } CloseHandle(th); - } } } - env->ReleaseStringChars(path, pathStr); + free(winPath); return result; } - -JNIEXPORT jobjectArray JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_listChildren0(JNIEnv *env, jobject method, jstring path) { - jclass fileInfoClass = getFileInfoClass(env); +JNIEXPORT jobjectArray JNICALL Java_com_intellij_openapi_util_io_win32_IdeaWin32_listChildren0(JNIEnv* env, jobject method, jstring path) { + jclass fileInfoClass = env->FindClass(FILE_INFO_CLASS); if (fileInfoClass == NULL) { return NULL; } - size_t pathLen = env->GetStringLength(path) + 3; - wchar_t* pathStr = (wchar_t *)malloc(pathLen * sizeof(wchar_t)); - if (pathStr == NULL) { + wchar_t* winPath = ToWinPath(env, path, true); + if (winPath == NULL) { return NULL; } - const jchar* str = env->GetStringChars(path, 0); - wcscpy_s(pathStr, pathLen, (LPCWSTR)str); - wcscat_s(pathStr, pathLen, L"\\*"); - env->ReleaseStringChars(path, str); WIN32_FIND_DATA data; - HANDLE h = FindFirstFile((LPCWSTR)pathStr, &data); + HANDLE h = FindFirstFileW(winPath, &data); if (h == INVALID_HANDLE_VALUE) { - free(pathStr); + free(winPath); return NULL; } - jobjectArray rv, old; - int len = 0, maxlen = 16; - rv = env->NewObjectArray(maxlen, fileInfoClass, NULL); - if (rv == NULL) { - goto error; - } - - do { - if (len == maxlen) { - old = rv; - rv = env->NewObjectArray(maxlen <<= 1, fileInfoClass, NULL); - if (rv == NULL || !CopyObjectArray(env, rv, old, len)) { - goto error; + jsize len = 0, maxLen = 16; + jobjectArray result = env->NewObjectArray(maxLen, fileInfoClass, NULL); + if (result != NULL) { + do { + if (wcscmp(data.cFileName, L".") == 0 || wcscmp(data.cFileName, L"..") == 0) { + continue; } - env->DeleteLocalRef(old); + + if (len == maxLen) { + result = CopyObjectArray(env, result, fileInfoClass, len, maxLen <<= 1); + if (result == NULL) { + goto exit; + } + } + + jobject o = CreateFileInfo(env, winPath, true, &data, fileInfoClass); + env->SetObjectArrayElement(result, len++, o); + env->DeleteLocalRef(o); } - jobject o = CreateFileInfo(env, path, true, &data, fileInfoClass); - env->SetObjectArrayElement(rv, len++, o); - env->DeleteLocalRef(o); - } - while (FindNextFile(h, &data)); + while (FindNextFile(h, &data)); - free(pathStr); - FindClose(h); - - old = rv; - rv = env->NewObjectArray(len, fileInfoClass, NULL); - if (rv == NULL || !CopyObjectArray(env, rv, old, len)) { - goto error; + if (len != maxLen) { + result = CopyObjectArray(env, result, fileInfoClass, len, len); + } } - return rv; - -error: - free(pathStr); +exit: + free(winPath); FindClose(h); - return NULL; + return result; } - BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { return TRUE; } + + +// utility methods + +static inline LONGLONG pairToInt64(DWORD lowPart, DWORD highPart); + +static wchar_t* ToWinPath(JNIEnv* env, jstring path, bool dirSuffix) { + jsize len = env->GetStringLength(path), prefix = 0, suffix = 0; + const jchar* jstr = env->GetStringChars(path, NULL); + while (len > 0 && jstr[len - 1] == L'\\') --len; // trim trailing separators + if (len == 0) return NULL; + if (len >= MAX_PATH) prefix = 4; // prefix long paths by UNC marker + if (dirSuffix) suffix = 2; + + wchar_t* pathBuf = (wchar_t*)malloc((prefix + len + suffix + 1) * sizeof(wchar_t)); + if (pathBuf != NULL) { + if (prefix > 0) { + wcsncpy_s(pathBuf, prefix + 1, L"\\\\?\\", prefix); + } + wcsncpy_s(pathBuf + prefix, len + 1, (wchar_t*)jstr, len); + if (suffix > 0) { + wcsncpy_s(pathBuf + prefix + len, suffix + 1, L"\\*", suffix); + } + pathBuf[prefix + len + suffix] = L'\0'; + } + + env->ReleaseStringChars(path, jstr); + + return pathBuf; +} + +static jobject CreateFileInfo(JNIEnv* env, wchar_t* path, bool isDirectory, LPWIN32_FIND_DATA lpData, jclass aClass) { + DWORD attributes = lpData->dwFileAttributes; + LONGLONG timestamp = pairToInt64(lpData->ftLastWriteTime.dwLowDateTime, lpData->ftLastWriteTime.dwHighDateTime); + LONGLONG length = pairToInt64(lpData->nFileSizeLow, lpData->nFileSizeHigh); + + if (IS_SET(attributes, FILE_ATTRIBUTE_REPARSE_POINT)) { + if (IS_SET(lpData->dwReserved0, IO_REPARSE_TAG_SYMLINK)) { + attributes = BROKEN_SYMLINK_ATTR; + timestamp = 0; + length = 0; + + wchar_t* fullPath = path; + if (isDirectory) { + // trim '*' and append file name + size_t dirLen = wcslen(path) - 1, nameLen = wcslen(lpData->cFileName), fullLen = dirLen + nameLen + 1; + fullPath = (wchar_t*)malloc(fullLen * sizeof(wchar_t)); + if (fullPath == NULL) { + return NULL; + } + wcsncpy_s(fullPath, dirLen + 1, path, dirLen); + wcsncpy_s(fullPath + dirLen, nameLen + 1, lpData->cFileName, nameLen); + } + + // read symlink target attributes + HANDLE h = CreateFileW(fullPath, 0, FILE_SHARE_ATTRIBUTES, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (h != INVALID_HANDLE_VALUE) { + BY_HANDLE_FILE_INFORMATION targetData; + if (GetFileInformationByHandle(h, &targetData)) { + attributes = targetData.dwFileAttributes | FILE_ATTRIBUTE_REPARSE_POINT; + timestamp = pairToInt64(targetData.ftLastWriteTime.dwLowDateTime, targetData.ftLastWriteTime.dwHighDateTime); + length = pairToInt64(targetData.nFileSizeLow, targetData.nFileSizeHigh); + } + CloseHandle(h); + } + + if (fullPath != path) { + free(fullPath); + } + } + else { + attributes &= (~ FILE_ATTRIBUTE_REPARSE_POINT); // keep reparse flag only for symlinks + } + } + + jobject o = env->AllocObject(aClass); + if (o == NULL) { + return NULL; + } + + jstring fileName = env->NewString((jchar*)lpData->cFileName, (jsize)wcslen(lpData->cFileName)); + if (fileName == NULL) { + return NULL; + } + + env->SetObjectField(o, nameID, fileName); + env->SetIntField(o, attributesID, attributes); + env->SetLongField(o, timestampID, timestamp); + env->SetLongField(o, lengthID, length); + + return o; +} + +static jobjectArray CopyObjectArray(JNIEnv* env, jobjectArray src, jclass aClass, jsize count, jsize newSize) { + jobjectArray dst = env->NewObjectArray(newSize, aClass, NULL); + if (dst != NULL) { + for (jsize i = 0; i < count; i++) { + jobject o = env->GetObjectArrayElement(src, i); + env->SetObjectArrayElement(dst, i, o); + env->DeleteLocalRef(o); + } + } + env->DeleteLocalRef(src); + return dst; +} + +static inline LONGLONG pairToInt64(DWORD lowPart, DWORD highPart) { + ULARGE_INTEGER large; + large.LowPart = lowPart; + large.HighPart = highPart; + return large.QuadPart; +} diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32FsCache.java b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32FsCache.java index 578d2e0d830e..840f321cad91 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32FsCache.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/impl/win32/Win32FsCache.java @@ -52,8 +52,8 @@ class Win32FsCache { } @NotNull - String[] list(@NotNull String absolutePath) { - FileInfo[] fileInfo = myKernel.listChildren(absolutePath.replace('/', '\\')); + String[] list(@NotNull String path) { + FileInfo[] fileInfo = myKernel.listChildren(path); if (fileInfo == null) { return ArrayUtil.EMPTY_STRING_ARRAY; } @@ -62,14 +62,7 @@ class Win32FsCache { Map map = getMap(); for (FileInfo info : fileInfo) { String name = info.getName(); - if (name.equals(".")) { - map.put(absolutePath, info); - continue; - } - if (name.equals("..")) { - continue; - } - map.put(absolutePath + "/" + name, info); + map.put(path + "/" + name, info); names.add(name); } @@ -82,7 +75,7 @@ class Win32FsCache { Map map = getMap(); FileInfo info = map.get(path); if (info == null) { - info = myKernel.getInfo(path.replace('/', '\\')); + info = myKernel.getInfo(path); if (info == null) { return null; } diff --git a/platform/platform-tests/testSrc/IdeaWin32PerformanceTest.java b/platform/platform-tests/testSrc/IdeaWin32PerformanceTest.java new file mode 100644 index 000000000000..5e8ec895d8cb --- /dev/null +++ b/platform/platform-tests/testSrc/IdeaWin32PerformanceTest.java @@ -0,0 +1,77 @@ +/* + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.win32.FileInfo; +import com.intellij.openapi.util.io.win32.IdeaWin32; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +public class IdeaWin32PerformanceTest { + private IdeaWin32 myDriver; + private long myJavaTotal, myIdeaTotal; + + @Before + public void setUp() throws Exception { + assumeTrue(SystemInfo.isWindows); + myDriver = IdeaWin32.getInstance(); + myIdeaTotal = myJavaTotal = 0; + } + + @Test + public void list() throws Exception { + String path = PathManager.getHomePath(); + doTest(new File(path)); + long gain = (myJavaTotal - myIdeaTotal) * 100 / myJavaTotal; + String message = "home=" + path + " java.io=" + myJavaTotal / 1000 + "ms IdeaWin32=" + myIdeaTotal / 1000 + "ms gain=" + gain + "%"; + assertTrue(message, myIdeaTotal <= myJavaTotal); + //noinspection UseOfSystemOutOrSystemErr + System.out.println(message); + } + + private void doTest(File file) { + final String path = file.getPath(); + + assertNotNull(file.listFiles()); + assertNotNull(myDriver.listChildren(path)); + + long t1 = System.nanoTime(); + final File[] children1 = file.listFiles(); + long t2 = System.nanoTime(); + final FileInfo[] children2 = myDriver.listChildren(path); + long t3 = System.nanoTime(); + myJavaTotal += (t2 - t1) / 1000; + myIdeaTotal += (t3 - t2) / 1000; + + assertNotNull(path, children1); + assertNotNull(path, children2); + assertEquals(children1.length, children2.length); + + for (File child : children1) { + if (child.isDirectory()) { + doTest(child); + } + } + } +} diff --git a/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java b/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java index 5a4589d2a25e..7e159ce83b00 100644 --- a/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java +++ b/platform/util/src/com/intellij/openapi/util/io/win32/IdeaWin32.java @@ -33,10 +33,7 @@ import java.io.FileNotFoundException; */ public class IdeaWin32 { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.io.win32.IdeaWin32"); - - private static final String PATH_PREFIX = "\\\\?\\"; - private static final int PREFIX_SIZE = PATH_PREFIX.length(); - private static final int MAX_PATH = 260; + private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled(); private static final IdeaWin32 ourInstance; @@ -96,46 +93,51 @@ public class IdeaWin32 { private static native void initIDs(); @Nullable - public FileInfo getInfo(@NotNull final String path) { - LogUtil.debug(LOG, "getInfo(%s)", path); - return getInfo0(path(path)); + public FileInfo getInfo(@NotNull String path) { + path = path.replace('/', '\\'); + if (DEBUG_ENABLED) { + long t = System.nanoTime(); + final FileInfo result = getInfo0(path); + t = (System.nanoTime() - t) / 1000; + LOG.debug("getInfo(" + path + "): " + t + " mks"); + LogUtil.debug(LOG, "getInfo(%s)", path); + return result; + } + else { + return getInfo0(path); + } } @Nullable - public String resolveSymLink(@NotNull final String path) { - final String result = resolveSymLink0(path(path)); - return result != null && result.startsWith(PATH_PREFIX) ? result.substring(PREFIX_SIZE) : result; + public String resolveSymLink(@NotNull String path) { + path = path.replace('/', '\\'); + if (DEBUG_ENABLED) { + long t = System.nanoTime(); + final String result = resolveSymLink0(path); + t = (System.nanoTime() - t) / 1000; + LOG.debug("resolveSymLink(" + path + "): " + t + " mks"); + return result; + } + else { + return resolveSymLink0(path); + } } @Nullable - public FileInfo[] listChildren(@NotNull final String path) { - if (LOG.isDebugEnabled()) { - long t = System.currentTimeMillis(); - FileInfo[] children = listChildren0(path(path)); - t = System.currentTimeMillis() - t; - LOG.debug("list(" + path + "): " + children.length + " children, " + t + " ms"); + public FileInfo[] listChildren(@NotNull String path) { + path = path.replace('/', '\\'); + if (DEBUG_ENABLED) { + long t = System.nanoTime(); + FileInfo[] children = listChildren0(path); + t = (System.nanoTime() - t) / 1000; + LOG.debug("list(" + path + "): " + children.length + " children, " + t + " mks"); return children; } else { - return listChildren0(path(path)); + return listChildren0(path); } } - private static String path(final String path) { - final int length = path.length(); - if (length > 0 && path.charAt(length - 1) == '\\' || length >= MAX_PATH) { - final StringBuilder sb = new StringBuilder(path); - while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '\\') { - sb.deleteCharAt(sb.length() - 1); - } - if (sb.length() >= MAX_PATH) { - sb.insert(0, PATH_PREFIX); - } - return sb.toString(); - } - return path; - } - private native FileInfo getInfo0(String path); private native String resolveSymLink0(String path);