You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by iv...@apache.org on 2015/09/03 15:24:04 UTC

svn commit: r1701017 - in /subversion/trunk/subversion: include/ libsvn_client/ libsvn_fs_fs/ libsvn_fs_x/ libsvn_subr/ libsvn_wc/ tests/libsvn_subr/

Author: ivan
Date: Thu Sep  3 13:24:03 2015
New Revision: 1701017

URL: http://svn.apache.org/r1701017
Log:
Implement svn_io_file_rename2() with FLUSH_TO_DISK flag to require OS to
wait until rename operation is actually written to disk. Discussed in thread
"svn commit: r1682265 - /subversion/trunk/subversion/libsvn_fs_fs/util.c" on
dev@s.a.o [1]

[1] http://svn.haxx.se/dev/archive-2015-05/0211.shtml

* subversion/include/svn_io.h
  (svn_io_file_rename2): New function declaration.
  (svn_io_file_rename): Deprecate.

* subversion/libsvn_subr/io.c
  (win32_file_rename): Use MOVEFILE_WRITE_THROUGH flag in call to
   MoveFileExW if FLUSH_TO_DISK is non-zero.
  (svn_io_file_rename2): Revv from svn_io_file_rename(). Add FLUSH_TO_DISK
   parameter and perform flush to disk operation depending on the platform:
   use MoveFileEx flag on Windows, fsync() target directory on POSIX and 
   fsync() target file on all other platforms. This logic mostly copied 
   from svn_fs_fs__move_into_place().
  (svn_io_copy_link, svn_io_copy_file, svn_io_write_atomic,
   svn_io_write_version_file): Use svn_io_rename2() with 
   FLUSH_TO_DISK=FALSE instead of svn_io_rename().

* subversion/tests/libsvn_subr/io-test.c
  (test_file_rename2): Simple tests for svn_io_file_rename2().
  (test_funcs): Add test_file_rename2.

* subversion/libsvn_subr/deprecated.c
  (svn_io_file_rename): Call svn_io_file_rename2() with FLUSH_TO_DISK=FALSE.

* subversion/libsvn_client/copy.c
* subversion/libsvn_client/export.c
* subversion/libsvn_client/externals.c
* subversion/libsvn_fs_fs/fs_fs.c
* subversion/libsvn_fs_fs/lock.c
* subversion/libsvn_fs_fs/transaction.c
* subversion/libsvn_fs_fs/util.c
* subversion/libsvn_fs_x/lock.c
* subversion/libsvn_fs_x/transaction.c
* subversion/libsvn_fs_x/util.c
* subversion/libsvn_subr/config_auth.c
* subversion/libsvn_subr/stream.c
* subversion/libsvn_subr/subst.c
* subversion/libsvn_wc/copy.c
* subversion/libsvn_wc/node.c
* subversion/libsvn_wc/upgrade.c
* subversion/libsvn_wc/wc_db_pristine.c
* subversion/libsvn_wc/workqueue.c
  (*): Use svn_io_file_rename2() with FLUSH_TO_DISK=FALSE instead of
  svn_io_file_rename().

Modified:
    subversion/trunk/subversion/include/svn_io.h
    subversion/trunk/subversion/libsvn_client/copy.c
    subversion/trunk/subversion/libsvn_client/export.c
    subversion/trunk/subversion/libsvn_client/externals.c
    subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c
    subversion/trunk/subversion/libsvn_fs_fs/lock.c
    subversion/trunk/subversion/libsvn_fs_fs/transaction.c
    subversion/trunk/subversion/libsvn_fs_fs/util.c
    subversion/trunk/subversion/libsvn_fs_x/lock.c
    subversion/trunk/subversion/libsvn_fs_x/transaction.c
    subversion/trunk/subversion/libsvn_fs_x/util.c
    subversion/trunk/subversion/libsvn_subr/config_auth.c
    subversion/trunk/subversion/libsvn_subr/deprecated.c
    subversion/trunk/subversion/libsvn_subr/io.c
    subversion/trunk/subversion/libsvn_subr/stream.c
    subversion/trunk/subversion/libsvn_subr/subst.c
    subversion/trunk/subversion/libsvn_wc/copy.c
    subversion/trunk/subversion/libsvn_wc/node.c
    subversion/trunk/subversion/libsvn_wc/upgrade.c
    subversion/trunk/subversion/libsvn_wc/wc_db_pristine.c
    subversion/trunk/subversion/libsvn_wc/workqueue.c
    subversion/trunk/subversion/tests/libsvn_subr/io-test.c

