You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/01/21 17:22:22 UTC

svn commit: r1653578 [17/18] - in /subversion/branches/pin-externals: ./ notes/ subversion/bindings/swig/ subversion/bindings/swig/include/ subversion/bindings/swig/perl/native/ subversion/bindings/swig/perl/native/t/ subversion/bindings/swig/python/te...

Modified: subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c (original)
+++ subversion/branches/pin-externals/subversion/svnrdump/dump_editor.c Wed Jan 21 16:22:19 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"
@@ -50,17 +51,10 @@
 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;
-
-  /* has this directory been written to the output stream? */
-  svn_boolean_t written_out;
-
   /* the path to this directory */
   const char *repos_relpath; /* a relpath */
 
@@ -90,7 +84,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;
@@ -164,53 +157,42 @@ 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;
   struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
   const char *repos_relpath;
-  apr_pool_t *dir_pool;
 
   /* Construct the full path of this node. */
   if (pb)
-    {
-      dir_pool = svn_pool_create(pb->pool);
-      repos_relpath = svn_relpath_canonicalize(path, dir_pool);
-    }
+    repos_relpath = svn_relpath_canonicalize(path, pool);
   else
-    {
-      dir_pool = svn_pool_create(eb->pool);
-      repos_relpath = "";
-    }
+    repos_relpath = "";
 
   /* Strip leading slash from copyfrom_path so that the path is
      canonical and svn_relpath_join can be used */
   if (copyfrom_path)
-    copyfrom_path = svn_relpath_canonicalize(copyfrom_path, dir_pool);
+    copyfrom_path = svn_relpath_canonicalize(copyfrom_path, pool);
 
   new_db->eb = eb;
-  new_db->parent_dir_baton = pb;
-  new_db->pool = dir_pool;
+  new_db->pool = pool;
   new_db->repos_relpath = repos_relpath;
   new_db->copyfrom_path = copyfrom_path
-                            ? svn_relpath_canonicalize(copyfrom_path, dir_pool)
+                            ? svn_relpath_canonicalize(copyfrom_path, pool)
                             : NULL;
   new_db->copyfrom_rev = copyfrom_rev;
-  new_db->added = added;
-  new_db->written_out = FALSE;
-  new_db->props = apr_hash_make(dir_pool);
-  new_db->deleted_props = apr_hash_make(dir_pool);
-  new_db->deleted_entries = apr_hash_make(dir_pool);
+  new_db->props = apr_hash_make(pool);
+  new_db->deleted_props = apr_hash_make(pool);
+  new_db->deleted_entries = apr_hash_make(pool);
 
   return new_db;
 }
@@ -224,15 +206,13 @@ make_file_baton(const char *path,
                 struct dir_baton *pb,
                 apr_pool_t *pool)
 {
-  apr_pool_t *file_pool = svn_pool_create(pb->pool);
-  struct file_baton *new_fb = apr_pcalloc(file_pool, sizeof(*new_fb));
+  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 = file_pool;
-  new_fb->repos_relpath = svn_relpath_canonicalize(path, file_pool);
-  new_fb->props = apr_hash_make(file_pool);
-  new_fb->deleted_props = apr_hash_make(file_pool);
+  new_fb->pool = pool;
+  new_fb->repos_relpath = svn_relpath_canonicalize(path, pool);
+  new_fb->props = apr_hash_make(pool);
+  new_fb->deleted_props = apr_hash_make(pool);
   new_fb->is_copy = FALSE;
   new_fb->copyfrom_path = NULL;
   new_fb->copyfrom_rev = SVN_INVALID_REVNUM;
@@ -241,9 +221,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,
@@ -252,10 +234,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);
 
@@ -266,71 +246,13 @@ 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");
+  svn_repos__dumpfile_header_push(
+    headers, SVN_REPOS_DUMPFILE_PROP_DELTA, "true");
 
   /* 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);
-
-  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.
- *
- * 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.
- */
-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));
-
-      /* 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"));
-
-      /* Cleanup so that data is never dumped twice. */
-      apr_hash_clear(props);
-      apr_hash_clear(deleted_props);
-      if (trigger_var)
-        *trigger_var = FALSE;
-    }
+  svn_repos__dumpfile_header_pushf(
+    headers, SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH,
+    "%" APR_SIZE_T_FMT, (*content)->len);
 
   return SVN_NO_ERROR;
 }
