subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bre...@apache.org
Subject svn commit: r1655189 [8/9] - in /subversion/branches/svn-auth-x509: ./ build/ build/generator/ subversion/bindings/javahl/native/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_fs_base/ subversion/libsvn_fs_...
Date Tue, 27 Jan 2015 23:27:46 GMT
Modified: subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c?rev=1655189&r1=1655188&r2=1655189&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c (original)
+++ subversion/branches/svn-auth-x509/subversion/svndumpfilter/svndumpfilter.c Tue Jan 27 23:27:44 2015
@@ -43,6 +43,7 @@
 #include "svn_mergeinfo.h"
 #include "svn_version.h"
 
+#include "private/svn_repos_private.h"
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_cmdline_private.h"
 #include "private/svn_sorts_private.h"
@@ -240,7 +241,6 @@ struct revision_baton_t
 
   /* Does this revision have node or prop changes? */
   svn_boolean_t has_nodes;
-  svn_boolean_t has_props;
 
   /* Did we drop any nodes? */
   svn_boolean_t had_dropped_nodes;
@@ -253,7 +253,7 @@ struct revision_baton_t
   svn_revnum_t rev_actual;
 
   /* Pointers to dumpfile data. */
-  svn_stringbuf_t *header;
+  apr_hash_t *original_headers;
   apr_hash_t *props;
 };
 
@@ -278,7 +278,7 @@ struct node_baton_t
   svn_filesize_t tcl;
 
   /* Pointers to dumpfile data. */
-  svn_stringbuf_t *header;
+  apr_array_header_t *headers;
   svn_stringbuf_t *props;
 
   /* Expect deltas? */
@@ -287,6 +287,8 @@ struct node_baton_t
 
   /* We might need the node path in a parse error message. */
   char *node_path;
+
+  apr_pool_t *node_pool;
 };
 
 
@@ -310,6 +312,24 @@ magic_header_record(int version, void *p
 }
 
 
+/* Return a deep copy of a (char * -> char *) hash. */
+static apr_hash_t *
+headers_dup(apr_hash_t *headers,
+            apr_pool_t *pool)
+{
+  apr_hash_t *new_hash = apr_hash_make(pool);
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
+    {
+      const char *key = apr_hash_this_key(hi);
+      const char *val = apr_hash_this_val(hi);
+
+      svn_hash_sets(new_hash, apr_pstrdup(pool, key), apr_pstrdup(pool, val));
+    }
+  return new_hash;
+}
+
 /* New revision: set up revision_baton, decide if we skip it. */
 static svn_error_t *
 new_revision_record(void **revision_baton,
@@ -318,21 +338,16 @@ new_revision_record(void **revision_bato
                     apr_pool_t *pool)
 {
   struct revision_baton_t *rb;
-  apr_hash_index_t *hi;
   const char *rev_orig;
-  svn_stream_t *header_stream;
 
   *revision_baton = apr_palloc(pool, sizeof(struct revision_baton_t));
   rb = *revision_baton;
   rb->pb = parse_baton;
   rb->has_nodes = FALSE;
-  rb->has_props = FALSE;
   rb->had_dropped_nodes = FALSE;
   rb->writing_begun = FALSE;
-  rb->header = svn_stringbuf_create_empty(pool);
   rb->props = apr_hash_make(pool);
-
-  header_stream = svn_stream_from_stringbuf(rb->header, pool);
+  rb->original_headers = headers_dup(headers, pool);
 
   rev_orig = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_REVISION_NUMBER);
   rb->rev_orig = SVN_STR_TO_REV(rev_orig);
@@ -342,28 +357,6 @@ new_revision_record(void **revision_bato
   else
     rb->rev_actual = rb->rev_orig;
 
-  SVN_ERR(svn_stream_printf(header_stream, pool,
-                            SVN_REPOS_DUMPFILE_REVISION_NUMBER ": %ld\n",
-                            rb->rev_actual));
-
-  for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
-    {
-      const char *key = apr_hash_this_key(hi);
-      const char *val = apr_hash_this_val(hi);
-
-      if ((!strcmp(key, SVN_REPOS_DUMPFILE_CONTENT_LENGTH))
-          || (!strcmp(key, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH))
-          || (!strcmp(key, SVN_REPOS_DUMPFILE_REVISION_NUMBER)))
-        continue;
-
-      /* passthru: put header into header stringbuf. */
-
-      SVN_ERR(svn_stream_printf(header_stream, pool, "%s: %s\n",
-                                key, val));
-    }
-
-  SVN_ERR(svn_stream_close(header_stream));
-
   return SVN_NO_ERROR;
 }
 
@@ -375,12 +368,8 @@ new_revision_record(void **revision_bato
 static svn_error_t *
 output_revision(struct revision_baton_t *rb)
 {
-  int bytes_used;
-  char buf[SVN_KEYLINE_MAXLEN];
-  apr_hash_index_t *hi;
   svn_boolean_t write_out_rev = FALSE;
   apr_pool_t *hash_pool = apr_hash_pool_get(rb->props);
-  svn_stringbuf_t *props = svn_stringbuf_create_empty(hash_pool);
   apr_pool_t *subpool = svn_pool_create(hash_pool);
 
   rb->writing_begun = TRUE;
@@ -398,7 +387,6 @@ output_revision(struct revision_baton_t
       && (! rb->pb->drop_all_empty_revs))
     {
       apr_hash_t *old_props = rb->props;
-      rb->has_props = TRUE;
       rb->props = apr_hash_make(hash_pool);
       svn_hash_sets(rb->props, SVN_PROP_REVISION_DATE,
                     svn_hash_gets(old_props, SVN_PROP_REVISION_DATE));
@@ -407,39 +395,6 @@ output_revision(struct revision_baton_t
                                         "padding."), hash_pool));
     }
 
-  /* Now, "rasterize" the props to a string, and append the property
-     information to the header string.  */
-  if (rb->has_props)
-    {
-      for (hi = apr_hash_first(subpool, rb->props);
-           hi;
-           hi = apr_hash_next(hi))
-        {
-          const char *pname = apr_hash_this_key(hi);
-          const svn_string_t *pval = apr_hash_this_val(hi);
-
-          write_prop_to_stringbuf(props, pname, pval);
-        }
-      svn_stringbuf_appendcstr(props, "PROPS-END\n");
-      svn_stringbuf_appendcstr(rb->header,
-                               SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH);
-      bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT,
-                                props->len);
-      svn_stringbuf_appendbytes(rb->header, buf, bytes_used);
-      svn_stringbuf_appendbyte(rb->header, '\n');
-    }
-
-  svn_stringbuf_appendcstr(rb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH);
-  bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT, props->len);
-  svn_stringbuf_appendbytes(rb->header, buf, bytes_used);
-  svn_stringbuf_appendbyte(rb->header, '\n');
-
-  /* put an end to headers */
-  svn_stringbuf_appendbyte(rb->header, '\n');
-
-  /* put an end to revision */
-  svn_stringbuf_appendbyte(props, '\n');
-
   /* write out the revision */
   /* Revision is written out in the following cases:
      1. If the revision has nodes or
@@ -459,10 +414,12 @@ output_revision(struct revision_baton_t
   if (write_out_rev)
     {
       /* This revision is a keeper. */
-      SVN_ERR(svn_stream_write(rb->pb->out_stream,
-                               rb->header->data, &(rb->header->len)));
-      SVN_ERR(svn_stream_write(rb->pb->out_stream,
-                               props->data, &(props->len)));
+      SVN_ERR(svn_repos__dump_revision_record(rb->pb->out_stream,
+                                              rb->rev_actual,
+                                              rb->original_headers,
+                                              rb->props,
+                                              FALSE /*props_section_always*/,
+                                              subpool));
 
       /* Stash the oldest original rev not dropped. */
       if (rb->rev_orig > 0
@@ -544,6 +501,7 @@ new_node_record(void **node_baton,
   *node_baton = apr_palloc(pool, sizeof(struct node_baton_t));
   nb          = *node_baton;
   nb->rb      = rev_baton;
+  nb->node_pool = pool;
   pb          = nb->rb->pb;
 
   node_path = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_PATH);
@@ -615,7 +573,7 @@ new_node_record(void **node_baton,
       nb->has_text_delta = FALSE;
       nb->writing_begun = FALSE;
       nb->tcl = tcl ? svn__atoui64(tcl) : 0;
-      nb->header = svn_stringbuf_create_empty(pool);
+      nb->headers = svn_repos__dumpfile_headers_create(pool);
       nb->props = svn_stringbuf_create_empty(pool);
       nb->node_path = apr_pstrdup(pool, node_path);
 
@@ -627,23 +585,20 @@ new_node_record(void **node_baton,
 
       /* A node record is required to begin with 'Node-path', skip the
          leading '/' to match the form used by 'svnadmin dump'. */
-      SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                pool, "%s: %s\n",
-                                SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1));
+      svn_repos__dumpfile_header_push(
+        nb->headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_path + 1);
 
       /* Node-kind is next and is optional. */
       kind = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_KIND);
       if (kind)
-        SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                  pool, "%s: %s\n",
-                                  SVN_REPOS_DUMPFILE_NODE_KIND, kind));
+        svn_repos__dumpfile_header_push(
+          nb->headers, SVN_REPOS_DUMPFILE_NODE_KIND, kind);
 
       /* Node-action is next and required. */
       action = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_ACTION);
       if (action)