Modified: subversion/trunk/subversion/include/svn_io.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_io.h?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_io.h (original)
+++ subversion/trunk/subversion/include/svn_io.h Thu Sep  3 13:24:03 2015
@@ -2356,9 +2356,26 @@ svn_io_stat(apr_finfo_t *finfo,
  * @a from_path to a new path @a to_path within the same filesystem.
  * In some cases, an existing node at @a to_path will be overwritten.
  *
- * A wrapper for apr_file_rename().  @a from_path and @a to_path are
- * utf8-encoded.
+ * @a from_path and @a to_path are utf8-encoded.  If @a flush_to_disk
+ * is non-zero, do not return until the node has actually been moved on
+ * the disk.
+ *
+ * @note The flush to disk operation can be very expensive on systems
+ * that implement flushing on all IO layers, like Windows. Please use
+ * @a flush_to_disk flag only for critical data.
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_io_file_rename2(const char *from_path, const char *to_path,
+                    svn_boolean_t flush_to_disk, apr_pool_t *pool);
+
+/** Similar to svn_io_file_rename2(), but with @a flush_to_disk set
+ * to @c FALSE.
+ *
+ * @deprecated Provided for backward compatibility with the 1.9 API
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_io_file_rename(const char *from_path,
                    const char *to_path,

Modified: subversion/trunk/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/copy.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/copy.c (original)
+++ subversion/trunk/subversion/libsvn_client/copy.c Thu Sep  3 13:24:03 2015
@@ -2433,7 +2433,7 @@ repos_to_wc_copy_single(svn_boolean_t *t
                                                        pool));
 
           /* Move the temporary disk tree into place. */
-          SVN_ERR(svn_io_file_rename(tmp_abspath, dst_abspath, pool));
+          SVN_ERR(svn_io_file_rename2(tmp_abspath, dst_abspath, FALSE, pool));
         }
       else
         {

Modified: subversion/trunk/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/export.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/export.c (original)
+++ subversion/trunk/subversion/libsvn_client/export.c Thu Sep  3 13:24:03 2015
@@ -432,7 +432,7 @@ export_node(void *baton,
                                                              scratch_pool));
 
   /* Now that dst_tmp contains the translated data, do the atomic rename. */