@@ -349,15 +271,17 @@ do_dump_newlines(struct dump_edit_baton
 }
 
 /*
- * Write out a node record for PATH of type KIND under EB->FS_ROOT.
+ * Write out a partial node record for PATH of type KIND.
  * ACTION describes what is happening to the node (see enum
- * svn_node_action). Write record to writable EB->STREAM, using
- * EB->BUFFER to write in chunks.
+ * svn_node_action). Write record to writable EB->STREAM.
  *
  * 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.
+
+ * Note: only when ACTION=delete, write a complete dumpfile record
+ * terminated with blank lines.
  */
 static svn_error_t *
 dump_node(struct dump_edit_baton *eb,
@@ -371,6 +295,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));
@@ -382,17 +307,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 */
@@ -404,26 +328,32 @@ 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_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));
+          /* More complex case: is_copy is true, and copyfrom_path/
+             copyfrom_rev are present: delete the original, and then re-add
+             it */
+
+          svn_repos__dumpfile_header_push(
+            headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
+
+          SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
+
+          /* Recurse: Print an additional add-with-history record. */
           SVN_ERR(dump_node(eb, repos_relpath, db, fb, svn_node_action_add,
                             is_copy, copyfrom_path, copyfrom_rev, pool));
+          return SVN_NO_ERROR;
         }
       else
         {
           /* 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 */
@@ -436,30 +366,29 @@ dump_node(struct dump_edit_baton *eb,
 
     case svn_node_action_delete:
       /* Node-action: delete */
-      SVN_ERR(svn_stream_puts(eb->stream,
-                              SVN_REPOS_DUMPFILE_NODE_ACTION ": delete\n"));
+      svn_repos__dumpfile_header_push(
+        headers, SVN_REPOS_DUMPFILE_NODE_ACTION, "delete");
 
       /* 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"));
+         print the headers terminated by one blank line, and an extra
+         blank line because we're not dumping props or text. */
+      SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
+      SVN_ERR(svn_stream_puts(eb->stream, "\n"));
 
-      break;
+      return SVN_NO_ERROR;
 
     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
@@ -497,6 +426,11 @@ dump_node(struct dump_edit_baton *eb,
 
       break;
     }
+
+  /* Write the headers so far. We don't necessarily have all the headers
+     yet -- there may be property-related and content length headers to
+     come -- so don't write a terminating blank line. */
+  SVN_ERR(svn_repos__dump_headers(eb->stream, headers, FALSE, pool));
   return SVN_NO_ERROR;
 }
 
@@ -505,34 +439,30 @@ dump_mkdir(struct dump_edit_baton *eb,
            const char *repos_relpath,
            apr_pool_t *pool)
 {
-  svn_stringbuf_t *prop_header, *prop_content;
+  svn_stringbuf_t *prop_content;
   apr_size_t len;
-  const char *buf;
+  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_repos__dumpfile_header_pushf(headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+                                   "%" APR_SIZE_T_FMT, len);
+  SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
   SVN_ERR(svn_stream_write(eb->stream, prop_content->data, &len));
 
   /* Newlines to tie it all off. */
@@ -547,31 +477,79 @@ static svn_error_t *
 dump_pending(struct dump_edit_baton *eb,
              apr_pool_t *scratch_pool)
 {
+  svn_boolean_t dump_props = FALSE;
+  apr_hash_t *props, *deleted_props;
+
   if (! eb->pending_baton)
     return SVN_NO_ERROR;
 
+  /* Some pending properties to dump? */
   if (eb->pending_kind == svn_node_dir)
     {
       struct dir_baton *db = eb->pending_baton;
 
-      /* 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)
+        {
+          dump_props = TRUE;
+          props = db->props;
+          deleted_props = db->deleted_props;
 
-      /* Some pending newlines to dump? */
-      SVN_ERR(do_dump_newlines(eb, &(db->dump_newlines), scratch_pool));
+          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));
+      if (fb->dump_props)
+        {
+          dump_props = TRUE;
+          props = fb->props;
+          deleted_props = fb->deleted_props;
+          fb->dump_props = FALSE;
+        }
     }
   else
     abort();
 
+  if (dump_props)
+    {
+      apr_array_header_t *headers
+        = svn_repos__dumpfile_headers_create(scratch_pool);
+      svn_stringbuf_t *content;
+      apr_size_t len;
+
+      SVN_ERR(get_props_content(headers, &content, props, deleted_props,
+                                scratch_pool, scratch_pool));
+
+      /* Content-length: 14 */
+      svn_repos__dumpfile_header_pushf(
+        headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+        "%" APR_SIZE_T_FMT, content->len);
+
+      SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE,
+                                      scratch_pool));
+
+      len = content->len;
+      SVN_ERR(svn_stream_write(eb->stream, content->data, &len));
+
+      /* 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"));
+
+      /* Cleanup so that data is never dumped twice. */
+      apr_hash_clear(props);
+      apr_hash_clear(deleted_props);
+    }
+
+  if (eb->pending_kind == svn_node_dir)
+    {
+      struct dir_baton *db = eb->pending_baton;
+
+      /* Some pending newlines to dump? */
+      SVN_ERR(do_dump_newlines(eb, &(db->dump_newlines), scratch_pool));
+    }
+
   /* Anything that was pending is pending no longer. */
   eb->pending_baton = NULL;
   eb->pending_kind = svn_node_none;
