You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2018/11/07 12:30:11 UTC

svn commit: r1846002 [34/44] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ build/generator/util/ build/win32/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contr...

Modified: subversion/branches/ra-git/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnrdump/load_editor.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/ra-git/subversion/svnrdump/load_editor.c Wed Nov  7 12:30:06 2018
@@ -45,15 +45,58 @@
 
 
 /**
+ * A vtable that is driven by get_dumpstream_loader().
+ */
+typedef struct loader_fns_t
+{
+  /* Callback on starting a revision, to obtain an editor for the revision.
+   *
+   * This callback returns in *EDITOR and *EDIT_BATON an editor through which
+   * its caller will drive the changes for revision REVISION.
+   *
+   * This callback should call the editor's SET_TARGET_REVISION method if
+   * required.
+   *
+   * REV_PROPS holds the revision properties.
+   *
+   * POOL (and REV_PROPS) will persist until after the REVFINISH callback
+   * returns.
+   *
+   * Modelled on svn_ra_replay_revstart_callback_t.
+   */
+  svn_error_t *(*revstart)(
+    svn_revnum_t revision,
+    void *baton,
+    const svn_delta_editor_t **editor,
+    void **edit_baton,
+    apr_hash_t *rev_props,
+    apr_pool_t *pool);
+
+  /* Fetch the node props for ORIG_PATH @ ORIG_REV, a node of kind KIND.
+   *
+   * This callback is required if a non-deltas-format dump is parsed;
+   * otherwise it will not be called and may be null. If required and not
+   * provided, the loader will return SVN_ERR_UNSUPPORTED_FEATURE.
+   *
+   * Only regular props are needed. Any special kinds of property such as
+   * entry-props and DAV/WC-props will be ignored.
+   */
+  svn_error_t *(*fetch_props)(
+    apr_hash_t **props,
+    void *baton,
+    const char *orig_path,
+    svn_revnum_t orig_rev,
+    svn_node_kind_t kind,
+    apr_pool_t *result_pool,
+    apr_pool_t *scratch_pool);
+
+} loader_fns_t;
+
+/**
  * General baton used by the parser functions.
  */
 struct parse_baton
 {
-  /* Commit editor and baton used to transfer loaded revisions to
-     the target repository. */
-  const svn_delta_editor_t *commit_editor;
-  void *commit_edit_baton;
-
   /* RA session(s) for committing to the target repository. */
   svn_ra_session_t *session;
   svn_ra_session_t *aux_session;
@@ -72,7 +115,7 @@ struct parse_baton
 
   /* A mapping of svn_revnum_t * dump stream revisions to their
      corresponding svn_revnum_t * target repository revisions. */
-  /* ### See http://subversion.tigris.org/issues/show_bug.cgi?id=3903
+  /* ### See https://issues.apache.org/jira/browse/SVN-3903
      ### for discussion about improving the memory costs of this mapping. */
   apr_hash_t *rev_map;
 
@@ -87,6 +130,9 @@ struct parse_baton
   /* An hash containing specific revision properties to skip while
      loading. */
   apr_hash_t *skip_revprops;
+
+  const loader_fns_t *callbacks;
+  void *cb_baton;
 };
 
 /**
@@ -144,8 +190,14 @@ struct revision_baton
 {
   svn_revnum_t rev;
   apr_hash_t *revprop_table;
+  svn_revnum_t head_rev_before_commit;
   apr_int32_t rev_offset;
 
+  /* Commit editor and baton used to transfer loaded revisions to
+     the target repository. */
+  const svn_delta_editor_t *commit_editor;
+  void *commit_edit_baton;
+
   const svn_string_t *datestamp;
   const svn_string_t *author;
 
@@ -183,204 +235,83 @@ get_revision_mapping(apr_hash_t *rev_map
 
 
 static svn_error_t *
-commit_callback(const svn_commit_info_t *commit_info,
-                void *baton,
-                apr_pool_t *pool)
+magic_header_record(int version,
+            void *parse_baton,
+            apr_pool_t *pool)
 {
-  struct revision_baton *rb = baton;
-  struct parse_baton *pb = rb->pb;
-
-  /* ### Don't print directly; generate a notification. */
-  if (! pb->quiet)
-    SVN_ERR(svn_cmdline_printf(pool, "* Loaded revision %ld.\n",
-                               commit_info->revision));
-
-  /* Add the mapping of the dumpstream revision to the committed revision. */
-  set_revision_mapping(pb->rev_map, rb->rev, commit_info->revision);
-
-  /* If the incoming dump stream has non-contiguous revisions (e.g. from
-     using svndumpfilter --drop-empty-revs without --renumber-revs) then
-     we must account for the missing gaps in PB->REV_MAP.  Otherwise we
-     might not be able to map all mergeinfo source revisions to the correct
-     revisions in the target repos. */
-  if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
-      && (rb->rev != pb->last_rev_mapped + 1))
-    {
-      svn_revnum_t i;
-
-      for (i = pb->last_rev_mapped + 1; i < rb->rev; i++)
-        {
-          set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
-        }
-    }
-
-  /* Update our "last revision mapped". */
-  pb->last_rev_mapped = rb->rev;
-
   return SVN_NO_ERROR;
 }
 
-/* Implements `svn_ra__lock_retry_func_t'. */
-static svn_error_t *
-lock_retry_func(void *baton,
-                const svn_string_t *reposlocktoken,
-                apr_pool_t *pool)
-{
-  return svn_cmdline_printf(pool,
-                            _("Failed to get lock on destination "
-                              "repos, currently held by '%s'\n"),
-                            reposlocktoken->data);
-}
-
-
 static svn_error_t *