-  SVN_ERR(svn_io_file_rename(dst_tmp, to_abspath, scratch_pool));
+  SVN_ERR(svn_io_file_rename2(dst_tmp, to_abspath, FALSE, scratch_pool));
 
   if (eib->notify_func)
     {
@@ -816,7 +816,7 @@ close_file(void *file_baton,
 
   if ((! fb->eol_style_val) && (! fb->keywords_val) && (! fb->special))
     {
-      SVN_ERR(svn_io_file_rename(fb->tmppath, fb->path, pool));
+      SVN_ERR(svn_io_file_rename2(fb->tmppath, fb->path, FALSE, pool));
     }
   else
     {
@@ -1035,7 +1035,7 @@ add_file_ev2(void *baton,
                                eb->cancel_baton, scratch_pool));
 
       /* Move the file into place. */
-      SVN_ERR(svn_io_file_rename(tmppath, full_path, scratch_pool));
+      SVN_ERR(svn_io_file_rename2(tmppath, full_path, FALSE, scratch_pool));
     }
 
   if (executable_val)

Modified: subversion/trunk/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/externals.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/externals.c (original)
+++ subversion/trunk/subversion/libsvn_client/externals.c Thu Sep  3 13:24:03 2015
@@ -120,7 +120,7 @@ relegate_dir_external(svn_wc_context_t *
 
           /* And if it is no longer a working copy, we should just rename
              it */
-          err = svn_io_file_rename(local_abspath, new_path, scratch_pool);
+          err = svn_io_file_rename2(local_abspath, new_path, FALSE, scratch_pool);
         }
 
       /* ### TODO: We should notify the user about the rename */

Modified: subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/fs_fs.c Thu Sep  3 13:24:03 2015
@@ -2010,7 +2010,7 @@ set_node_origins_for_file(svn_fs_t *fs,
   SVN_ERR(svn_stream_close(stream));
 
   /* Rename the temp file as the real destination */
-  return svn_io_file_rename(path_tmp, node_origins_path, pool);
+  return svn_io_file_rename2(path_tmp, node_origins_path, FALSE, pool);
 }
 
 

Modified: subversion/trunk/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/lock.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/lock.c Thu Sep  3 13:24:03 2015
@@ -230,7 +230,7 @@ write_digest_file(apr_hash_t *children,
     }
 
   SVN_ERR(svn_stream_close(stream));
-  SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool));
+  SVN_ERR(svn_io_file_rename2(tmp_path, digest_path, FALSE, pool));
   SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, pool));
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/transaction.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/transaction.c Thu Sep  3 13:24:03 2015
@@ -1167,7 +1167,7 @@ set_txn_proplist(svn_fs_t *fs,
   SVN_ERR(svn_hash_write2(props, tmp_stream, SVN_HASH_TERMINATOR, pool));
   SVN_ERR(svn_stream_close(tmp_stream));
 
-  SVN_ERR(svn_io_file_rename(tmp_path, final_path, pool));
+  SVN_ERR(svn_io_file_rename2(tmp_path, final_path, FALSE, pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/libsvn_fs_fs/util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/util.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/util.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/util.c Thu Sep  3 13:24:03 2015
@@ -643,7 +643,7 @@ svn_fs_fs__move_into_place(const char *o
 
   /* APR will *not* error out on Win32 if this requires a copy instead of
      of a move. */
-  SVN_ERR(svn_io_file_rename(old_filename, new_filename, pool));
+  SVN_ERR(svn_io_file_rename2(old_filename, new_filename, FALSE, pool));
 
   /* Flush the target of the copy to disk. */
   SVN_ERR(svn_io_file_open(&file, new_filename, APR_WRITE,
@@ -657,7 +657,7 @@ svn_fs_fs__move_into_place(const char *o
   SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool));
 
   /* Move the file into place. */
-  err = svn_io_file_rename(old_filename, new_filename, pool);
+  err = svn_io_file_rename2(old_filename, new_filename, FALSE, pool);
   if (err && APR_STATUS_IS_EXDEV(err->apr_err))
     {
       /* Can't rename across devices; fall back to copying. */

Modified: subversion/trunk/subversion/libsvn_fs_x/lock.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/lock.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/lock.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/lock.c Thu Sep  3 13:24:03 2015
@@ -244,7 +244,7 @@ write_digest_file(apr_hash_t *children,
     }
 
   SVN_ERR(svn_stream_close(stream));
-  SVN_ERR(svn_io_file_rename(tmp_path, digest_path, scratch_pool));
+  SVN_ERR(svn_io_file_rename2(tmp_path, digest_path, FALSE, scratch_pool));
   SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, scratch_pool));
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/transaction.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/transaction.c Thu Sep  3 13:24:03 2015
@@ -1223,7 +1223,8 @@ bump_txn_key(svn_fs_t *fs,
 
   /* Increment the key and add a trailing \n to the string so the
      txn-current file has a newline in it. */
-  SVN_ERR(svn_io_file_rename(txn_next_path, txn_current_path, scratch_pool));
+  SVN_ERR(svn_io_file_rename2(txn_next_path, txn_current_path, FALSE,
+                              scratch_pool));
   SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, txn_current_path,
                                          scratch_pool));
 
@@ -1412,10 +1413,11 @@ set_txn_proplist(svn_fs_t *fs,
   SVN_ERR(svn_stream_close(stream));
 
   /* Replace the old file with the new one. */
-  SVN_ERR(svn_io_file_rename(temp_path,
-                             svn_fs_x__path_txn_props(fs, txn_id,
-                                                      scratch_pool),
-                             scratch_pool));
+  SVN_ERR(svn_io_file_rename2(temp_path,
+                              svn_fs_x__path_txn_props(fs, txn_id,
+                                                       scratch_pool),
+                              FALSE,
+                              scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -3413,9 +3415,10 @@ get_writable_final_rev(apr_file_t **file
 
   /* Move the proto-rev file to its final location as revision data file.
      After that, we don't need to protect it anymore and can unlock it. */
-  SVN_ERR(svn_error_compose_create(svn_io_file_rename(proto_rev_filename,
-                                                      final_rev_filename,
-                                                      scratch_pool),
+  SVN_ERR(svn_error_compose_create(svn_io_file_rename2(proto_rev_filename,
+                                                       final_rev_filename,
+                                                       FALSE,
+                                                       scratch_pool),
                                    unlock_proto_rev(fs, txn_id, lockcookie,
                                                     scratch_pool)));
   SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, final_rev_filename,
@@ -3493,8 +3496,8 @@ bump_ids(void *baton,
 
   /* Make the revision visible to all processes and threads. */
   current_filename = svn_fs_x__path_current(b->fs, scratch_pool);
-  SVN_ERR(svn_io_file_rename(svn_fs_x__path_next(b->fs, scratch_pool),
-                             current_filename, scratch_pool));
+  SVN_ERR(svn_io_file_rename2(svn_fs_x__path_next(b->fs, scratch_pool),
+                              current_filename, FALSE, scratch_pool));
   SVN_ERR(svn_fs_x__batch_fsync_new_path(b->batch, current_filename,
                                          scratch_pool));
 

Modified: subversion/trunk/subversion/libsvn_fs_x/util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/util.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/util.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/util.c Thu Sep  3 13:24:03 2015
@@ -734,7 +734,7 @@ svn_fs_x__move_into_place(const char *ol
   SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, scratch_pool));
 
   /* Move the file into place. */
-  err = svn_io_file_rename(old_filename, new_filename, scratch_pool);
+  err = svn_io_file_rename2(old_filename, new_filename, FALSE, scratch_pool);
   if (err && APR_STATUS_IS_EXDEV(err->apr_err))
     {
       apr_file_t *file;

Modified: subversion/trunk/subversion/libsvn_subr/config_auth.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/config_auth.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/config_auth.c (original)
+++ subversion/trunk/subversion/libsvn_subr/config_auth.c Thu Sep  3 13:24:03 2015
@@ -144,7 +144,7 @@ svn_config_write_auth_data(apr_hash_t *h
             apr_psprintf(pool, _("Error writing hash to '%s'"),
                          svn_dirent_local_style(auth_path, pool)));
   SVN_ERR(svn_stream_close(stream));
-  SVN_ERR(svn_io_file_rename(tmp_path, auth_path, pool));
+  SVN_ERR(svn_io_file_rename2(tmp_path, auth_path, FALSE, pool));
 
   /* To be nice, remove the realmstring from the hash again, just in
      case the caller wants their hash unchanged.

Modified: subversion/trunk/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/deprecated.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_subr/deprecated.c Thu Sep  3 13:24:03 2015
@@ -889,6 +889,14 @@ svn_io_stat_dirent(const svn_io_dirent2_
                                 scratch_pool));
 }
 
+svn_error_t *
+svn_io_file_rename(const char *from_path, const char *to_path,
+                   apr_pool_t *pool)
+{
+  return svn_error_trace(svn_io_file_rename2(from_path, to_path,
+                                             FALSE, pool));
+}
+
 /*** From constructors.c ***/
 svn_log_changed_path_t *
 svn_log_changed_path_dup(const svn_log_changed_path_t *changed_path,

Modified: subversion/trunk/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/io.c (original)
+++ subversion/trunk/subversion/libsvn_subr/io.c Thu Sep  3 13:24:03 2015
@@ -750,7 +750,7 @@ svn_io_copy_link(const char *src,
                                     ".tmp", pool));
 
   /* Move the tmp-link to link. */
-  return svn_io_file_rename(dst_tmp, dst, pool);
+  return svn_io_file_rename2(dst_tmp, dst, FALSE, pool);
 
 #else
   return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
@@ -919,7 +919,7 @@ svn_io_copy_file(const char *src,
   if (copy_perms)
     SVN_ERR(svn_io_copy_perms(src, dst_tmp, pool));
 
-  return svn_error_trace(svn_io_file_rename(dst_tmp, dst, pool));
+  return svn_error_trace(svn_io_file_rename2(dst_tmp, dst, FALSE, pool));
 }
 
 #if !defined(WIN32) && !defined(__OS2__)
@@ -1504,7 +1504,7 @@ reown_file(const char *path,
   SVN_ERR(svn_io_open_unique_file3(NULL, &unique_name,
                                    svn_dirent_dirname(path, pool),
                                    svn_io_file_del_none, pool, pool));
-  SVN_ERR(svn_io_file_rename(path, unique_name, pool));
+  SVN_ERR(svn_io_file_rename2(path, unique_name, FALSE, pool));
   SVN_ERR(svn_io_copy_file(unique_name, path, TRUE, pool));
   return svn_error_trace(svn_io_remove_file2(unique_name, FALSE, pool));
 }
@@ -3874,7 +3874,7 @@ svn_io_write_atomic(const char *final_pa
     err = svn_io_copy_perms(copy_perms_path, tmp_path, scratch_pool);
 
   if (!err)
-    err = svn_io_file_rename(tmp_path, final_path, scratch_pool);
+    err = svn_io_file_rename2(tmp_path, final_path, FALSE, scratch_pool);
 
   if (err)
     {
@@ -4030,13 +4030,23 @@ svn_io_stat(apr_finfo_t *finfo, const ch
 static apr_status_t
 win32_file_rename(const WCHAR *from_path_w,
                   const WCHAR *to_path_w,
+                  svn_boolean_t flush_to_disk,
                   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))
+
+  DWORD flags = MOVEFILE_REPLACE_EXISTING;
+
+  if (flush_to_disk)
+    {
+      /* Do not return until the file has actually been moved on the disk. */
+      flags |= MOVEFILE_WRITE_THROUGH;
+    }
+
+  if (!MoveFileExW(from_path_w, to_path_w, flags))
       return apr_get_os_error();
 
   return APR_SUCCESS;
@@ -4044,8 +4054,8 @@ win32_file_rename(const WCHAR *from_path
 #endif
 
 svn_error_t *
-svn_io_file_rename(const char *from_path, const char *to_path,
-                   apr_pool_t *pool)
+svn_io_file_rename2(const char *from_path, const char *to_path,
+                    svn_boolean_t flush_to_disk, apr_pool_t *pool)
 {
   apr_status_t status = APR_SUCCESS;
   const char *from_path_apr, *to_path_apr;
@@ -4060,7 +4070,7 @@ svn_io_file_rename(const char *from_path
 #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);
+  status = win32_file_rename(from_path_w, to_path_w, flush_to_disk, pool);
 
   /* If the target file is read only NTFS reports EACCESS and
      FAT/FAT32 reports EEXIST */
@@ -4071,9 +4081,10 @@ 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);
+      status = win32_file_rename(from_path_w, to_path_w, flush_to_disk, pool);
     }
-  WIN32_RETRY_LOOP(status, win32_file_rename(from_path_w, to_path_w, pool));
+  WIN32_RETRY_LOOP(status, win32_file_rename(from_path_w, to_path_w,
+                                             flush_to_disk, pool));
 #elif defined(__OS2__)
   status = apr_file_rename(from_path_apr, to_path_apr, pool);
   /* If the target file is read only NTFS reports EACCESS and
@@ -4096,6 +4107,34 @@ svn_io_file_rename(const char *from_path
                               svn_dirent_local_style(from_path, pool),
                               svn_dirent_local_style(to_path, pool));
 
+#if defined(SVN_ON_POSIX)
+  if (flush_to_disk)
+    {
+      /* On POSIX, the file name is stored in the file's directory entry.
+         Hence, we need to fsync() that directory as well.
+         On other operating systems, we'd only be asking for trouble
+         by trying to open and fsync a directory. */
+      const char *dirname;
+      apr_file_t *file;
+
+      dirname = svn_dirent_dirname(to_path, pool);
+      SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
+                               pool));
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
+    }
+#elif !defined(WIN32)
+  /* Flush the target of the rename to disk. */
+  if (flush_to_disk)
+    {
+      apr_file_t *file;
+      SVN_ERR(svn_io_file_open(&file, to_path, APR_WRITE,
+                               APR_OS_DEFAULT, pool));
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
+    }
+#endif
+
   return SVN_NO_ERROR;
 }
 
@@ -4104,8 +4143,8 @@ svn_error_t *
 svn_io_file_move(const char *from_path, const char *to_path,
                  apr_pool_t *pool)
 {
-  svn_error_t *err = svn_error_trace(svn_io_file_rename(from_path, to_path,
-                                                        pool));
+  svn_error_t *err = svn_error_trace(svn_io_file_rename2(from_path, to_path,
+                                                         FALSE, pool));
 
   if (err && APR_STATUS_IS_EXDEV(err->apr_err))
     {
@@ -4545,7 +4584,7 @@ svn_io_write_version_file(const char *pa
 #endif /* WIN32 || __OS2__ */
 
   /* rename the temp file as the real destination */
-  SVN_ERR(svn_io_file_rename(path_tmp, path, pool));
+  SVN_ERR(svn_io_file_rename2(path_tmp, path, FALSE, pool));
 
   /* And finally remove the perms to make it read only */
   return svn_io_set_file_read_only(path, FALSE, pool);

Modified: subversion/trunk/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/stream.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/stream.c (original)
+++ subversion/trunk/subversion/libsvn_subr/stream.c Thu Sep  3 13:24:03 2015
@@ -2410,7 +2410,7 @@ svn_stream__install_stream(svn_stream_t
     }
 #endif
 
-  err = svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool);
+  err = svn_io_file_rename2(ib->tmp_path, final_abspath, FALSE, scratch_pool);
 
   /* A missing directory is too common to not cover here. */
   if (make_parents && err && APR_STATUS_IS_ENOENT(err->apr_err))
@@ -2428,7 +2428,7 @@ svn_stream__install_stream(svn_stream_t
         /* We could create a directory: retry install */
         svn_error_clear(err);
 
-      SVN_ERR(svn_io_file_rename(ib->tmp_path, final_abspath, scratch_pool));
+      SVN_ERR(svn_io_file_rename2(ib->tmp_path, final_abspath, FALSE, scratch_pool));
     }
   else
     SVN_ERR(err);

Modified: subversion/trunk/subversion/libsvn_subr/subst.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/subst.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/subst.c (original)
+++ subversion/trunk/subversion/libsvn_subr/subst.c Thu Sep  3 13:24:03 2015
@@ -1649,7 +1649,7 @@ detranslate_special_file(const char *src
                            cancel_func, cancel_baton, scratch_pool));
 
   /* Do the atomic rename from our temporary location. */
-  return svn_error_trace(svn_io_file_rename(dst_tmp, dst, scratch_pool));
+  return svn_error_trace(svn_io_file_rename2(dst_tmp, dst, FALSE, scratch_pool));
 }
 
 /* Creates a special file DST from the "normal form" located in SOURCE.
@@ -1733,7 +1733,7 @@ create_special_file_from_stream(svn_stre
     }
 
   /* Do the atomic rename from our temporary location. */
-  return svn_error_trace(svn_io_file_rename(dst_tmp, dst, pool));
+  return svn_error_trace(svn_io_file_rename2(dst_tmp, dst, FALSE, pool));
 }
 
 
@@ -1824,7 +1824,7 @@ svn_subst_copy_and_translate4(const char
     }
 
   /* Now that dst_tmp contains the translated data, do the atomic rename. */
-  SVN_ERR(svn_io_file_rename(dst_tmp, dst, pool));
+  SVN_ERR(svn_io_file_rename2(dst_tmp, dst, FALSE, pool));
 
   /* Preserve the source file's permission bits. */
   SVN_ERR(svn_io_copy_perms(src, dst, pool));

Modified: subversion/trunk/subversion/libsvn_wc/copy.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/copy.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/copy.c (original)
+++ subversion/trunk/subversion/libsvn_wc/copy.c Thu Sep  3 13:24:03 2015
@@ -1104,8 +1104,8 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
     {
       svn_error_t *err;
 
-      err = svn_error_trace(svn_io_file_rename(src_abspath, dst_abspath,
-                                               scratch_pool));
+      err = svn_error_trace(svn_io_file_rename2(src_abspath, dst_abspath,
+                                                FALSE, scratch_pool));
 
       /* Let's try if we can keep wc.db consistent even when the move
          fails. Deleting the target is a wc.db only operation, while

Modified: subversion/trunk/subversion/libsvn_wc/node.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/node.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/node.c (original)
+++ subversion/trunk/subversion/libsvn_wc/node.c Thu Sep  3 13:24:03 2015
@@ -906,7 +906,8 @@ svn_wc__rename_wc(svn_wc_context_t *wc_c
     {
       SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool));
 
-      SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool));
+      SVN_ERR(svn_io_file_rename2(from_abspath, dst_abspath, FALSE,
+                                  scratch_pool));
     }
   else
     return svn_error_createf(

Modified: subversion/trunk/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/upgrade.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/trunk/subversion/libsvn_wc/upgrade.c Thu Sep  3 13:24:03 2015
@@ -1434,7 +1434,7 @@ rename_pristine_file(void *baton,
       const char *new_abspath
         = apr_pstrcat(pool, abspath, PRISTINE_STORAGE_EXT, SVN_VA_NULL);
 
-      SVN_ERR(svn_io_file_rename(abspath, new_abspath, pool));
+      SVN_ERR(svn_io_file_rename2(abspath, new_abspath, FALSE, pool));
     }
   return SVN_NO_ERROR;
 }
@@ -2513,7 +2513,7 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
   /* Renaming the db file is what makes the pre-wcng into a wcng */
   db_from = svn_wc__adm_child(data.root_abspath, SDB_FILE, scratch_pool);
   db_to = svn_wc__adm_child(local_abspath, SDB_FILE, scratch_pool);
-  SVN_ERR(svn_io_file_rename(db_from, db_to, scratch_pool));
+  SVN_ERR(svn_io_file_rename2(db_from, db_to, FALSE, scratch_pool));
 
   /* Now we have a working wcng, tidy up the droppings */
   SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, FALSE, FALSE,

Modified: subversion/trunk/subversion/libsvn_wc/wc_db_pristine.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db_pristine.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db_pristine.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db_pristine.c Thu Sep  3 13:24:03 2015
@@ -569,7 +569,8 @@ maybe_transfer_one_pristine(svn_wc__db_w
 
   /* Move the file to its target location.  (If it is already there, it is
    * an orphan file and it doesn't matter if we overwrite it.) */
-  err = svn_io_file_rename(tmp_abspath, pristine_abspath, scratch_pool);
+  err = svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE,
+                            scratch_pool);
 
   /* Maybe the directory doesn't exist yet? */
   if (err && APR_STATUS_IS_ENOENT(err->apr_err))
@@ -587,7 +588,8 @@ maybe_transfer_one_pristine(svn_wc__db_w
         /* We could create a directory: retry install */
         svn_error_clear(err);
 
-      SVN_ERR(svn_io_file_rename(tmp_abspath, pristine_abspath, scratch_pool));
+      SVN_ERR(svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE,
+                                  scratch_pool));
     }
   else
     SVN_ERR(err);
@@ -709,7 +711,7 @@ remove_file(const char *file_abspath,
   SVN_ERR(svn_io_open_unique_file3(NULL, &temp_abspath, temp_dir_abspath,
                                    svn_io_file_del_none,
                                    scratch_pool, scratch_pool));
-  err = svn_io_file_rename(file_abspath, temp_abspath, scratch_pool);
+  err = svn_io_file_rename2(file_abspath, temp_abspath, FALSE, scratch_pool);
   if (err && ignore_enoent && APR_STATUS_IS_ENOENT(err->apr_err))
     svn_error_clear(err);
   else

Modified: subversion/trunk/subversion/libsvn_wc/workqueue.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/workqueue.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/workqueue.c (original)
+++ subversion/trunk/subversion/libsvn_wc/workqueue.c Thu Sep  3 13:24:03 2015
@@ -257,7 +257,8 @@ install_committed_file(svn_boolean_t *ov
 
   if (! same)
     {
-      SVN_ERR(svn_io_file_rename(tmp_wfile, file_abspath, scratch_pool));
+      SVN_ERR(svn_io_file_rename2(tmp_wfile, file_abspath, FALSE,
+                                  scratch_pool));
       *overwrote_working = TRUE;
     }
 
@@ -1127,9 +1128,9 @@ run_prej_install(work_item_baton_t *wqb,
                                   scratch_pool, scratch_pool));
 
   /* ... and atomically move it into place.  */
-  SVN_ERR(svn_io_file_rename(tmp_prejfile_abspath,
-                             prejfile_abspath,
-                             scratch_pool));
+  SVN_ERR(svn_io_file_rename2(tmp_prejfile_abspath,
+                              prejfile_abspath, FALSE,
+                              scratch_pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/tests/libsvn_subr/io-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/io-test.c?rev=1701017&r1=1701016&r2=1701017&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/io-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/io-test.c Thu Sep  3 13:24:03 2015
@@ -823,6 +823,64 @@ test_file_size_get(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_file_rename2(apr_pool_t *pool)
+{
+  const char *tmp_dir;
+  const char *foo_path;
+  const char *bar_path;
+  svn_stringbuf_t *actual_content;
+  svn_node_kind_t actual_kind;
+
+  /* Create an empty directory. */
+  SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_file_rename2", pool));
+  SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool));
+  SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool));
+  svn_test_add_dir_cleanup(tmp_dir);
+
+  foo_path = svn_dirent_join(tmp_dir, "foo", pool);
+  bar_path = svn_dirent_join(tmp_dir, "bar", pool);
+
+  /* Test 1: Simple file rename. */
+  SVN_ERR(svn_io_file_create(foo_path, "file content", pool));
+
+  SVN_ERR(svn_io_file_rename2(foo_path, bar_path, FALSE, pool));
+
+  SVN_ERR(svn_stringbuf_from_file2(&actual_content, bar_path, pool));
+  SVN_TEST_STRING_ASSERT(actual_content->data, "file content");
+
+  SVN_ERR(svn_io_check_path(foo_path, &actual_kind, pool));
+  SVN_TEST_ASSERT(actual_kind == svn_node_none);
+  SVN_ERR(svn_io_remove_file2(bar_path, FALSE, pool));
+
+  /* Test 2: Rename file with flush_to_disk flag. */
+  SVN_ERR(svn_io_file_create(foo_path, "file content", pool));
+
+  SVN_ERR(svn_io_file_rename2(foo_path, bar_path, TRUE, pool));
+
+  SVN_ERR(svn_stringbuf_from_file2(&actual_content, bar_path, pool));
+  SVN_TEST_STRING_ASSERT(actual_content->data, "file content");
+  SVN_ERR(svn_io_check_path(foo_path, &actual_kind, pool));
+  SVN_TEST_ASSERT(actual_kind == svn_node_none);
+
+  SVN_ERR(svn_io_remove_file2(bar_path, FALSE, pool));
+
+  /* Test 3: Rename file over existing read-only file. */
+  SVN_ERR(svn_io_file_create(foo_path, "file content", pool));
+  SVN_ERR(svn_io_file_create(bar_path, "bar content", pool));
+  SVN_ERR(svn_io_set_file_read_only(bar_path, FALSE, pool));
+
+  SVN_ERR(svn_io_file_rename2(foo_path, bar_path, FALSE, pool));
+
+  SVN_ERR(svn_stringbuf_from_file2(&actual_content, bar_path, pool));
+  SVN_TEST_STRING_ASSERT(actual_content->data, "file content");
+  SVN_ERR(svn_io_check_path(foo_path, &actual_kind, pool));
+  SVN_TEST_ASSERT(actual_kind == svn_node_none);
+  SVN_ERR(svn_io_remove_file2(bar_path, FALSE, pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* The test table.  */
 
 static int max_threads = 3;
@@ -848,6 +906,8 @@ static struct svn_test_descriptor_t test
                    "test svn_stream__install_stream to long path"),
     SVN_TEST_PASS2(test_file_size_get,
                    "test svn_io_file_size_get"),
+    SVN_TEST_PASS2(test_file_rename2,
+                   "test svn_io_file_rename2"),
     SVN_TEST_NULL
   };