Index: io.c =================================================================== --- io.c (revision 7934) +++ io.c (working copy) @@ -397,7 +397,8 @@ } #endif /* ! SVN_WIN32 */ - return svn_io_file_rename (dst_tmp, dst, pool); + SVN_ERR(svn_io_file_copy (dst_tmp, dst, APR_FILE_SOURCE_PERMS, pool)); + return svn_io_remove_file(dst_tmp, pool); } @@ -1896,6 +1897,56 @@ } +svn_error_t * +svn_io_file_copy (const char *from_path, const char *to_path, + apr_fileperms_t perm, apr_pool_t *pool) +{ + apr_status_t status; + const char *from_path_apr, *to_path_apr; + + SVN_ERR (svn_path_cstring_from_utf8 (&from_path_apr, from_path, pool)); + SVN_ERR (svn_path_cstring_from_utf8 (&to_path_apr, to_path, pool)); + + status = apr_file_copy (from_path_apr, to_path_apr, perm, pool); + +#ifdef SVN_WIN32 + /* + Windows is 'aided' by a number of types of applications that + follow other applications around and open up files they have + changed for various reasons (the most intrusive are virus + scanners). So, if one of these other apps has glommed onto + our file we may get an 'access denied' error. + + This retry loop does not completely solve the problem (who + knows how long the other app is going to hold onto it for), but + goes a long way towards minimizing it. It is not an infinite + loop because there might really be an error. + */ + { + int retries = 0; + int sleep_count = 1000; + + for ( retries = 0; + APR_TO_OS_ERROR (status) == ERROR_ACCESS_DENIED && retries < 100; + ++retries ) + { + apr_sleep (sleep_count); + if (sleep_count < 128000) + sleep_count *= 2; + status = apr_file_copy (from_path_apr, to_path_apr, perm, pool); + } + } +#endif /* SVN_WIN32 */ + + if (status) + return svn_error_createf (status, NULL, + "svn_io_file_copy: can't copy '%s' to '%s'", + from_path, to_path); + else + return SVN_NO_ERROR; +} + + /* Common implementation of svn_io_dir_make and svn_io_dir_make_hidden. HIDDEN determines if the hidden attribute should be set on the newly created directory. */