-fetch_base_func(const char **filename,
-                void *baton,
-                const char *path,
-                svn_revnum_t base_revision,
-                apr_pool_t *result_pool,
-                apr_pool_t *scratch_pool)
+uuid_record(const char *uuid,
+            void *parse_baton,
+            apr_pool_t *pool)
 {
-  struct revision_baton *rb = baton;
-  svn_stream_t *fstream;
-  svn_error_t *err;
-
-  if (! SVN_IS_VALID_REVNUM(base_revision))
-    base_revision = rb->rev - 1;
-
-  SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
-                                 svn_io_file_del_on_pool_cleanup,
-                                 result_pool, scratch_pool));
-
-  err = svn_ra_get_file(rb->pb->aux_session, path, base_revision,
-                        fstream, NULL, NULL, scratch_pool);
-  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
-    {
-      svn_error_clear(err);
-      SVN_ERR(svn_stream_close(fstream));
-
-      *filename = NULL;
-      return SVN_NO_ERROR;
-    }
-  else if (err)
-    return svn_error_trace(err);
-
-  SVN_ERR(svn_stream_close(fstream));
-
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-fetch_props_func(apr_hash_t **props,
-                 void *baton,
-                 const char *path,
-                 svn_revnum_t base_revision,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
+/* Push information about another directory onto the linked list RB->db.
+ *
+ * CHILD_BATON is the baton returned by the commit editor. RELPATH is the
+ * repository-relative path of this directory. IS_ADDED is true iff this
+ * directory is being added (with or without history). If added with
+ * history then COPYFROM_PATH/COPYFROM_REV are the copyfrom source, else
+ * are NULL/SVN_INVALID_REVNUM.
+ */
+static void
+push_directory(struct revision_baton *rb,
+               void *child_baton,
+               const char *relpath,
+               svn_boolean_t is_added,
+               const char *copyfrom_path,
+               svn_revnum_t copyfrom_rev)
 {
-  struct revision_baton *rb = baton;
-  svn_node_kind_t node_kind;
-
-  if (! SVN_IS_VALID_REVNUM(base_revision))
-    base_revision = rb->rev - 1;
+  struct directory_baton *child_db = apr_pcalloc(rb->pool, sizeof (*child_db));
 
-  SVN_ERR(svn_ra_check_path(rb->pb->aux_session, path, base_revision,
-                            &node_kind, scratch_pool));
+  SVN_ERR_ASSERT_NO_RETURN(
+    is_added || (copyfrom_path == NULL && copyfrom_rev == SVN_INVALID_REVNUM));
 
-  if (node_kind == svn_node_file)
-    {
-      SVN_ERR(svn_ra_get_file(rb->pb->aux_session, path, base_revision,
-                              NULL, NULL, props, result_pool));
-    }
-  else if (node_kind == svn_node_dir)
+  /* If this node is an existing (not newly added) child of a copied node,
+     calculate where it was copied from. */
+  if (!is_added
+      && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
     {
-      apr_array_header_t *tmp_props;
+      const char *name = svn_relpath_basename(relpath, NULL);
 
-      SVN_ERR(svn_ra_get_dir2(rb->pb->aux_session, NULL, NULL, props, path,
-                              base_revision, 0 /* Dirent fields */,
-                              result_pool));
-      tmp_props = svn_prop_hash_to_array(*props, result_pool);
-      SVN_ERR(svn_categorize_props(tmp_props, NULL, NULL, &tmp_props,
-                                   result_pool));
-      *props = svn_prop_array_to_hash(tmp_props, result_pool);
-    }
-  else
-    {
-      *props = apr_hash_make(result_pool);
+      copyfrom_path = svn_relpath_join(rb->db->copyfrom_path, name,
+                                       rb->pool);
+      copyfrom_rev = rb->db->copyfrom_rev;
     }
 
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-fetch_kind_func(svn_node_kind_t *kind,
-                void *baton,
-                const char *path,
-                svn_revnum_t base_revision,
-                apr_pool_t *scratch_pool)
-{
-  struct revision_baton *rb = baton;
-
-  if (! SVN_IS_VALID_REVNUM(base_revision))
-    base_revision = rb->rev - 1;
-
-  SVN_ERR(svn_ra_check_path(rb->pb->aux_session, path, base_revision,
-                            kind, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
-static svn_delta_shim_callbacks_t *
-get_shim_callbacks(struct revision_baton *rb,
-                   apr_pool_t *pool)
-{
-  svn_delta_shim_callbacks_t *callbacks =
-                        svn_delta_shim_callbacks_default(pool);
-
-  callbacks->fetch_props_func = fetch_props_func;
-  callbacks->fetch_kind_func = fetch_kind_func;
-  callbacks->fetch_base_func = fetch_base_func;
-  callbacks->fetch_baton = rb;
-
-  return callbacks;
+  child_db->baton = child_baton;
+  child_db->relpath = relpath;
+  child_db->copyfrom_path = copyfrom_path;
+  child_db->copyfrom_rev = copyfrom_rev;
+  child_db->parent = rb->db;
+  rb->db = child_db;
 }
 
-/* Acquire a lock (of sorts) on the repository associated with the
- * given RA SESSION. This lock is just a revprop change attempt in a
- * time-delay loop. This function is duplicated by svnsync in
- * svnsync/svnsync.c
- *
- * ### TODO: Make this function more generic and
- * expose it through a header for use by other Subversion
- * applications to avoid duplication.
+/* Called to obtain an editor for the revision described by RB.
  */
 static svn_error_t *
-get_lock(const svn_string_t **lock_string_p,
-         svn_ra_session_t *session,
-         svn_cancel_func_t cancel_func,
-         void *cancel_baton,
-         apr_pool_t *pool)
+revision_start_edit(struct revision_baton *rb,
+                    apr_pool_t *scratch_pool)
 {
-  svn_boolean_t be_atomic;
-
-  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
-                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
-                                pool));
-  if (! be_atomic)
-    {
-      /* Pre-1.7 servers can't lock without a race condition.  (Issue #3546) */
-      svn_error_t *err =
-        svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-                         _("Target server does not support atomic revision "
-                           "property edits; consider upgrading it to 1.7."));
-      svn_handle_warning2(stderr, err, "svnrdump: ");
-      svn_error_clear(err);
-    }
+  struct parse_baton *pb = rb->pb;
+  void *child_baton;
 
-  return svn_ra__get_operational_lock(lock_string_p, NULL, session,
-                                      SVNRDUMP_PROP_LOCK, FALSE,
-                                      10 /* retries */, lock_retry_func, NULL,
-                                      cancel_func, cancel_baton, pool);
+  SVN_ERR(pb->callbacks->revstart(rb->rev,
+                                  pb->cb_baton,
+                                  &rb->commit_editor, &rb->commit_edit_baton,
+                                  rb->revprop_table,
+                                  rb->pool));
+  SVN_ERR(rb->commit_editor->open_root(rb->commit_edit_baton,
+                                       rb->head_rev_before_commit,
+                                       rb->pool, &child_baton));
+  /* child_baton corresponds to the root directory baton here */
+  push_directory(rb, child_baton, "", TRUE /*is_added*/,
+                 NULL, SVN_INVALID_REVNUM);
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t *
@@ -389,13 +320,11 @@ new_revision_record(void **revision_bato
                     void *parse_baton,
                     apr_pool_t *pool)
 {
+  struct parse_baton *pb = parse_baton;
   struct revision_baton *rb;
-  struct parse_baton *pb;
   const char *rev_str;
-  svn_revnum_t head_rev;
 
   rb = apr_pcalloc(pool, sizeof(*rb));
-  pb = parse_baton;
   rb->pool = svn_pool_create(pool);
   rb->pb = pb;
   rb->db = NULL;
@@ -404,13 +333,14 @@ new_revision_record(void **revision_bato
   if (rev_str)
     rb->rev = SVN_STR_TO_REV(rev_str);
 
-  SVN_ERR(svn_ra_get_latest_revnum(pb->session, &head_rev, pool));
+  SVN_ERR(svn_ra_get_latest_revnum(pb->session, &rb->head_rev_before_commit,
+                                   pool));
 
   /* FIXME: This is a lame fallback loading multiple segments of dump in
      several separate operations. It is highly susceptible to race conditions.
      Calculate the revision 'offset' for finding copyfrom sources.
      It might be positive or negative. */
-  rb->rev_offset = (apr_int32_t) ((rb->rev) - (head_rev + 1));
+  rb->rev_offset = (apr_int32_t) ((rb->rev) - (rb->head_rev_before_commit + 1));
 
   /* Stash the oldest (non-zero) dumpstream revision seen. */
   if ((rb->rev > 0) && (!SVN_IS_VALID_REVNUM(pb->oldest_dumpstream_rev)))
@@ -418,8 +348,8 @@ new_revision_record(void **revision_bato
 
   /* Set the commit_editor/ commit_edit_baton to NULL and wait for
      them to be created in new_node_record */
-  rb->pb->commit_editor = NULL;
-  rb->pb->commit_edit_baton = NULL;
+  rb->commit_editor = NULL;
+  rb->commit_edit_baton = NULL;
   rb->revprop_table = apr_hash_make(rb->pool);
 
   *revision_baton = rb;
@@ -427,88 +357,28 @@ new_revision_record(void **revision_bato
 }
 
 static svn_error_t *
-magic_header_record(int version,
-            void *parse_baton,
-            apr_pool_t *pool)
+new_node_record(void **node_baton,
+                apr_hash_t *headers,
+                void *revision_baton,
+                apr_pool_t *pool)
 {
-  return SVN_NO_ERROR;
-}
+  struct revision_baton *rb = revision_baton;
+  const struct svn_delta_editor_t *commit_editor = rb->commit_editor;
+  struct node_baton *nb;
+  apr_hash_index_t *hi;
+  void *child_baton;
+  const char *nb_dirname;
 
-static svn_error_t *
-uuid_record(const char *uuid,
-            void *parse_baton,
-            apr_pool_t *pool)
-{
-  return SVN_NO_ERROR;
-}
-
-/* Push information about another directory onto the linked list RB->db.
- *
- * CHILD_BATON is the baton returned by the commit editor. RELPATH is the
- * repository-relative path of this directory. IS_ADDED is true iff this
- * directory is being added (with or without history). If added with
- * history then COPYFROM_PATH/COPYFROM_REV are the copyfrom source, else
- * are NULL/SVN_INVALID_REVNUM.
- */
-static void
-push_directory(struct revision_baton *rb,
-               void *child_baton,
-               const char *relpath,
-               svn_boolean_t is_added,
-               const char *copyfrom_path,
-               svn_revnum_t copyfrom_rev)
-{
-  struct directory_baton *child_db = apr_pcalloc(rb->pool, sizeof (*child_db));
-
-  SVN_ERR_ASSERT_NO_RETURN(
-    is_added || (copyfrom_path == NULL && copyfrom_rev == SVN_INVALID_REVNUM));
-
-  /* If this node is an existing (not newly added) child of a copied node,
-     calculate where it was copied from. */
-  if (!is_added
-      && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
-    {
-      const char *name = svn_relpath_basename(relpath, NULL);
-
-      copyfrom_path = svn_relpath_join(rb->db->copyfrom_path, name,
-                                       rb->pool);
-      copyfrom_rev = rb->db->copyfrom_rev;
-    }
-
-  child_db->baton = child_baton;
-  child_db->relpath = relpath;
-  child_db->copyfrom_path = copyfrom_path;
-  child_db->copyfrom_rev = copyfrom_rev;
-  child_db->parent = rb->db;
-  rb->db = child_db;
-}
-
-static svn_error_t *
-new_node_record(void **node_baton,
-                apr_hash_t *headers,
-                void *revision_baton,
-                apr_pool_t *pool)
-{
-  struct revision_baton *rb = revision_baton;
-  const struct svn_delta_editor_t *commit_editor = rb->pb->commit_editor;
-  void *commit_edit_baton = rb->pb->commit_edit_baton;
-  struct node_baton *nb;
-  svn_revnum_t head_rev_before_commit = rb->rev - rb->rev_offset - 1;
-  apr_hash_index_t *hi;
-  void *child_baton;
-  const char *nb_dirname;
-
-  nb = apr_pcalloc(rb->pool, sizeof(*nb));
-  nb->rb = rb;
-  nb->is_added = FALSE;
-  nb->copyfrom_path = NULL;
-  nb->copyfrom_url = NULL;
-  nb->copyfrom_rev = SVN_INVALID_REVNUM;
-  nb->prop_changes = apr_hash_make(rb->pool);
+  nb = apr_pcalloc(rb->pool, sizeof(*nb));
+  nb->rb = rb;
+  nb->is_added = FALSE;
+  nb->copyfrom_path = NULL;
+  nb->copyfrom_url = NULL;
+  nb->copyfrom_rev = SVN_INVALID_REVNUM;
+  nb->prop_changes = apr_hash_make(rb->pool);
 
   /* If the creation of commit_editor is pending, create it now and
      open_root on it; also create a top-level directory baton. */
-
   if (!commit_editor)
     {
       /* The revprop_table should have been filled in with important
@@ -521,23 +391,8 @@ new_node_record(void **node_baton,
       svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_AUTHOR, NULL);
       svn_hash_sets(rb->revprop_table, SVN_PROP_REVISION_DATE, NULL);
 
-      SVN_ERR(svn_ra__register_editor_shim_callbacks(rb->pb->session,
-                                    get_shim_callbacks(rb, rb->pool)));
-      SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor,
-                                        &commit_edit_baton, rb->revprop_table,
-                                        commit_callback, revision_baton,
-                                        NULL, FALSE, rb->pool));
-
-      rb->pb->commit_editor = commit_editor;
-      rb->pb->commit_edit_baton = commit_edit_baton;
-
-      SVN_ERR(commit_editor->open_root(commit_edit_baton,
-                                       head_rev_before_commit,
-                                       rb->pool, &child_baton));
-
-      /* child_baton corresponds to the root directory baton here */
-      push_directory(rb, child_baton, "", TRUE /*is_added*/,
-                     NULL, SVN_INVALID_REVNUM);
+      SVN_ERR(revision_start_edit(rb, pool));
+      commit_editor = rb->commit_editor;
     }
 
   for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi))
@@ -612,7 +467,7 @@ new_node_record(void **node_baton,
                              rb->pool);
           SVN_ERR(commit_editor->open_directory(relpath_compose,
                                                 rb->db->baton,
-                                                head_rev_before_commit,
+                                                rb->head_rev_before_commit,
                                                 rb->pool, &child_baton));
           push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/,
                          NULL, SVN_INVALID_REVNUM);
@@ -655,7 +510,7 @@ new_node_record(void **node_baton,
     case svn_node_action_delete:
     case svn_node_action_replace:
       SVN_ERR(commit_editor->delete_entry(nb->path,
-                                          head_rev_before_commit,
+                                          rb->head_rev_before_commit,
                                           rb->db->baton, rb->pool));
       if (nb->action == svn_node_action_delete)
         break;
@@ -693,7 +548,7 @@ new_node_record(void **node_baton,
           break;
         default:
           SVN_ERR(commit_editor->open_directory(nb->path, rb->db->baton,
-                                                head_rev_before_commit,
+                                                rb->head_rev_before_commit,
                                                 rb->pool, &child_baton));
           push_directory(rb, child_baton, nb->path, FALSE /*is_added*/,
                          NULL, SVN_INVALID_REVNUM);
@@ -713,18 +568,17 @@ set_revision_property(void *baton,
 {
   struct revision_baton *rb = baton;
 
-  SVN_ERR(svn_rdump__normalize_prop(name, &value, rb->pool));
-
+  SVN_ERR(svn_repos__normalize_prop(&value, NULL, name, value,
+                                    rb->pool, rb->pool));
   SVN_ERR(svn_repos__validate_prop(name, value, rb->pool));
 
   if (rb->rev > 0)
     {
       if (! svn_hash_gets(rb->pb->skip_revprops, name))
         svn_hash_sets(rb->revprop_table,
-                      apr_pstrdup(rb->pool, name),
-                      svn_string_dup(value, rb->pool));
+                      apr_pstrdup(rb->pool, name), value);
     }
-  else if (rb->rev_offset == -1
+  else if (rb->head_rev_before_commit == 0
            && ! svn_hash_gets(rb->pb->skip_revprops, name))
     {
       /* Special case: set revision 0 properties directly (which is
@@ -737,9 +591,9 @@ set_revision_property(void *baton,
   /* Remember any datestamp/ author that passes through (see comment
      in close_revision). */
   if (!strcmp(name, SVN_PROP_REVISION_DATE))
-    rb->datestamp = svn_string_dup(value, rb->pool);
+    rb->datestamp = value;
   if (!strcmp(name, SVN_PROP_REVISION_AUTHOR))
-    rb->author = svn_string_dup(value, rb->pool);
+    rb->author = value;
 
   return SVN_NO_ERROR;
 }
@@ -776,13 +630,13 @@ set_node_property(void *baton,
       value = new_value;
     }
 
-  SVN_ERR(svn_rdump__normalize_prop(name, &value, pool));
+  SVN_ERR(svn_repos__normalize_prop(&value, NULL, name, value, pool, pool));
 
   SVN_ERR(svn_repos__validate_prop(name, value, pool));
 
   prop = apr_palloc(nb->rb->pool, sizeof (*prop));
   prop->name = apr_pstrdup(pool, name);
-  prop->value = svn_string_dup(value, pool);
+  prop->value = value;
   svn_hash_sets(nb->prop_changes, prop->name, prop);
 
   return SVN_NO_ERROR;
@@ -857,16 +711,14 @@ remove_node_props(void *baton)
     /* Add-without-history; no "old" properties to worry about. */
     return SVN_NO_ERROR;
 
-  if (nb->kind == svn_node_file)
-    {
-      SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session,
-                              orig_path, orig_rev, NULL, NULL, &props, pool));
-    }
-  else  /* nb->kind == svn_node_dir */
-    {
-      SVN_ERR(svn_ra_get_dir2(nb->rb->pb->aux_session, NULL, NULL, &props,
-                              orig_path, orig_rev, 0, pool));
-    }
+  if (! rb->pb->callbacks->fetch_props)
+    return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                            _("This dumpstream reader requires a delta "
+                              "format dumpstream"));
+  SVN_ERR(rb->pb->callbacks->fetch_props(&props,
+                                         rb->pb->cb_baton,
+                                         orig_path, orig_rev, nb->kind,
+                                         pool, pool));
 
   for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
     {
@@ -885,7 +737,7 @@ set_fulltext(svn_stream_t **stream,
              void *node_baton)
 {
   struct node_baton *nb = node_baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  const struct svn_delta_editor_t *commit_editor = nb->rb->commit_editor;
   svn_txdelta_window_handler_t handler;
   void *handler_baton;
   apr_pool_t *pool = nb->rb->pool;
@@ -903,7 +755,7 @@ apply_textdelta(svn_txdelta_window_handl
                 void *node_baton)
 {
   struct node_baton *nb = node_baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  const struct svn_delta_editor_t *commit_editor = nb->rb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
 
   SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum,
@@ -916,7 +768,7 @@ static svn_error_t *
 close_node(void *baton)
 {
   struct node_baton *nb = baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  const struct svn_delta_editor_t *commit_editor = nb->rb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
   apr_hash_index_t *hi;
 
@@ -957,8 +809,8 @@ static svn_error_t *
 close_revision(void *baton)
 {
   struct revision_baton *rb = baton;
-  const svn_delta_editor_t *commit_editor = rb->pb->commit_editor;
-  void *commit_edit_baton = rb->pb->commit_edit_baton;
+  const svn_delta_editor_t *commit_editor = rb->commit_editor;
+  void *commit_edit_baton = rb->commit_edit_baton;
   svn_revnum_t committed_rev = SVN_INVALID_REVNUM;
 
   /* Fake revision 0 */
@@ -983,20 +835,12 @@ close_revision(void *baton)
     }
   else
     {
-      svn_revnum_t head_rev_before_commit = rb->rev - rb->rev_offset - 1;
-      void *child_baton;
-
       /* Legitimate revision with no node information */
-      SVN_ERR(svn_ra_get_commit_editor3(rb->pb->session, &commit_editor,
-                                        &commit_edit_baton, rb->revprop_table,
-                                        commit_callback, baton,
-                                        NULL, FALSE, rb->pool));
+      SVN_ERR(revision_start_edit(rb, rb->pool));
+      commit_editor = rb->commit_editor;
+      commit_edit_baton = rb->commit_edit_baton;
 
-      SVN_ERR(commit_editor->open_root(commit_edit_baton,
-                                       head_rev_before_commit,
-                                       rb->pool, &child_baton));
-
-      SVN_ERR(commit_editor->close_directory(child_baton, rb->pool));
+      SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
       SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool));
     }
 
@@ -1008,7 +852,7 @@ close_revision(void *baton)
     {
       committed_rev = get_revision_mapping(rb->pb->rev_map, rb->rev);
     }
-  else if (rb->rev_offset == -1)
+  else if (rb->head_rev_before_commit == 0)
     {
       committed_rev = 0;
     }
@@ -1017,16 +861,12 @@ close_revision(void *baton)
     {
       if (!svn_hash_gets(rb->pb->skip_revprops, SVN_PROP_REVISION_DATE))
         {
-          SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_DATE,
-                                           rb->datestamp, rb->pool));
           SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev,
                                           SVN_PROP_REVISION_DATE,
                                           NULL, rb->datestamp, rb->pool));
         }
       if (!svn_hash_gets(rb->pb->skip_revprops, SVN_PROP_REVISION_AUTHOR))
         {
-          SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_AUTHOR,
-                                           rb->author, rb->pool));
           SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev,
                                           SVN_PROP_REVISION_AUTHOR,
                                           NULL, rb->author, rb->pool));
@@ -1038,27 +878,238 @@ close_revision(void *baton)
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_rdump__load_dumpstream(svn_stream_t *stream,
-                           svn_ra_session_t *session,
-                           svn_ra_session_t *aux_session,
-                           svn_boolean_t quiet,
-                           apr_hash_t *skip_revprops,
-                           svn_cancel_func_t cancel_func,
-                           void *cancel_baton,
-                           apr_pool_t *pool)
+/*----------------------------------------------------------------------*/
+
+/**
+ * Baton used for commit callback (and Ev2 shims).
+ */
+struct commit_baton_t
+{
+  svn_revnum_t rev;
+  struct parse_baton *pb;
+};
+
+/*
+ * - Notification of the commit.
+ * - Update the revision number mapping to take account of the actual
+ *   committed revision number.
+ */
+static svn_error_t *
+commit_callback(const svn_commit_info_t *commit_info,
+                void *baton,
+                apr_pool_t *pool)
+{
+  struct commit_baton_t *cb = baton;
+  struct parse_baton *pb = cb->pb;
+
+  /* ### Don't print directly; generate a notification. */
+  if (! pb->quiet)
+    SVN_ERR(svn_cmdline_printf(pool, "* Loaded revision %ld.\n",
+                               commit_info->revision));
+
+  /* Add the mapping of the dumpstream revision to the committed revision. */
+  set_revision_mapping(pb->rev_map, cb->rev, commit_info->revision);
+
+  /* If the incoming dump stream has non-contiguous revisions (e.g. from
+     using svndumpfilter --drop-empty-revs without --renumber-revs) then
+     we must account for the missing gaps in PB->REV_MAP.  Otherwise we
+     might not be able to map all mergeinfo source revisions to the correct
+     revisions in the target repos. */
+  if ((pb->last_rev_mapped != SVN_INVALID_REVNUM)
+      && (cb->rev != pb->last_rev_mapped + 1))
+    {
+      svn_revnum_t i;
+
+      for (i = pb->last_rev_mapped + 1; i < cb->rev; i++)
+        {
+          set_revision_mapping(pb->rev_map, i, pb->last_rev_mapped);
+        }
+    }
+
+  /* Update our "last revision mapped". */
+  pb->last_rev_mapped = cb->rev;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_base_func(const char **filename,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  struct commit_baton_t *cb = baton;
+  svn_stream_t *fstream;
+  svn_error_t *err;
+
+  if (! SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = cb->rev - 1;
+
+  SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 result_pool, scratch_pool));
+
+  err = svn_ra_get_file(cb->pb->aux_session, path, base_revision,
+                        fstream, NULL, NULL, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      SVN_ERR(svn_stream_close(fstream));
+
+      *filename = NULL;
+      return SVN_NO_ERROR;
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  SVN_ERR(svn_stream_close(fstream));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_props(apr_hash_t **props,
+            void *baton,
+            const char *path,
+            svn_revnum_t base_revision,
+            svn_node_kind_t node_kind,
+            apr_pool_t *result_pool,
+            apr_pool_t *scratch_pool)
+{
+  struct parse_baton *pb = baton;
+
+  if (node_kind == svn_node_file)
+    {
+      SVN_ERR(svn_ra_get_file(pb->aux_session, path, base_revision,
+                              NULL, NULL, props, result_pool));
+    }
+  else if (node_kind == svn_node_dir)
+    {
+      apr_array_header_t *tmp_props;
+
+      SVN_ERR(svn_ra_get_dir2(pb->aux_session, NULL, NULL, props, path,
+                              base_revision, 0 /* Dirent fields */,
+                              result_pool));
+      tmp_props = svn_prop_hash_to_array(*props, result_pool);
+      SVN_ERR(svn_categorize_props(tmp_props, NULL, NULL, &tmp_props,
+                                   result_pool));
+      *props = svn_prop_array_to_hash(tmp_props, result_pool);
+    }
+  else
+    {
+      *props = apr_hash_make(result_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_props_func(apr_hash_t **props,
+                 void *baton,
+                 const char *path,
+                 svn_revnum_t base_revision,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  struct commit_baton_t *cb = baton;
+  svn_node_kind_t node_kind;
+
+  if (! SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = cb->rev - 1;
+
+  SVN_ERR(svn_ra_check_path(cb->pb->aux_session, path, base_revision,
+                            &node_kind, scratch_pool));
+  SVN_ERR(fetch_props(props, cb->pb, path, base_revision, node_kind,
+                      result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_kind_func(svn_node_kind_t *kind,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *scratch_pool)
+{
+  struct commit_baton_t *cb = baton;
+
+  if (! SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = cb->rev - 1;
+
+  SVN_ERR(svn_ra_check_path(cb->pb->aux_session, path, base_revision,
+                            kind, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_delta_shim_callbacks_t *
+get_shim_callbacks(struct commit_baton_t *cb,
+                   apr_pool_t *pool)
+{
+  svn_delta_shim_callbacks_t *callbacks =
+                        svn_delta_shim_callbacks_default(pool);
+
+  callbacks->fetch_props_func = fetch_props_func;
+  callbacks->fetch_kind_func = fetch_kind_func;
+  callbacks->fetch_base_func = fetch_base_func;
+  callbacks->fetch_baton = cb;
+
+  return callbacks;
+}
+
+/*  */
+static svn_error_t *
+revstart(svn_revnum_t revision,
+         void *baton,
+         const svn_delta_editor_t **editor_p,
+         void **edit_baton_p,
+         apr_hash_t *rev_props,
+         apr_pool_t *result_pool)
+{
+  struct parse_baton *pb = baton;
+  struct commit_baton_t *cb = apr_palloc(result_pool, sizeof(*cb));
+
+  cb->rev = revision;
+  cb->pb = pb;
+  SVN_ERR(svn_ra__register_editor_shim_callbacks(pb->session,
+                                                 get_shim_callbacks(cb, result_pool)));
+  SVN_ERR(svn_ra_get_commit_editor3(pb->session,
+                                    editor_p, edit_baton_p,
+                                    rev_props,
+                                    commit_callback, cb,
+                                    NULL, FALSE, result_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Return an implementation of the dumpstream parser API that will drive
+ * commits over the RA layer to the location described by SESSION.
+ *
+ * Use AUX_SESSION (which is opened to the same URL as SESSION)
+ * for any secondary, out-of-band RA communications required. This is
+ * needed when loading a non-deltas dump, and for Ev2.
+ *
+ * Print feedback to the console for each revision, unless QUIET is true.
+ *
+ * Ignore (don't set) any revision property whose name is a key in
+ * SKIP_REVPROPS. The values in the hash are unimportant.
+ */
+static svn_error_t *
+get_dumpstream_loader(svn_repos_parse_fns3_t **parser_p,
+                      void **parse_baton_p,
+                      svn_ra_session_t *session,
+                      svn_ra_session_t *aux_session,
+                      svn_boolean_t quiet,
+                      apr_hash_t *skip_revprops,
+                      apr_pool_t *pool)
 {
   svn_repos_parse_fns3_t *parser;
   struct parse_baton *parse_baton;
-  const svn_string_t *lock_string;
-  svn_boolean_t be_atomic;
-  svn_error_t *err;
   const char *session_url, *root_url, *parent_dir;
+  static const loader_fns_t callbacks = { revstart, fetch_props };
 
-  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
-                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
-                                pool));
-  SVN_ERR(get_lock(&lock_string, session, cancel_func, cancel_baton, pool));
   SVN_ERR(svn_ra_get_repos_root2(session, &root_url, pool));
   SVN_ERR(svn_ra_get_session_url(session, &session_url, pool));
   SVN_ERR(svn_ra_get_path_relative_to_root(session, &parent_dir,
@@ -1088,6 +1139,300 @@ svn_rdump__load_dumpstream(svn_stream_t
   parse_baton->last_rev_mapped = SVN_INVALID_REVNUM;
   parse_baton->oldest_dumpstream_rev = SVN_INVALID_REVNUM;
   parse_baton->skip_revprops = skip_revprops;
+  parse_baton->callbacks = &callbacks;
+  parse_baton->cb_baton = parse_baton;
+
+  *parser_p = parser;
+  *parse_baton_p = parse_baton;
+  return SVN_NO_ERROR;
+}
+
+/*----------------------------------------------------------------------*/
+
+/* Dump-stream parser wrapper */
+
+struct filter_parse_baton_t
+{
+  const svn_repos_parse_fns3_t *wrapped_parser;
+  struct parse_baton *wrapped_pb;
+};
+
+struct filter_revision_baton_t
+{
+  struct filter_parse_baton_t *pb;
+  void *wrapped_rb;
+};
+
+struct filter_node_baton_t
+{
+  struct filter_revision_baton_t *rb;
+  void *wrapped_nb;
+};
+
+static svn_error_t *
+filter_magic_header_record(int version,
+                           void *parse_baton,
+                           apr_pool_t *pool)
+{
+  struct filter_parse_baton_t *pb = parse_baton;
+
+  SVN_ERR(pb->wrapped_parser->magic_header_record(version, pb->wrapped_pb,
+                                                  pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_uuid_record(const char *uuid,
+                   void *parse_baton,
+                   apr_pool_t *pool)
+{
+  struct filter_parse_baton_t *pb = parse_baton;
+
+  SVN_ERR(pb->wrapped_parser->uuid_record(uuid, pb->wrapped_pb, pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_new_revision_record(void **revision_baton,
+                           apr_hash_t *headers,
+                           void *parse_baton,
+                           apr_pool_t *pool)
+{
+  struct filter_parse_baton_t *pb = parse_baton;
+  struct filter_revision_baton_t *rb = apr_pcalloc(pool, sizeof (*rb));
+
+  rb->pb = pb;
+  SVN_ERR(pb->wrapped_parser->new_revision_record(&rb->wrapped_rb, headers,
+                                                  pb->wrapped_pb, pool));
+  *revision_baton = rb;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_new_node_record(void **node_baton,
+                       apr_hash_t *headers,
+                       void *revision_baton,
+                       apr_pool_t *pool)
+{
+  struct filter_revision_baton_t *rb = revision_baton;
+  struct filter_parse_baton_t *pb = rb->pb;
+  struct filter_node_baton_t *nb = apr_pcalloc(pool, sizeof (*nb));
+
+  nb->rb = rb;
+  SVN_ERR(pb->wrapped_parser->new_node_record(&nb->wrapped_nb, headers,
+                                              rb->wrapped_rb, pool));
+  *node_baton = nb;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_set_revision_property(void *revision_baton,
+                             const char *name,
+                             const svn_string_t *value)
+{
+  struct filter_revision_baton_t *rb = revision_baton;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->set_revision_property(rb->wrapped_rb,
+                                                    name, value));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_set_node_property(void *node_baton,
+                         const char *name,
+                         const svn_string_t *value)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->set_node_property(nb->wrapped_nb,
+                                                name, value));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_delete_node_property(void *node_baton,
+                            const char *name)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->delete_node_property(nb->wrapped_nb, name));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_remove_node_props(void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->remove_node_props(nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_set_fulltext(svn_stream_t **stream,
+                    void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->set_fulltext(stream, nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_apply_textdelta(svn_txdelta_window_handler_t *handler,
+                       void **handler_baton,
+                       void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->apply_textdelta(handler, handler_baton,
+                                              nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_close_node(void *node_baton)
+{
+  struct filter_node_baton_t *nb = node_baton;
+  struct filter_revision_baton_t *rb = nb->rb;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->close_node(nb->wrapped_nb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_close_revision(void *revision_baton)
+{
+  struct filter_revision_baton_t *rb = revision_baton;
+  struct filter_parse_baton_t *pb = rb->pb;
+
+  SVN_ERR(pb->wrapped_parser->close_revision(rb->wrapped_rb));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_dumpstream_filter(svn_repos_parse_fns3_t **parser_p,
+                      void **parse_baton_p,
+                      const svn_repos_parse_fns3_t *wrapped_parser,
+                      void *wrapped_baton,
+                      apr_pool_t *pool)
+{
+  svn_repos_parse_fns3_t *parser;
+  struct filter_parse_baton_t *b;
+
+  parser = apr_pcalloc(pool, sizeof(*parser));
+  parser->magic_header_record = filter_magic_header_record;
+  parser->uuid_record = filter_uuid_record;
+  parser->new_revision_record = filter_new_revision_record;
+  parser->new_node_record = filter_new_node_record;
+  parser->set_revision_property = filter_set_revision_property;
+  parser->set_node_property = filter_set_node_property;
+  parser->delete_node_property = filter_delete_node_property;
+  parser->remove_node_props = filter_remove_node_props;
+  parser->set_fulltext = filter_set_fulltext;
+  parser->apply_textdelta = filter_apply_textdelta;
+  parser->close_node = filter_close_node;
+  parser->close_revision = filter_close_revision;
+
+  b = apr_pcalloc(pool, sizeof(*b));
+  b->wrapped_parser = wrapped_parser;
+  b->wrapped_pb = wrapped_baton;
+
+  *parser_p = parser;
+  *parse_baton_p = b;
+  return SVN_NO_ERROR;
+}
+
+/*----------------------------------------------------------------------*/
+
+/* Implements `svn_ra__lock_retry_func_t'. */
+static svn_error_t *
+lock_retry_func(void *baton,
+                const svn_string_t *reposlocktoken,
+                apr_pool_t *pool)
+{
+  return svn_cmdline_printf(pool,
+                            _("Failed to get lock on destination "
+                              "repos, currently held by '%s'\n"),
+                            reposlocktoken->data);
+}
+
+/* Acquire a lock (of sorts) on the repository associated with the
+ * given RA SESSION. This lock is just a revprop change attempt in a
+ * time-delay loop. This function is duplicated by svnsync in
+ * svnsync/svnsync.c
+ *
+ * ### TODO: Make this function more generic and
+ * expose it through a header for use by other Subversion
+ * applications to avoid duplication.
+ */
+static svn_error_t *
+get_lock(const svn_string_t **lock_string_p,
+         svn_ra_session_t *session,
+         svn_cancel_func_t cancel_func,
+         void *cancel_baton,
+         apr_pool_t *pool)
+{
+  svn_boolean_t be_atomic;
+
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                pool));
+  if (! be_atomic)
+    {
+      /* Pre-1.7 servers can't lock without a race condition.  (Issue #3546) */
+      svn_error_t *err =
+        svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                         _("Target server does not support atomic revision "
+                           "property edits; consider upgrading it to 1.7."));
+      svn_handle_warning2(stderr, err, "svnrdump: ");
+      svn_error_clear(err);
+    }
+
+  return svn_ra__get_operational_lock(lock_string_p, NULL, session,
+                                      SVNRDUMP_PROP_LOCK, FALSE,
+                                      10 /* retries */, lock_retry_func, NULL,
+                                      cancel_func, cancel_baton, pool);
+}
+
+svn_error_t *
+svn_rdump__load_dumpstream(svn_stream_t *stream,
+                           svn_ra_session_t *session,
+                           svn_ra_session_t *aux_session,
+                           svn_boolean_t quiet,
+                           apr_hash_t *skip_revprops,
+                           svn_cancel_func_t cancel_func,
+                           void *cancel_baton,
+                           apr_pool_t *pool)
+{
+  svn_repos_parse_fns3_t *parser;
+  void *parse_baton;
+  const svn_string_t *lock_string;
+  svn_error_t *err;
+
+  SVN_ERR(get_lock(&lock_string, session, cancel_func, cancel_baton, pool));
+
+  SVN_ERR(get_dumpstream_loader(&parser, &parse_baton,
+                                session, aux_session,
+                                quiet, skip_revprops,
+                                pool));
+
+  /* Interpose a filtering layer: currently doing nothing */
+  SVN_ERR(get_dumpstream_filter(&parser, &parse_baton,
+                                parser, parse_baton,
+                                pool));
 
   err = svn_repos_parse_dumpstream3(stream, parser, parse_baton, FALSE,
                                     cancel_func, cancel_baton, pool);

Modified: subversion/branches/ra-git/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnrdump/svnrdump.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/ra-git/subversion/svnrdump/svnrdump.c Wed Nov  7 12:30:06 2018
@@ -59,6 +59,7 @@ enum svn_svnrdump__longopt_t
     opt_config_option,
     opt_auth_username,
     opt_auth_password,
+    opt_auth_password_from_stdin,
     opt_auth_nocache,
     opt_non_interactive,
     opt_skip_revprop,
@@ -73,29 +74,38 @@ enum svn_svnrdump__longopt_t
                                    opt_config_option, \
                                    opt_auth_username, \
                                    opt_auth_password, \
+                                   opt_auth_password_from_stdin, \
                                    opt_auth_nocache, \
                                    opt_trust_server_cert, \
                                    opt_trust_server_cert_failures, \
                                    opt_non_interactive, \
                                    opt_force_interactive
 
-static const svn_opt_subcommand_desc2_t svnrdump__cmd_table[] =
+static const svn_opt_subcommand_desc3_t svnrdump__cmd_table[] =
 {
-  { "dump", dump_cmd, { 0 },
-    N_("usage: svnrdump dump URL [-r LOWER[:UPPER]]\n\n"
+  { "dump", dump_cmd, { 0 }, {N_(
+       "usage: svnrdump dump URL [-r LOWER[:UPPER]]\n"
+       "\n"), N_(
        "Dump revisions LOWER to UPPER of repository at remote URL to stdout\n"
        "in a 'dumpfile' portable format.  If only LOWER is given, dump that\n"
-       "one revision.\n"),
-    { 'r', 'q', opt_incremental, SVN_SVNRDUMP__BASE_OPTIONS } },
-  { "load", load_cmd, { 0 },
-    N_("usage: svnrdump load URL\n\n"
-       "Load a 'dumpfile' given on stdin to a repository at remote URL.\n"),
-    { 'q', opt_skip_revprop, SVN_SVNRDUMP__BASE_OPTIONS } },
-  { "help", 0, { "?", "h" },
-    N_("usage: svnrdump help [SUBCOMMAND...]\n\n"
-       "Describe the usage of this program or its subcommands.\n"),
+       "one revision.\n"
+    )},
+    { 'r', 'q', opt_incremental, 'F', SVN_SVNRDUMP__BASE_OPTIONS },
+    {{'F', N_("write to file ARG instead of stdout")}} },
+  { "load", load_cmd, { 0 }, {N_(
+       "usage: svnrdump load URL\n"
+       "\n"), N_(
+       "Load a 'dumpfile' given on stdin to a repository at remote URL.\n"
+    )},
+    { 'q', opt_skip_revprop, 'F', SVN_SVNRDUMP__BASE_OPTIONS },
+    {{'F', N_("read from file ARG instead of stdin")}} },
+  { "help", 0, { "?", "h" }, {N_(
+       "usage: svnrdump help [SUBCOMMAND...]\n"
+       "\n"), N_(
+       "Describe the usage of this program or its subcommands.\n"
+    )},
     { 0 } },
-  { NULL, NULL, { 0 }, NULL, { 0 } }
+  { NULL, NULL, { 0 }, {NULL}, { 0 } }
 };
 
 static const apr_getopt_option_t svnrdump__options[] =
@@ -114,6 +124,8 @@ static const apr_getopt_option_t svnrdum
                       N_("specify a username ARG")},
     {"password",      opt_auth_password, 1,
                       N_("specify a password ARG")},
+    {"password-from-stdin",   opt_auth_password_from_stdin, 0,
+                      N_("read password from stdin")},
     {"non-interactive", opt_non_interactive, 0,
                       N_("do no interactive prompting (default is to prompt\n"
                          "                             "
@@ -154,6 +166,8 @@ static const apr_getopt_option_t svnrdum
                        "valid certificate) and 'other' (all other not\n"
                        "                             "
                        "separately classified certificate errors).")},
+    {"file",          'F', 1,
+                      N_("read/write file ARG instead of stdin/stdout")},
     {0, 0, 0, 0}
   };
 
@@ -174,6 +188,7 @@ typedef struct opt_baton_t {
   svn_client_ctx_t *ctx;
   svn_ra_session_t *session;
   const char *url;
+  const char *dumpfile;
   svn_boolean_t help;
   svn_boolean_t version;
   svn_opt_revision_t start_revision;
@@ -332,7 +347,7 @@ init_client_context(svn_client_ctx_t **c
      ### auxiliary GETs/PROPFINDs to happening (well-ordered) on a
      ### single server connection.
      ###
-     ### See http://subversion.tigris.org/issues/show_bug.cgi?id=4116.
+     ### See https://issues.apache.org/jira/browse/SVN-4116.
   */
   cfg_servers = svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_SERVERS);
   svn_config_set_bool(cfg_servers, SVN_CONFIG_SECTION_GLOBAL,
@@ -417,7 +432,7 @@ dump_initial_full_revision(svn_ra_sessio
      our update-driven dump generation work the way a replay-driven
      one would.
 
-     See http://subversion.tigris.org/issues/show_bug.cgi?id=4101
+     See https://issues.apache.org/jira/browse/SVN-4101
   */
   SVN_ERR(svn_ra_get_session_url(session, &session_url, pool));
   SVN_ERR(svn_ra_get_path_relative_to_root(session, &source_relpath,
@@ -463,31 +478,38 @@ replay_revisions(svn_ra_session_t *sessi
                  svn_revnum_t end_revision,
                  svn_boolean_t quiet,
                  svn_boolean_t incremental,
+                 const char *dumpfile,
                  apr_pool_t *pool)
 {
   struct replay_baton *replay_baton;
   const char *uuid;
-  svn_stream_t *stdout_stream;
+  svn_stream_t *output_stream;
 
-  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+  if (dumpfile)
+    {
+      SVN_ERR(svn_stream_open_writable(&output_stream, dumpfile, pool, pool));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_for_stdout(&output_stream, pool));
+    }
 
   replay_baton = apr_pcalloc(pool, sizeof(*replay_baton));
-  replay_baton->stdout_stream = stdout_stream;
+  replay_baton->stdout_stream = output_stream;
   replay_baton->extra_ra_session = extra_ra_session;
   replay_baton->quiet = quiet;
 
   /* Write the magic header and UUID */
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n",
-                            SVN_REPOS_DUMPFILE_FORMAT_VERSION));
+  SVN_ERR(svn_repos__dump_magic_header_record(output_stream,
+                                              SVN_REPOS_DUMPFILE_FORMAT_VERSION,
+                                              pool));
   SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool));
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid));
+  SVN_ERR(svn_repos__dump_uuid_header_record(output_stream, uuid, pool));
 
   /* Fake revision 0 if necessary */
   if (start_revision == 0)
     {
-      SVN_ERR(dump_revision_header(session, stdout_stream,
+      SVN_ERR(dump_revision_header(session, output_stream,
                                    start_revision, pool));
 
       /* Revision 0 has no tree changes, so we're done. */
@@ -506,7 +528,7 @@ replay_revisions(svn_ra_session_t *sessi
   if (!incremental)
     {
       SVN_ERR(dump_initial_full_revision(session, extra_ra_session,
-                                         stdout_stream, start_revision,
+                                         output_stream, start_revision,
                                          quiet, pool));
       start_revision++;
     }
@@ -526,6 +548,7 @@ replay_revisions(svn_ra_session_t *sessi
 #endif
     }
 
+  SVN_ERR(svn_stream_close(output_stream));
   return SVN_NO_ERROR;
 }
 
@@ -538,19 +561,27 @@ replay_revisions(svn_ra_session_t *sessi
 static svn_error_t *
 load_revisions(svn_ra_session_t *session,
                svn_ra_session_t *aux_session,
-               const char *url,
+               const char *dumpfile,
                svn_boolean_t quiet,
                apr_hash_t *skip_revprops,
                apr_pool_t *pool)
 {
-  svn_stream_t *stdin_stream;
+  svn_stream_t *output_stream;
 
-  SVN_ERR(svn_stream_for_stdin2(&stdin_stream, TRUE, pool));
+  if (dumpfile)
+    {
+      SVN_ERR(svn_stream_open_readonly(&output_stream, dumpfile, pool, pool));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_for_stdin2(&output_stream, TRUE, pool));
+    }
 
-  SVN_ERR(svn_rdump__load_dumpstream(stdin_stream, session, aux_session,
+  SVN_ERR(svn_rdump__load_dumpstream(output_stream, session, aux_session,
                                      quiet, skip_revprops,
                                      check_cancel, NULL, pool));
 
+  SVN_ERR(svn_stream_close(output_stream));
   return SVN_NO_ERROR;
 }
 
@@ -591,7 +622,7 @@ version(const char *progname,
                          pool);
 
   SVN_ERR(svn_ra_print_modules(version_footer, pool));
-  return svn_opt_print_help4(NULL, ensure_appname(progname, pool),
+  return svn_opt_print_help5(NULL, ensure_appname(progname, pool),
                              TRUE, quiet, FALSE, version_footer->data,
                              NULL, NULL, NULL, NULL, NULL, pool);
 }
@@ -616,7 +647,8 @@ dump_cmd(apr_getopt_t *os,
   return replay_revisions(opt_baton->session, extra_ra_session,
                           opt_baton->start_revision.value.number,
                           opt_baton->end_revision.value.number,
-                          opt_baton->quiet, opt_baton->incremental, pool);
+                          opt_baton->quiet, opt_baton->incremental,
+                          opt_baton->dumpfile, pool);
 }
 
 /* Handle the "load" subcommand.  Implements `svn_opt_subcommand_t'.  */
@@ -630,8 +662,9 @@ load_cmd(apr_getopt_t *os,
 
   SVN_ERR(svn_client_open_ra_session2(&aux_session, opt_baton->url, NULL,
                                       opt_baton->ctx, pool, pool));
-  return load_revisions(opt_baton->session, aux_session, opt_baton->url,
-                        opt_baton->quiet, opt_baton->skip_revprops, pool);
+  return load_revisions(opt_baton->session, aux_session,
+                        opt_baton->dumpfile, opt_baton->quiet,
+                        opt_baton->skip_revprops, pool);
 }
 
 /* Handle the "help" subcommand.  Implements `svn_opt_subcommand_t'.  */
@@ -648,7 +681,7 @@ help_cmd(apr_getopt_t *os,
       "\n"
       "Available subcommands:\n");
 
-  return svn_opt_print_help4(os, "svnrdump", FALSE, FALSE, FALSE, NULL,
+  return svn_opt_print_help5(os, "svnrdump", FALSE, FALSE, FALSE, NULL,
                              header, svnrdump__cmd_table, svnrdump__options,
                              NULL, NULL, pool);
 }
@@ -754,7 +787,7 @@ static svn_error_t *
 sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
 {
   svn_error_t *err = SVN_NO_ERROR;
-  const svn_opt_subcommand_desc2_t *subcommand = NULL;
+  const svn_opt_subcommand_desc3_t *subcommand = NULL;
   opt_baton_t *opt_baton;
   svn_revnum_t latest_revision = SVN_INVALID_REVNUM;
   const char *config_dir = NULL;
@@ -770,15 +803,16 @@ sub_main(int *exit_code, int argc, const
   svn_boolean_t force_interactive = FALSE;
   apr_array_header_t *config_options = NULL;
   apr_getopt_t *os;
-  const char *first_arg;
   apr_array_header_t *received_opts;
   int i;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   opt_baton = apr_pcalloc(pool, sizeof(*opt_baton));
   opt_baton->start_revision.kind = svn_opt_revision_unspecified;
   opt_baton->end_revision.kind = svn_opt_revision_unspecified;
   opt_baton->url = NULL;
   opt_baton->skip_revprops = apr_hash_make(pool);
+  opt_baton->dumpfile = NULL;
 
   SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
 
@@ -851,6 +885,9 @@ sub_main(int *exit_code, int argc, const
         case opt_auth_password:
           SVN_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
           break;
+        case opt_auth_password_from_stdin:
+          read_pass_from_stdin = TRUE;
+          break;
         case opt_auth_nocache:
           no_auth_cache = TRUE;
           break;
@@ -891,6 +928,11 @@ sub_main(int *exit_code, int argc, const
                                                      opt_arg, 
                                                      "svnrdump: ",
                                                      pool));
+          break;
+        case 'F':
+          SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+          opt_baton->dumpfile = opt_arg;
+          break;
         }
     }
 
@@ -905,7 +947,7 @@ sub_main(int *exit_code, int argc, const
 
   if (opt_baton->help)
     {
-      subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
+      subcommand = svn_opt_get_canonical_subcommand3(svnrdump__cmd_table,
                                                      "help");
     }
   if (subcommand == NULL)
@@ -915,8 +957,8 @@ sub_main(int *exit_code, int argc, const
           if (opt_baton->version)
             {
               /* Use the "help" subcommand to handle the "--version" option. */
-              static const svn_opt_subcommand_desc2_t pseudo_cmd =
-                { "--version", help_cmd, {0}, "",
+              static const svn_opt_subcommand_desc3_t pseudo_cmd =
+                { "--version", help_cmd, {0}, {""},
                   {opt_version,  /* must accept its own option */
                    'q',  /* --quiet */
                   } };
@@ -932,19 +974,19 @@ sub_main(int *exit_code, int argc, const
         }
       else
         {
-          first_arg = os->argv[os->ind++];
-          subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
+          const char *first_arg;
+
+          SVN_ERR(svn_utf_cstring_to_utf8(&first_arg, os->argv[os->ind++],
+                                          pool));
+          subcommand = svn_opt_get_canonical_subcommand3(svnrdump__cmd_table,
                                                          first_arg);
 
           if (subcommand == NULL)
             {
-              const char *first_arg_utf8;
-              SVN_ERR(svn_utf_cstring_to_utf8(&first_arg_utf8, first_arg,
-                                              pool));
               svn_error_clear(
                 svn_cmdline_fprintf(stderr, pool,
                                     _("Unknown subcommand: '%s'\n"),
-                                    first_arg_utf8));
+                                    first_arg));
               SVN_ERR(help_cmd(NULL, NULL, pool));
               *exit_code = EXIT_FAILURE;
               return SVN_NO_ERROR;
@@ -964,11 +1006,11 @@ sub_main(int *exit_code, int argc, const
       if (opt_id == 'h' || opt_id == '?')
         continue;
 
-      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
+      if (! svn_opt_subcommand_takes_option4(subcommand, opt_id, NULL))
         {
           const char *optstr;
           const apr_getopt_option_t *badopt =
-            svn_opt_get_option_from_code2(opt_id, svnrdump__options,
+            svn_opt_get_option_from_code3(opt_id, svnrdump__options,
                                           subcommand, pool);
           svn_opt_format_option(&optstr, badopt, FALSE, pool);
           if (subcommand->name[0] == '-')
@@ -1006,6 +1048,24 @@ sub_main(int *exit_code, int argc, const
                                   "--non-interactive"));
     }
 
+  if (read_pass_from_stdin && !non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
+
+  if (strcmp(subcommand->name, "load") == 0)
+    {
+      if (read_pass_from_stdin && opt_baton->dumpfile == NULL)
+        {
+          /* error here, since load cannot process a password over stdin */
+          return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                  _("load subcommand with "
+                                    "--password-from-stdin requires -F"));
+        }
+    }
+
   /* Expect one more non-option argument:  the repository URL. */
   if (os->ind != os->argc - 1)
     {
@@ -1040,6 +1100,12 @@ sub_main(int *exit_code, int argc, const
         force_interactive = (username == NULL || password == NULL);
     }
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      SVN_ERR(svn_cmdline__stdin_readline(&password, pool, pool));
+    }
+
   non_interactive = !svn_cmdline__be_interactive(non_interactive,
                                                  force_interactive);
 

Modified: subversion/branches/ra-git/subversion/svnrdump/svnrdump.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnrdump/svnrdump.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnrdump/svnrdump.h (original)
+++ subversion/branches/ra-git/subversion/svnrdump/svnrdump.h Wed Nov  7 12:30:06 2018
@@ -77,12 +77,21 @@ svn_rdump__get_dump_editor_v2(svn_editor
 
 /**
  * Load the dumpstream carried in @a stream to the location described
- * by @a session.  Use @a aux_session (which is opened to the same URL
- * as @a session) for any secondary, out-of-band RA communications
- * required.  If @a quiet is set, suppress notifications.  Use @a pool
- * for all memory allocations.  Use @a cancel_func and @a cancel_baton
- * to check for user cancellation of the operation (for
- * timely-but-safe termination).
+ * by @a session.
+ *
+ * Use @a aux_session (which is opened to the same URL as @a session)
+ * for any secondary, out-of-band RA communications required. This is
+ * needed when loading a non-deltas dump, and for Ev2.
+ *
+ * Print feedback to the console for each revision, unless @a quiet is true.
+ *
+ * Ignore (don't set) any revision property whose name is a key in
+ * @a skip_revprops. The values in the hash are unimportant.
+ *
+ * Use @a cancel_func and @a cancel_baton to check for user cancellation
+ * of the operation (for timely-but-safe termination).
+ *
+ * Use @a pool for all memory allocations.
  */
 svn_error_t *
 svn_rdump__load_dumpstream(svn_stream_t *stream,
@@ -100,29 +109,12 @@ svn_rdump__load_dumpstream(svn_stream_t
  * currently all svn:* props) so that they contain only LF (\n) line endings.
  *
  * Put the normalized props into NORMAL_PROPS, allocated in RESULT_POOL.
- *
- * Note: this function does not do a deep copy; it is expected that PROPS has
- * a longer lifetime than NORMAL_PROPS.
  */
 svn_error_t *
 svn_rdump__normalize_props(apr_hash_t **normal_props,
                            apr_hash_t *props,
                            apr_pool_t *result_pool);
 
-/* Normalize the line ending style of a single property that "needs
- * translation" (according to svn_prop_needs_translation(),
- * currently all svn:* props) so that they contain only LF (\n) line endings.
- * "\r" characters found mid-line are replaced with "\n".
- * "\r\n" sequences are replaced with "\n"
- *
- * NAME is used to check that VALUE should be normalized, and if this is the
- * case, VALUE is then normalized, allocated from RESULT_POOL
- */
-svn_error_t *
-svn_rdump__normalize_prop(const char *name,
-                          const svn_string_t **value,
-                          apr_pool_t *result_pool);
-
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/ra-git/subversion/svnrdump/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnrdump/util.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnrdump/util.c (original)
+++ subversion/branches/ra-git/subversion/svnrdump/util.c Wed Nov  7 12:30:06 2018
@@ -21,53 +21,35 @@
  * ====================================================================
  */
 
-#include "svn_error.h"
-#include "svn_pools.h"
-#include "svn_string.h"
-#include "svn_props.h"
-#include "svn_subst.h"
+#include "private/svn_repos_private.h"
 
 #include "svnrdump.h"
 
 
 svn_error_t *
-svn_rdump__normalize_prop(const char *name,
-                          const svn_string_t **value,
-                          apr_pool_t *result_pool)
-{
-  if (svn_prop_needs_translation(name) && *value)
-    {
-      const char *cstring;
-
-      SVN_ERR(svn_subst_translate_cstring2((*value)->data, &cstring,
-                                           "\n", TRUE,
-                                           NULL, FALSE,
-                                           result_pool));
-
-      *value = svn_string_create(cstring, result_pool);
-    }
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
 svn_rdump__normalize_props(apr_hash_t **normal_props,
                            apr_hash_t *props,
                            apr_pool_t *result_pool)
 {
   apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
 
   *normal_props = apr_hash_make(result_pool);
 
+  iterpool = svn_pool_create(result_pool);
   for (hi = apr_hash_first(result_pool, props); hi;
         hi = apr_hash_next(hi))
     {
       const char *key = apr_hash_this_key(hi);
       const svn_string_t *value = apr_hash_this_val(hi);
 
-      SVN_ERR(svn_rdump__normalize_prop(key, &value,
-                                        result_pool));
+      svn_pool_clear(iterpool);
 
+      SVN_ERR(svn_repos__normalize_prop(&value, NULL, key, value,
+                                        result_pool, iterpool));
       svn_hash_sets(*normal_props, key, value);
     }
+  svn_pool_destroy(iterpool);
+
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnserve/serve.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnserve/serve.c (original)
+++ subversion/branches/ra-git/subversion/svnserve/serve.c Wed Nov  7 12:30:06 2018
@@ -226,8 +226,8 @@ load_pwdb_config(repository_t *repositor
       pwdb_path = svn_dirent_internal_style(pwdb_path, pool);
       pwdb_path = svn_dirent_join(repository->base, pwdb_path, pool);
 
-      err = svn_repos__config_pool_get(&repository->pwdb, NULL, config_pool,
-                                       pwdb_path, TRUE, FALSE,
+      err = svn_repos__config_pool_get(&repository->pwdb, config_pool,
+                                       pwdb_path, TRUE,
                                        repository->repos, pool);
       if (err)
         {
@@ -285,8 +285,8 @@ canonicalize_access_file(const char **ac
   return SVN_NO_ERROR;
 }
 
-/* Load the authz database for the listening server through AUTHZ_POOL
-   based on the entries in the SERVER struct.
+/* Load the authz database for the listening server based on the entries
+   in the SERVER struct.
 
    SERVER and CONN must not be NULL. The real errors will be logged with
    SERVER and CONN but return generic errors to the client. */
@@ -294,7 +294,6 @@ static svn_error_t *
 load_authz_config(repository_t *repository,
                   const char *repos_root,
                   svn_config_t *cfg,
-                  svn_repos__authz_pool_t *authz_pool,
                   apr_pool_t *pool)
 {
   const char *authzdb_path;
@@ -322,9 +321,9 @@ load_authz_config(repository_t *reposito
                                        repos_root, pool);
 
       if (!err)
-        err = svn_repos__authz_pool_get(&repository->authzdb, authz_pool,
-                                        authzdb_path, groupsdb_path, TRUE,
-                                        repository->repos, pool);
+        err = svn_repos_authz_read3(&repository->authzdb, authzdb_path,
+                                    groupsdb_path, TRUE, repository->repos,
+                                    pool, pool);
 
       if (err)
         return svn_error_create(SVN_ERR_AUTHZ_INVALID_CONFIG, err, NULL);
@@ -370,7 +369,7 @@ handle_config_error(svn_error_t *error,
 
       /* Now that we've logged the error, clear it and return a
        * nice, generic error to the user:
-       * http://subversion.tigris.org/issues/show_bug.cgi?id=2271 */
+       * https://issues.apache.org/jira/browse/SVN-2271 */
       svn_error_clear(error);
       return svn_error_create(apr_err, NULL, NULL);
     }
@@ -446,7 +445,7 @@ static svn_error_t *authz_check_access(s
      absolute path. Passing such a malformed path to the authz
      routines throws them into an infinite loop and makes them miss
      ACLs. */
-  if (path)
+  if (path && *path != '/')
     path = svn_fspath__canonicalize(path, pool);
 
   /* If we have a username, and we've not yet used it + any username
@@ -1682,7 +1681,7 @@ get_file(svn_ra_svn_conn_t *conn,
 /* Translate all the words in DIRENT_FIELDS_LIST into the flags in
  * DIRENT_FIELDS_P.  If DIRENT_FIELDS_LIST is NULL, set all flags. */
 static svn_error_t *
-parse_dirent_fields(apr_uint64_t *dirent_fields_p,
+parse_dirent_fields(apr_uint32_t *dirent_fields_p,
                     svn_ra_svn__list_t *dirent_fields_list)
 {
   static const svn_string_t str_kind
@@ -1698,7 +1697,7 @@ parse_dirent_fields(apr_uint64_t *dirent
   static const svn_string_t str_last_author
     = SVN__STATIC_STRING(SVN_RA_SVN_DIRENT_LAST_AUTHOR);
 
-  apr_uint64_t dirent_fields;
+  apr_uint32_t dirent_fields;
 
   if (! dirent_fields_list)
     {
@@ -1753,7 +1752,7 @@ get_dir(svn_ra_svn_conn_t *conn,
   apr_pool_t *subpool;
   svn_boolean_t want_props, want_contents;
   apr_uint64_t wants_inherited_props;
-  apr_uint64_t dirent_fields;
+  apr_uint32_t dirent_fields;
   svn_ra_svn__list_t *dirent_fields_list = NULL;
   int i;
   authz_baton_t ab;
@@ -2123,6 +2122,61 @@ diff(svn_ra_svn_conn_t *conn,
   return SVN_NO_ERROR;
 }
 
+/* Baton type to be used with mergeinfo_receiver. */
+typedef struct mergeinfo_receiver_baton_t
+{
+  /* Send the response over this connection. */
+  svn_ra_svn_conn_t *conn;
+
+  /* Start path of the query; report paths relative to this one. */
+  const char *fs_path;
+
+  /* Did we already send the opening sequence? */
+  svn_boolean_t starting_tuple_sent;
+} mergeinfo_receiver_baton_t;
+
+/* Utility method sending the start of the "get m/i" response once
+   over BATON->CONN. */
+static svn_error_t *
+send_mergeinfo_starting_tuple(mergeinfo_receiver_baton_t *baton,
+                              apr_pool_t *scratch_pool)
+{
+  if (baton->starting_tuple_sent)
+    return SVN_NO_ERROR;
+
+  SVN_ERR(svn_ra_svn__write_tuple(baton->conn, scratch_pool,
+                                  "w((!", "success"));
+  baton->starting_tuple_sent = TRUE;
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements svn_repos_mergeinfo_receiver_t, sending the MERGEINFO
+ * out over the connection in the mergeinfo_receiver_baton_t * BATON. */
+static svn_error_t *
+mergeinfo_receiver(const char *path,
+                   svn_mergeinfo_t mergeinfo,
+                   void *baton,
+                   apr_pool_t *scratch_pool)
+{
+  mergeinfo_receiver_baton_t *b = baton;
+  svn_string_t *mergeinfo_string;
+
+  /* Delay starting the response until we checked that the initial
+     request went through.  We are at that point now b/c we've got
+     the first results in. */
+  SVN_ERR(send_mergeinfo_starting_tuple(b, scratch_pool));
+
+  /* Adjust the path info and send the m/i. */
+  path = svn_fspath__skip_ancestor(b->fs_path, path);
+  SVN_ERR(svn_mergeinfo_to_string(&mergeinfo_string, mergeinfo,
+                                  scratch_pool));
+  SVN_ERR(svn_ra_svn__write_tuple(b->conn, scratch_pool, "cs", path,
+                                  mergeinfo_string));
+
+  return SVN_NO_ERROR;
+}
+
 /* Regardless of whether a client's capabilities indicate an
    understanding of this command (by way of SVN_RA_SVN_CAP_MERGEINFO),
    we provide a response.
@@ -2139,18 +2193,20 @@ get_mergeinfo(svn_ra_svn_conn_t *conn,
   svn_revnum_t rev;
   svn_ra_svn__list_t *paths;
   apr_array_header_t *canonical_paths;
-  svn_mergeinfo_catalog_t mergeinfo;
   int i;
-  apr_hash_index_t *hi;
   const char *inherit_word;
   svn_mergeinfo_inheritance_t inherit;
   svn_boolean_t include_descendants;
-  apr_pool_t *iterpool;
   authz_baton_t ab;
+  mergeinfo_receiver_baton_t mergeinfo_baton;
 
   ab.server = b;
   ab.conn = conn;
 
+  mergeinfo_baton.conn = conn;
+  mergeinfo_baton.fs_path = b->repository->fs_path->data;
+  mergeinfo_baton.starting_tuple_sent = FALSE;
+
   SVN_ERR(svn_ra_svn__parse_tuple(params, "l(?r)wb", &paths, &rev,
                                   &inherit_word, &include_descendants));
   inherit = svn_inheritance_from_word(inherit_word);
@@ -2176,29 +2232,19 @@ get_mergeinfo(svn_ra_svn_conn_t *conn,
                                              pool)));
 
   SVN_ERR(trivial_auth_request(conn, pool, b));
-  SVN_CMD_ERR(svn_repos_fs_get_mergeinfo(&mergeinfo, b->repository->repos,
-                                         canonical_paths, rev,
-                                         inherit,
-                                         include_descendants,
-                                         authz_check_access_cb_func(b), &ab,
-                                         pool));
-  SVN_ERR(svn_mergeinfo__remove_prefix_from_catalog(&mergeinfo, mergeinfo,
-                                      b->repository->fs_path->data, pool));
-  SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w((!", "success"));
-  iterpool = svn_pool_create(pool);
-  for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
-    {
-      const char *key = apr_hash_this_key(hi);
-      svn_mergeinfo_t value = apr_hash_this_val(hi);
-      svn_string_t *mergeinfo_string;
-
-      svn_pool_clear(iterpool);
 
-      SVN_ERR(svn_mergeinfo_to_string(&mergeinfo_string, value, iterpool));
-      SVN_ERR(svn_ra_svn__write_tuple(conn, iterpool, "cs", key,
-                                      mergeinfo_string));
-    }
-  svn_pool_destroy(iterpool);
+  SVN_CMD_ERR(svn_repos_fs_get_mergeinfo2(b->repository->repos,
+                                          canonical_paths, rev,
+                                          inherit,
+                                          include_descendants,
+                                          authz_check_access_cb_func(b), &ab,
+                                          mergeinfo_receiver,
+                                          &mergeinfo_baton,
+                                          pool));
+
+  /* We might not have sent anything
+     => ensure to begin the response in any case. */
+  SVN_ERR(send_mergeinfo_starting_tuple(&mergeinfo_baton, pool));
   SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "!))"));
 
   return SVN_NO_ERROR;
@@ -2775,15 +2821,9 @@ static svn_error_t *file_rev_handler(voi
       svn_stream_set_write(stream, svndiff_handler);
       svn_stream_set_close(stream, svndiff_close_handler);
 
-      /* If the connection does not support SVNDIFF1 or if we don't want to use
-       * compression, use the non-compressing "version 0" implementation */
-      if (   svn_ra_svn_compression_level(frb->conn) > 0
-          && svn_ra_svn_has_capability(frb->conn, SVN_RA_SVN_CAP_SVNDIFF1))
-        svn_txdelta_to_svndiff3(d_handler, d_baton, stream, 1,
-                                svn_ra_svn_compression_level(frb->conn), pool);
-      else
-        svn_txdelta_to_svndiff3(d_handler, d_baton, stream, 0,
-                                svn_ra_svn_compression_level(frb->conn), pool);
+      svn_txdelta_to_svndiff3(d_handler, d_baton, stream,
+                              svn_ra_svn__svndiff_version(frb->conn),
+                              svn_ra_svn_compression_level(frb->conn), pool);
     }
   else
     SVN_ERR(svn_ra_svn__write_cstring(frb->conn, pool, ""));
@@ -3545,7 +3585,7 @@ typedef struct list_receiver_baton_t
   svn_ra_svn_conn_t *conn;
 
   /* Send the field selected by these flags. */
-  apr_uint64_t dirent_fields;
+  apr_uint32_t dirent_fields;
 } list_receiver_baton_t;
 
 /* Implements svn_repos_dirent_receiver_t, sending DIRENT and PATH to the
@@ -3739,8 +3779,7 @@ repos_path_valid(const char *path)
  * and fs_path fields of REPOSITORY.  VHOST and READ_ONLY flags are the
  * same as in the server baton.
  *
- * CONFIG_POOL and AUTHZ_POOL shall be used to load any object of the
- * respective type.
+ * CONFIG_POOL shall be used to load config objects.
  *
  * Use SCRATCH_POOL for temporary allocations.
  *
@@ -3753,13 +3792,13 @@ find_repos(const char *url,
            svn_config_t *cfg,
            repository_t *repository,
            svn_repos__config_pool_t *config_pool,
-           svn_repos__authz_pool_t *authz_pool,
            apr_hash_t *fs_config,
            apr_pool_t *result_pool,
            apr_pool_t *scratch_pool)
 {
   const char *path, *full_path, *fs_path, *hooks_env;
   svn_stringbuf_t *url_buf;
+  svn_boolean_t sasl_requested;
 
   /* Skip past the scheme and authority part. */
   path = skip_scheme_part(url);
@@ -3822,25 +3861,27 @@ find_repos(const char *url,
     {
       repository->base = svn_repos_conf_dir(repository->repos, result_pool);
 
-      SVN_ERR(svn_repos__config_pool_get(&cfg, NULL, config_pool,
+      SVN_ERR(svn_repos__config_pool_get(&cfg, config_pool,
                                          svn_repos_svnserve_conf
                                             (repository->repos, result_pool),
-                                         FALSE, FALSE, repository->repos,
+                                         FALSE, repository->repos,
                                          result_pool));
     }
 
   SVN_ERR(load_pwdb_config(repository, cfg, config_pool, result_pool));
   SVN_ERR(load_authz_config(repository, repository->repos_root, cfg,
-                            authz_pool, result_pool));
+                            result_pool));
 
-#ifdef SVN_HAVE_SASL
+  /* Should we use Cyrus SASL? */
+  SVN_ERR(svn_config_get_bool(cfg, &sasl_requested,
+                              SVN_CONFIG_SECTION_SASL,
+                              SVN_CONFIG_OPTION_USE_SASL, FALSE));
+  if (sasl_requested)
     {
+#ifdef SVN_HAVE_SASL
       const char *val;
 
-      /* Should we use Cyrus SASL? */
-      SVN_ERR(svn_config_get_bool(cfg, &repository->use_sasl,
-                                  SVN_CONFIG_SECTION_SASL,
-                                  SVN_CONFIG_OPTION_USE_SASL, FALSE));
+      repository->use_sasl = sasl_requested;
 
       svn_config_get(cfg, &val, SVN_CONFIG_SECTION_SASL,
                     SVN_CONFIG_OPTION_MIN_SSF, "0");
@@ -3849,8 +3890,18 @@ find_repos(const char *url,
       svn_config_get(cfg, &val, SVN_CONFIG_SECTION_SASL,
                     SVN_CONFIG_OPTION_MAX_SSF, "256");
       SVN_ERR(svn_cstring_atoui(&repository->max_ssf, val));
+#else /* !SVN_HAVE_SASL */
+      return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+                               _("SASL requested but not compiled in; "
+                                 "set '%s' to 'false' or recompile "
+                                 "svnserve with SASL support"),
+                               SVN_CONFIG_OPTION_USE_SASL);
+#endif /* SVN_HAVE_SASL */
+    }
+  else
+    {
+      repository->use_sasl = FALSE;
     }
-#endif
 
   /* Use the repository UUID as the default realm. */
   SVN_ERR(svn_fs_get_uuid(repository->fs, &repository->realm, scratch_pool));
@@ -4078,10 +4129,11 @@ construct_server_baton(server_baton_t **
    * send an empty mechlist. */
   if (params->compression_level > 0)
     SVN_ERR(svn_ra_svn__write_cmd_response(conn, scratch_pool,
-                                           "nn()(wwwwwwwwwwww)",
+                                           "nn()(wwwwwwwwwwwww)",
                                            (apr_uint64_t) 2, (apr_uint64_t) 2,
                                            SVN_RA_SVN_CAP_EDIT_PIPELINE,
                                            SVN_RA_SVN_CAP_SVNDIFF1,
+                                           SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED,
                                            SVN_RA_SVN_CAP_ABSENT_ENTRIES,
                                            SVN_RA_SVN_CAP_COMMIT_REVPROPS,
                                            SVN_RA_SVN_CAP_DEPTH,
@@ -4165,7 +4217,7 @@ construct_server_baton(server_baton_t **
   err = handle_config_error(find_repos(client_url, params->root, b->vhost,
                                        b->read_only, params->cfg,
                                        b->repository, params->config_pool,
-                                       params->authz_pool, params->fs_config,
+                                       params->fs_config,
                                        conn_pool, scratch_pool),
                             b);
   if (!err)

Modified: subversion/branches/ra-git/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnserve/server.h?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnserve/server.h (original)
+++ subversion/branches/ra-git/subversion/svnserve/server.h Wed Nov  7 12:30:06 2018
@@ -127,9 +127,6 @@ typedef struct serve_params_t {
   /* all configurations should be opened through this factory */
   svn_repos__config_pool_t *config_pool;
 
-  /* all authz data should be opened through this factory */
-  svn_repos__authz_pool_t *authz_pool;
-
   /* The FS configuration to be applied to all repositories.
      It mainly contains things like cache settings. */
   apr_hash_t *fs_config;

Modified: subversion/branches/ra-git/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/svnserve/svnserve.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/ra-git/subversion/svnserve/svnserve.c Wed Nov  7 12:30:06 2018
@@ -479,7 +479,7 @@ static svn_error_t * version(svn_boolean
                            _("\nCyrus SASL authentication is available.\n"));
 #endif
 
-  return svn_opt_print_help4(NULL, "svnserve", TRUE, quiet, FALSE,
+  return svn_opt_print_help5(NULL, "svnserve", TRUE, quiet, FALSE,
                              version_footer->data,
                              NULL, NULL, NULL, NULL, NULL, pool);
 }
@@ -752,6 +752,9 @@ sub_main(int *exit_code, int argc, const
   /* Initialize the FS library. */
   SVN_ERR(svn_fs_initialize(pool));
 
+  /* Initialize the efficient Authz support. */
+  SVN_ERR(svn_repos_authz_initialize(pool));
+
   SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
 
   params.root = "/";
@@ -763,7 +766,6 @@ sub_main(int *exit_code, int argc, const
   params.compression_level = SVN_DELTA_COMPRESSION_LEVEL_DEFAULT;
   params.logger = NULL;
   params.config_pool = NULL;
-  params.authz_pool = NULL;
   params.fs_config = NULL;
   params.vhost = FALSE;
   params.username_case = CASE_ASIS;
@@ -899,7 +901,12 @@ sub_main(int *exit_code, int argc, const
           break;
 
         case 'M':
-          params.memory_cache_size = 0x100000 * apr_strtoi64(arg, NULL, 0);
+          {
+            apr_uint64_t sz_val;
+            SVN_ERR(svn_cstring_atoui64(&sz_val, arg));
+
+            params.memory_cache_size = 0x100000 * sz_val;
+          }
           break;
 
         case SVNSERVE_OPT_CACHE_TXDELTAS:
@@ -1046,10 +1053,6 @@ sub_main(int *exit_code, int argc, const
   SVN_ERR(svn_repos__config_pool_create(&params.config_pool,
                                         is_multi_threaded,
                                         pool));
-  SVN_ERR(svn_repos__authz_pool_create(&params.authz_pool,
-                                       params.config_pool,
-                                       is_multi_threaded,
-                                       pool));
 
   /* If a configuration file is specified, load it and any referenced
    * password and authorization files. */
@@ -1057,11 +1060,10 @@ sub_main(int *exit_code, int argc, const
     {
       params.base = svn_dirent_dirname(config_filename, pool);
 
-      SVN_ERR(svn_repos__config_pool_get(&params.cfg, NULL,
+      SVN_ERR(svn_repos__config_pool_get(&params.cfg,
                                          params.config_pool,
                                          config_filename,
                                          TRUE, /* must_exist */
-                                         FALSE, /* names_case_sensitive */
                                          NULL,
                                          pool));
     }