From 2ff8d3c4f24176d9522ae54503df15742e87385c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Tue, 9 Aug 2022 18:27:43 +0300 Subject: [PATCH] mdbx: native `wchar_t` pathname for Windows. --- mdbx.h | 35 +++++++++ mdbx.h++ | 8 +++ src/core.c | 174 ++++++++++++++++++++++++++++++++++---------- src/internals.h | 2 +- src/mdbx.c++ | 188 ++++++++++++++++-------------------------------- src/osal.c | 39 +++------- src/osal.h | 16 +++-- 7 files changed, 264 insertions(+), 198 deletions(-) diff --git a/mdbx.h b/mdbx.h index 3d13751b..82d46ef4 100644 --- a/mdbx.h +++ b/mdbx.h @@ -827,18 +827,30 @@ enum MDBX_constants { #ifndef MDBX_LOCKNAME /** \brief The name of the lock file in the environment * without using \ref MDBX_NOSUBDIR */ +#if !(defined(_WIN32) || defined(_WIN64)) #define MDBX_LOCKNAME "/mdbx.lck" +#else +#define MDBX_LOCKNAME L"\\mdbx.lck" #endif +#endif /* MDBX_LOCKNAME */ #ifndef MDBX_DATANAME /** \brief The name of the data file in the environment * without using \ref MDBX_NOSUBDIR */ +#if !(defined(_WIN32) || defined(_WIN64)) #define MDBX_DATANAME "/mdbx.dat" +#else +#define MDBX_DATANAME L"\\mdbx.dat" #endif +#endif /* MDBX_DATANAME */ #ifndef MDBX_LOCK_SUFFIX /** \brief The suffix of the lock file when \ref MDBX_NOSUBDIR is used */ +#if !(defined(_WIN32) || defined(_WIN64)) #define MDBX_LOCK_SUFFIX "-lck" +#else +#define MDBX_LOCK_SUFFIX L"-lck" #endif +#endif /* MDBX_LOCK_SUFFIX */ /* DEBUG & LOGGING ************************************************************/ @@ -2275,6 +2287,11 @@ LIBMDBX_API int mdbx_env_get_option(const MDBX_env *env, LIBMDBX_API int mdbx_env_open(MDBX_env *env, const char *pathname, MDBX_env_flags_t flags, mdbx_mode_t mode); +#if defined(_WIN32) || defined(_WIN64) +LIBMDBX_API int mdbx_env_openW(MDBX_env *env, const wchar_t *pathnameW, + MDBX_env_flags_t flags, mdbx_mode_t mode); +#endif /* Windows */ + /** \brief Deletion modes for \ref mdbx_env_delete(). * \ingroup c_extra * \see mdbx_env_delete() */ @@ -2317,6 +2334,10 @@ typedef enum MDBX_env_delete_mode_t MDBX_env_delete_mode_t; * so no deletion was performed. */ LIBMDBX_API int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode); +#if defined(_WIN32) || defined(_WIN64) +LIBMDBX_API int mdbx_env_deleteW(const wchar_t *pathnameW, + MDBX_env_delete_mode_t mode); +#endif /* Windows */ /** \brief Copy an MDBX environment to the specified path, with options. * \ingroup c_extra @@ -2351,6 +2372,10 @@ LIBMDBX_API int mdbx_env_delete(const char *pathname, * \returns A non-zero error value on failure and 0 on success. */ LIBMDBX_API int mdbx_env_copy(MDBX_env *env, const char *dest, MDBX_copy_flags_t flags); +#if defined(_WIN32) || defined(_WIN64) +LIBMDBX_API int mdbx_env_copyW(MDBX_env *env, const wchar_t *dest, + MDBX_copy_flags_t flags); +#endif /* Windows */ /** \brief Copy an environment to the specified file descriptor, with * options. @@ -2803,7 +2828,11 @@ LIBMDBX_API int mdbx_env_get_flags(const MDBX_env *env, unsigned *flags); * \returns A non-zero error value on failure and 0 on success, * some possible errors are: * \retval MDBX_EINVAL An invalid parameter was specified. */ +#if !(defined(_WIN32) || defined(_WIN64)) LIBMDBX_API int mdbx_env_get_path(const MDBX_env *env, const char **dest); +#else +LIBMDBX_API int mdbx_env_get_pathW(const MDBX_env *env, const wchar_t **dest); +#endif /* Windows */ /** \brief Return the file descriptor for the given environment. * \ingroup c_statinfo @@ -5195,6 +5224,12 @@ LIBMDBX_API int mdbx_env_pgwalk(MDBX_txn *txn, MDBX_pgvisitor_func *visitor, LIBMDBX_API int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname, unsigned target_meta, bool writeable); +#if defined(_WIN32) || defined(_WIN64) +LIBMDBX_API int mdbx_env_open_for_recoveryW(MDBX_env *env, + const wchar_t *pathnameW, + unsigned target_meta, + bool writeable); +#endif /* Windows */ /** \brief Turn database to the specified meta-page. * diff --git a/mdbx.h++ b/mdbx.h++ index 64143c48..623b4cc2 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -3225,6 +3225,8 @@ public: #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) env ©(const ::std::wstring &destination, bool compactify, bool force_dynamic_size = false); + env ©(const wchar_t *destination, bool compactify, + bool force_dynamic_size = false); #endif /* Windows */ env ©(const ::std::string &destination, bool compactify, bool force_dynamic_size = false); @@ -3260,6 +3262,8 @@ public: #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) static bool remove(const ::std::wstring &pathname, const remove_mode mode = just_remove); + static bool remove(const wchar_t *pathname, + const remove_mode mode = just_remove); #endif /* Windows */ static bool remove(const ::std::string &pathname, const remove_mode mode = just_remove); @@ -3507,6 +3511,8 @@ public: #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) env_managed(const ::std::wstring &pathname, const operate_parameters &, bool accede = true); + explicit env_managed(const wchar_t *pathname, const operate_parameters &, + bool accede = true); #endif /* Windows */ env_managed(const ::std::string &pathname, const operate_parameters &, bool accede = true); @@ -3531,6 +3537,8 @@ public: #if defined(_WIN32) || defined(_WIN64) || defined(DOXYGEN) env_managed(const ::std::wstring &pathname, const create_parameters &, const operate_parameters &, bool accede = true); + explicit env_managed(const wchar_t *pathname, const create_parameters &, + const operate_parameters &, bool accede = true); #endif /* Windows */ env_managed(const ::std::string &pathname, const create_parameters &, const operate_parameters &, bool accede = true); diff --git a/src/core.c b/src/core.c index b54c91a1..62914508 100644 --- a/src/core.c +++ b/src/core.c @@ -12433,7 +12433,7 @@ __cold static int mdbx_setup_dxb(MDBX_env *env, const int lck_rc, /******************************************************************************/ /* Open and/or initialize the lock region for the environment. */ -__cold static int mdbx_setup_lck(MDBX_env *env, char *lck_pathname, +__cold static int mdbx_setup_lck(MDBX_env *env, pathchar_t *lck_pathname, mdbx_mode_t mode) { mdbx_assert(env, env->me_lazy_fd != INVALID_HANDLE_VALUE); mdbx_assert(env, env->me_lfd == INVALID_HANDLE_VALUE); @@ -12816,6 +12816,21 @@ __cold int mdbx_env_turn_for_recovery(MDBX_env *env, unsigned target) { __cold int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname, unsigned target_meta, bool writeable) { +#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; + + return mdbx_env_open_for_recoveryW(env, pathnameW, target_meta, writeable); +} + +__cold int mdbx_env_open_for_recoveryW(MDBX_env *env, const wchar_t *pathname, + unsigned target_meta, bool writeable) { +#endif /* Windows */ + if (unlikely(target_meta >= NUM_METAS)) return MDBX_EINVAL; int rc = check_env(env, false); @@ -12825,35 +12840,49 @@ __cold int mdbx_env_open_for_recovery(MDBX_env *env, const char *pathname, return MDBX_EPERM; env->me_stuck_meta = (int8_t)target_meta; - return mdbx_env_open( - env, pathname, writeable ? MDBX_EXCLUSIVE : MDBX_EXCLUSIVE | MDBX_RDONLY, - 0); + return +#if defined(_WIN32) || defined(_WIN64) + mdbx_env_openW +#else + mdbx_env_open +#endif /* Windows */ + (env, pathname, writeable ? MDBX_EXCLUSIVE : MDBX_EXCLUSIVE | MDBX_RDONLY, + 0); } typedef struct { void *buffer_for_free; - char *lck, *dxb; + pathchar_t *lck, *dxb; size_t ent_len; } MDBX_handle_env_pathname; +static bool path_equal(const pathchar_t *l, const pathchar_t *r, size_t len) { +#if defined(_WIN32) || defined(_WIN64) + while (len > 0) { + pathchar_t a = *l++; + pathchar_t b = *r++; + a = (a == '\\') ? '/' : a; + b = (b == '\\') ? '/' : b; + if (a != b) + return false; + } + return true; +#else + return memcmp(l, r, len * sizeof(pathchar_t)) == 0; +#endif +} + __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *ctx, - const char *pathname, + const pathchar_t *pathname, MDBX_env_flags_t *flags, const mdbx_mode_t mode) { - int rc; memset(ctx, 0, sizeof(*ctx)); - if (unlikely(!pathname)) + if (unlikely(!pathname || !*pathname)) return MDBX_EINVAL; + int rc; #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 DWORD dwAttrib = GetFileAttributesW(pathnameW); + const DWORD dwAttrib = GetFileAttributesW(pathname); if (dwAttrib == INVALID_FILE_ATTRIBUTES) { rc = GetLastError(); if (rc != MDBX_ENOFILE) @@ -12863,8 +12892,7 @@ __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *ctx, return rc; /* auto-create directory if requested */ - if ((*flags & MDBX_NOSUBDIR) == 0 && - !CreateDirectoryW(pathnameW, nullptr)) { + if ((*flags & MDBX_NOSUBDIR) == 0 && !CreateDirectoryW(pathname, nullptr)) { rc = GetLastError(); if (rc != ERROR_ALREADY_EXISTS) return rc; @@ -12905,41 +12933,66 @@ __cold static int mdbx_handle_env_pathname(MDBX_handle_env_pathname *ctx, } #endif - static const char dxb_name[] = MDBX_DATANAME; - static const size_t dxb_name_len = sizeof(dxb_name) - 1; - static const char lck_name[] = MDBX_LOCKNAME; - static const char lock_suffix[] = MDBX_LOCK_SUFFIX; + static const pathchar_t dxb_name[] = MDBX_DATANAME; + static const pathchar_t lck_name[] = MDBX_LOCKNAME; + static const pathchar_t lock_suffix[] = MDBX_LOCK_SUFFIX; - ctx->ent_len = strlen(pathname); - if ((*flags & MDBX_NOSUBDIR) && ctx->ent_len >= dxb_name_len && - !memcmp(dxb_name, pathname + ctx->ent_len - dxb_name_len, dxb_name_len)) { +#if defined(_WIN32) || defined(_WIN64) + assert(dxb_name[0] == '\\' && lck_name[0] == '\\'); + const size_t pathname_len = wcslen(pathname); +#else + assert(dxb_name[0] == '/' && lck_name[0] == '/'); + const size_t pathname_len = strlen(pathname); +#endif + assert(lock_suffix[0] != '\\' && lock_suffix[0] != '/'); + ctx->ent_len = pathname_len; + static const size_t dxb_name_len = ARRAY_LENGTH(dxb_name) - 1; + if ((*flags & MDBX_NOSUBDIR) && ctx->ent_len > dxb_name_len && + path_equal(pathname + ctx->ent_len - dxb_name_len, dxb_name, + dxb_name_len)) { *flags -= MDBX_NOSUBDIR; ctx->ent_len -= dxb_name_len; } const size_t bytes_needed = - ctx->ent_len * 2 + ((*flags & MDBX_NOSUBDIR) - ? sizeof(lock_suffix) + 1 - : sizeof(lck_name) + sizeof(dxb_name)); + sizeof(pathchar_t) * ctx->ent_len * 2 + + ((*flags & MDBX_NOSUBDIR) ? sizeof(lock_suffix) + sizeof(pathchar_t) + : sizeof(lck_name) + sizeof(dxb_name)); ctx->buffer_for_free = mdbx_malloc(bytes_needed); if (!ctx->buffer_for_free) return MDBX_ENOMEM; - ctx->lck = ctx->buffer_for_free; + ctx->dxb = ctx->buffer_for_free; + ctx->lck = ctx->dxb + ctx->ent_len + 1; + memcpy(ctx->dxb, pathname, sizeof(pathchar_t) * (ctx->ent_len + 1)); if (*flags & MDBX_NOSUBDIR) { - ctx->dxb = ctx->lck + ctx->ent_len + sizeof(lock_suffix); - sprintf(ctx->lck, "%s%s", pathname, lock_suffix); - strcpy(ctx->dxb, pathname); + memcpy(ctx->lck + ctx->ent_len, lock_suffix, sizeof(lock_suffix)); } else { - ctx->dxb = ctx->lck + ctx->ent_len + sizeof(lck_name); - sprintf(ctx->lck, "%.*s%s", (int)ctx->ent_len, pathname, lck_name); - sprintf(ctx->dxb, "%.*s%s", (int)ctx->ent_len, pathname, dxb_name); + ctx->lck += dxb_name_len; + memcpy(ctx->lck + ctx->ent_len, lck_name, sizeof(lck_name)); + memcpy(ctx->dxb + ctx->ent_len, dxb_name, sizeof(dxb_name)); } + memcpy(ctx->lck, pathname, sizeof(pathchar_t) * ctx->ent_len); return MDBX_SUCCESS; } __cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) { +#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; + + return mdbx_env_deleteW(pathnameW, mode); +} + +__cold int mdbx_env_deleteW(const wchar_t *pathname, + MDBX_env_delete_mode_t mode) { +#endif /* Windows */ + switch (mode) { default: return MDBX_EINVAL; @@ -12959,7 +13012,7 @@ __cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) { (mode == MDBX_ENV_ENSURE_UNUSED) ? MDBX_EXCLUSIVE : MDBX_ENV_DEFAULTS; dummy_env->me_os_psize = (unsigned)mdbx_syspagesize(); dummy_env->me_psize = (unsigned)mdbx_default_pagesize(); - dummy_env->me_pathname = (char *)pathname; + dummy_env->me_pathname = (pathchar_t *)pathname; MDBX_handle_env_pathname env_pathname; STATIC_ASSERT(sizeof(dummy_env->me_flags) == sizeof(MDBX_env_flags_t)); @@ -13021,6 +13074,21 @@ __cold int mdbx_env_delete(const char *pathname, MDBX_env_delete_mode_t mode) { __cold int mdbx_env_open(MDBX_env *env, const char *pathname, MDBX_env_flags_t flags, mdbx_mode_t mode) { +#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; + + return mdbx_env_openW(env, pathnameW, flags, mode); +} + +__cold int mdbx_env_openW(MDBX_env *env, const wchar_t *pathname, + MDBX_env_flags_t flags, mdbx_mode_t mode) { +#endif /* Windows */ + int rc = check_env(env, false); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -13066,7 +13134,7 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, goto bailout; env->me_flags = (flags & ~MDBX_FATAL_ERROR) | MDBX_ENV_ACTIVE; - env->me_pathname = mdbx_calloc(env_pathname.ent_len + 1, 1); + env->me_pathname = mdbx_calloc(env_pathname.ent_len + 1, sizeof(pathchar_t)); env->me_dbxs = mdbx_calloc(env->me_maxdbs, sizeof(MDBX_dbx)); env->me_dbflags = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbflags[0])); env->me_dbiseqs = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbiseqs[0])); @@ -13075,7 +13143,8 @@ __cold int mdbx_env_open(MDBX_env *env, const char *pathname, rc = MDBX_ENOMEM; goto bailout; } - memcpy(env->me_pathname, env_pathname.dxb, env_pathname.ent_len); + memcpy(env->me_pathname, env_pathname.dxb, + env_pathname.ent_len * sizeof(pathchar_t)); env->me_dbxs[FREE_DBI].md_cmp = cmp_int_align4; /* aligned MDBX_INTEGERKEY */ env->me_dbxs[FREE_DBI].md_dcmp = cmp_lenfast; @@ -19911,6 +19980,21 @@ __cold int mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd, __cold int mdbx_env_copy(MDBX_env *env, const char *dest_path, MDBX_copy_flags_t flags) { +#if defined(_WIN32) || defined(_WIN64) + const size_t wlen = mbstowcs(nullptr, dest_path, INT_MAX); + if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX) + return ERROR_INVALID_NAME; + wchar_t *const dest_pathW = _alloca((wlen + 1) * sizeof(wchar_t)); + if (wlen != mbstowcs(dest_pathW, dest_path, wlen + 1)) + return ERROR_INVALID_NAME; + + return mdbx_env_copyW(env, dest_pathW, flags); +} + +LIBMDBX_API int mdbx_env_copyW(MDBX_env *env, const wchar_t *dest_path, + MDBX_copy_flags_t flags) { +#endif /* Windows */ + int rc = check_env(env, true); if (unlikely(rc != MDBX_SUCCESS)) return rc; @@ -20049,6 +20133,7 @@ __cold int mdbx_env_set_assert(MDBX_env *env, MDBX_assert_func *func) { #endif } +#if !(defined(_WIN32) || defined(_WIN64)) __cold int mdbx_env_get_path(const MDBX_env *env, const char **arg) { int rc = check_env(env, true); if (unlikely(rc != MDBX_SUCCESS)) @@ -20060,6 +20145,19 @@ __cold int mdbx_env_get_path(const MDBX_env *env, const char **arg) { *arg = env->me_pathname; return MDBX_SUCCESS; } +#else +__cold int mdbx_env_get_pathW(const MDBX_env *env, const wchar_t **arg) { + int rc = check_env(env, true); + if (unlikely(rc != MDBX_SUCCESS)) + return rc; + + if (unlikely(!arg)) + return MDBX_EINVAL; + + *arg = env->me_pathname; + return MDBX_SUCCESS; +} +#endif /* Windows */ __cold int mdbx_env_get_fd(const MDBX_env *env, mdbx_filehandle_t *arg) { int rc = check_env(env, true); diff --git a/src/internals.h b/src/internals.h index 4d830abf..af82934e 100644 --- a/src/internals.h +++ b/src/internals.h @@ -1143,7 +1143,7 @@ struct MDBX_env { MDBX_dbi me_maxdbs; /* size of the DB table */ uint32_t me_pid; /* process ID of this env */ mdbx_thread_key_t me_txkey; /* thread-key for readers */ - char *me_pathname; /* path to the DB files */ + pathchar_t *me_pathname; /* path to the DB files */ void *me_pbuf; /* scratch area for DUPSORT put() */ MDBX_txn *me_txn0; /* preallocated write transaction */ diff --git a/src/mdbx.c++ b/src/mdbx.c++ index ccb5fa3e..a3587ff7 100644 --- a/src/mdbx.c++ +++ b/src/mdbx.c++ @@ -201,64 +201,6 @@ __cold bug::~bug() noexcept {} #endif /* Unused*/ -//------------------------------------------------------------------------------ - -template struct path_to_pchar { - const std::string str; - path_to_pchar(const PATH &path) : str(path.generic_string()) {} - operator const char *() const { return str.c_str(); } -}; - -template -MDBX_MAYBE_UNUSED PATH pchar_to_path(const char *c_str) { - return PATH(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) - 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); - } - } - operator const char *() const { return str.c_str(); } -}; - -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) - 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; -} - -#endif /* Windows */ - } // namespace //------------------------------------------------------------------------------ @@ -1239,29 +1181,20 @@ bool env::is_pristine() const { bool env::is_empty() const { return get_stat().ms_leaf_pages == 0; } -#ifdef MDBX_STD_FILESYSTEM_PATH -env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify, +#if defined(_WIN32) || defined(_WIN64) +env &env::copy(const wchar_t *destination, bool compactify, bool force_dynamic_size) { - const path_to_pchar utf8(destination); error::success_or_throw( - ::mdbx_env_copy(handle_, utf8, - (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | - (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE - : MDBX_CP_DEFAULTS))); + ::mdbx_env_copyW(handle_, destination, + (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | + (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE + : MDBX_CP_DEFAULTS))); return *this; } -#endif /* MDBX_STD_FILESYSTEM_PATH */ -#if defined(_WIN32) || defined(_WIN64) env &env::copy(const ::std::wstring &destination, bool compactify, bool force_dynamic_size) { - const path_to_pchar<::std::wstring> utf8(destination); - error::success_or_throw( - ::mdbx_env_copy(handle_, utf8, - (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) | - (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE - : MDBX_CP_DEFAULTS))); - return *this; + return copy(destination.c_str(), compactify, force_dynamic_size); } #endif /* Windows */ @@ -1289,26 +1222,33 @@ env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) { return *this; } -path env::get_path() const { - const char *c_str; - error::success_or_throw(::mdbx_env_get_path(handle_, &c_str)); - return pchar_to_path(c_str); -} - #ifdef MDBX_STD_FILESYSTEM_PATH -bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname, - const remove_mode mode) { - const path_to_pchar utf8(pathname); - return error::boolean_or_throw( - ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); +env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify, + bool force_dynamic_size) { + return copy(destination.native(), compactify, force_dynamic_size); } #endif /* MDBX_STD_FILESYSTEM_PATH */ +path env::get_path() const { #if defined(_WIN32) || defined(_WIN64) -bool env::remove(const ::std::wstring &pathname, const remove_mode mode) { - const path_to_pchar<::std::wstring> utf8(pathname); + const wchar_t *c_wstr; + error::success_or_throw(::mdbx_env_get_pathW(handle_, &c_wstr)); + return path(c_wstr); +#else + const char *c_str; + error::success_or_throw(::mdbx_env_get_path(handle_, &c_str)); + return path(c_str); +#endif +} + +#if defined(_WIN32) || defined(_WIN64) +bool env::remove(const wchar_t *pathname, const remove_mode mode) { return error::boolean_or_throw( - ::mdbx_env_delete(utf8, MDBX_env_delete_mode_t(mode))); + ::mdbx_env_deleteW(pathname, MDBX_env_delete_mode_t(mode))); +} + +bool env::remove(const ::std::wstring &pathname, const remove_mode mode) { + return remove(pathname.c_str(), mode); } #endif /* Windows */ @@ -1321,6 +1261,13 @@ bool env::remove(const ::std::string &pathname, const remove_mode mode) { return remove(pathname.c_str(), mode); } +#ifdef MDBX_STD_FILESYSTEM_PATH +bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname, + const remove_mode mode) { + return remove(pathname.native(), mode); +} +#endif /* MDBX_STD_FILESYSTEM_PATH */ + //------------------------------------------------------------------------------ static inline MDBX_env *create_env() { @@ -1357,66 +1304,42 @@ __cold void env_managed::setup(unsigned max_maps, unsigned max_readers) { error::success_or_throw(::mdbx_env_set_maxdbs(handle_, max_maps)); } -#ifdef MDBX_STD_FILESYSTEM_PATH -__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, - const operate_parameters &op, bool accede) - : env_managed(create_env()) { - setup(op.max_maps, op.max_readers); - const path_to_pchar utf8(pathname); - error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0)); - - if (op.options.nested_write_transactions && - !get_options().nested_write_transactions) - MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); -} - -__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, - const env_managed::create_parameters &cp, - const env::operate_parameters &op, bool accede) - : env_managed(create_env()) { - setup(op.max_maps, op.max_readers); - const path_to_pchar utf8(pathname); - set_geometry(cp.geometry); - error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory), - cp.file_mode_bits)); - - if (op.options.nested_write_transactions && - !get_options().nested_write_transactions) - MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); -} -#endif /* MDBX_STD_FILESYSTEM_PATH */ - #if defined(_WIN32) || defined(_WIN64) -__cold env_managed::env_managed(const ::std::wstring &pathname, +__cold env_managed::env_managed(const wchar_t *pathname, const operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); - const path_to_pchar<::std::wstring> utf8(pathname); error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0)); + ::mdbx_env_openW(handle_, pathname, op.make_flags(accede), 0)); if (op.options.nested_write_transactions && !get_options().nested_write_transactions) MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); } -__cold env_managed::env_managed(const ::std::wstring &pathname, +__cold env_managed::env_managed(const wchar_t *pathname, const env_managed::create_parameters &cp, const env::operate_parameters &op, bool accede) : env_managed(create_env()) { setup(op.max_maps, op.max_readers); - const path_to_pchar<::std::wstring> utf8(pathname); set_geometry(cp.geometry); - error::success_or_throw( - ::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory), - cp.file_mode_bits)); + error::success_or_throw(::mdbx_env_openW( + handle_, pathname, op.make_flags(accede, cp.use_subdirectory), + cp.file_mode_bits)); if (op.options.nested_write_transactions && !get_options().nested_write_transactions) MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE); } + +__cold env_managed::env_managed(const ::std::wstring &pathname, + const operate_parameters &op, bool accede) + : env_managed(pathname.c_str(), op, accede) {} + +__cold env_managed::env_managed(const ::std::wstring &pathname, + const env_managed::create_parameters &cp, + const env::operate_parameters &op, bool accede) + : env_managed(pathname.c_str(), cp, op, accede) {} #endif /* Windows */ __cold env_managed::env_managed(const char *pathname, @@ -1455,6 +1378,17 @@ __cold env_managed::env_managed(const ::std::string &pathname, const env::operate_parameters &op, bool accede) : env_managed(pathname.c_str(), cp, op, accede) {} +#ifdef MDBX_STD_FILESYSTEM_PATH +__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, + const operate_parameters &op, bool accede) + : env_managed(pathname.native(), op, accede) {} + +__cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, + const env_managed::create_parameters &cp, + const env::operate_parameters &op, bool accede) + : env_managed(pathname.native(), cp, op, accede) {} +#endif /* MDBX_STD_FILESYSTEM_PATH */ + //------------------------------------------------------------------------------ txn_managed txn::start_nested() { diff --git a/src/osal.c b/src/osal.c index f2ad4ab8..8d44eb65 100644 --- a/src/osal.c +++ b/src/osal.c @@ -518,15 +518,9 @@ MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex) { /*----------------------------------------------------------------------------*/ -MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) { +MDBX_INTERNAL_FUNC int mdbx_removefile(const pathchar_t *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; - return DeleteFileW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError(); + return DeleteFileW(pathname) ? MDBX_SUCCESS : (int)GetLastError(); #else return unlink(pathname) ? errno : MDBX_SUCCESS; #endif @@ -536,34 +530,22 @@ MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) { static bool is_valid_fd(int fd) { return !(isatty(fd) < 0 && errno == EBADF); } #endif /*! Windows */ -MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname) { +MDBX_INTERNAL_FUNC int mdbx_removedirectory(const pathchar_t *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; - return RemoveDirectoryW(pathnameW) ? MDBX_SUCCESS : (int)GetLastError(); + return RemoveDirectoryW(pathname) ? MDBX_SUCCESS : (int)GetLastError(); #else return rmdir(pathname) ? errno : MDBX_SUCCESS; #endif } MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, - const MDBX_env *env, const char *pathname, + const MDBX_env *env, + const pathchar_t *pathname, mdbx_filehandle_t *fd, mdbx_mode_t unix_mode_bits) { *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; - DWORD CreationDisposition = unix_mode_bits ? OPEN_ALWAYS : OPEN_EXISTING; DWORD FlagsAndAttributes = FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; @@ -608,12 +590,12 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, break; } - *fd = CreateFileW(pathnameW, DesiredAccess, ShareMode, NULL, + *fd = CreateFileW(pathname, DesiredAccess, ShareMode, NULL, CreationDisposition, FlagsAndAttributes, NULL); if (*fd == INVALID_HANDLE_VALUE) { int err = (int)GetLastError(); if (err == ERROR_ACCESS_DENIED && purpose == MDBX_OPEN_LCK) { - if (GetFileAttributesW(pathnameW) == INVALID_FILE_ATTRIBUTES && + if (GetFileAttributesW(pathname) == INVALID_FILE_ATTRIBUTES && GetLastError() == ERROR_FILE_NOT_FOUND) err = ERROR_FILE_NOT_FOUND; } @@ -632,7 +614,7 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_COMPRESSED); if (AttributesDiff) - (void)SetFileAttributesW(pathnameW, info.dwFileAttributes ^ AttributesDiff); + (void)SetFileAttributesW(pathname, info.dwFileAttributes ^ AttributesDiff); #else int flags = unix_mode_bits ? O_CREAT : 0; @@ -1089,7 +1071,8 @@ MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset, } MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle, - const char *pathname, int err) { + const pathchar_t *pathname, + int err) { #if defined(_WIN32) || defined(_WIN64) (void)pathname; (void)err; diff --git a/src/osal.h b/src/osal.h index 049d99dc..7c5ab9bb 100644 --- a/src/osal.h +++ b/src/osal.h @@ -224,6 +224,12 @@ mdbx_syspagesize(void) { #endif } +#if defined(_WIN32) || defined(_WIN64) +typedef wchar_t pathchar_t; +#else +typedef char pathchar_t; +#endif + typedef struct mdbx_mmap_param { union { void *address; @@ -365,12 +371,13 @@ enum mdbx_openfile_purpose { }; MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose, - const MDBX_env *env, const char *pathname, + const MDBX_env *env, + const pathchar_t *pathname, mdbx_filehandle_t *fd, mdbx_mode_t unix_mode_bits); MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd); -MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname); -MDBX_INTERNAL_FUNC int mdbx_removedirectory(const char *pathname); +MDBX_INTERNAL_FUNC int mdbx_removefile(const pathchar_t *pathname); +MDBX_INTERNAL_FUNC int mdbx_removedirectory(const pathchar_t *pathname); MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd); MDBX_INTERNAL_FUNC int mdbx_lockfile(mdbx_filehandle_t fd, bool wait); @@ -398,7 +405,8 @@ MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset, size_t length, enum mdbx_syncmode_bits mode_bits); MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle, - const char *pathname, int err); + const pathchar_t *pathname, + int err); MDBX_MAYBE_UNUSED static __inline uint32_t mdbx_getpid(void) { STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));