diff --git a/src/core.c b/src/core.c index 553f8c7d..0dc38fba 100644 --- a/src/core.c +++ b/src/core.c @@ -12971,12 +12971,8 @@ __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *ctx, return MDBX_EINVAL; #if defined(_WIN32) || defined(_WIN64) - const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX); - if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX) - return ERROR_INVALID_NAME; - wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t)); - if (wlen != mbstowcs(pathnameW, pathname, wlen + 1)) - return ERROR_INVALID_NAME; + const wchar_t *pathnameW = nullptr; + MUSTDIE_MB2WIDE(pathname, pathnameW); const DWORD dwAttrib = GetFileAttributesW(pathnameW); if (dwAttrib == INVALID_FILE_ATTRIBUTES) { diff --git a/src/mdbx.c++ b/src/mdbx.c++ index ccb5fa3e..56cb345f 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -216,26 +216,17 @@ MDBX_MAYBE_UNUSED PATH pchar_to_path(const char *c_str) { #if defined(_WIN32) || defined(_WIN64) -#ifndef WC_ERR_INVALID_CHARS -static const DWORD WC_ERR_INVALID_CHARS = - (6 /* Windows Vista */ <= /* MajorVersion */ LOBYTE(LOWORD(GetVersion()))) - ? 0x00000080 - : 0; -#endif /* WC_ERR_INVALID_CHARS */ - template <> struct path_to_pchar { std::string str; path_to_pchar(const std::wstring &path) { if (!path.empty()) { - const int chars = - WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(), - int(path.size()), nullptr, 0, nullptr, nullptr); - if (chars == 0) + const auto chars = mdbx_w2mb(nullptr, 0, path.data(), path.size()); + if (chars < 1) mdbx::error::throw_exception(GetLastError()); str.append(chars, '\0'); - WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(), - int(path.size()), const_cast(str.data()), - chars, nullptr, nullptr); + if (!mdbx_w2mb(const_cast(str.data()), chars, path.data(), + path.size())) + mdbx::error::throw_exception(GetLastError()); } } operator const char *() const { return str.c_str(); } @@ -245,14 +236,14 @@ template <> MDBX_MAYBE_UNUSED std::wstring pchar_to_path(const char *c_str) { std::wstring wstr; if (c_str && *c_str) { - const int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str, - int(strlen(c_str)), nullptr, 0); - if (chars == 0) + const auto c_str_len = strlen(c_str); + const auto wchars = mdbx_mb2w(nullptr, 0, c_str, c_str_len); + if (wchars < 1) + mdbx::error::throw_exception(GetLastError()); + wstr.append(wchars, '\0'); + if (!mdbx_mb2w(const_cast(wstr.data()), wchars, c_str, + c_str_len)) mdbx::error::throw_exception(GetLastError()); - wstr.append(chars, '\0'); - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str, - int(strlen(c_str)), const_cast(wstr.data()), - chars); } return wstr; } diff --git a/src/osal.c b/src/osal.c index f2ad4ab8..f0bbbc32 100644 --- a/src/osal.c +++ b/src/osal.c @@ -518,14 +518,35 @@ MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex) { /*----------------------------------------------------------------------------*/ +#if defined(_WIN32) || defined(_WIN64) + +#ifndef WC_ERR_INVALID_CHARS +static const DWORD WC_ERR_INVALID_CHARS = + (6 /* Windows Vista */ <= /* MajorVersion */ LOBYTE(LOWORD(GetVersion()))) + ? 0x00000080 + : 0; +#endif /* WC_ERR_INVALID_CHARS */ + +MDBX_INTERNAL_FUNC size_t mdbx_mb2w(wchar_t *dst, size_t dst_n, const char *src, + size_t src_n) { + return MultiByteToWideChar(CP_THREAD_ACP, MB_ERR_INVALID_CHARS, src, + (int)src_n, dst, (int)dst_n); +} + +MDBX_INTERNAL_FUNC size_t mdbx_w2mb(char *dst, size_t dst_n, const wchar_t *src, + size_t src_n) { + return WideCharToMultiByte(CP_THREAD_ACP, WC_ERR_INVALID_CHARS, src, + (int)src_n, dst, (int)dst_n, nullptr, nullptr); +} + +#endif /* Windows */ + +/*----------------------------------------------------------------------------*/ + MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) { #if defined(_WIN32) || defined(_WIN64) - const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX); - if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX) - return ERROR_INVALID_NAME; - wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t)); - if (wlen != mbstowcs(pathnameW, pathname, wlen + 1)) - return ERROR_INVALID_NAME; + const wchar_t *pathnameW = nullptr; + MUSTDIE_MB2WIDE(pathname, pathnameW); return DeleteFileW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError(); #else return unlink(pathname) ? errno : MDBX_SUCCESS; @@ -538,12 +559,8 @@ static bool is_valid_fd(int fd) { return !(isatty(fd) < 0 && errno == EBADF); } MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname) { #if defined(_WIN32) || defined(_WIN64) - const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX); - if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX) - return ERROR_INVALID_NAME; - wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t)); - if (wlen != mbstowcs(pathnameW, pathname, wlen + 1)) - return ERROR_INVALID_NAME; + const wchar_t *pathnameW = nullptr; + MUSTDIE_MB2WIDE(pathname, pathnameW); return RemoveDirectoryW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError(); #else return rmdir(pathname) ? errno : MDBX_SUCCESS; @@ -557,12 +574,8 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, *fd = INVALID_HANDLE_VALUE; #if defined(_WIN32) || defined(_WIN64) - const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX); - if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX) - return ERROR_INVALID_NAME; - wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t)); - if (wlen != mbstowcs(pathnameW, pathname, wlen + 1)) - return ERROR_INVALID_NAME; + const wchar_t *pathnameW = nullptr; + MUSTDIE_MB2WIDE(pathname, pathnameW); DWORD CreationDisposition = unix_mode_bits ? OPEN_ALWAYS : OPEN_EXISTING; DWORD FlagsAndAttributes = diff --git a/src/osal.h b/src/osal.h index 049d99dc..3ac5ce44 100644 --- a/src/osal.h +++ b/src/osal.h @@ -180,6 +180,11 @@ static inline void mdbx_free(void *ptr) { HeapFree(GetProcessHeap(), 0, ptr); } #define vsnprintf _vsnprintf /* ntdll */ #endif +MDBX_INTERNAL_FUNC size_t mdbx_mb2w(wchar_t *dst, size_t dst_n, const char *src, + size_t src_n); +MDBX_INTERNAL_FUNC size_t mdbx_w2mb(char *dst, size_t dst_n, const wchar_t *src, + size_t src_n); + #else /*----------------------------------------------------------------------*/ typedef pthread_t mdbx_thread_t; @@ -549,6 +554,20 @@ MDBX_INTERNAL_FUNC int mdbx_rpid_check(MDBX_env *env, uint32_t pid); #if defined(_WIN32) || defined(_WIN64) +#define MUSTDIE_MB2WIDE(FROM, TO) \ + do { \ + const char *const from_tmp = (FROM); \ + const size_t from_mblen = strlen(from_tmp); \ + const size_t to_wlen = mdbx_mb2w(nullptr, 0, from_tmp, from_mblen); \ + if (to_wlen < 1 || to_wlen > /* MAX_PATH */ INT16_MAX) \ + return ERROR_INVALID_NAME; \ + wchar_t *const to_tmp = _alloca((to_wlen + 1) * sizeof(wchar_t)); \ + if (to_wlen + 1 != \ + mdbx_mb2w(to_tmp, to_wlen + 1, from_tmp, from_mblen + 1)) \ + return ERROR_INVALID_NAME; \ + (TO) = to_tmp; \ + } while (0) + typedef void(WINAPI *MDBX_srwlock_function)(MDBX_srwlock *); MDBX_INTERNAL_VAR MDBX_srwlock_function mdbx_srwlock_Init, mdbx_srwlock_AcquireShared, mdbx_srwlock_ReleaseShared,