Hello Subversion community!
I've run into an error: when performing 2 specially constructed updates one 
after another
within the same session, SVN fails with 

  $ ./ra-test 15
  svn_tests: E160016: Can't get entries of non-directory
  XFAIL: ra-test 15: check that there's no "Can't get entries" error

error. I believe these updates constructed that way are valid, so the problem is
somewhere in FSFS code. It's also interesting that if these updates are run
separately (e.g. by adding "if (FALSE)" to one or another), they succeed.

Originally I've discovered this when communicating with 'svnserve' but the 
problem
is also reproducible with pure FSFS with the latest trunk.

[[[
Add a reproducing test for "Can't get entries of non-directory" error.

* subversion/tests/libsvn_ra/ra-test.c
  (cant_get_entries_of_non_directory): Expect no error. Currently
   it fails with "Can't get entries of non-directory" error.
]]]
[[[
Index: subversion/tests/libsvn_ra/ra-test.c
===================================================================
--- subversion/tests/libsvn_ra/ra-test.c        (revision 1846889)
+++ subversion/tests/libsvn_ra/ra-test.c        (working copy)
@@ -1784,7 +1784,113 @@ commit_locked_file(const svn_test_opts_t *opts, ap
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+cant_get_entries_of_non_directory(const svn_test_opts_t *opts, apr_pool_t 
*pool)
+{
+  svn_ra_session_t *session;
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  const svn_ra_reporter3_t *reporter;
+  void *report_baton;
 
+  SVN_ERR(make_and_open_repos(&session,
+                              "cant_get_entries_of_non_directory", opts,
+                              pool));
+  
+  {
+    SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+                                      apr_hash_make(pool), NULL,
+                                      NULL, NULL, FALSE, pool));
+    void *root_baton;
+    void *dir_baton;
+    void *file_baton;
+
+    SVN_ERR(editor->open_root(edit_baton, 0, pool, &root_baton));
+    SVN_ERR(editor->add_directory("A", root_baton, NULL, SVN_INVALID_REVNUM,
+                                  pool, &dir_baton));
+    SVN_ERR(editor->add_file("A/mu", dir_baton, NULL, SVN_INVALID_REVNUM,
+                             pool, &file_baton));
+    SVN_ERR(editor->close_file(file_baton, NULL, pool));
+    SVN_ERR(editor->close_directory(dir_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  {
+    void *root_baton;
+    void *dir_baton;
+    const char* repos_root_url;
+    const char* A_url;
+    
+    SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, pool));
+    A_url = svn_path_url_add_component2(repos_root_url, "A", pool);
+    
+
+    SVN_ERR(editor->open_root(edit_baton, 1, pool, &root_baton));
+    SVN_ERR(editor->add_directory("B", root_baton, A_url, 1,
+                                  pool, &dir_baton));
+    SVN_ERR(editor->close_directory(dir_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  {
+    void *root_baton;
+
+    SVN_ERR(editor->open_root(edit_baton, 2, pool, &root_baton));
+    SVN_ERR(editor->delete_entry("B/mu", 2, root_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  {
+    void *root_baton;
+    void *dir_baton;
+    void *subdir_baton;
+    void *file_baton;
+
+    SVN_ERR(editor->open_root(edit_baton, 3, pool, &root_baton));
+    SVN_ERR(editor->open_directory("B", root_baton, 3, pool, &dir_baton));
+    SVN_ERR(editor->add_directory("B/mu", root_baton, NULL, SVN_INVALID_REVNUM,
+                                  pool, &subdir_baton));
+    SVN_ERR(editor->add_file("B/mu/iota", subdir_baton, NULL, 
SVN_INVALID_REVNUM,
+                             pool, &file_baton));
+    SVN_ERR(editor->close_file(file_baton, NULL, pool));
+    SVN_ERR(editor->close_directory(subdir_baton, pool));
+    SVN_ERR(editor->close_directory(dir_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  /* The following updates fail when executed in this order
+     one after another within the same session.
+     
+     When commenting out one of the blocks the test passes
+     */
+  {
+    SVN_ERR(svn_ra_do_update3(session, &reporter, &report_baton,
+                            3, "", svn_depth_infinity, TRUE, FALSE,
+                            svn_delta_default_editor(pool), NULL,
+                            pool, pool));
+    SVN_ERR(reporter->set_path(report_baton, "", 3, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->set_path(report_baton, "B", 2, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->finish_report(report_baton, pool));
+    
+    
+  }
+  {
+    SVN_ERR(svn_ra_do_update3(session, &reporter, &report_baton,
+                            4, "", svn_depth_infinity, TRUE, FALSE,
+                            svn_delta_default_editor(pool), NULL,
+                            pool, pool));
+    SVN_ERR(reporter->set_path(report_baton, "", 4, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->set_path(report_baton, "B", 3, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->finish_report(report_baton, pool));
+  }
+  return SVN_NO_ERROR;
+}
+
+
 /* The test table.  */
 
 static int max_threads = 4;
@@ -1820,6 +1926,8 @@ static struct svn_test_descriptor_t test_funcs[] =
                        "check how last change applies to empty commit"),
     SVN_TEST_OPTS_PASS(commit_locked_file,
                        "check commit editor for a locked file"),
+    SVN_TEST_OPTS_XFAIL(cant_get_entries_of_non_directory,
+                       "check that there's no \"Can't get entries\" error"),
     SVN_TEST_NULL
   };
]]]
-- 
Dmitry Pavlenko,
TMate Software,
http://subgit.com/ - git-svn bridge
Index: subversion/tests/libsvn_ra/ra-test.c
===================================================================
--- subversion/tests/libsvn_ra/ra-test.c	(revision 1846889)
+++ subversion/tests/libsvn_ra/ra-test.c	(working copy)
@@ -1784,7 +1784,113 @@ commit_locked_file(const svn_test_opts_t *opts, ap
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+cant_get_entries_of_non_directory(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_ra_session_t *session;
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  const svn_ra_reporter3_t *reporter;
+  void *report_baton;
 
+  SVN_ERR(make_and_open_repos(&session,
+                              "cant_get_entries_of_non_directory", opts,
+                              pool));
+  
+  {
+    SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton,
+                                      apr_hash_make(pool), NULL,
+                                      NULL, NULL, FALSE, pool));
+    void *root_baton;
+    void *dir_baton;
+    void *file_baton;
+
+    SVN_ERR(editor->open_root(edit_baton, 0, pool, &root_baton));
+    SVN_ERR(editor->add_directory("A", root_baton, NULL, SVN_INVALID_REVNUM,
+                                  pool, &dir_baton));
+    SVN_ERR(editor->add_file("A/mu", dir_baton, NULL, SVN_INVALID_REVNUM,
+                             pool, &file_baton));
+    SVN_ERR(editor->close_file(file_baton, NULL, pool));
+    SVN_ERR(editor->close_directory(dir_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  {
+    void *root_baton;
+    void *dir_baton;
+    const char* repos_root_url;
+    const char* A_url;
+    
+    SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, pool));
+    A_url = svn_path_url_add_component2(repos_root_url, "A", pool);
+    
+
+    SVN_ERR(editor->open_root(edit_baton, 1, pool, &root_baton));
+    SVN_ERR(editor->add_directory("B", root_baton, A_url, 1,
+                                  pool, &dir_baton));
+    SVN_ERR(editor->close_directory(dir_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  {
+    void *root_baton;
+
+    SVN_ERR(editor->open_root(edit_baton, 2, pool, &root_baton));
+    SVN_ERR(editor->delete_entry("B/mu", 2, root_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  {
+    void *root_baton;
+    void *dir_baton;
+    void *subdir_baton;
+    void *file_baton;
+
+    SVN_ERR(editor->open_root(edit_baton, 3, pool, &root_baton));
+    SVN_ERR(editor->open_directory("B", root_baton, 3, pool, &dir_baton));
+    SVN_ERR(editor->add_directory("B/mu", root_baton, NULL, SVN_INVALID_REVNUM,
+                                  pool, &subdir_baton));
+    SVN_ERR(editor->add_file("B/mu/iota", subdir_baton, NULL, SVN_INVALID_REVNUM,
+                             pool, &file_baton));
+    SVN_ERR(editor->close_file(file_baton, NULL, pool));
+    SVN_ERR(editor->close_directory(subdir_baton, pool));
+    SVN_ERR(editor->close_directory(dir_baton, pool));
+    SVN_ERR(editor->close_directory(root_baton, pool));
+    SVN_ERR(editor->close_edit(edit_baton, pool));
+  }
+  /* The following updates fail when executed in this order
+     one after another within the same session.
+     
+     When commenting out one of the blocks the test passes
+     */
+  {
+    SVN_ERR(svn_ra_do_update3(session, &reporter, &report_baton,
+                            3, "", svn_depth_infinity, TRUE, FALSE,
+                            svn_delta_default_editor(pool), NULL,
+                            pool, pool));
+    SVN_ERR(reporter->set_path(report_baton, "", 3, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->set_path(report_baton, "B", 2, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->finish_report(report_baton, pool));
+    
+    
+  }
+  {
+    SVN_ERR(svn_ra_do_update3(session, &reporter, &report_baton,
+                            4, "", svn_depth_infinity, TRUE, FALSE,
+                            svn_delta_default_editor(pool), NULL,
+                            pool, pool));
+    SVN_ERR(reporter->set_path(report_baton, "", 4, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->set_path(report_baton, "B", 3, svn_depth_infinity, FALSE,
+                               NULL, pool));
+    SVN_ERR(reporter->finish_report(report_baton, pool));
+  }
+  return SVN_NO_ERROR;
+}
+
+
 /* The test table.  */
 
 static int max_threads = 4;
@@ -1820,6 +1926,8 @@ static struct svn_test_descriptor_t test_funcs[] =
                        "check how last change applies to empty commit"),
     SVN_TEST_OPTS_PASS(commit_locked_file,
                        "check commit editor for a locked file"),
+    SVN_TEST_OPTS_XFAIL(cant_get_entries_of_non_directory,
+                       "check that there's no \"Can't get entries\" error"),
     SVN_TEST_NULL
   };
 

Reply via email to