@@ -629,14 +607,13 @@ 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);
+                                      edit_baton, NULL, pool);
               SVN_ERR(dump_node(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. */
-              new_db->written_out = TRUE;
               eb->pending_baton = new_db;
               eb->pending_kind = svn_node_dir;
             }
@@ -647,7 +624,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;
@@ -684,7 +661,7 @@ 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;
 
@@ -693,29 +670,28 @@ add_directory(const char *path,
   SVN_ERR(dump_pending(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,
+                    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. */
-  new_db->written_out = TRUE;
   pb->eb->pending_baton = new_db;
   pb->eb->pending_kind = svn_node_dir;
 
@@ -750,7 +726,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;
@@ -801,7 +777,7 @@ close_directory(void *dir_baton,
     }
 
   /* ### should be unnecessary */
-  svn_pool_destroy(db->pool);
+  apr_hash_clear(db->deleted_entries);
 
   return SVN_NO_ERROR;
 }
@@ -816,7 +792,7 @@ add_file(const char *path,
 {
   struct dir_baton *pb = parent_baton;
   struct file_baton *fb;
-  void *val;
+  void *was_deleted;
 
   LDR_DBG(("add_file %s\n", path));
 
@@ -826,7 +802,7 @@ add_file(const char *path,
   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))
@@ -835,10 +811,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;
@@ -975,6 +951,7 @@ close_file(void *file_baton,
   struct dump_edit_baton *eb = fb->eb;
   apr_finfo_t *info = apr_pcalloc(pool, sizeof(apr_finfo_t));
   svn_stringbuf_t *propstring;
+  apr_array_header_t *headers = svn_repos__dumpfile_headers_create(pool);
 
   LDR_DBG(("close_file %p\n", file_baton));
 
@@ -988,8 +965,12 @@ close_file(void *file_baton,
   /* 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)
@@ -997,9 +978,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)
@@ -1007,36 +987,31 @@ 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));
+        svn_repos__dumpfile_header_push(
+          headers, SVN_REPOS_DUMPFILE_TEXT_DELTA_BASE_MD5, 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_pushf(
+        headers, SVN_REPOS_DUMPFILE_TEXT_CONTENT_LENGTH,
+        "%lu", (unsigned long)info->size);
 
       /* 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));
+    svn_repos__dumpfile_header_pushf(
+      headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+      "%lu", (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));
+    svn_repos__dumpfile_header_pushf(
+      headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH,
+      "%lu", (unsigned long)info->size);
+
+  SVN_ERR(svn_repos__dump_headers(eb->stream, headers, TRUE, pool));
 
   /* Dump the props now */
   if (fb->dump_props)
@@ -1074,8 +1049,6 @@ close_file(void *file_baton,
      dump` */
   SVN_ERR(svn_stream_puts(eb->stream, "\n\n"));
 
-  svn_pool_clear(fb->pool);
-
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/pin-externals/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnrdump/load_editor.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/pin-externals/subversion/svnrdump/load_editor.c Wed Jan 21 16:22:19 2015
@@ -66,9 +66,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 +96,12 @@ 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;
   struct directory_baton *parent;
 };
 
@@ -175,169 +171,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_sort(final_mergeinfo, subpool));
-
-  /* Mergeinfo revision sources for r0 and r1 are invalid; you can't merge r0
-     or r1.  However, svndumpfilter can be abused to produce r1 merge source
-     revs.  So if we encounter any, then strip them out, no need to put them
-     into the load target. */
-  SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(&final_mergeinfo,
-                                                    final_mergeinfo,
-                                                    1, 0, FALSE,
-                                                    subpool, 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,
@@ -599,9 +432,6 @@ 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;
 }
 
@@ -661,7 +491,6 @@ new_node_record(void **node_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;
@@ -745,7 +574,6 @@ new_node_record(void **node_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;
@@ -813,7 +641,6 @@ new_node_record(void **node_baton,
                    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;
@@ -836,7 +663,6 @@ new_node_record(void **node_baton,
                                                 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;
@@ -893,51 +719,30 @@ set_node_property(void *baton,
                   const svn_string_t *value)
 {
   struct node_baton *nb = baton;
+  struct revision_baton *rb = nb->rb;
+  struct parse_baton *pb = rb->pb;
   const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
 
   if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
     {
-      svn_string_t *renumbered_mergeinfo;
-      svn_string_t prop_val;
+      svn_string_t *new_value;
+      svn_error_t *err;
 
-      /* Tolerate mergeinfo with "\r\n" line endings because some
-         dumpstream sources might contain as much.  If so normalize
-         the line endings to '\n' and make a notification to
-         PARSE_BATON->FEEDBACK_STREAM that we have made this
-         correction. */
-      if (strstr(value->data, "\r"))
+      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)
         {
-          const char *prop_eol_normalized;
-
-          SVN_ERR(svn_subst_translate_cstring2(value->data,
-                                               &prop_eol_normalized,
-                                               "\n",  /* translate to LF */
-                                               FALSE, /* no repair */
-                                               NULL,  /* no keywords */
-                                               FALSE, /* no expansion */
-                                               pool));
-          prop_val.data = prop_eol_normalized;
-          prop_val.len = strlen(prop_eol_normalized);
-          value = &prop_val;
-
-          /* ### TODO: notify? */
+          return svn_error_quick_wrap(err,
+                                      _("Invalid svn:mergeinfo value"));
         }
 
-      /* Renumber mergeinfo as appropriate. */
-      SVN_ERR(renumber_mergeinfo_revs(&renumbered_mergeinfo, value,
-                                      nb->rb, pool));
-      value = renumbered_mergeinfo;
-
-      if (nb->rb->pb->parent_dir)
-        {
-          /* Prefix the merge source paths with PB->parent_dir. */
-          /* ASSUMPTION: All source paths are included in the dump stream. */
-          svn_string_t *mergeinfo_val;
-          SVN_ERR(prefix_mergeinfo_paths(&mergeinfo_val, value,
-                                         nb->rb->pb->parent_dir, pool));
-          value = mergeinfo_val;
-        }
+      value = new_value;
     }
 
   SVN_ERR(svn_rdump__normalize_prop(name, &value, pool));

Modified: subversion/branches/pin-externals/subversion/svnrdump/svnrdump.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnrdump/svnrdump.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/pin-externals/subversion/svnrdump/svnrdump.c Wed Jan 21 16:22:19 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,38 +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 *stdout_stream;
-  svn_stream_t *revprop_stream;
-
-  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
 
-  /* Revision-number: 19 */
-  SVN_ERR(svn_stream_printf(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(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n", propstring->len));
-
-  /* Content-length: 29 */
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
-
-  /* Property data. */
-  SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
-                           &(propstring->len)));
-
-  SVN_ERR(svn_stream_puts(stdout_stream, "\n"));
-  SVN_ERR(svn_stream_close(stdout_stream));
+  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,
@@ -303,38 +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 *stdout_stream;
-  svn_stream_t *revprop_stream;
 
-  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
-
-  /* Revision-number: 19 */
-  SVN_ERR(svn_stream_printf(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(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_PROP_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n", propstring->len));
-
-  /* Content-length: 29 */
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_CONTENT_LENGTH
-                            ": %" APR_SIZE_T_FMT "\n\n", propstring->len));
-
-  /* Property data. */
-  SVN_ERR(svn_stream_write(stdout_stream, propstring->data,
-                           &(propstring->len)));
-
-  SVN_ERR(svn_stream_puts(stdout_stream, "\n"));
-  SVN_ERR(svn_stream_close(stdout_stream));
+  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,
@@ -471,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;
 }
 
@@ -1176,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

Modified: subversion/branches/pin-externals/subversion/svnserve/logger.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnserve/logger.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnserve/logger.c (original)
+++ subversion/branches/pin-externals/subversion/svnserve/logger.c Wed Jan 21 16:22:19 2015
@@ -134,7 +134,10 @@ logger__log_error(logger_t *logger,
           if (len > sizeof(errstr) - sizeof(APR_EOL_STR)) {
             len = sizeof(errstr) - sizeof(APR_EOL_STR);
           }
+
           memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR));
+          len += sizeof(APR_EOL_STR) -1;  /* add NL, ex terminating NUL */
+
           svn_error_clear(svn_stream_write(logger->stream, errstr, &len));
 
           continuation = "-";

Modified: subversion/branches/pin-externals/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnserve/svnserve.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/pin-externals/subversion/svnserve/svnserve.c Wed Jan 21 16:22:19 2015
@@ -271,6 +271,8 @@ static const apr_getopt_option_t svnserv
         "                             "
         "Default is 16.\n"
         "                             "
+        "0 switches to dynamically sized caches.\n"
+        "                             "
         "[used for FSFS and FSX repositories only]")},
     {"cache-txdeltas", SVNSERVE_OPT_CACHE_TXDELTAS, 1,
      N_("enable or disable caching of deltas between older\n"

Modified: subversion/branches/pin-externals/subversion/svnsync/sync.c
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/svnsync/sync.c?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/svnsync/sync.c (original)
+++ subversion/branches/pin-externals/subversion/svnsync/sync.c Wed Jan 21 16:22:19 2015
@@ -34,6 +34,8 @@
 #include "svn_subst.h"
 #include "svn_string.h"
 
+#include "private/svn_string_private.h"
+
 #include "sync.h"
 
 #include "svn_private_config.h"
@@ -83,6 +85,90 @@ normalize_string(const svn_string_t **st
   return SVN_NO_ERROR;
 }
 
+/* Remove r0 references from the mergeinfo string *STR.
+ *
+ * r0 was never a valid mergeinfo reference and cannot be committed with
+ * recent servers, but can be committed through a server older than 1.6.18
+ * for HTTP or older than 1.6.17 for the other protocols. See issue #4476
+ * "Mergeinfo containing r0 makes svnsync and dump and load fail".
+ *
+ * Set *WAS_CHANGED to TRUE if *STR was changed, otherwise to FALSE.
+ */
+static svn_error_t *
+remove_r0_mergeinfo(const svn_string_t **str,
+                    svn_boolean_t *was_changed,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  svn_stringbuf_t *new_str = svn_stringbuf_create_empty(result_pool);
+  apr_array_header_t *lines;
+  int i;
+
+  SVN_ERR_ASSERT(*str && (*str)->data);
+
+  *was_changed = FALSE;
+
+  /* for each line */
+  lines = svn_cstring_split((*str)->data, "\n", FALSE, scratch_pool);
+
+  for (i = 0; i < lines->nelts; i++)
+    {
+      char *line = APR_ARRAY_IDX(lines, i, char *);
+      char *colon;
+
+      /* split at the last colon */
+      colon = strrchr(line, ':');
+
+      if (! colon)
+        return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
+                                 _("Missing colon in svn:mergeinfo "
+                                   "property"));
+
+      /* remove r0 */
+      if (colon[1] == '0')
+        {
+          char *rangelist;
+
+          rangelist = colon + 1;
+
+          if (strncmp(rangelist, "0*,", 3) == 0)
+            {
+              rangelist += 3;
+            }
+          else if (strcmp(rangelist, "0*") == 0
+                   || strncmp(rangelist, "0,", 2) == 0
+                   || strncmp(rangelist, "0-1*", 4) == 0
+                   || strncmp(rangelist, "0-1,", 4) == 0
+                   || strcmp(rangelist, "0-1") == 0)
+            {
+              rangelist += 2;
+            }
+          else if (strcmp(rangelist, "0") == 0)
+            {
+              rangelist += 1;
+            }
+          else if (strncmp(rangelist, "0-", 2) == 0)
+            {
+              rangelist[0] = '1';
+            }
+
+          /* reassemble */
+          if (new_str->len)
+            svn_stringbuf_appendbyte(new_str, '\n');
+          svn_stringbuf_appendbytes(new_str, line, colon + 1 - line);
+          svn_stringbuf_appendcstr(new_str, rangelist);
+        }
+    }
+
+  if (strcmp((*str)->data, new_str->data) != 0)
+    {
+      *was_changed = TRUE;
+    }
+
+  *str = svn_stringbuf__morph_into_string(new_str);
+  return SVN_NO_ERROR;
+}
+
 
 /* Normalize the encoding and line ending style of the values of properties
  * in REV_PROPS that "need translation" (according to
@@ -153,6 +239,7 @@ typedef struct edit_baton_t {
   svn_boolean_t got_textdeltas;
   svn_revnum_t base_revision;
   svn_boolean_t quiet;
+  svn_boolean_t mergeinfo_tweaked;  /* Did we tweak svn:mergeinfo? */
   svn_boolean_t strip_mergeinfo;    /* Are we stripping svn:mergeinfo? */
   svn_boolean_t migrate_svnmerge;   /* Are we converting svnmerge.py data? */
   svn_boolean_t mergeinfo_stripped; /* Did we strip svn:mergeinfo? */
@@ -414,8 +501,19 @@ change_file_prop(void *file_baton,
   if (svn_prop_needs_translation(name))
     {
       svn_boolean_t was_normalized;
+      svn_boolean_t mergeinfo_tweaked = FALSE;
+
+      /* Normalize encoding to UTF-8, and EOL style to LF. */
       SVN_ERR(normalize_string(&value, &was_normalized,
                                eb->source_prop_encoding, pool, pool));
+      /* Correct malformed mergeinfo. */
+      if (strcmp(name, SVN_PROP_MERGEINFO) == 0)
+        {
+          SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
+                                      pool, pool));
+          if (mergeinfo_tweaked)
+            eb->mergeinfo_tweaked = TRUE;
+        }
       if (was_normalized)
         (*(eb->normalized_node_props_counter))++;
     }
@@ -513,8 +611,19 @@ change_dir_prop(void *dir_baton,
   if (svn_prop_needs_translation(name))
     {
       svn_boolean_t was_normalized;
+      svn_boolean_t mergeinfo_tweaked = FALSE;
+
+      /* Normalize encoding to UTF-8, and EOL style to LF. */
       SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding,
                                pool, pool));
+      /* Maybe adjust svn:mergeinfo. */
+      if (strcmp(name, SVN_PROP_MERGEINFO) == 0)
+        {
+          SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
+                                      pool, pool));
+          if (mergeinfo_tweaked)
+            eb->mergeinfo_tweaked = TRUE;
+        }
       if (was_normalized)
         (*(eb->normalized_node_props_counter))++;
     }
@@ -548,6 +657,10 @@ close_edit(void *edit_baton,
     {
       if (eb->got_textdeltas)
         SVN_ERR(svn_cmdline_printf(pool, "\n"));
+      if (eb->mergeinfo_tweaked)
+        SVN_ERR(svn_cmdline_printf(pool,
+                                   "NOTE: Adjusted Subversion mergeinfo in "
+                                   "this revision.\n"));
       if (eb->mergeinfo_stripped)
         SVN_ERR(svn_cmdline_printf(pool,
                                    "NOTE: Dropped Subversion mergeinfo "

Modified: subversion/branches/pin-externals/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/tests/cmdline/basic_tests.py?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/pin-externals/subversion/tests/cmdline/basic_tests.py Wed Jan 21 16:22:19 2015
@@ -3146,6 +3146,31 @@ def basic_youngest(sbox):
                                            'youngest', path)
 
 
+# With 'svn mkdir --parents' the target directory may already exist on disk.
+# In that case it was wrongly performing a recursive 'add' on its contents.
+def mkdir_parents_target_exists_on_disk(sbox):
+  "mkdir parents target exists on disk"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  Y_path = sbox.ospath('Y')
+  Y_Z_path = sbox.ospath('Y/Z')
+
+  os.mkdir(Y_path)
+  os.mkdir(Y_Z_path)
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'mkdir', '--parents', Y_path)
+
+  # Y should be added, and Z should not. There was a regression in which Z
+  # was also added.
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  expected_status.add({
+    'Y'      : Item(status='A ', wc_rev=0),
+    })
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+
 ########################################################################
 # Run the tests
 
@@ -3215,6 +3240,7 @@ test_list = [ None,
               delete_conflicts_one_of_many,
               peg_rev_on_non_existent_wc_path,
               basic_youngest,
+              mkdir_parents_target_exists_on_disk,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/pin-externals/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/tests/cmdline/copy_tests.py?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/pin-externals/subversion/tests/cmdline/copy_tests.py Wed Jan 21 16:22:19 2015
@@ -560,7 +560,7 @@ def no_copy_overwrites(sbox):
   # Repeat the last command.  It should *fail* because A/D/H/G already exists.
   svntest.actions.run_and_verify_svn(
     "Whoa, I was able to overwrite a directory!",
-    None, svntest.verify.AnyOutput,
+    None, ".*'/A/D/H/G'.*",
     'cp', dirURL1, dirURL2,
     '-m', 'fooogle')
 

Modified: subversion/branches/pin-externals/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/tests/cmdline/externals_tests.py?rev=1653578&r1=1653577&r2=1653578&view=diff
==============================================================================
--- subversion/branches/pin-externals/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/pin-externals/subversion/tests/cmdline/externals_tests.py Wed Jan 21 16:22:19 2015
@@ -3479,6 +3479,74 @@ def switch_relative_externals(sbox):
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'up', wc)
 
+
+def copy_file_external_to_repo(sbox):
+  "explicitly copy file external to repo"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  change_external(sbox.ospath('A'), '^/A/mu ext')
+  sbox.simple_update()
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'cp',
+                                     '--message', 'external copy',
+                                     sbox.ospath('A/ext'),
+                                     sbox.repo_url + '/ext_copy')
+
+  expected_output = svntest.wc.State(wc_dir, {
+      'ext_copy' : Item(status='A '),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+      'A/ext'    : Item('This is the file \'mu\'.\n'),
+      'ext_copy' : Item('This is the file \'mu\'.\n'),
+      })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output, expected_disk, None)
+
+@Issue(4550)
+def replace_tree_with_foreign_external(sbox):
+  "replace tree with foreign external"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  repo_dir = sbox.repo_dir
+
+  other_repo_dir, other_repo_url = sbox.add_repo_path('other')
+  svntest.main.copy_repos(repo_dir, other_repo_dir, 1)
+
+  sbox.simple_propset('svn:externals', other_repo_url + '/A/B X', 'A')
+  sbox.simple_commit()
+  sbox.simple_propdel('svn:externals', 'A')
+  sbox.simple_mkdir('A/X')
+  sbox.simple_mkdir('A/X/E')
+  sbox.simple_commit()
+  sbox.simple_update()
+
+  expected_output = svntest.wc.State(wc_dir, {
+      'A/X'         : Item(status='D '),
+      'A'           : Item(status=' U'),
+      'A/X/lambda'  : Item(status='A '),
+      'A/X/E'       : Item(status='A '),
+      'A/X/E/alpha' : Item(status='A '),
+      'A/X/E/beta'  : Item(status='A '),
+      'A/X/F'       : Item(status='A '),
+      })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({
+    'A/X'         : Item(status='  ', wc_rev=1, prev_status='X '),
+    'A/X/E'       : Item(status='  ', wc_rev=1, prev_status='  '),
+    'A/X/E/alpha' : Item(status='  ', wc_rev=1),
+    'A/X/E/beta'  : Item(status='  ', wc_rev=1),
+    'A/X/F'       : Item(status='  ', wc_rev=1),
+    'A/X/lambda'  : Item(status='  ', wc_rev=1),
+    })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output, None, expected_status,
+                                        None, None, None, None, None, 1,
+                                        '-r', '2', wc_dir)
+
 def pin_externals(sbox):
   "test svn copy --pin-externals"
 
@@ -3564,6 +3632,8 @@ test_list = [ None,
               update_external_peg_rev,
               update_deletes_file_external,
               switch_relative_externals,
+              copy_file_external_to_repo,
+              replace_tree_with_foreign_external,
               pin_externals,
              ]