From 9cebfaee2075896abb10009ad261bff63c71a7e2 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Mon, 8 Oct 2012 11:36:55 +0200 Subject: [PATCH] IdeaWin32 tune-up --- bin/win/IdeaWin32.dll | Bin 35840 -> 36352 bytes bin/win/IdeaWin64.dll | Bin 42496 -> 42496 bytes native/IdeaWin32/IdeaWin32.cpp | 393 +++++++++--------- .../openapi/vfs/impl/win32/Win32FsCache.java | 15 +- .../testSrc/IdeaWin32PerformanceTest.java | 77 ++++ .../openapi/util/io/win32/IdeaWin32.java | 66 +-- 6 files changed, 318 insertions(+), 233 deletions(-) create mode 100644 platform/platform-tests/testSrc/IdeaWin32PerformanceTest.java diff --git a/bin/win/IdeaWin32.dll b/bin/win/IdeaWin32.dll index 16c7b25be82f67fc0b26954e6ba7eaa951d5cc90..b08710b6bb8df836b503ad05b6e5b7853f2ce770 100644 GIT binary patch delta 9691 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 IHVg^+Pg|qH3IG5A delta 9325 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 VXwMV5VQOo7>#Zm53EQNR{10LN9zFm7 diff --git a/bin/win/IdeaWin64.dll b/bin/win/IdeaWin64.dll index e5e8896b45503e7a9734705a3bb44e4f48b983a7..ecc9ae3d52ae4653cbf2fcd3fca5569e4347ca35 100644 GIT binary patch delta 15402 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 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);