diff --git a/mdbx.h b/mdbx.h index fdfcd04e..01b2e3b0 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1666,7 +1666,7 @@ DEFINE_ENUM_FLAG_OPERATORS(MDBX_put_flags) /** \brief Environment copy flags * \ingroup c_extra - * \see mdbx_env_copy() \see mdbx_env_copy2fd() */ + * \see mdbx_env_copy() \see mdbx_env_copy2fd() \see mdbx_txn_copy2pathname() */ typedef enum MDBX_copy_flags { MDBX_CP_DEFAULTS = 0, @@ -1691,7 +1691,11 @@ typedef enum MDBX_copy_flags { /** Enable renew/restart read transaction in case it use outdated * MVCC shapshot, otherwise the \ref MDBX_MVCC_RETARDED will be returned * \see mdbx_txn_copy2fd() \see mdbx_txn_copy2pathname() */ - MDBX_CP_RENEW_TXN = 32u + MDBX_CP_RENEW_TXN = 32u, + + /** Silently overwrite the target file, if it exists, instead of returning an error + * \see mdbx_txn_copy2pathname() \see mdbx_env_copy() */ + MDBX_CP_OVERWRITE = 64u } MDBX_copy_flags_t; DEFINE_ENUM_FLAG_OPERATORS(MDBX_copy_flags) diff --git a/src/api-copy.c b/src/api-copy.c index 8c0ffb64..bb7cda78 100644 --- a/src/api-copy.c +++ b/src/api-copy.c @@ -748,7 +748,8 @@ __cold static int copy2pathname(MDBX_txn *txn, const pathchar_t *dest_path, MDBX * We don't want the OS to cache the writes, since the source data is * already in the OS cache. */ mdbx_filehandle_t newfd = INVALID_HANDLE_VALUE; - int rc = osal_openfile(MDBX_OPEN_COPY, txn->env, dest_path, &newfd, + int rc = osal_openfile((flags & MDBX_CP_OVERWRITE) ? MDBX_OPEN_COPY_OVERWRITE : MDBX_OPEN_COPY_EXCL, txn->env, + dest_path, &newfd, #if defined(_WIN32) || defined(_WIN64) (mdbx_mode_t)-1 #else diff --git a/src/osal.c b/src/osal.c index 66d72596..b83e2776 100644 --- a/src/osal.c +++ b/src/osal.c @@ -1198,29 +1198,29 @@ MDBX_INTERNAL int osal_openfile(const enum osal_openfile_purpose purpose, const break; case MDBX_OPEN_DXB_OVERLAPPED_DIRECT: FlagsAndAttributes |= FILE_FLAG_NO_BUFFERING; - /* fall through */ - __fallthrough; + __fallthrough /* fall through */; case MDBX_OPEN_DXB_OVERLAPPED: FlagsAndAttributes |= FILE_FLAG_OVERLAPPED; - /* fall through */ - __fallthrough; + __fallthrough /* fall through */; case MDBX_OPEN_DXB_DSYNC: CreationDisposition = OPEN_EXISTING; DesiredAccess |= GENERIC_WRITE | GENERIC_READ; FlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH; break; - case MDBX_OPEN_COPY: - CreationDisposition = CREATE_NEW; - ShareMode = 0; - DesiredAccess |= GENERIC_WRITE; - if (env->ps >= globals.sys_pagesize) - FlagsAndAttributes |= FILE_FLAG_NO_BUFFERING; - break; case MDBX_OPEN_DELETE: CreationDisposition = OPEN_EXISTING; ShareMode |= FILE_SHARE_DELETE; DesiredAccess = FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE; break; + case MDBX_OPEN_COPY_EXCL: + CreationDisposition = CREATE_NEW; + __fallthrough /* fall through */; + case MDBX_OPEN_COPY_OVERWRITE: + ShareMode = 0; + DesiredAccess |= GENERIC_WRITE; + if (env->ps >= globals.sys_pagesize) + FlagsAndAttributes |= FILE_FLAG_NO_BUFFERING; + break; } *fd = CreateFileW(pathname, DesiredAccess, ShareMode, nullptr, CreationDisposition, FlagsAndAttributes, nullptr); @@ -1260,9 +1260,6 @@ MDBX_INTERNAL int osal_openfile(const enum osal_openfile_purpose purpose, const case MDBX_OPEN_DXB_LAZY: flags |= O_RDWR; break; - case MDBX_OPEN_COPY: - flags = O_CREAT | O_WRONLY | O_EXCL; - break; case MDBX_OPEN_DXB_DSYNC: flags |= O_WRONLY; #if defined(O_DSYNC) @@ -1276,9 +1273,14 @@ MDBX_INTERNAL int osal_openfile(const enum osal_openfile_purpose purpose, const case MDBX_OPEN_DELETE: flags = O_RDWR; break; + case MDBX_OPEN_COPY_EXCL: + flags |= O_EXCL; + __fallthrough /* fall through */; + case MDBX_OPEN_COPY_OVERWRITE: + flags |= O_WRONLY; } - const bool direct_nocache_for_copy = env->ps >= globals.sys_pagesize && purpose == MDBX_OPEN_COPY; + const bool direct_nocache_for_copy = env->ps >= globals.sys_pagesize && purpose >= MDBX_OPEN_COPY_EXCL; if (direct_nocache_for_copy) { #if defined(O_DIRECT) flags |= O_DIRECT; diff --git a/src/osal.h b/src/osal.h index b286f037..7622d432 100644 --- a/src/osal.h +++ b/src/osal.h @@ -446,8 +446,9 @@ enum osal_openfile_purpose { MDBX_OPEN_DXB_OVERLAPPED_DIRECT, #endif /* Windows */ MDBX_OPEN_LCK, - MDBX_OPEN_COPY, - MDBX_OPEN_DELETE + MDBX_OPEN_DELETE, + MDBX_OPEN_COPY_EXCL, + MDBX_OPEN_COPY_OVERWRITE, }; MDBX_MAYBE_UNUSED static inline bool osal_isdirsep(pathchar_t c) {