-        SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                  pool, "%s: %s\n",
-                                  SVN_REPOS_DUMPFILE_NODE_ACTION, action));
+        svn_repos__dumpfile_header_push(
+          nb->headers, SVN_REPOS_DUMPFILE_NODE_ACTION, action);
       else
         return svn_error_createf(SVN_ERR_INCOMPLETE_DATA, 0,
                                  _("Missing Node-action for path '%s'"),
@@ -690,18 +645,14 @@ new_node_record(void **node_baton,
                 return svn_error_createf
                   (SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
                    _("No valid copyfrom revision in filtered stream"));
-              SVN_ERR(svn_stream_printf
-                      (nb->rb->pb->out_stream, pool,
-                       SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV ": %ld\n",
-                       cf_renum_val->rev));
+              svn_repos__dumpfile_header_pushf(
+                nb->headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV,
+                "%ld", cf_renum_val->rev);
               continue;
             }
 
           /* passthru: put header straight to output */
-
-          SVN_ERR(svn_stream_printf(nb->rb->pb->out_stream,
-                                    pool, "%s: %s\n",
-                                    key, val));
+          svn_repos__dumpfile_header_push(nb->headers, key, val);
         }
     }
 
@@ -709,65 +660,6 @@ new_node_record(void **node_baton,
 }
 
 
