http://subversion.tigris.org/issues/show_bug.cgi?id=3641

Briefly, the issue is that when svnsync encounters the following history:
    ------------------------------------------------------------------------
    r5 | pm | 2010-05-18 17:53:46 +0100 (Tue, 18 May 2010)
    Changed paths:
       A /H (from /A:4)
       R /H/B (from /X:4)
    ------------------------------------------------------------------------
    r3 | pm | 2010-05-18 17:53:46 +0100 (Tue, 18 May 2010)
    Changed paths:
       A /A/B/C
    ------------------------------------------------------------------------
it looks for /H/B/C in the sync source when trying to replay r5.

I've attached a patch (with log msg) that seems to have some positive
effects: it causes the sync to pass (and properly add children of /X as
children of /H/B).

I'm asking for review for two reasons:

* authz.  The whole function is authz-sensitive --- its goal is to
  represent a copy as an add.  I think the patch is okay from this
  angle, but a second pair of eyes wouldn't hurt.

* assertions.  The patch asserts that svn_fs_path_change2_t->copyfrom_known 
  is TRUE.  However, the FS API used --- svn_fs_paths_changed2() ---
  does not guarantee that copyfrom_known will in fact be TRUE, and
  I haven't found a different API that does promise to provide the
  copyfrom information.  (I think the patch only needs this information
  for directory replaces.)

Testing, analysis, reviews are welcome.

Daniel
[[[
Fix issue #3641: improve svn_repos_replay2()'s handling of dir replaces.

* subversion/libsvn_repos/replay.c
  (add_subdir):
    Set SOURCE_PATH and SOURCE_ROOT correctly when recursing.

* subversion/tests/cmdline/svnsync_tests.py
  (test_bikeshed, test_list):
    TODO: Add a test for this issue.
]]]

Index: subversion/libsvn_repos/replay.c
===================================================================
--- subversion/libsvn_repos/replay.c    (revision 956596)
+++ subversion/libsvn_repos/replay.c    (working copy)
@@ -199,6 +201,8 @@ add_subdir(svn_fs_root_t *source_root,
       svn_fs_path_change2_t *change;
       svn_boolean_t readable = TRUE;
       svn_fs_dirent_t *dent;
+      const char *copyfrom_path = NULL;
+      svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
       const char *new_path;
       void *val;
 
@@ -221,6 +225,13 @@ add_subdir(svn_fs_root_t *source_root,
           /* If it's a delete, skip this entry. */
           if (change->change_kind == svn_fs_path_change_delete)
             continue;
+          else if (change->change_kind == svn_fs_path_change_replace)
+            {
+              /* XXX: can this assert fail? */
+              SVN_ERR_ASSERT(change->copyfrom_known);
+              copyfrom_path = change->copyfrom_path;
+              copyfrom_rev = change->copyfrom_rev;
+            }
         }
 
       if (authz_read_func)
@@ -232,12 +243,32 @@ add_subdir(svn_fs_root_t *source_root,
 
       if (dent->kind == svn_node_dir)
         {
+          /* XXX: add a test to svnsync_tests.py */
+          svn_fs_root_t *new_source_root;
+          const char *new_source_path;
           void *new_dir_baton;
 
-          SVN_ERR(add_subdir(source_root, target_root, editor, edit_baton,
+          if (copyfrom_path)
+            {
+              svn_fs_t *fs = svn_fs_root_fs(source_root);
+              SVN_ERR(svn_fs_revision_root(&new_source_root, fs, copyfrom_rev, 
pool));
+              new_source_path = copyfrom_path;
+            }
+          else
+            {
+              new_source_root = source_root;
+              new_source_path = svn_path_join(source_path, dent->name,
+                                              subpool);
+            }
+
+          /* XXX: authz considerations?
+           *
+           * I think not; when path_driver_cb_func() calls add_subdir(), it
+           * passes SOURCE_ROOT and SOURCE_PATH that are unreadable.
+           */
+          SVN_ERR(add_subdir(new_source_root, target_root, editor, edit_baton,
                              new_path, *dir_baton,
-                             svn_path_join(source_path, dent->name,
-                                           subpool),
+                             new_source_path,
                              authz_read_func, authz_read_baton,
                              changed_paths, subpool, &new_dir_baton));
 

Reply via email to