From 0e831d5c2d9c5a7baed75cfe2fb914daaf4a6182 Mon Sep 17 00:00:00 2001 From: drgler Date: Sun, 19 Mar 2017 16:21:46 +0100 Subject: [PATCH] Extended patch for ticket #10731 and ticket #9480: Replace expensive call of RtlInitUnicodeString by wcslen and get rid of CompareStringOrdinal completely, because it has no longer any advantages. Also, replace Windows TEXT macro by selecting GetModuleHandleW with wide character argument to prevent any additional conversions. --- src/operations.cpp | 80 ++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/src/operations.cpp b/src/operations.cpp index d004827..37ec1b8 100644 --- a/src/operations.cpp +++ b/src/operations.cpp @@ -101,6 +101,7 @@ using std::wstring; // See MinGW's windef.h # define WINVER 0x501 # endif +# include # include # include # include @@ -518,79 +519,58 @@ namespace } // File name case-insensitive comparison needs to be locale- and collation-independent. - // The approach used below follows a combined strategy described here + // The approach used below follows a combined strategy described in the following + // articles: // http://archives.miloush.net/michkap/archive/2005/10/17/481600.html - // and here: // http://archives.miloush.net/michkap/archive/2007/09/14/4900107.html - // If possible, we use CompareStringOrdinal, alternatively we fallback to - // RtlEqualUnicodeString, and if all fails we perform the equivalent characterwise - // comparsion using LCMapString and uppercase binary equality. + // http://archives.miloush.net/michkap/archive/2007/10/12/5396685.html + // CompareStringOrdinal is only available on newer systems and is just a wrapper of + // RtlCompareUnicodeString, but measurements showed that RtlEqualUnicodeString has better + // performance. Therefore we use RtlEqualUnicodeString, and if that does not exist + // we perform the equivalent characterwise comparsion using LCMapString and uppercase + // binary equality. Instead of calling RtlInitUnicodeString we use wcslen directly + // because that results in better performance as well. - // Windows kernel32.dll and ntdll.dll functions that may or may not be present + // Windows ntdll.dll functions that may or may not be present // must be accessed through pointers - typedef int (WINAPI *PtrCompareStringOrdinal)( - /*__in*/ LPCWSTR lpString1, - /*__in*/ int cchCount1, - /*__in*/ LPCWSTR lpString2, - /*__in*/ int cchCount2, - /*__in*/ BOOL bIgnoreCase - ); - - PtrCompareStringOrdinal compare_string_ordinal_api = PtrCompareStringOrdinal( - ::GetProcAddress( - ::GetModuleHandle(TEXT("kernel32.dll")), "CompareStringOrdinal")); - typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING; - typedef UNICODE_STRING *PUNICODE_STRING; typedef const UNICODE_STRING *PCUNICODE_STRING; - typedef VOID (WINAPI *PtrRtlInitUnicodeString)( - /*_Inout_*/ PUNICODE_STRING DestinationString, - /*_In_opt_*/ PCWSTR SourceString - ); - typedef BOOLEAN (WINAPI *PtrRtlEqualUnicodeString)( /*_In_*/ PCUNICODE_STRING String1, /*_In_*/ PCUNICODE_STRING String2, /*_In_*/ BOOLEAN CaseInSensitive ); - PtrRtlInitUnicodeString rtl_init_unicode_string_api = PtrRtlInitUnicodeString( - ::GetProcAddress( - ::GetModuleHandle(TEXT("ntdll.dll")), "RtlInitUnicodeString")); - PtrRtlEqualUnicodeString rtl_equal_unicode_string_api = PtrRtlEqualUnicodeString( ::GetProcAddress( - ::GetModuleHandle(TEXT("ntdll.dll")), "RtlEqualUnicodeString")); + ::GetModuleHandleW(L"ntdll.dll"), "RtlEqualUnicodeString")); #ifndef LOCALE_INVARIANT -# define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT, SUBLANG_NEUTRAL), SORT_DEFAULT)) +# define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT, SUBLANG_NEUTRAL), SORT_DEFAULT)) #endif bool equal_string_ordinal_ic_1(const wchar_t* s1, const wchar_t* s2) { - int res = compare_string_ordinal_api(s1, -1, s2, -1, TRUE); - if (res != 0) - return res == 2; - assert(!"CompareStringOrdinal failed to compare strings"); - res = wcscmp(s1, s2); // Should never happen, but this is a safe fallback. - return res == 0; - } - - bool equal_string_ordinal_ic_2(const wchar_t* s1, const wchar_t* s2) - { - UNICODE_STRING us1, us2; - rtl_init_unicode_string_api(&us1, s1); - rtl_init_unicode_string_api(&us2, s2); + std::size_t len1 = std::wcslen(s1); + UNICODE_STRING us1; + us1.Buffer = const_cast(s1); + us1.Length = static_cast(sizeof(*s1) * len1); + us1.MaximumLength = us1.Length + sizeof(*s1); + std::size_t len2 = std::wcslen(s2); + UNICODE_STRING us2; + us2.Buffer = const_cast(s2); + us2.Length = static_cast(sizeof(*s2) * len2); + us2.MaximumLength = us2.Length + sizeof(*s2); BOOLEAN res = rtl_equal_unicode_string_api(&us1, &us2, TRUE); return res != FALSE; } - + inline wchar_t to_upper_invariant(wchar_t input) { @@ -606,7 +586,7 @@ namespace return input; // Should never happen, but this is a safe fallback. } - bool equal_string_ordinal_ic_3(const wchar_t* s1, const wchar_t* s2) + bool equal_string_ordinal_ic_2(const wchar_t* s1, const wchar_t* s2) { for (;; ++s1, ++s2) { @@ -634,11 +614,7 @@ namespace typedef bool (*Ptr_equal_string_ordinal_ic)(const wchar_t*, const wchar_t*); Ptr_equal_string_ordinal_ic equal_string_ordinal_ic = - compare_string_ordinal_api ? - equal_string_ordinal_ic_1 : - (rtl_init_unicode_string_api && rtl_equal_unicode_string_api) ? - equal_string_ordinal_ic_2 : - equal_string_ordinal_ic_3; + rtl_equal_unicode_string_api ? equal_string_ordinal_ic_1 : equal_string_ordinal_ic_2; perms make_permissions(const path& p, DWORD attr) { @@ -811,7 +787,7 @@ namespace PtrCreateHardLinkW create_hard_link_api = PtrCreateHardLinkW( ::GetProcAddress( - ::GetModuleHandle(TEXT("kernel32.dll")), "CreateHardLinkW")); + ::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( /*__in*/ LPCWSTR lpSymlinkFileName, @@ -821,7 +797,7 @@ namespace PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( ::GetProcAddress( - ::GetModuleHandle(TEXT("kernel32.dll")), "CreateSymbolicLinkW")); + ::GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); #endif