Author: ivan
Date: Thu Jun 25 17:13:05 2015
New Revision: 1687583
URL: http://svn.apache.org/r1687583
Log:
Add workaround for APR problem that apr_file_rename() performs cross-volume
renames non-atomically on Windows.
* subversion/libsvn_subr/io.c
(win32_file_rename): New. Windows specific re-implementation of
apr_file_rename().
(svn_io_file_rename): Use win32_file_rename() on Windows and keep the
code for other platforms unchanged
Modified:
subversion/trunk/subversion/libsvn_subr/io.c
Modified: subversion/trunk/subversion/libsvn_subr/io.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=1687583&r1=1687582&r2=1687583&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/io.c (original)
+++ subversion/trunk/subversion/libsvn_subr/io.c Thu Jun 25 17:13:05 2015
@@ -4024,6 +4024,24 @@ svn_io_stat(apr_finfo_t *finfo, const ch
return SVN_NO_ERROR;
}
+#if defined(WIN32)
+/* Platform specific implementation of apr_file_rename() to workaround
+ APR problems on Windows. */
+static apr_status_t
+win32_file_rename(const WCHAR *from_path_w,
+ const WCHAR *to_path_w,
+ apr_pool_t *pool)
+{
+ /* APR calls MoveFileExW() with MOVEFILE_COPY_ALLOWED, while we rely
+ * that rename is atomic operation. Call MoveFileEx directly on Windows
+ * without MOVEFILE_COPY_ALLOWED flag to workaround it.
+ */
+ if (!MoveFileExW(from_path_w, to_path_w, MOVEFILE_REPLACE_EXISTING))
+ return apr_get_os_error();
+
+ return APR_SUCCESS;
+}
+#endif
svn_error_t *
svn_io_file_rename(const char *from_path, const char *to_path,
@@ -4031,13 +4049,19 @@ svn_io_file_rename(const char *from_path
{
apr_status_t status = APR_SUCCESS;
const char *from_path_apr, *to_path_apr;
+#if defined(WIN32)
+ WCHAR *from_path_w;
+ WCHAR *to_path_w;
+#endif
SVN_ERR(cstring_from_utf8(&from_path_apr, from_path, pool));
SVN_ERR(cstring_from_utf8(&to_path_apr, to_path, pool));
- status = apr_file_rename(from_path_apr, to_path_apr, pool);
+#if defined(WIN32)
+ SVN_ERR(svn_io__utf8_to_unicode_longpath(&from_path_w, from_path_apr, pool));
+ SVN_ERR(svn_io__utf8_to_unicode_longpath(&to_path_w, to_path_apr, pool));
+ status = win32_file_rename(from_path_w, to_path_w, pool);
-#if defined(WIN32) || defined(__OS2__)
/* If the target file is read only NTFS reports EACCESS and
FAT/FAT32 reports EEXIST */
if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status))
@@ -4047,9 +4071,23 @@ svn_io_file_rename(const char *from_path
allow renaming when from_path is read only. */
SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool));
+ status = win32_file_rename(from_path_w, to_path_w, pool);
+ }
+ WIN32_RETRY_LOOP(status, win32_file_rename(from_path_w, to_path_w, pool));
+#elif defined(__OS2__)
+ /* If the target file is read only NTFS reports EACCESS and
+ FAT/FAT32 reports EEXIST */
+ if (APR_STATUS_IS_EACCES(status) || APR_STATUS_IS_EEXIST(status))
+ {
+ /* Set the destination file writable because OS/2 will not
+ allow us to rename when to_path is read-only, but will
+ allow renaming when from_path is read only. */
+ SVN_ERR(svn_io_set_file_read_write(to_path, TRUE, pool));
+
status = apr_file_rename(from_path_apr, to_path_apr, pool);
}
- WIN32_RETRY_LOOP(status, apr_file_rename(from_path_apr, to_path_apr, pool));
+#else
+ status = apr_file_rename(from_path_apr, to_path_apr, pool);
#endif /* WIN32 || __OS2__ */
if (status)