-/* Output node header and props to dumpstream
-   This will be called by set_fulltext() after setting nb->has_text to TRUE,
-   if the node has any text, or by close_node() otherwise. This must only
-   be called if nb->writing_begun is FALSE. */
-static svn_error_t *
-output_node(struct node_baton_t *nb)
-{
-  int bytes_used;
-  char buf[SVN_KEYLINE_MAXLEN];
-
-  nb->writing_begun = TRUE;
-
-  /* when there are no props nb->props->len would be zero and won't mess up
-     Content-Length. */
-  if (nb->has_props)
-    svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
-
-  /* 1. recalculate & check text-md5 if present. Passed through right now. */
-
-  /* 2. recalculate and add content-lengths */
-
-  if (nb->has_props)
-    {
-      svn_stringbuf_appendcstr(nb->header,
-                               SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH);
-      bytes_used = apr_snprintf(buf, sizeof(buf), ": %" APR_SIZE_T_FMT,
-                                nb->props->len);
-      svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
-      svn_stringbuf_appendbyte(nb->header, '\n');
-    }
-  if (nb->has_text)
-    {
-      svn_stringbuf_appendcstr(nb->header,
-                               SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH);
-      bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT,
-                                nb->tcl);
-      svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
-      svn_stringbuf_appendbyte(nb->header, '\n');
-    }
-  svn_stringbuf_appendcstr(nb->header, SVN_REPOS_DUMPFILE_CONTENT_LENGTH);
-  bytes_used = apr_snprintf(buf, sizeof(buf), ": %" SVN_FILESIZE_T_FMT,
-                            (svn_filesize_t) (nb->props->len + nb->tcl));
-  svn_stringbuf_appendbytes(nb->header, buf, bytes_used);
-  svn_stringbuf_appendbyte(nb->header, '\n');
-
-  /* put an end to headers */
-  svn_stringbuf_appendbyte(nb->header, '\n');
-
-  /* 3. output all the stuff */
-
-  SVN_ERR(svn_stream_write(nb->rb->pb->out_stream,
-                           nb->header->data , &(nb->header->len)));
-  SVN_ERR(svn_stream_write(nb->rb->pb->out_stream,
-                           nb->props->data , &(nb->props->len)));
-
-  return SVN_NO_ERROR;
-}
-
-
 /* Examine the mergeinfo in INITIAL_VAL, omitting missing merge
    sources or renumbering revisions in rangelists as appropriate, and
    return the (possibly new) mergeinfo in *FINAL_VAL (allocated from
@@ -874,7 +766,6 @@ set_revision_property(void *revision_bat
   struct revision_baton_t *rb = revision_baton;
   apr_pool_t *hash_pool = apr_hash_pool_get(rb->props);
 
-  rb->has_props = TRUE;
   svn_hash_sets(rb->props,
                 apr_pstrdup(hash_pool, name),
                 svn_string_dup(value, hash_pool));
@@ -893,6 +784,9 @@ set_node_property(void *node_baton,
   if (nb->do_skip)
     return SVN_NO_ERROR;
 
+  /* Try to detect if a delta-mode property occurs unexpectedly. HAS_PROPS
+     can be false here only if the parser didn't call remove_node_props(),
+     so this may indicate a bug rather than bad data. */
   if (! (nb->has_props || nb->has_prop_delta))
     return svn_error_createf(SVN_ERR_STREAM_MALFORMED_DATA, NULL,
                              _("Delta property block detected, but deltas "
@@ -938,14 +832,17 @@ delete_node_property(void *node_baton, c
 }
 
 
+/* The parser calls this method if the node record has a non-delta
+ * property content section, before any calls to set_node_property().
+ * If the node record uses property deltas, this is not called.
+ */
 static svn_error_t *
 remove_node_props(void *node_baton)
 {
   struct node_baton_t *nb = node_baton;
 
   /* In this case, not actually indicating that the node *has* props,
-     rather that we know about all the props that it has, since it now
-     has none. */
+     rather that it has a property content section. */
   nb->has_props = TRUE;
 
   return SVN_NO_ERROR;
@@ -961,7 +858,20 @@ set_fulltext(svn_stream_t **stream, void
     {
       nb->has_text = TRUE;
       if (! nb->writing_begun)
-        SVN_ERR(output_node(nb));
+        {
+          nb->writing_begun = TRUE;
+          if (nb->has_props)
+            {
+              svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
+            }
+          SVN_ERR(svn_repos__dump_node_record(nb->rb->pb->out_stream,
+                                              nb->headers,
+                                              nb->has_props ? nb->props : NULL,
+                                              nb->has_text,
+                                              nb->tcl,
+                                              TRUE /*content_length_always*/,
+                                              nb->node_pool));
+        }
       *stream = nb->rb->pb->out_stream;
     }
 
@@ -982,7 +892,20 @@ close_node(void *node_baton)
 
   /* If the node was not flushed already to output its text, do it now. */
   if (! nb->writing_begun)
-    SVN_ERR(output_node(nb));
+    {
+      nb->writing_begun = TRUE;
+      if (nb->has_props)
+        {
+          svn_stringbuf_appendcstr(nb->props, "PROPS-END\n");
+        }
+      SVN_ERR(svn_repos__dump_node_record(nb->rb->pb->out_stream,
+                                          nb->headers,
+                                          nb->has_props ? nb->props : NULL,
+                                          nb->has_text,
+                                          nb->tcl,
+                                          TRUE /*content_length_always*/,
+                                          nb->node_pool));
+    }
 
   /* put an end to node. */
   SVN_ERR(svn_stream_write(nb->rb->pb->out_stream, "\n\n", &len));

Modified: subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c?rev=1655189&r1=1655188&r2=1655189&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c (original)
+++ subversion/branches/svn-auth-x509/subversion/svnmucc/svnmucc.c Tue Jan 27 23:27:44 2015
@@ -222,7 +222,7 @@ execute(const apr_array_header_t *action
                                 mtcc, iterpool);
 
   svn_pool_destroy(iterpool);
-  return svn_error_trace(err);;
+  return svn_error_trace(err);
 }
 
 static svn_error_t *

Modified: subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c?rev=1655189&r1=1655188&r2=1655189&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/svn-auth-x509/subversion/svnrdump/dump_editor.c Tue Jan 27 23:27:44 2015
@@ -30,6 +30,7 @@
 #include "svn_subst.h"
 #include "svn_dirent_uri.h"
 
+#include "private/svn_repos_private.h"
 #include "private/svn_subr_private.h"
 #include "private/svn_dep_compat.h"
 #include "private/svn_editor.h"
@@ -39,25 +40,16 @@
 
 #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
 
-#if 0
-#define LDR_DBG(x) SVN_DBG(x)
-#else
-#define LDR_DBG(x) while(0)
-#endif
 
 /* A directory baton used by all directory-related callback functions
  * in the dump editor.  */
 struct dir_baton
 {
   struct dump_edit_baton *eb;
-  struct dir_baton *parent_dir_baton;
 
   /* Pool for per-directory allocations */
   apr_pool_t *pool;
 
-  /* is this directory a new addition to this revision? */
-  svn_boolean_t added;
-
   /* the path to this directory */
   const char *repos_relpath; /* a relpath */
 
@@ -65,6 +57,9 @@ struct dir_baton
   const char *copyfrom_path; /* a relpath */
   svn_revnum_t copyfrom_rev;
 
+  /* Headers accumulated so far for this directory */
+  apr_array_header_t *headers;
+
   /* Properties which were modified during change_dir_prop. */
   apr_hash_t *props;
 
@@ -87,7 +82,6 @@ struct dir_baton
 struct file_baton
 {
   struct dump_edit_baton *eb;
-  struct dir_baton *parent_dir_baton;
 
   /* Pool for per-file allocations */
   apr_pool_t *pool;
@@ -145,11 +139,10 @@ struct dump_edit_baton {
   /* The revision we're currently dumping. */
   svn_revnum_t current_revision;
 
-  /* The kind (file or directory) and baton of the item whose block of
+  /* The baton of the directory node whose block of
      dump stream data has not been fully completed; NULL if there's no
      such item. */
-  svn_node_kind_t pending_kind;
-  void *pending_baton;
+  struct dir_baton *pending_db;
 };
 
 /* Make a directory baton to represent the directory at PATH (relative
@@ -161,16 +154,15 @@ struct dump_edit_baton {
  * copy source.
  *
  * PB is the directory baton of this directory's parent, or NULL if
- * this is the top-level directory of the edit.  ADDED indicates if
- * this directory is newly added in this revision.  Perform all
- * allocations in POOL.  */
+ * this is the top-level directory of the edit.
+ *
+ * Perform all allocations in POOL.  */
 static struct dir_baton *
 make_dir_baton(const char *path,
                const char *copyfrom_path,
                svn_revnum_t copyfrom_rev,
                void *edit_baton,
                struct dir_baton *pb,
-               svn_boolean_t added,
                apr_pool_t *pool)
 {
   struct dump_edit_baton *eb = edit_baton;
@@ -189,14 +181,13 @@ make_dir_baton(const char *path,
     copyfrom_path = svn_relpath_canonicalize(copyfrom_path, pool);
 
   new_db->eb = eb;
-  new_db->parent_dir_baton = pb;
   new_db->pool = pool;
   new_db->repos_relpath = repos_relpath;
   new_db->copyfrom_path = copyfrom_path
                             ? svn_relpath_canonicalize(copyfrom_path, pool)
                             : NULL;
   new_db->copyfrom_rev = copyfrom_rev;
-  new_db->added = added;
+  new_db->headers = NULL;
   new_db->props = apr_hash_make(pool);
   new_db->deleted_props = apr_hash_make(pool);
   new_db->deleted_entries = apr_hash_make(pool);
@@ -216,7 +207,6 @@ make_file_baton(const char *path,
   struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
 
   new_fb->eb = pb->eb;
-  new_fb->parent_dir_baton = pb;
   new_fb->pool = pool;
   new_fb->repos_relpath = svn_relpath_canonicalize(path, pool);
   new_fb->props = apr_hash_make(pool);
@@ -229,9 +219,11 @@ make_file_baton(const char *path,
   return new_fb;
 }
 
-/* Return in *HEADER and *CONTENT the headers and content for PROPS. */
+/* Append to HEADERS the required headers, and set *CONTENT to the property
+ * content section, to represent the property delta of PROPS/DELETED_PROPS.
+ */
 static svn_error_t *
-get_props_content(svn_stringbuf_t **header,
+get_props_content(apr_array_header_t *headers,
                   svn_stringbuf_t **content,
                   apr_hash_t *props,
                   apr_hash_t *deleted_props,
@@ -240,10 +232,8 @@ get_props_content(svn_stringbuf_t **head
 {
   svn_stream_t *content_stream;
   apr_hash_t *normal_props;
-  const char *buf;
 
   *content = svn_stringbuf_create_empty(result_pool);
-  *header = svn_stringbuf_create_empty(result_pool);
 
   content_stream = svn_stream_from_stringbuf(*content, scratch_pool);
 
@@ -254,100 +244,60 @@ get_props_content(svn_stringbuf_t **head
   SVN_ERR(svn_stream_close(content_stream));
 
   /* Prop-delta: true */
-  *header = svn_stringbuf_createf(result_pool, SVN_REPOS_DUMPFILE_PROP_DELTA
-                                  ": true\n");
-
-  /* Prop-content-length: 193 */
-  buf = apr_psprintf(scratch_pool, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                     ": %" APR_SIZE_T_FMT "\n", (*content)->len);
-  svn_stringbuf_appendcstr(*header, buf);
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_PROP_DELTA, "true");
 
   return SVN_NO_ERROR;
 }
 
-/* Extract and dump properties stored in PROPS and property deletions
- * stored in DELETED_PROPS. If TRIGGER_VAR is not NULL, it is set to
- * FALSE.
+/* A special case of dump_node(), for a delete record.
  *
- * If PROPSTRING is non-NULL, set *PROPSTRING to a string containing
- * the content block of the property changes; otherwise, dump that to
- * the stream, too.
+ * The only thing special about this version is it only writes one blank
+ * line, not two, after the headers. Why? Historical precedent for the
+ * case where a delete record is used as part of a (delete + add-with-history)
+ * in implementing a replacement.
  */
 static svn_error_t *
-do_dump_props(svn_stringbuf_t **propstring,
-              svn_stream_t *stream,
-              apr_hash_t *props,
-              apr_hash_t *deleted_props,
-              svn_boolean_t *trigger_var,
-              apr_pool_t *result_pool,
-              apr_pool_t *scratch_pool)
-{
-  svn_stringbuf_t *header;
-  svn_stringbuf_t *content;
-  apr_size_t len;
-
-  if (trigger_var && !*trigger_var)
-    return SVN_NO_ERROR;
-
-  SVN_ERR(get_props_content(&header, &content, props, deleted_props,
-                            result_pool, scratch_pool));
-  len = header->len;
-  SVN_ERR(svn_stream_write(stream, header->data, &len));
-
-  if (propstring)
-    {
-      *propstring = content;
-    }
-  else
-    {
-      /* Content-length: 14 */
-      SVN_ERR(svn_stream_printf(stream, scratch_pool,
-                                SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                                ": %" APR_SIZE_T_FMT "\n\n",
-                                content->len));
-
-      len = content->len;
-      SVN_ERR(svn_stream_write(stream, content->data, &len));
+dump_node_delete(svn_stream_t *stream,
+                 const char *node_relpath,
+                 apr_pool_t *pool)
+{
+  apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
 
-      /* No text is going to be dumped. Write a couple of newlines and
-         wait for the next node/ revision. */
-      SVN_ERR(svn_stream_puts(stream, "\n\n"));
+  assert(svn_relpath_is_canonical(node_relpath));
 
-      /* Cleanup so that data is never dumped twice. */
-      apr_hash_clear(props);
-      apr_hash_clear(deleted_props);
-      if (trigger_var)
-        *trigger_var = FALSE;
-    }
+  /* Node-path: ... */
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
 
-  return SVN_NO_ERROR;
-}
+  /* Node-action: delete */
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
 
-static svn_error_t *
-do_dump_newlines(struct dump_edit_baton *eb,
-                 svn_boolean_t *trigger_var,
-                 apr_pool_t *pool)
-{
-  if (trigger_var && *trigger_var)
-    {
-      SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
-      *trigger_var = FALSE;
-    }
+  SVN_ERR(svn_repos__dump_headers(stream, headers, TRUE, pool));
   return SVN_NO_ERROR;
 }
 
-/*
- * Write out a node record for PATH of type KIND under EB->FS_ROOT.
+/* Set *HEADERS_P to contain some headers for the node at PATH of type KIND.
+ *
  * ACTION describes what is happening to the node (see enum
- * svn_node_action). Write record to writable EB->STREAM.
+ * svn_node_action).
  *
  * If the node was itself copied, IS_COPY is TRUE and the
  * path/revision of the copy source are in COPYFROM_PATH/COPYFROM_REV.
  * If IS_COPY is FALSE, yet COPYFROM_PATH/COPYFROM_REV are valid, this
  * node is part of a copied subtree.
+ *
+ * Iff ACTION is svn_node_action_replace and IS_COPY, then first write a
+ * complete deletion record to the dump stream.
+ *
+ * If ACTION is svn_node_action_delete, then the node record will be
+ * complete. (The caller may want to write two blank lines after the
+ * header block.)
  */
 static svn_error_t *
-dump_node(struct dump_edit_baton *eb,
+dump_node(apr_array_header_t **headers_p,
+          struct dump_edit_baton *eb,
           const char *repos_relpath,
           struct dir_baton *db,
           struct file_baton *fb,
@@ -358,6 +308,7 @@ dump_node(struct dump_edit_baton *eb,
           apr_pool_t *pool)
 {
   const char *node_relpath = repos_relpath;
+  apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
 
   assert(svn_relpath_is_canonical(repos_relpath));
   assert(!copyfrom_path || svn_relpath_is_canonical(copyfrom_path));
@@ -369,17 +320,16 @@ dump_node(struct dump_edit_baton *eb,
                                     node_relpath, pool);
 
   /* Node-path: ... */
-  SVN_ERR(svn_stream_printf(eb->stream, pool,
-                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
-                            node_relpath));
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_PATH, node_relpath);
 
   /* Node-kind: "file" | "dir" */
   if (fb)
-    SVN_ERR(svn_stream_printf(eb->stream, pool,
-                              SVN_REPOS_DUMPFILE_NODE_KIND ": file\n"));
+    svn_repos__dumpfile_header_push(
+      headers, SVN_REPOS_DUMPFILE_NODE_KIND, "file");
   else if (db)
-    SVN_ERR(svn_stream_printf(eb->stream, pool,
-                              SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+    svn_repos__dumpfile_header_push(
+      headers, SVN_REPOS_DUMPFILE_NODE_KIND, "dir");
 
 
   /* Write the appropriate Node-action header */
@@ -391,26 +341,22 @@ dump_node(struct dump_edit_baton *eb,
          do here but print node action information.
 
          Node-action: change.  */
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": change\n"));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "change");
+      break;
+
+    case svn_node_action_delete:
+      /* Node-action: delete */
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
       break;
 
     case svn_node_action_replace:
-      if (is_copy)
-        {
-          /* Delete the original, and then re-add the replacement as a
-             copy using recursive calls into this function. */
-          SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_delete,
-                            FALSE, NULL, SVN_INVALID_REVNUM, pool));
-          SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_add,
-                            is_copy, copyfrom_path, copyfrom_rev, pool));
-        }
-      else
+      if (! is_copy)
         {
           /* Node-action: replace */
-          SVN_ERR(svn_stream_puts(eb->stream,
-                                  SVN_REPOS_DUMPFILE_NODE_ACTION
-                                  ": replace\n"));
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "replace");
 
           /* Wait for a change_*_prop to be called before dumping
              anything */
@@ -418,35 +364,36 @@ dump_node(struct dump_edit_baton *eb,
             fb->dump_props = TRUE;
           else if (db)
             db->dump_props = TRUE;
+          break;
         }
-      break;
-
-    case svn_node_action_delete:
-      /* Node-action: delete */
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
-
-      /* We can leave this routine quietly now. Nothing more to do-
-         print a couple of newlines because we're not dumping props or
-         text. */
-      SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
+      else
+        {
+          /* More complex case: is_copy is true, and copyfrom_path/
+             copyfrom_rev are present: delete the original, and then re-add
+             it */
+          /* ### Why not write a 'replace' record? Don't know. */
+
+          /* ### Unusually, we end this 'delete' node record with only a single
+                 blank line after the header block -- no extra blank line. */
+          SVN_ERR(dump_node_delete(eb->stream, repos_relpath, pool));
 
-      break;
+          /* The remaining action is a non-replacing add-with-history */
+          /* action = svn_node_action_add; */
+        }
+      /* FALL THROUGH to 'add' */
 
     case svn_node_action_add:
       /* Node-action: add */
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "add");
 
       if (is_copy)
         {
           /* Node-copyfrom-rev / Node-copyfrom-path */
-          SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV
-                                    ": %ld\n"
-                                    SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH
-                                    ": %s\n",
-                                    copyfrom_rev, copyfrom_path));
+          svn_repos__dumpfile_header_pushf(
+            headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_REV, "%ld", copyfrom_rev);
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_NODE_COPYFROM_PATH, copyfrom_path);
 
           /* Ugly hack: If a directory was copied from a previous
              revision, nothing like close_file() will be called to write two
@@ -484,6 +431,11 @@ dump_node(struct dump_edit_baton *eb,
 
       break;
     }
+
+  /* Return the headers so far. We don't necessarily have all the headers
+     yet -- there may be property-related and content length headers to
+     come, if this was not a 'delete' record. */
+  *headers_p = headers;
   return SVN_NO_ERROR;
 }
 
@@ -492,35 +444,28 @@ dump_mkdir(struct dump_edit_baton *eb,
            const char *repos_relpath,
            apr_pool_t *pool)
 {
-  svn_stringbuf_t *prop_header, *prop_content;
-  apr_size_t len;
-  const char *buf;
+  svn_stringbuf_t *prop_content;
+  apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
 
   /* Node-path: ... */
-  SVN_ERR(svn_stream_printf(eb->stream, pool,
-                            SVN_REPOS_DUMPFILE_NODE_PATH ": %s\n",
-                            repos_relpath));
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_PATH, repos_relpath);
 
   /* Node-kind: dir */
-  SVN_ERR(svn_stream_printf(eb->stream, pool,
-                            SVN_REPOS_DUMPFILE_NODE_KIND ": dir\n"));
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_KIND, "dir");
 
   /* Node-action: add */
-  SVN_ERR(svn_stream_puts(eb->stream,
-                          SVN_REPOS_DUMPFILE_NODE_ACTION ": add\n"));
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "add");
 
   /* Dump the (empty) property block. */
-  SVN_ERR(get_props_content(&prop_header, &prop_content,
+  SVN_ERR(get_props_content(headers, &prop_content,
                             apr_hash_make(pool), apr_hash_make(pool),
                             pool, pool));
-  len = prop_header->len;
-  SVN_ERR(svn_stream_write(eb->stream, prop_header->data, &len));
-  len = prop_content->len;
-  buf = apr_psprintf(pool, SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                     ": %" APR_SIZE_T_FMT "\n", len);
-  SVN_ERR(svn_stream_puts(eb->stream, buf));
-  SVN_ERR(svn_stream_puts(eb->stream, "\n"));
-  SVN_ERR(svn_stream_write(eb->stream, prop_content->data, &len));
+  SVN_ERR(svn_repos__dump_node_record(eb->stream, headers, prop_content,
+                                      FALSE, 0, FALSE /*content_length_always*/,
+                                      pool));
 
   /* Newlines to tie it all off. */
   SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
@@ -528,40 +473,50 @@ dump_mkdir(struct dump_edit_baton *eb,
   return SVN_NO_ERROR;
 }
 
-/* Dump pending items from the specified node, to allow starting the dump
-   of a child node */
+/* Dump pending headers and properties for the directory EB->pending_db (if
+ * not null), to allow starting the dump of a child node */
 static svn_error_t *
-dump_pending(struct dump_edit_baton *eb,
-             apr_pool_t *scratch_pool)
+dump_pending_dir(struct dump_edit_baton *eb,
+                 apr_pool_t *scratch_pool)
 {
-  if (! eb->pending_baton)
+  struct dir_baton *db = eb->pending_db;
+  svn_stringbuf_t *prop_content = NULL;
+
+  if (! db)
     return SVN_NO_ERROR;
 
-  if (eb->pending_kind == svn_node_dir)
+  /* Some pending properties to dump? */
+  if (db->dump_props)
     {
-      struct dir_baton *db = eb->pending_baton;
+      SVN_ERR(get_props_content(db->headers, &prop_content,
+                                db->props, db->deleted_props,
+                                scratch_pool, scratch_pool));
+    }
+  SVN_ERR(svn_repos__dump_node_record(eb->stream, db->headers, prop_content,
+                                      FALSE, 0, FALSE /*content_length_always*/,
+                                      scratch_pool));
 
-      /* Some pending properties to dump? */
-      SVN_ERR(do_dump_props(NULL, eb->stream, db->props, db->deleted_props,
-                            &(db->dump_props), db->pool, scratch_pool));
+  if (db->dump_props)
+    {
+      /* No text is going to be dumped. Write a couple of newlines and
+         wait for the next node/ revision. */
+      SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
 
-      /* Some pending newlines to dump? */
-      SVN_ERR(do_dump_newlines(eb, &(db->dump_newlines), scratch_pool));
+      /* Cleanup so that data is never dumped twice. */
+      apr_hash_clear(db->props);
+      apr_hash_clear(db->deleted_props);
+      db->dump_props = FALSE;
     }
-  else if (eb->pending_kind == svn_node_file)
-    {
-      struct file_baton *fb = eb->pending_baton;
 
-      /* Some pending properties to dump? */
-      SVN_ERR(do_dump_props(NULL, eb->stream, fb->props, fb->deleted_props,
-                            &(fb->dump_props), fb->pool, scratch_pool));
+  /* Some pending newlines to dump? */
+  if (db->dump_newlines)
+    {
+      SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
+      db->dump_newlines = FALSE;
     }
-  else
-    abort();
 
   /* Anything that was pending is pending no longer. */
-  eb->pending_baton = NULL;
-  eb->pending_kind = svn_node_none;
+  eb->pending_db = NULL;
 
   return SVN_NO_ERROR;
 }
@@ -582,8 +537,6 @@ open_root(void *edit_baton,
   /* Clear the per-revision pool after each revision */
   svn_pool_clear(eb->pool);
 
-  LDR_DBG(("open_root %p\n", *root_baton));
-
   if (eb->update_anchor_relpath)
     {
       int i;
@@ -616,15 +569,15 @@ open_root(void *edit_baton,
               /* ... but for the source directory itself, we'll defer
                  to letting the typical plumbing handle this task. */
               new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                                      edit_baton, NULL, TRUE, pool);
-              SVN_ERR(dump_node(eb, new_db->repos_relpath, new_db,
+                                      edit_baton, NULL, pool);
+              SVN_ERR(dump_node(&new_db->headers,
+                                eb, new_db->repos_relpath, new_db,
                                 NULL, svn_node_action_add, FALSE,
                                 NULL, SVN_INVALID_REVNUM, pool));
 
               /* Remember that we've started but not yet finished
                  handling this directory. */
-              eb->pending_baton = new_db;
-              eb->pending_kind = svn_node_dir;
+              eb->pending_db = new_db;
             }
         }
       svn_pool_destroy(iterpool);
@@ -633,7 +586,7 @@ open_root(void *edit_baton,
   if (! new_db)
     {
       new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                              edit_baton, NULL, FALSE, pool);
+                              edit_baton, NULL, pool);
     }
 
   *root_baton = new_db;
@@ -648,9 +601,7 @@ delete_entry(const char *path,
 {
   struct dir_baton *pb = parent_baton;
 
-  LDR_DBG(("delete_entry %s\n", path));
-
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* We don't dump this deletion immediate.  Rather, we add this path
      to the deleted_entries of the parent directory baton.  That way,
@@ -670,39 +621,37 @@ add_directory(const char *path,
               void **child_baton)
 {
   struct dir_baton *pb = parent_baton;
-  void *val;
+  void *was_deleted;
   struct dir_baton *new_db;
   svn_boolean_t is_copy;
 
-  LDR_DBG(("add_directory %s\n", path));
-
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
-                          pb, TRUE, pb->pool);
+                          pb, pb->pool);
 
   /* This might be a replacement -- is the path already deleted? */
-  val = svn_hash_gets(pb->deleted_entries, path);
+  was_deleted = svn_hash_gets(pb->deleted_entries, path);
 
   /* Detect an add-with-history */
   is_copy = ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev);
 
   /* Dump the node */
-  SVN_ERR(dump_node(pb->eb, new_db->repos_relpath, new_db, NULL,
-                    val ? svn_node_action_replace : svn_node_action_add,
+  SVN_ERR(dump_node(&new_db->headers,
+                    pb->eb, new_db->repos_relpath, new_db, NULL,
+                    was_deleted ? svn_node_action_replace : svn_node_action_add,
                     is_copy,
                     is_copy ? new_db->copyfrom_path : NULL,
                     is_copy ? copyfrom_rev : SVN_INVALID_REVNUM,
                     pool));
 
-  if (val)
+  if (was_deleted)
     /* Delete the path, it's now been dumped */
     svn_hash_sets(pb->deleted_entries, path, NULL);
 
   /* Remember that we've started, but not yet finished handling this
      directory. */
-  pb->eb->pending_baton = new_db;
-  pb->eb->pending_kind = svn_node_dir;
+  pb->eb->pending_db = new_db;
 
   *child_baton = new_db;
   return SVN_NO_ERROR;
@@ -720,9 +669,7 @@ open_directory(const char *path,
   const char *copyfrom_path = NULL;
   svn_revnum_t copyfrom_rev = SVN_INVALID_REVNUM;
 
-  LDR_DBG(("open_directory %s\n", path));
-
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* If the parent directory has explicit comparison path and rev,
      record the same for this one. */
@@ -735,7 +682,7 @@ open_directory(const char *path,
     }
 
   new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
-                          FALSE, pb->pool);
+                          pb->pool);
 
   *child_baton = new_db;
   return SVN_NO_ERROR;
@@ -749,12 +696,10 @@ close_directory(void *dir_baton,
   apr_hash_index_t *hi;
   svn_boolean_t this_pending;
 
-  LDR_DBG(("close_directory %p\n", dir_baton));
-
   /* Remember if this directory is the one currently pending. */
-  this_pending = (db->eb->pending_baton == db);
+  this_pending = (db->eb->pending_db == db);
 
-  SVN_ERR(dump_pending(db->eb, pool));
+  SVN_ERR(dump_pending_dir(db->eb, pool));
 
   /* If this directory was pending, then dump_pending() should have
      taken care of all the props and such.  Of course, the only way
@@ -767,12 +712,12 @@ close_directory(void *dir_baton,
      directory. */
   if ((! this_pending) && (db->dump_props))
     {
-      SVN_ERR(dump_node(db->eb, db->repos_relpath, db, NULL,
+      SVN_ERR(dump_node(&db->headers,
+                        db->eb, db->repos_relpath, db, NULL,
                         svn_node_action_change, FALSE,
                         NULL, SVN_INVALID_REVNUM, pool));
-      db->eb->pending_baton = db;
-      db->eb->pending_kind = svn_node_dir;
-      SVN_ERR(dump_pending(db->eb, pool));
+      db->eb->pending_db = db;
+      SVN_ERR(dump_pending_dir(db->eb, pool));
     }
 
   /* Dump the deleted directory entries */
@@ -781,8 +726,9 @@ close_directory(void *dir_baton,
     {
       const char *path = apr_hash_this_key(hi);
 
-      SVN_ERR(dump_node(db->eb, path, NULL, NULL, svn_node_action_delete,
-                        FALSE, NULL, SVN_INVALID_REVNUM, pool));
+      SVN_ERR(dump_node_delete(db->eb->stream, path, pool));
+      /* This deletion record is complete -- write an extra newline */
+      SVN_ERR(svn_stream_puts(db->eb->stream, "\n"));
     }
 
   /* ### should be unnecessary */
@@ -801,17 +747,15 @@ add_file(const char *path,
 {
   struct dir_baton *pb = parent_baton;
   struct file_baton *fb;
-  void *val;
-
-  LDR_DBG(("add_file %s\n", path));
+  void *was_deleted;
 
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* Make the file baton. */
   fb = make_file_baton(path, pb, pool);
 
   /* This might be a replacement -- is the path already deleted? */
-  val = svn_hash_gets(pb->deleted_entries, path);
+  was_deleted = svn_hash_gets(pb->deleted_entries, path);
 
   /* Detect add-with-history. */
   if (ARE_VALID_COPY_ARGS(copyfrom_path, copyfrom_rev))
@@ -820,10 +764,10 @@ add_file(const char *path,
       fb->copyfrom_rev = copyfrom_rev;
       fb->is_copy = TRUE;
     }
-  fb->action = val ? svn_node_action_replace : svn_node_action_add;
+  fb->action = was_deleted ? svn_node_action_replace : svn_node_action_add;
 
   /* Delete the path, it's now been dumped. */
-  if (val)
+  if (was_deleted)
     svn_hash_sets(pb->deleted_entries, path, NULL);
 
   *file_baton = fb;
@@ -840,9 +784,7 @@ open_file(const char *path,
   struct dir_baton *pb = parent_baton;
   struct file_baton *fb;
 
-  LDR_DBG(("open_file %s\n", path));
-
-  SVN_ERR(dump_pending(pb->eb, pool));
+  SVN_ERR(dump_pending_dir(pb->eb, pool));
 
   /* Make the file baton. */
   fb = make_file_baton(path, pb, pool);
@@ -870,13 +812,11 @@ change_dir_prop(void *parent_baton,
   struct dir_baton *db = parent_baton;
   svn_boolean_t this_pending;
 
-  LDR_DBG(("change_dir_prop %p\n", parent_baton));
-
   /* This directory is not pending, but something else is, so handle
      the "something else".  */
-  this_pending = (db->eb->pending_baton == db);
+  this_pending = (db->eb->pending_db == db);
   if (! this_pending)
-    SVN_ERR(dump_pending(db->eb, pool));
+    SVN_ERR(dump_pending_dir(db->eb, pool));
 
   if (svn_property_kind2(name) != svn_prop_regular_kind)
     return SVN_NO_ERROR;
@@ -904,8 +844,6 @@ change_file_prop(void *file_baton,
 {
   struct file_baton *fb = file_baton;
 
-  LDR_DBG(("change_file_prop %p\n", file_baton));
-
   if (svn_property_kind2(name) != svn_prop_regular_kind)
     return SVN_NO_ERROR;
 
@@ -934,8 +872,6 @@ apply_textdelta(void *file_baton, const
   struct dump_edit_baton *eb = fb->eb;
   svn_stream_t *delta_filestream;
 
-  LDR_DBG(("apply_textdelta %p\n", file_baton));
-
   /* Use a temporary file to measure the Text-content-length */
   delta_filestream = svn_stream_from_aprfile2(eb->delta_file, TRUE, pool);
 
@@ -959,22 +895,25 @@ close_file(void *file_baton,
   struct file_baton *fb = file_baton;
   struct dump_edit_baton *eb = fb->eb;
   apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
-  svn_stringbuf_t *propstring;
-
-  LDR_DBG(("close_file %p\n", file_baton));
+  svn_stringbuf_t *propstring = NULL;
+  apr_array_header_t *headers;
 
-  SVN_ERR(dump_pending(eb, pool));
+  SVN_ERR(dump_pending_dir(eb, pool));
 
-  /* Dump the node. */
-  SVN_ERR(dump_node(eb, fb->repos_relpath, NULL, fb,
+  /* Start dumping this node, by collecting some basic headers for it. */
+  SVN_ERR(dump_node(&headers, eb, fb->repos_relpath, NULL, fb,
                     fb->action, fb->is_copy, fb->copyfrom_path,
                     fb->copyfrom_rev, pool));
 
   /* Some pending properties to dump?  We'll dump just the headers for
      now, then dump the actual propchange content only after dumping
      the text headers too (if present). */
-  SVN_ERR(do_dump_props(&propstring, eb->stream, fb->props, fb->deleted_props,
-                        &(fb->dump_props), pool, pool));
+  if (fb->dump_props)
+    {
+      SVN_ERR(get_props_content(headers, &propstring,
+                                fb->props, fb->deleted_props,
+                                pool, pool));
+    }
 
   /* Dump the text headers */
   if (fb->dump_text)
@@ -982,9 +921,8 @@ close_file(void *file_baton,
       apr_status_t err;
 
       /* Text-delta: true */
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_TEXT_DELTA
-                              ": true\n"));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_TEXT_DELTA, "true");
 
       err = apr_file_info_get(info, APR_FINFO_SIZE, eb->delta_file);
       if (err)
@@ -992,43 +930,22 @@ close_file(void *file_baton,
 
       if (fb->base_checksum)
         /* Text-delta-base-md5: */
-        SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                  SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5
-                                  ": %s\n",
-                                  fb->base_checksum));
-
-      /* Text-content-length: 39 */
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH
-                                ": %lu\n",
-                                (unsigned long)info->size));
+        svn_repos__dumpfile_header_push(
+          headers, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5, fb->base_checksum);
 
       /* Text-content-md5: 82705804337e04dcd0e586bfa2389a7f */
-      SVN_ERR(svn_stream_printf(eb->stream, pool,
-                                SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5
-                                ": %s\n",
-                                text_checksum));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_MD5, text_checksum);
     }
 
-  /* Content-length: 1549 */
-  /* If both text and props are absent, skip this header */
-  if (fb->dump_props)
-    SVN_ERR(svn_stream_printf(eb->stream, pool,
-                              SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                              ": %ld\n\n",
-                              (unsigned long)info->size + propstring->len));
-  else if (fb->dump_text)
-    SVN_ERR(svn_stream_printf(eb->stream, pool,
-                              SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                              ": %ld\n\n",
-                              (unsigned long)info->size));
+  /* Dump the headers and props now */
+  SVN_ERR(svn_repos__dump_node_record(eb->stream, headers, propstring,
+                                      fb->dump_text, info->size,
+                                      FALSE /*content_length_always*/,
+                                      pool));
 
-  /* Dump the props now */
   if (fb->dump_props)
     {
-      SVN_ERR(svn_stream_write(eb->stream, propstring->data,
-                               &(propstring->len)));
-
       /* Cleanup */
       fb->dump_props = FALSE;
       apr_hash_clear(fb->props);
@@ -1195,7 +1112,7 @@ svn_rdump__get_dump_editor(const svn_del
   eb->ra_session = ra_session;
   eb->update_anchor_relpath = update_anchor_relpath;
   eb->current_revision = revision;
-  eb->pending_kind = svn_node_none;
+  eb->pending_db = NULL;
 
   /* Create a special per-revision pool */
   eb->pool = svn_pool_create(pool);

Modified: subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c?rev=1655189&r1=1655188&r2=1655189&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/svn-auth-x509/subversion/svnrdump/load_editor.c Tue Jan 27 23:27:44 2015
@@ -41,14 +41,9 @@
 
 #define SVNRDUMP_PROP_LOCK SVN_PROP_PREFIX "rdump-lock"
 
-#if 0
-#define LDR_DBG(x) SVN_DBG(x)
-#else
-#define LDR_DBG(x) while(0)
-#endif
+#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
 
 
-
 /**
  * General baton used by the parser functions.
  */
@@ -66,9 +61,6 @@ struct parse_baton
   /* To bleep, or not to bleep?  (What kind of question is that?) */
   svn_boolean_t quiet;
 
-  /* UUID found in the dumpstream, if any; NULL otherwise. */
-  const char *uuid;
-
   /* Root URL of the target repository. */
   const char *root_url;
 
@@ -99,13 +91,21 @@ struct parse_baton
 
 /**
  * Use to wrap the dir_context_t in commit.c so we can keep track of
- * depth, relpath and parent for open_directory and close_directory.
+ * relpath and parent for open_directory and close_directory.
  */
 struct directory_baton
 {
   void *baton;
   const char *relpath;
-  int depth;
+
+  /* The copy-from source of this directory, no matter whether it is
+     copied explicitly (the root node of a copy) or implicitly (being an
+     existing child of a copied directory). For a node that is newly
+     added (without history), even inside a copied parent, these are
+     NULL and SVN_INVALID_REVNUM. */
+  const char *copyfrom_path;
+  svn_revnum_t copyfrom_rev;
+
   struct directory_baton *parent;
 };
 
@@ -119,12 +119,20 @@ struct node_baton
   svn_node_kind_t kind;
   enum svn_node_action action;
 
+  /* Is this directory explicitly added? If not, then it already existed
+     or is a child of a copy. */
+  svn_boolean_t is_added;
+
   svn_revnum_t copyfrom_rev;
   const char *copyfrom_path;
+  const char *copyfrom_url;
 
   void *file_baton;
   const char *base_checksum;
 
+  /* (const char *name) -> (svn_prop_t *) */
+  apr_hash_t *prop_changes;
+
   struct revision_baton *rb;
 };
 
@@ -175,160 +183,6 @@ get_revision_mapping(apr_hash_t *rev_map
 }
 
 
-/* Prepend the mergeinfo source paths in MERGEINFO_ORIG with
-   PARENT_DIR, and return it in *MERGEINFO_VAL. */
-/* ### FIXME:  Consider somehow sharing code with
-   ### libsvn_repos/load-fs-vtable.c:prefix_mergeinfo_paths() */
-static svn_error_t *
-prefix_mergeinfo_paths(svn_string_t **mergeinfo_val,
-                       const svn_string_t *mergeinfo_orig,
-                       const char *parent_dir,
-                       apr_pool_t *pool)
-{
-  apr_hash_t *prefixed_mergeinfo, *mergeinfo;
-  apr_hash_index_t *hi;
-  void *rangelist;
-
-  SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_orig->data, pool));
-  prefixed_mergeinfo = apr_hash_make(pool);
-  for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
-    {
-      const void *key;
-      const char *path, *merge_source;
-
-      apr_hash_this(hi, &key, NULL, &rangelist);
-      merge_source = svn_relpath_canonicalize(key, pool);
-
-      /* The svn:mergeinfo property syntax demands a repos abspath */
-      path = svn_fspath__canonicalize(svn_relpath_join(parent_dir,
-                                                       merge_source, pool),
-                                      pool);
-      svn_hash_sets(prefixed_mergeinfo, path, rangelist);
-    }
-  return svn_mergeinfo_to_string(mergeinfo_val, prefixed_mergeinfo, pool);
-}
-
-
-/* Examine the mergeinfo in INITIAL_VAL, renumber revisions in rangelists
-   as appropriate, and return the (possibly new) mergeinfo in *FINAL_VAL
-   (allocated from POOL). */
-/* ### FIXME:  Consider somehow sharing code with
-   ### libsvn_repos/load-fs-vtable.c:renumber_mergeinfo_revs() */
-static svn_error_t *
-renumber_mergeinfo_revs(svn_string_t **final_val,
-                        const svn_string_t *initial_val,
-                        struct revision_baton *rb,
-                        apr_pool_t *pool)
-{
-  apr_pool_t *subpool = svn_pool_create(pool);
-  svn_mergeinfo_t mergeinfo, predates_stream_mergeinfo;
-  svn_mergeinfo_t final_mergeinfo = apr_hash_make(subpool);
-  apr_hash_index_t *hi;
-
-  SVN_ERR(svn_mergeinfo_parse(&mergeinfo, initial_val->data, subpool));
-
-  /* Issue #3020
-     http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16
-     Remove mergeinfo older than the oldest revision in the dump stream
-     and adjust its revisions by the difference between the head rev of
-     the target repository and the current dump stream rev. */
-  if (rb->pb->oldest_dumpstream_rev > 1)
-    {
-      SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
-                  &predates_stream_mergeinfo, mergeinfo,
-                  rb->pb->oldest_dumpstream_rev - 1, 0,
-                  TRUE, subpool, subpool));
-      SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
-                  &mergeinfo, mergeinfo,
-                  rb->pb->oldest_dumpstream_rev - 1, 0,
-                  FALSE, subpool, subpool));
-      SVN_ERR(svn_mergeinfo__adjust_mergeinfo_rangelists(
-                  &predates_stream_mergeinfo,
-                  predates_stream_mergeinfo,
-                  -rb->rev_offset, subpool, subpool));
-    }
-  else
-    {
-      predates_stream_mergeinfo = NULL;
-    }
-
-  for (hi = apr_hash_first(subpool, mergeinfo); hi; hi = apr_hash_next(hi))
-    {
-      svn_rangelist_t *rangelist;
-      struct parse_baton *pb = rb->pb;
-      int i;
-      const void *path;
-      apr_ssize_t pathlen;
-      void *val;
-
-      apr_hash_this(hi, &path, &pathlen, &val);
-      rangelist = val;
-
-      /* Possibly renumber revisions in merge source's rangelist. */
-      for (i = 0; i < rangelist->nelts; i++)
-        {
-          svn_revnum_t rev_from_map;
-          svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, i,
-                                                   svn_merge_range_t *);
-          rev_from_map = get_revision_mapping(pb->rev_map, range->start);
-          if (SVN_IS_VALID_REVNUM(rev_from_map))
-            {
-              range->start = rev_from_map;
-            }
-          else if (range->start == pb->oldest_dumpstream_rev - 1)
-            {
-              /* Since the start revision of svn_merge_range_t are not
-                 inclusive there is one possible valid start revision that
-                 won't be found in the PB->REV_MAP mapping of load stream
-                 revsions to loaded revisions: The revision immediately
-                 preceding the oldest revision from the load stream.
-                 This is a valid revision for mergeinfo, but not a valid
-                 copy from revision (which PB->REV_MAP also maps for) so it
-                 will never be in the mapping.
-
-                 If that is what we have here, then find the mapping for the
-                 oldest rev from the load stream and subtract 1 to get the
-                 renumbered, non-inclusive, start revision. */
-              rev_from_map = get_revision_mapping(pb->rev_map,
-                                                  pb->oldest_dumpstream_rev);
-              if (SVN_IS_VALID_REVNUM(rev_from_map))
-                range->start = rev_from_map - 1;
-            }
-          else
-            {
-              /* If we can't remap the start revision then don't even bother
-                 trying to remap the end revision.  It's possible we might
-                 actually succeed at the latter, which can result in invalid
-                 mergeinfo with a start rev > end rev.  If that gets into the
-                 repository then a world of bustage breaks loose anytime that
-                 bogus mergeinfo is parsed.  See
-                 http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16.
-                 */
-              continue;
-            }
-
-          rev_from_map = get_revision_mapping(pb->rev_map, range->end);
-          if (SVN_IS_VALID_REVNUM(rev_from_map))
-            range->end = rev_from_map;
-        }
-      apr_hash_set(final_mergeinfo, path, pathlen, rangelist);
-    }
-
-  if (predates_stream_mergeinfo)
-    {
-      SVN_ERR(svn_mergeinfo_merge2(final_mergeinfo, predates_stream_mergeinfo,
-                                   subpool, subpool));
-    }
-
-  SVN_ERR(svn_mergeinfo__canonicalize_ranges(final_mergeinfo, subpool));
-
-  SVN_ERR(svn_mergeinfo_to_string(final_val, final_mergeinfo, pool));
-  svn_pool_destroy(subpool);
-
-  return SVN_NO_ERROR;
-}
-
-
 static svn_error_t *
 commit_callback(const svn_commit_info_t *commit_info,
                 void *baton,
@@ -545,6 +399,7 @@ new_revision_record(void **revision_bato
   pb = parse_baton;
   rb->pool = svn_pool_create(pool);
   rb->pb = pb;
+  rb->db = NULL;
 
   for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
     {
@@ -590,12 +445,50 @@ uuid_record(const char *uuid,
             void *parse_baton,
             apr_pool_t *pool)
 {
-  struct parse_baton *pb;
-  pb = parse_baton;
-  pb->uuid = apr_pstrdup(pool, uuid);
   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,
@@ -606,17 +499,17 @@ new_node_record(void **node_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;
-  struct directory_baton *child_db;
   apr_hash_index_t *hi;
   void *child_baton;
-  char *relpath_compose;
   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);
 
   /* If the creation of commit_editor is pending, create it now and
      open_root on it; also create a top-level directory baton. */
@@ -647,15 +540,9 @@ new_node_record(void **node_baton,
                                        rb->rev - rb->rev_offset - 1,
                                        rb->pool, &child_baton));
 
-      LDR_DBG(("Opened root %p\n", child_baton));
-
-      /* child_db corresponds to the root directory baton here */
-      child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-      child_db->baton = child_baton;
-      child_db->depth = 0;
-      child_db->relpath = "";
-      child_db->parent = NULL;
-      rb->db = child_db;
+      /* child_baton corresponds to the root directory baton here */
+      push_directory(rb, child_baton, "", TRUE /*is_added*/,
+                     NULL, SVN_INVALID_REVNUM);
     }
 
   for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi))
@@ -688,6 +575,9 @@ new_node_record(void **node_baton,
         nb->copyfrom_path = apr_pstrdup(rb->pool, hval);
     }
 
+  /* Before handling the new node, ensure depth-first editing order by
+     traversing the directory hierarchy from the old node's to the new
+     node's parent directory. */
   nb_dirname = svn_relpath_dirname(nb->path, pool);
   if (svn_path_compare_paths(nb_dirname,
                              rb->db->relpath) != 0)
@@ -698,9 +588,6 @@ new_node_record(void **node_baton,
       int i;
       apr_size_t n;
 
-      /* Before attempting to handle the action, call open_directory
-         for all the path components and set the directory baton
-         accordingly */
       ancestor_path =
         svn_relpath_get_longest_ancestor(nb_dirname,
                                          rb->db->relpath, pool);
@@ -718,14 +605,13 @@ new_node_record(void **node_baton,
           /* Don't worry about destroying the actual rb->db object,
              since the pool we're using has the lifetime of one
              revision anyway */
-          LDR_DBG(("Closing dir %p\n", rb->db->baton));
           SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
           rb->db = rb->db->parent;
         }
 
       for (i = 0; i < residual_open_path->nelts; i ++)
         {
-          relpath_compose =
+          char *relpath_compose =
             svn_relpath_join(rb->db->relpath,
                              APR_ARRAY_IDX(residual_open_path, i, const char *),
                              rb->pool);
@@ -733,13 +619,8 @@ new_node_record(void **node_baton,
                                                 rb->db->baton,
                                                 rb->rev - rb->rev_offset - 1,
                                                 rb->pool, &child_baton));
-          LDR_DBG(("Opened dir %p\n", child_baton));
-          child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-          child_db->baton = child_baton;
-          child_db->depth = rb->db->depth + 1;
-          child_db->relpath = relpath_compose;
-          child_db->parent = rb->db;
-          rb->db = child_db;
+          push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/,
+                         NULL, SVN_INVALID_REVNUM);
         }
     }
 
@@ -767,7 +648,8 @@ new_node_record(void **node_baton,
       if (rb->pb->parent_dir)
         nb->copyfrom_path = svn_relpath_join(rb->pb->parent_dir,
                                              nb->copyfrom_path, rb->pool);
-      nb->copyfrom_path = svn_path_url_add_component2(rb->pb->root_url,
+      /* Convert to a URL, as the commit editor requires. */
+      nb->copyfrom_url = svn_path_url_add_component2(rb->pb->root_url,
                                                       nb->copyfrom_path,
                                                       rb->pool);
     }
@@ -777,7 +659,6 @@ new_node_record(void **node_baton,
     {
     case svn_node_action_delete:
     case svn_node_action_replace:
-      LDR_DBG(("Deleting entry %s in %p\n", nb->path, rb->db->baton));
       SVN_ERR(commit_editor->delete_entry(nb->path, rb->rev - rb->rev_offset,
                                           rb->db->baton, rb->pool));
       if (nb->action == svn_node_action_delete)
@@ -785,29 +666,22 @@ new_node_record(void **node_baton,
       else
         /* FALL THROUGH */;
     case svn_node_action_add:
+      nb->is_added = TRUE;
       switch (nb->kind)
         {
         case svn_node_file:
           SVN_ERR(commit_editor->add_file(nb->path, rb->db->baton,
-                                          nb->copyfrom_path,
+                                          nb->copyfrom_url,
                                           nb->copyfrom_rev,
                                           rb->pool, &(nb->file_baton)));
-          LDR_DBG(("Added file %s to dir %p as %p\n",
-                   nb->path, rb->db->baton, nb->file_baton));
           break;
         case svn_node_dir:
           SVN_ERR(commit_editor->add_directory(nb->path, rb->db->baton,
-                                               nb->copyfrom_path,
+                                               nb->copyfrom_url,
                                                nb->copyfrom_rev,
                                                rb->pool, &child_baton));
-          LDR_DBG(("Added dir %s to dir %p as %p\n",
-                   nb->path, rb->db->baton, child_baton));
-          child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-          child_db->baton = child_baton;
-          child_db->depth = rb->db->depth + 1;
-          child_db->relpath = apr_pstrdup(rb->pool, nb->path);
-          child_db->parent = rb->db;
-          rb->db = child_db;
+          push_directory(rb, child_baton, nb->path, TRUE /*is_added*/,
+                         nb->copyfrom_path, nb->copyfrom_rev);
           break;
         default:
           break;
@@ -825,12 +699,8 @@ new_node_record(void **node_baton,
           SVN_ERR(commit_editor->open_directory(nb->path, rb->db->baton,
                                                 rb->rev - rb->rev_offset - 1,
                                                 rb->pool, &child_baton));
-          child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-          child_db->baton = child_baton;
-          child_db->depth = rb->db->depth + 1;
-          child_db->relpath = apr_pstrdup(rb->pool, nb->path);
-          child_db->parent = rb->db;
-          rb->db = child_db;
+          push_directory(rb, child_baton, nb->path, FALSE /*is_added*/,
+                         NULL, SVN_INVALID_REVNUM);
           break;
         }
       break;
@@ -878,70 +748,35 @@ set_revision_property(void *baton,
   return SVN_NO_ERROR;
 }
 
-/* Adjust mergeinfo:
- *   - normalize line endings (if all CRLF, change to LF; but error if mixed);
- *   - adjust revision numbers (see renumber_mergeinfo_revs());
- *   - adjust paths (see prefix_mergeinfo_paths()).
- */
-static svn_error_t *
-adjust_mergeinfo_property(struct revision_baton *rb,
-                          svn_string_t **new_value_p,
-                          const svn_string_t *old_value,
-                          apr_pool_t *result_pool)
-{
-  struct parse_baton *pb = rb->pb;
-  svn_string_t prop_val = *old_value;
-
-  /* Tolerate mergeinfo with "\r\n" line endings because some
-     dumpstream sources might contain as much.  If so normalize
-     the line endings to '\n' and notify that we have made this
-     correction. */
-  if (strstr(prop_val.data, "\r"))
-    {
-      const char *prop_eol_normalized;
-
-      SVN_ERR(svn_subst_translate_cstring2(prop_val.data,
-                                           &prop_eol_normalized,
-                                           "\n",  /* translate to LF */
-                                           FALSE, /* no repair */
-                                           NULL,  /* no keywords */
-                                           FALSE, /* no expansion */
-                                           result_pool));
-      prop_val.data = prop_eol_normalized;
-      prop_val.len = strlen(prop_eol_normalized);
-
-      /* ### TODO: notify? */
-    }
-
-  /* Renumber mergeinfo as appropriate. */
-  SVN_ERR(renumber_mergeinfo_revs(new_value_p, &prop_val, rb,
-                                  result_pool));
-
-  if (pb->parent_dir)
-    {
-      /* Prefix the merge source paths with PB->parent_dir. */
-      /* ASSUMPTION: All source paths are included in the dump stream. */
-      SVN_ERR(prefix_mergeinfo_paths(new_value_p, *new_value_p,
-                                     pb->parent_dir, result_pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
 static svn_error_t *
 set_node_property(void *baton,
                   const char *name,
                   const svn_string_t *value)
 {
   struct node_baton *nb = baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  struct revision_baton *rb = nb->rb;
+  struct parse_baton *pb = rb->pb;
   apr_pool_t *pool = nb->rb->pool;
+  svn_prop_t *prop;
 
   if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
     {
       svn_string_t *new_value;
+      svn_error_t *err;
+
+      err = svn_repos__adjust_mergeinfo_property(&new_value, value,
+                                                 pb->parent_dir,
+                                                 pb->rev_map,
+                                                 pb->oldest_dumpstream_rev,
+                                                 rb->rev_offset,
+                                                 NULL, NULL, /*notify*/
+                                                 pool, pool);
+      if (err)
+        {
+          return svn_error_quick_wrap(err,
+                                      _("Invalid svn:mergeinfo value"));
+        }
 
-      SVN_ERR(adjust_mergeinfo_property(nb->rb, &new_value, value, pool));
       value = new_value;
     }
 
@@ -949,21 +784,11 @@ set_node_property(void *baton,
 
   SVN_ERR(svn_repos__validate_prop(name, value, pool));
 
-  switch (nb->kind)
-    {
-    case svn_node_file:
-      LDR_DBG(("Applying properties on %p\n", nb->file_baton));
-      SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
-                                              value, pool));
-      break;
-    case svn_node_dir:
-      LDR_DBG(("Applying properties on %p\n", nb->rb->db->baton));
-      SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
-                                             value, pool));
-      break;
-    default:
-      break;
-    }
+  prop = apr_palloc(nb->rb->pool, sizeof (*prop));
+  prop->name = apr_pstrdup(pool, name);
+  prop->value = value ? svn_string_dup(value, pool) : NULL;
+  svn_hash_sets(nb->prop_changes, prop->name, prop);
+
   return SVN_NO_ERROR;
 }
 
@@ -972,44 +797,79 @@ delete_node_property(void *baton,
                      const char *name)
 {
   struct node_baton *nb = baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
+  svn_prop_t *prop;
 
   SVN_ERR(svn_repos__validate_prop(name, NULL, pool));
 
-  if (nb->kind == svn_node_file)
-    SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
-                                            NULL, pool));
-  else
-    SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
-                                           NULL, pool));
+  prop = apr_palloc(pool, sizeof (*prop));
+  prop->name = apr_pstrdup(pool, name);
+  prop->value = NULL;
+  svn_hash_sets(nb->prop_changes, prop->name, prop);
 
   return SVN_NO_ERROR;
 }
 
+/* Delete all the properties of the node, if any.
+ *
+ * The commit editor doesn't have a method to delete a node's properties
+ * without knowing what they are, so we have to first find out what
+ * properties the node would have had. If it's copied (explicitly or
+ * implicitly), we look at the copy source. If it's only being changed,
+ * we look at the node's current path in the head revision.
+ */
 static svn_error_t *
 remove_node_props(void *baton)
 {
   struct node_baton *nb = baton;
+  struct revision_baton *rb = nb->rb;
   apr_pool_t *pool = nb->rb->pool;
   apr_hash_index_t *hi;
   apr_hash_t *props;
+  const char *orig_path;
+  svn_revnum_t orig_rev;
+
+  /* Find the path and revision that has the node's original properties */
+  if (ARE_VALID_COPY_ARGS(nb->copyfrom_path, nb->copyfrom_rev))
+    {
+      orig_path = nb->copyfrom_path;
+      orig_rev = nb->copyfrom_rev;
+    }
+  else if (!nb->is_added
+           && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
+    {
+      /* If this is a dir, then it's described by rb->db;
+         if this is a file, then it's a child of the dir in rb->db. */
+      orig_path = (nb->kind == svn_node_dir)
+                    ? rb->db->copyfrom_path
+                    : svn_relpath_join(rb->db->copyfrom_path,
+                                       svn_relpath_basename(nb->path, NULL),
+                                       rb->pool);
+      orig_rev = rb->db->copyfrom_rev;
+    }
+  else
+    {
+      /* ### Should we query at a known, fixed, "head" revision number
+         instead of passing SVN_INVALID_REVNUM and getting a moving target? */
+      orig_path = nb->path;
+      orig_rev = SVN_INVALID_REVNUM;
+    }
 
   if ((nb->action == svn_node_action_add
             || nb->action == svn_node_action_replace)
-      && ! SVN_IS_VALID_REVNUM(nb->copyfrom_rev))
+      && ! ARE_VALID_COPY_ARGS(orig_path, orig_rev))
     /* 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, nb->path,
-                              SVN_INVALID_REVNUM, NULL, NULL, &props, pool));
+      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,
-                              nb->path, SVN_INVALID_REVNUM, 0, pool));
+                              orig_path, orig_rev, 0, pool));
     }
 
   for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
@@ -1034,7 +894,6 @@ set_fulltext(svn_stream_t **stream,
   void *handler_baton;
   apr_pool_t *pool = nb->rb->pool;
 
-  LDR_DBG(("Setting fulltext for %p\n", nb->file_baton));
   SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum,
                                          pool, &handler, &handler_baton));
   *stream = svn_txdelta_target_push(handler, handler_baton,
@@ -1051,7 +910,6 @@ apply_textdelta(svn_txdelta_window_handl
   const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
 
-  LDR_DBG(("Applying textdelta to %p\n", nb->file_baton));
   SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum,
                                          pool, handler, handler_baton));
 
@@ -1063,12 +921,34 @@ close_node(void *baton)
 {
   struct node_baton *nb = baton;
   const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  apr_pool_t *pool = nb->rb->pool;
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(pool, nb->prop_changes);
+       hi; hi = apr_hash_next(hi))
+    {
+      const char *name = apr_hash_this_key(hi);
+      svn_prop_t *prop = apr_hash_this_val(hi);
+
+      switch (nb->kind)
+        {
+        case svn_node_file:
+          SVN_ERR(commit_editor->change_file_prop(nb->file_baton,
+                                                  name, prop->value, pool));
+          break;
+        case svn_node_dir:
+          SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton,
+                                                 name, prop->value, pool));
+          break;
+        default:
+          break;
+        }
+    }
 
   /* Pass a file node closure through to the editor *unless* we
      deleted the file (which doesn't require us to open it). */
   if ((nb->kind == svn_node_file) && (nb->file_baton))
     {
-      LDR_DBG(("Closing file %p\n", nb->file_baton));
       SVN_ERR(commit_editor->close_file(nb->file_baton, NULL, nb->rb->pool));
     }
 
@@ -1098,12 +978,10 @@ close_revision(void *baton)
          session itself */
       while (rb->db && rb->db->parent)
         {
-          LDR_DBG(("Closing dir %p\n", rb->db->baton));
           SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
           rb->db = rb->db->parent;
         }
       /* root dir's baton */
-      LDR_DBG(("Closing edit on %p\n", commit_edit_baton));
       SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool));
       SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool));
     }
@@ -1121,8 +999,6 @@ close_revision(void *baton)
                                        rb->rev - rb->rev_offset - 1,
                                        rb->pool, &child_baton));
 
-      LDR_DBG(("Opened root %p\n", child_baton));
-      LDR_DBG(("Closing edit on %p\n", commit_edit_baton));
       SVN_ERR(commit_editor->close_directory(child_baton, rb->pool));
       SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool));
     }

