Index: subversion/libsvn_subr/io.c =================================================================== --- subversion/libsvn_subr/io.c (revision 1687052) +++ subversion/libsvn_subr/io.c (working copy) @@ -4024,7 +4024,25 @@ return SVN_NO_ERROR; } +#if defined(WIN32) +/* Compatibility wrapper around 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. Use 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, apr_pool_t *pool) @@ -4031,13 +4049,19 @@ { 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 @@ 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)