diff --git a/src/operations.cpp b/src/operations.cpp index 4114e02..c04ed7c 100644 --- a/src/operations.cpp +++ b/src/operations.cpp @@ -518,115 +518,28 @@ namespace || errval == ERROR_BAD_PATHNAME // "//nosuch" on Win64 || errval == ERROR_BAD_NETPATH; // "//nosuch" on Win32 } - - // File name case-insensitive comparison needs to be locale- and collation-independent. - // The approach used below follows a combined strategy described in the following - // articles: - // http://archives.miloush.net/michkap/archive/2005/10/17/481600.html - // http://archives.miloush.net/michkap/archive/2007/09/14/4900107.html - // 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 ntdll.dll functions that may or may not be present - // must be accessed through pointers - typedef struct _UNICODE_STRING { - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; - } UNICODE_STRING; - - typedef const UNICODE_STRING *PCUNICODE_STRING; - - typedef BOOLEAN (WINAPI *PtrRtlEqualUnicodeString)( - /*_In_*/ PCUNICODE_STRING String1, - /*_In_*/ PCUNICODE_STRING String2, - /*_In_*/ BOOLEAN CaseInSensitive - ); - - PtrRtlEqualUnicodeString rtl_equal_unicode_string_api = PtrRtlEqualUnicodeString( - ::GetProcAddress( - ::GetModuleHandleW(L"ntdll.dll"), "RtlEqualUnicodeString")); - -#ifndef LOCALE_INVARIANT -# 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) + static bool equal_extension( wchar_t const* p, wchar_t const (&x1)[ 5 ], wchar_t const (&x2)[ 5 ] ) { - std::size_t len1 = std::wcslen(s1); - UNICODE_STRING us1; - us1.Buffer = const_cast(s1); - us1.Length = static_cast(sizeof(*s1) * len1); - us1.MaximumLength = static_cast(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 = static_cast(us2.Length + sizeof(*s2)); - BOOLEAN res = rtl_equal_unicode_string_api(&us1, &us2, TRUE); - return res != FALSE; + return + (p[0] == x1[0] || p[0] == x2[0]) && + (p[1] == x1[1] || p[1] == x2[1]) && + (p[2] == x1[2] || p[2] == x2[2]) && + (p[3] == x1[3] || p[3] == x2[3]) && + p[4] == 0; } - inline - wchar_t to_upper_invariant(wchar_t input) - { - wchar_t result; - // According to - // https://msdn.microsoft.com/en-us/library/windows/desktop/dd318144(v=vs.85).aspx - // "When transforming between uppercase and lowercase, the function always maps a - // single character to a single character." - int res = ::LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, &input, 1, &result, 1); - if (res != 0) - return result; - assert(!"LCMapStringW failed to convert a character to upper case"); - return input; // Should never happen, but this is a safe fallback. - } - - bool equal_string_ordinal_ic_2(const wchar_t* s1, const wchar_t* s2) - { - for (;; ++s1, ++s2) - { - const wchar_t c1 = *s1; - const wchar_t c2 = *s2; - if (c1 == c2) - { - if (!c1) - return true; // We have reached the end of both strings, no difference found. - } - else - { - if (!c1 || !c2) - return false; // We have reached the end of one string - // This needs to be upper case to match the behavior of the operating system, - // see http://archives.miloush.net/michkap/archive/2005/10/17/481600.html - const wchar_t u1 = to_upper_invariant(c1); - const wchar_t u2 = to_upper_invariant(c2); - if (u1 != u2) - return false; // strings are different - } - } - } - - typedef bool (*Ptr_equal_string_ordinal_ic)(const wchar_t*, const wchar_t*); - - Ptr_equal_string_ordinal_ic equal_string_ordinal_ic = - rtl_equal_unicode_string_api ? equal_string_ordinal_ic_1 : equal_string_ordinal_ic_2; - perms make_permissions(const path& p, DWORD attr) { perms prms = fs::owner_read | fs::group_read | fs::others_read; if ((attr & FILE_ATTRIBUTE_READONLY) == 0) prms |= fs::owner_write | fs::group_write | fs::others_write; path ext = p.extension(); - if (equal_string_ordinal_ic(ext.c_str(), L".exe") - || equal_string_ordinal_ic(ext.c_str(), L".com") - || equal_string_ordinal_ic(ext.c_str(), L".bat") - || equal_string_ordinal_ic(ext.c_str(), L".cmd")) + wchar_t const* q = ext.c_str(); + if (equal_extension(q, L".exe", L".EXE") + || equal_extension(q, L".com", L".COM") + || equal_extension(q, L".bat", L".BAT") + || equal_extension(q, L".cmd", L".CMD")) prms |= fs::owner_exe | fs::group_exe | fs::others_exe; return prms; }