Modified: subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c?rev=1655189&r1=1655188&r2=1655189&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/svn-auth-x509/subversion/svnrdump/svnrdump.c Tue Jan 27 23:27:44 2015
@@ -39,6 +39,7 @@
 
 #include "svnrdump.h"
 
+#include "private/svn_repos_private.h"
 #include "private/svn_cmdline_private.h"
 #include "private/svn_ra_private.h"
 
@@ -229,34 +230,13 @@ replay_revstart(svn_revnum_t revision,
 {
   struct replay_baton *rb = replay_baton;
   apr_hash_t *normal_props;
-  svn_stringbuf_t *propstring;
-  svn_stream_t *revprop_stream;
 
-  /* Revision-number: 19 */
-  SVN_ERR(svn_stream_printf(rb->stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_REVISION_NUMBER
-                            ": %ld\n", revision));
+  /* Normalize and dump the revprops */
   SVN_ERR(svn_rdump__normalize_props(&normal_props, rev_props, pool));
-  propstring = svn_stringbuf_create_ensure(0, pool);
-  revprop_stream = svn_stream_from_stringbuf(propstring, pool);
-  SVN_ERR(svn_hash_write2(normal_props, revprop_stream, "PROPS-END", pool));
-  SVN_ERR(svn_stream_close(revprop_stream));
-
-  /* Prop-content-length: 13 */
-  SVN_ERR(svn_stream_printf(rb->stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n", propstring->len));
-
-  /* Content-length: 29 */
-  SVN_ERR(svn_stream_printf(rb->stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
-
-  /* Property data. */
-  SVN_ERR(svn_stream_write(rb->stdout_stream, propstring->data,
-                           &(propstring->len)));
-
-  SVN_ERR(svn_stream_puts(rb->stdout_stream, "\n"));
+  SVN_ERR(svn_repos__dump_revision_record(rb->stdout_stream, revision, NULL,
+                                          normal_props,
+                                          TRUE /*props_section_always*/,
+                                          pool));
 
   SVN_ERR(svn_rdump__get_dump_editor(editor, edit_baton, revision,
                                      rb->stdout_stream, rb->extra_ra_session,
@@ -299,34 +279,13 @@ replay_revstart_v2(svn_revnum_t revision
 {
   struct replay_baton *rb = replay_baton;
   apr_hash_t *normal_props;
-  svn_stringbuf_t *propstring;
-  svn_stream_t *revprop_stream;
 
-  /* Revision-number: 19 */
-  SVN_ERR(svn_stream_printf(rb->stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_REVISION_NUMBER
-                            ": %ld\n", revision));
+  /* Normalize and dump the revprops */
   SVN_ERR(svn_rdump__normalize_props(&normal_props, rev_props, pool));
-  propstring = svn_stringbuf_create_ensure(0, pool);
-  revprop_stream = svn_stream_from_stringbuf(propstring, pool);
-  SVN_ERR(svn_hash_write2(normal_props, revprop_stream, "PROPS-END", pool));
-  SVN_ERR(svn_stream_close(revprop_stream));
-
-  /* Prop-content-length: 13 */
-  SVN_ERR(svn_stream_printf(rb->stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n", propstring->len));
-
-  /* Content-length: 29 */
-  SVN_ERR(svn_stream_printf(rb->stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
-
-  /* Property data. */
-  SVN_ERR(svn_stream_write(rb->stdout_stream, propstring->data,
-                           &(propstring->len)));
-
-  SVN_ERR(svn_stream_puts(rb->stdout_stream, "\n"));
+  SVN_ERR(svn_repos__dump_revision_record(rb->stdout_stream, revision,
+                                          normal_props,
+                                          TRUE /*props_section_always*/,
+                                          pool));
 
   SVN_ERR(svn_rdump__get_dump_editor_v2(editor, revision,
                                         rb->stdout_stream,
@@ -463,35 +422,12 @@ dump_revision_header(svn_ra_session_t *s
                      apr_pool_t *pool)
 {
   apr_hash_t *prophash;
-  svn_stringbuf_t *propstring;
-  svn_stream_t *propstream;
 
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_REVISION_NUMBER
-                            ": %ld\n", revision));
-
-  prophash = apr_hash_make(pool);
-  propstring = svn_stringbuf_create_empty(pool);
   SVN_ERR(svn_ra_rev_proplist(session, revision, &prophash, pool));
-
-  propstream = svn_stream_from_stringbuf(propstring, pool);
-  SVN_ERR(svn_hash_write2(prophash, propstream, "PROPS-END", pool));
-  SVN_ERR(svn_stream_close(propstream));
-
-  /* Property-content-length: 14; Content-length: 14 */
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n",
-                            propstring->len));
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n\n",
-                            propstring->len));
-  /* The properties */
-  SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
-                           &(propstring->len)));
-  SVN_ERR(svn_stream_puts(stdout_stream, "\n"));
-
+  SVN_ERR(svn_repos__dump_revision_record(stdout_stream, revision, NULL,
+                                          prophash,
+                                          TRUE /*props_section_always*/,
+                                          pool));
   return SVN_NO_ERROR;
 }
 
@@ -1168,7 +1104,7 @@ sub_main(int *exit_code, int argc, const
 
   if (strcmp(subcommand->name, "load") == 0)
     {
-      /* 
+      /*
        * By default (no --*-interactive options given), the 'load' subcommand
        * is interactive unless username and password were provided on the
        * command line. This allows prompting for auth creds to work without



Mime
View raw message