You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2012/05/16 22:32:54 UTC

svn commit: r1339349 [14/37] - in /subversion/branches/fix-rdump-editor: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/client-side/vim/ contrib/server-side/ notes/ notes/api-errat...

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/temp_serializer.h?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/temp_serializer.h (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/temp_serializer.h Wed May 16 20:32:43 2012
@@ -26,7 +26,7 @@
 #include "fs.h"
 
 /**
- * Prepend the @a number to the @a string in a space efficient way that
+ * Prepend the @a number to the @a string in a space efficient way such that
  * no other (number,string) combination can produce the same result.
  * Allocate temporaries as well as the result from @a pool.
  */
@@ -36,8 +36,8 @@ svn_fs_fs__combine_number_and_string(apr
                                      apr_pool_t *pool);
 
 /**
- * Combine the numbers @a a and @a b a space efficient way that no other
- * combination of numbers can produce the same result.
+ * Combine the numbers @a a and @a b in a space efficient way such that no
+ * other combination of numbers can produce the same result.
  * Allocate temporaries as well as the result from @a pool.
  */
 const char*
@@ -77,7 +77,7 @@ typedef struct
  * #svn_fs_fs__txdelta_cached_window_t.
  */
 svn_error_t *
-svn_fs_fs__serialize_txdelta_window(char **buffer,
+svn_fs_fs__serialize_txdelta_window(void **buffer,
                                     apr_size_t *buffer_size,
                                     void *item,
                                     apr_pool_t *pool);
@@ -88,7 +88,7 @@ svn_fs_fs__serialize_txdelta_window(char
  */
 svn_error_t *
 svn_fs_fs__deserialize_txdelta_window(void **item,
-                                      char *buffer,
+                                      void *buffer,
                                       apr_size_t buffer_size,
                                       apr_pool_t *pool);
 
@@ -97,7 +97,7 @@ svn_fs_fs__deserialize_txdelta_window(vo
  * (@a in is an #apr_array_header_t of apr_off_t elements).
  */
 svn_error_t *
-svn_fs_fs__serialize_manifest(char **data,
+svn_fs_fs__serialize_manifest(void **data,
                               apr_size_t *data_len,
                               void *in,
                               apr_pool_t *pool);
@@ -108,7 +108,7 @@ svn_fs_fs__serialize_manifest(char **dat
  */
 svn_error_t *
 svn_fs_fs__deserialize_manifest(void **out,
-                                char *data,
+                                void *data,
                                 apr_size_t data_len,
                                 apr_pool_t *pool);
 
@@ -117,7 +117,7 @@ svn_fs_fs__deserialize_manifest(void **o
  * (@a in is an #apr_hash_t of svn_string_t elements, keyed by const char*).
  */
 svn_error_t *
-svn_fs_fs__serialize_properties(char **data,
+svn_fs_fs__serialize_properties(void **data,
                                 apr_size_t *data_len,
                                 void *in,
                                 apr_pool_t *pool);
@@ -128,7 +128,7 @@ svn_fs_fs__serialize_properties(char **d
  */
 svn_error_t *
 svn_fs_fs__deserialize_properties(void **out,
-                                  char *data,
+                                  void *data,
                                   apr_size_t data_len,
                                   apr_pool_t *pool);
 
@@ -136,7 +136,7 @@ svn_fs_fs__deserialize_properties(void *
  * Implements #svn_cache__serialize_func_t for #svn_fs_id_t
  */
 svn_error_t *
-svn_fs_fs__serialize_id(char **data,
+svn_fs_fs__serialize_id(void **data,
                         apr_size_t *data_len,
                         void *in,
                         apr_pool_t *pool);
@@ -146,7 +146,7 @@ svn_fs_fs__serialize_id(char **data,
  */
 svn_error_t *
 svn_fs_fs__deserialize_id(void **out,
-                          char *data,
+                          void *data,
                           apr_size_t data_len,
                           apr_pool_t *pool);
 
@@ -154,7 +154,7 @@ svn_fs_fs__deserialize_id(void **out,
  * Implements #svn_cache__serialize_func_t for #node_revision_t
  */
 svn_error_t *
-svn_fs_fs__serialize_node_revision(char **buffer,
+svn_fs_fs__serialize_node_revision(void **buffer,
                                    apr_size_t *buffer_size,
                                    void *item,
                                    apr_pool_t *pool);
@@ -164,7 +164,7 @@ svn_fs_fs__serialize_node_revision(char 
  */
 svn_error_t *
 svn_fs_fs__deserialize_node_revision(void **item,
-                                     char *buffer,
+                                     void *buffer,
                                      apr_size_t buffer_size,
                                      apr_pool_t *pool);
 
@@ -172,7 +172,7 @@ svn_fs_fs__deserialize_node_revision(voi
  * Implements #svn_cache__serialize_func_t for a directory contents hash
  */
 svn_error_t *
-svn_fs_fs__serialize_dir_entries(char **data,
+svn_fs_fs__serialize_dir_entries(void **data,
                                  apr_size_t *data_len,
                                  void *in,
                                  apr_pool_t *pool);
@@ -182,7 +182,7 @@ svn_fs_fs__serialize_dir_entries(char **
  */
 svn_error_t *
 svn_fs_fs__deserialize_dir_entries(void **out,
-                                   char *data,
+                                   void *data,
                                    apr_size_t data_len,
                                    apr_pool_t *pool);
 
@@ -192,7 +192,7 @@ svn_fs_fs__deserialize_dir_entries(void 
  * serialized manifest array @a data and @a data_len. */
 svn_error_t *
 svn_fs_fs__get_sharded_offset(void **out,
-                              const char *data,
+                              const void *data,
                               apr_size_t data_len,
                               void *baton,
                               apr_pool_t *pool);
@@ -204,7 +204,7 @@ svn_fs_fs__get_sharded_offset(void **out
  */
 svn_error_t *
 svn_fs_fs__extract_dir_entry(void **out,
-                             const char *data,
+                             const void *data,
                              apr_size_t data_len,
                              void *baton,
                              apr_pool_t *pool);
@@ -230,7 +230,7 @@ typedef struct replace_baton_t
  * identified by its name in the #replace_baton_t in @a baton.
  */
 svn_error_t *
-svn_fs_fs__replace_dir_entry(char **data,
+svn_fs_fs__replace_dir_entry(void **data,
                              apr_size_t *data_len,
                              void *baton,
                              apr_pool_t *pool);

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.c Wed May 16 20:32:43 2012
@@ -57,6 +57,7 @@
 #include "tree.h"
 #include "fs_fs.h"
 #include "id.h"
+#include "temp_serializer.h"
 
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_fs_util.h"
@@ -154,8 +155,8 @@ locate_cache(svn_cache__t **cache,
     {
       fs_fs_data_t *ffd = root->fs->fsap_data;
       if (cache) *cache = ffd->rev_node_cache;
-      if (key && path) *key = apr_psprintf(pool, "%ld%s",
-                                           root->rev, path);
+      if (key && path) *key
+        = svn_fs_fs__combine_number_and_string(root->rev, path, pool);
     }
 }
 
@@ -358,7 +359,7 @@ mutable_root_node(dag_node_t **node_p,
     return svn_fs_fs__dag_clone_root(node_p, root->fs, root->txn, pool);
   else
     /* If it's not a transaction root, we can't change its contents.  */
-    return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path, pool);
+    return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path);
 }
 
 
@@ -502,7 +503,7 @@ get_copy_inheritance(copy_id_inherit_t *
      or if it is a branch point that we are accessing via its original
      copy destination path. */
   SVN_ERR(svn_fs_fs__dag_get_copyroot(&copyroot_rev, &copyroot_path,
-                                      child->node,pool));
+                                      child->node));
   SVN_ERR(svn_fs_fs__revision_root(&copyroot_root, fs, copyroot_rev, pool));
   SVN_ERR(get_dag(&copyroot_node, copyroot_root, copyroot_path, pool));
   copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
@@ -594,6 +595,7 @@ open_path(parent_path_t **parent_path_p,
   const char *rest; /* The portion of PATH we haven't traversed yet.  */
   const char *canon_path = svn_fs__canonicalize_abspath(path, pool);
   const char *path_so_far = "/";
+  apr_pool_t *iterpool = svn_pool_create(pool);
 
   /* Make a parent_path item for the root node, using its own current
      copy id.  */
@@ -614,6 +616,8 @@ open_path(parent_path_t **parent_path_p,
       char *entry;
       dag_node_t *child;
 
+      svn_pool_clear(iterpool);
+
       /* Parse out the next entry from the path.  */
       entry = svn_fs__next_entry_name(&next, rest, pool);
 
@@ -642,7 +646,7 @@ open_path(parent_path_t **parent_path_p,
           if (cached_node)
             child = cached_node;
           else
-            err = svn_fs_fs__dag_open(&child, here, entry, pool);
+            err = svn_fs_fs__dag_open(&child, here, entry, pool, iterpool);
 
           /* "file not found" requires special handling.  */
           if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
@@ -676,14 +680,14 @@ open_path(parent_path_t **parent_path_p,
           if (txn_id)
             {
               SVN_ERR(get_copy_inheritance(&inherit, &copy_path,
-                                           fs, parent_path, txn_id, pool));
+                                           fs, parent_path, txn_id, iterpool));
               parent_path->copy_inherit = inherit;
               parent_path->copy_src_path = apr_pstrdup(pool, copy_path);
             }
 
           /* Cache the node we found (if it wasn't already cached). */
           if (! cached_node)
-            SVN_ERR(dag_node_cache_set(root, path_so_far, child, pool));
+            SVN_ERR(dag_node_cache_set(root, path_so_far, child, iterpool));
         }
 
       /* Are we finished traversing the path?  */
@@ -692,13 +696,14 @@ open_path(parent_path_t **parent_path_p,
 
       /* The path isn't finished yet; we'd better be in a directory.  */
       if (svn_fs_fs__dag_node_kind(child) != svn_node_dir)
-        SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far, pool),
-                  apr_psprintf(pool, _("Failure opening '%s'"), path));
+        SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far),
+                  apr_psprintf(iterpool, _("Failure opening '%s'"), path));
 
       rest = next;
       here = child;
     }
 
+  svn_pool_destroy(iterpool);
   *parent_path_p = parent_path;
   return SVN_NO_ERROR;
 }
@@ -763,7 +768,7 @@ make_path_mutable(svn_fs_root_t *root,
 
       /* Determine what copyroot our new child node should use. */
       SVN_ERR(svn_fs_fs__dag_get_copyroot(&copyroot_rev, &copyroot_path,
-                                          parent_path->node, pool));
+                                          parent_path->node));
       SVN_ERR(svn_fs_fs__revision_root(&copyroot_root, root->fs,
                                        copyroot_rev, pool));
       SVN_ERR(get_dag(&copyroot_node, copyroot_root, copyroot_path, pool));
@@ -1072,8 +1077,7 @@ fs_change_node_prop(svn_fs_root_t *root,
     {
       apr_int64_t increment = 0;
       svn_boolean_t had_mergeinfo;
-      SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&had_mergeinfo, parent_path->node,
-                                           pool));
+      SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&had_mergeinfo, parent_path->node));
 
       if (value && !had_mergeinfo)
         increment = 1;
@@ -1127,7 +1131,7 @@ fs_props_changed(svn_boolean_t *changed_
   SVN_ERR(get_dag(&node1, root1, path1, pool));
   SVN_ERR(get_dag(&node2, root2, path2, pool));
   return svn_fs_fs__dag_things_different(changed_p, NULL,
-                                         node1, node2, pool);
+                                         node1, node2);
 }
 
 
@@ -1142,30 +1146,6 @@ get_root(dag_node_t **node, svn_fs_root_
 }
 
 
-static svn_error_t *
-update_ancestry(svn_fs_t *fs,
-                const svn_fs_id_t *source_id,
-                const svn_fs_id_t *target_id,
-                const char *target_path,
-                int source_pred_count,
-                apr_pool_t *pool)
-{
-  node_revision_t *noderev;
-
-  if (svn_fs_fs__id_txn_id(target_id) == NULL)
-    return svn_error_createf
-      (SVN_ERR_FS_NOT_MUTABLE, NULL,
-       _("Unexpected immutable node at '%s'"), target_path);
-
-  SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, target_id, pool));
-  noderev->predecessor_id = source_id;
-  noderev->predecessor_count = source_pred_count;
-  if (noderev->predecessor_count != -1)
-    noderev->predecessor_count++;
-  return svn_fs_fs__put_node_revision(fs, target_id, noderev, FALSE, pool);
-}
-
-
 /* Set the contents of CONFLICT_PATH to PATH, and return an
    SVN_ERR_FS_CONFLICT error that indicates that there was a conflict
    at PATH.  Perform all allocations in POOL (except the allocation of
@@ -1217,8 +1197,8 @@ merge(svn_stringbuf_t *conflict_p,
   apr_hash_index_t *hi;
   svn_fs_t *fs;
   apr_pool_t *iterpool;
-  int pred_count;
   apr_int64_t mergeinfo_increment = 0;
+  svn_boolean_t fs_supports_mergeinfo;
 
   /* Make sure everyone comes from the same filesystem. */
   fs = svn_fs_fs__dag_get_fs(ancestor);
@@ -1362,9 +1342,11 @@ merge(svn_stringbuf_t *conflict_p,
   /* ### todo: it would be more efficient to simply check for a NULL
      entries hash where necessary below than to allocate an empty hash
      here, but another day, another day... */
-  SVN_ERR(svn_fs_fs__dag_dir_entries(&s_entries, source, pool, pool));
-  SVN_ERR(svn_fs_fs__dag_dir_entries(&t_entries, target, pool, pool));
-  SVN_ERR(svn_fs_fs__dag_dir_entries(&a_entries, ancestor, pool, pool));
+  SVN_ERR(svn_fs_fs__dag_dir_entries(&s_entries, source, pool));
+  SVN_ERR(svn_fs_fs__dag_dir_entries(&t_entries, target, pool));
+  SVN_ERR(svn_fs_fs__dag_dir_entries(&a_entries, ancestor, pool));
+
+  fs_supports_mergeinfo = svn_fs_fs__fs_supports_mergeinfo(fs);
 
   /* for each entry E in a_entries... */
   iterpool = svn_pool_create(pool);
@@ -1397,12 +1379,11 @@ merge(svn_stringbuf_t *conflict_p,
           dag_node_t *t_ent_node;
           SVN_ERR(svn_fs_fs__dag_get_node(&t_ent_node, fs,
                                           t_entry->id, iterpool));
-          if (svn_fs_fs__fs_supports_mergeinfo(fs))
+          if (fs_supports_mergeinfo)
             {
               apr_int64_t mergeinfo_start;
               SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_start,
-                                                         t_ent_node,
-                                                         iterpool));
+                                                         t_ent_node));
               mergeinfo_increment -= mergeinfo_start;
             }
 
@@ -1412,12 +1393,11 @@ merge(svn_stringbuf_t *conflict_p,
               SVN_ERR(svn_fs_fs__dag_get_node(&s_ent_node, fs,
                                               s_entry->id, iterpool));
 
-              if (svn_fs_fs__fs_supports_mergeinfo(fs))
+              if (fs_supports_mergeinfo)
                 {
                   apr_int64_t mergeinfo_end;
                   SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_end,
-                                                             s_ent_node,
-                                                             iterpool));
+                                                             s_ent_node));
                   mergeinfo_increment += mergeinfo_end;
                 }
 
@@ -1490,7 +1470,7 @@ merge(svn_stringbuf_t *conflict_p,
                         txn_id,
                         &sub_mergeinfo_increment,
                         iterpool));
-          if (svn_fs_fs__fs_supports_mergeinfo(fs))
+          if (fs_supports_mergeinfo)
             mergeinfo_increment += sub_mergeinfo_increment;
         }
 
@@ -1526,12 +1506,11 @@ merge(svn_stringbuf_t *conflict_p,
 
       SVN_ERR(svn_fs_fs__dag_get_node(&s_ent_node, fs,
                                       s_entry->id, iterpool));
-      if (svn_fs_fs__fs_supports_mergeinfo(fs))
+      if (fs_supports_mergeinfo)
         {
           apr_int64_t mergeinfo_s;
           SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_s,
-                                                     s_ent_node,
-                                                     iterpool));
+                                                     s_ent_node));
           mergeinfo_increment += mergeinfo_s;
         }
 
@@ -1541,11 +1520,9 @@ merge(svn_stringbuf_t *conflict_p,
     }
   svn_pool_destroy(iterpool);
 
-  SVN_ERR(svn_fs_fs__dag_get_predecessor_count(&pred_count, source, pool));
-  SVN_ERR(update_ancestry(fs, source_id, target_id, target_path,
-                          pred_count, pool));
+  SVN_ERR(svn_fs_fs__dag_update_ancestry(target, source, pool));
 
-  if (svn_fs_fs__fs_supports_mergeinfo(fs))
+  if (fs_supports_mergeinfo)
     SVN_ERR(svn_fs_fs__dag_increment_mergeinfo_count(target,
                                                      mergeinfo_increment,
                                                      pool));
@@ -1830,7 +1807,7 @@ fs_dir_entries(apr_hash_t **table_p,
 
   /* Get the entries for this path in the caller's pool. */
   SVN_ERR(get_dag(&node, root, path, pool));
-  return svn_fs_fs__dag_dir_entries(table_p, node, pool, pool);
+  return svn_fs_fs__dag_dir_entries(table_p, node, pool);
 }
 
 
@@ -1860,7 +1837,7 @@ fs_make_dir(svn_fs_root_t *root,
   /* If there's already a sub-directory by that name, complain.  This
      also catches the case of trying to make a subdirectory named `/'.  */
   if (parent_path->node)
-    return SVN_FS__ALREADY_EXISTS(root, path, pool);
+    return SVN_FS__ALREADY_EXISTS(root, path);
 
   /* Create the subdirectory.  */
   SVN_ERR(make_path_mutable(root, parent_path->parent, path, pool));
@@ -1916,8 +1893,7 @@ fs_delete_node(svn_fs_root_t *root,
   SVN_ERR(make_path_mutable(root, parent_path->parent, path, pool));
   if (svn_fs_fs__fs_supports_mergeinfo(root->fs))
     SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_count,
-                                               parent_path->node,
-                                               pool));
+                                               parent_path->node));
   SVN_ERR(svn_fs_fs__dag_delete(parent_path->parent->node,
                                 parent_path->entry,
                                 txn_id, pool));
@@ -1949,17 +1925,7 @@ fs_same_p(svn_boolean_t *same_p,
           svn_fs_t *fs2,
           apr_pool_t *pool)
 {
-  const char *uuid1;
-  const char *uuid2;
-
-  /* Random thought: if fetching UUIDs to compare filesystems is too
-     expensive, one solution would be to cache the UUID in each fs
-     object (copying the UUID into fs->pool, of course). */
-
-  SVN_ERR(fs1->vtable->get_uuid(fs1, &uuid1, pool));
-  SVN_ERR(fs2->vtable->get_uuid(fs2, &uuid2, pool));
-
-  *same_p = ! strcmp(uuid1, uuid2);
+  *same_p = ! strcmp(fs1->uuid, fs2->uuid);
   return SVN_NO_ERROR;
 }
 
@@ -2032,8 +1998,7 @@ copy_helper(svn_fs_root_t *from_root,
           kind = svn_fs_path_change_replace;
           if (svn_fs_fs__fs_supports_mergeinfo(to_root->fs))
             SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_start,
-                                                       to_parent_path->node,
-                                                       pool));
+                                                       to_parent_path->node));
         }
       else
         {
@@ -2043,7 +2008,7 @@ copy_helper(svn_fs_root_t *from_root,
 
       if (svn_fs_fs__fs_supports_mergeinfo(to_root->fs))
         SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_end,
-                                                   from_node, pool));
+                                                   from_node));
 
       /* Make sure the target node's parents are mutable.  */
       SVN_ERR(make_path_mutable(to_root, to_parent_path->parent,
@@ -2176,8 +2141,8 @@ fs_copied_from(svn_revnum_t *rev_p,
       /* There is no cached entry, look it up the old-fashioned
          way. */
       SVN_ERR(get_dag(&node, root, path, pool));
-      SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(&copyfrom_rev, node, pool));
-      SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(&copyfrom_path, node, pool));
+      SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(&copyfrom_rev, node));
+      SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(&copyfrom_path, node));
     }
 
   *rev_p  = copyfrom_rev;
@@ -2207,7 +2172,7 @@ fs_make_file(svn_fs_root_t *root,
   /* If there's already a file by that name, complain.
      This also catches the case of trying to make a file named `/'.  */
   if (parent_path->node)
-    return SVN_FS__ALREADY_EXISTS(root, path, pool);
+    return SVN_FS__ALREADY_EXISTS(root, path);
 
   /* Check (non-recursively) to see if path is locked;  if so, check
      that we can use it. */
@@ -2493,17 +2458,8 @@ fs_apply_textdelta(svn_txdelta_window_ha
   tb->root = root;
   tb->path = path;
   tb->pool = pool;
-
-  if (base_checksum)
-    tb->base_checksum = svn_checksum_dup(base_checksum, pool);
-  else
-    tb->base_checksum = NULL;
-
-  if (result_checksum)
-    tb->result_checksum = svn_checksum_dup(result_checksum, pool);
-  else
-    tb->result_checksum = NULL;
-
+  tb->base_checksum = svn_checksum_dup(base_checksum, pool);
+  tb->result_checksum = svn_checksum_dup(result_checksum, pool);
 
   SVN_ERR(apply_textdelta(tb, pool));
 
@@ -2635,11 +2591,7 @@ fs_apply_text(svn_stream_t **contents_p,
   tb->root = root;
   tb->path = path;
   tb->pool = pool;
-
-  if (result_checksum)
-    tb->result_checksum = svn_checksum_dup(result_checksum, pool);
-  else
-    tb->result_checksum = NULL;
+  tb->result_checksum = svn_checksum_dup(result_checksum, pool);
 
   SVN_ERR(apply_text(tb, pool));
 
@@ -2687,7 +2639,7 @@ fs_contents_changed(svn_boolean_t *chang
   SVN_ERR(get_dag(&node1, root1, path1, pool));
   SVN_ERR(get_dag(&node2, root2, path2, pool));
   return svn_fs_fs__dag_things_different(NULL, changed_p,
-                                         node1, node2, pool);
+                                         node1, node2);
 }
 
 
@@ -2819,7 +2771,7 @@ find_youngest_copyroot(svn_revnum_t *rev
 
   /* Find our copyroot. */
   SVN_ERR(svn_fs_fs__dag_get_copyroot(&rev_mine, &path_mine,
-                                      parent_path->node, pool));
+                                      parent_path->node));
 
   /* If a parent and child were copied to in the same revision, prefer
      the child copy target, since it is the copy relevant to the
@@ -2899,7 +2851,7 @@ static svn_error_t *fs_closest_copy(svn_
   if (created_rev == copy_dst_rev)
     {
       const svn_fs_id_t *pred;
-      SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred, copy_dst_node, pool));
+      SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred, copy_dst_node));
       if (! pred)
         return SVN_NO_ERROR;
     }
@@ -3060,7 +3012,7 @@ fs_node_origin_rev(svn_revnum_t *revisio
            value cached in the node (which is allocated in
            SUBPOOL... maybe). */
         svn_pool_clear(predidpool);
-        SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred_id, node, subpool));
+        SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred_id, node));
         pred_id = pred_id ? svn_fs_fs__id_copy(pred_id, predidpool) : NULL;
       }
     while (pred_id);
@@ -3162,7 +3114,7 @@ history_prev(void *baton, apr_pool_t *po
              no predecessor, in which case we're all done!). */
           const svn_fs_id_t *pred_id;
 
-          SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred_id, node, pool));
+          SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred_id, node));
           if (! pred_id)
             return SVN_NO_ERROR;
 
@@ -3210,8 +3162,8 @@ history_prev(void *baton, apr_pool_t *po
           /* If we get here, then our current path is the destination
              of, or the child of the destination of, a copy.  Fill
              in the return values and get outta here.  */
-          SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(&src_rev, node, pool));
-          SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(&copy_src, node, pool));
+          SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(&src_rev, node));
+          SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(&copy_src, node));
 
           dst_rev = copyroot_rev;
           src_path = svn_fspath__join(copy_src, remainder_path, pool);
@@ -3375,7 +3327,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   SVN_ERR(svn_fs_fs__dag_dir_entries(&entries, dir_dag,
-                                     scratch_pool, scratch_pool));
+                                     scratch_pool));
 
   for (hi = apr_hash_first(scratch_pool, entries);
        hi;
@@ -3391,9 +3343,8 @@ crawl_directory_dag_for_mergeinfo(svn_fs
       kid_path = svn_fspath__join(this_path, dirent->name, iterpool);
       SVN_ERR(get_dag(&kid_dag, root, kid_path, iterpool));
 
-      SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, kid_dag, iterpool));
-      SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down, kid_dag,
-                                                            iterpool));
+      SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, kid_dag));
+      SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down, kid_dag));
 
       if (has_mergeinfo)
         {
@@ -3468,7 +3419,6 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
   parent_path_t *parent_path, *nearest_ancestor;
   apr_hash_t *proplist;
   svn_string_t *mergeinfo_string;
-  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   *mergeinfo = NULL;
 
@@ -3488,17 +3438,14 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
     {
       svn_boolean_t has_mergeinfo;
 
-      svn_pool_clear(iterpool);
-
       SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo,
-                                           nearest_ancestor->node, iterpool));
+                                           nearest_ancestor->node));
       if (has_mergeinfo)
         break;
 
       /* No need to loop if we're looking for explicit mergeinfo. */
       if (inherit == svn_mergeinfo_explicit)
         {
-          svn_pool_destroy(iterpool);
           return SVN_NO_ERROR;
         }
 
@@ -3507,13 +3454,10 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
       /* Run out?  There's no mergeinfo. */
       if (!nearest_ancestor)
         {
-          svn_pool_destroy(iterpool);
           return SVN_NO_ERROR;
         }
     }
 
-  svn_pool_destroy(iterpool);
-
   SVN_ERR(svn_fs_fs__dag_get_proplist(&proplist, nearest_ancestor->node,
                                       scratch_pool));
   mergeinfo_string = apr_hash_get(proplist, SVN_PROP_MERGEINFO,
@@ -3581,8 +3525,7 @@ add_descendant_mergeinfo(svn_mergeinfo_c
 
   SVN_ERR(get_dag(&this_dag, root, path, scratch_pool));
   SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down,
-                                                        this_dag,
-                                                        scratch_pool));
+                                                        this_dag));
   if (go_down)
     SVN_ERR(crawl_directory_dag_for_mergeinfo(root,
                                               path,
@@ -3783,7 +3726,8 @@ make_txn_root(svn_fs_root_t **root_p,
                                       svn_fs_fs__dag_deserialize,
                                       APR_HASH_KEY_STRING,
                                       32, 20, FALSE,
-                                      apr_pstrcat(pool, txn, ":TXN", (char *)NULL),
+                                      apr_pstrcat(pool, txn, ":TXN",
+                                                  (char *)NULL),
                                       root->pool));
 
   /* Initialize transaction-local caches in FS.
@@ -3797,3 +3741,170 @@ make_txn_root(svn_fs_root_t **root_p,
   *root_p = root;
   return SVN_NO_ERROR;
 }
+
+
+
+/* Verify. */
+static APR_INLINE const char *
+stringify_node(dag_node_t *node,
+               apr_pool_t *pool)
+{
+  /* ### TODO: print some PATH@REV to it, too. */
+  return svn_fs_fs__id_unparse(svn_fs_fs__dag_get_id(node), pool)->data;
+}
+
+/* Check metadata sanity on NODE, and on its children.  Manually verify
+   information for DAG nodes in revision REV, and trust the metadata
+   accuracy for nodes belonging to older revisions. */
+static svn_error_t *
+verify_node(dag_node_t *node,
+            svn_revnum_t rev,
+            apr_pool_t *pool)
+{
+  svn_boolean_t has_mergeinfo;
+  apr_int64_t mergeinfo_count;
+  const svn_fs_id_t *pred_id;
+  svn_fs_t *fs = svn_fs_fs__dag_get_fs(node);
+  int pred_count;
+  svn_node_kind_t kind;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+
+  /* Fetch some data. */
+  SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, node));
+  SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&mergeinfo_count, node));
+  SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred_id, node));
+  SVN_ERR(svn_fs_fs__dag_get_predecessor_count(&pred_count, node));
+  kind = svn_fs_fs__dag_node_kind(node);
+
+  /* Sanity check. */
+  if (mergeinfo_count < 0)
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Negative mergeinfo-count %" APR_INT64_T_FMT
+                             " on node '%s'",
+                             mergeinfo_count, stringify_node(node, iterpool));
+
+  /* Issue #4129. (This check will explicitly catch non-root instances too.) */
+  if (pred_id)
+    {
+      dag_node_t *pred;
+      int pred_pred_count;
+      SVN_ERR(svn_fs_fs__dag_get_node(&pred, fs, pred_id, iterpool));
+      SVN_ERR(svn_fs_fs__dag_get_predecessor_count(&pred_pred_count, pred));
+      if (pred_pred_count+1 != pred_count)
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                                 "Predecessor count mismatch: "
+                                 "%s has %d, but %s has %d",
+                                 stringify_node(node, iterpool), pred_count,
+                                 stringify_node(pred, iterpool),
+                                 pred_pred_count);
+    }
+
+  /* Kind-dependent verifications. */
+  if (kind == svn_node_none)
+    {
+      return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                               "Node '%s' has kind 'none'",
+                               stringify_node(node, iterpool));
+    }
+  if (kind == svn_node_file)
+    {
+      if (has_mergeinfo != mergeinfo_count) /* comparing int to bool */
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                                 "File node '%s' has inconsistent mergeinfo: "
+                                 "has_mergeinfo=%d, "
+                                 "mergeinfo_count=%" APR_INT64_T_FMT,
+                                 stringify_node(node, iterpool),
+                                 has_mergeinfo, mergeinfo_count);
+    }
+  if (kind == svn_node_dir)
+    {
+      apr_hash_t *entries;
+      apr_hash_index_t *hi;
+      apr_int64_t children_mergeinfo = 0;
+
+      SVN_ERR(svn_fs_fs__dag_dir_entries(&entries, node, pool));
+
+      /* Compute CHILDREN_MERGEINFO. */
+      for (hi = apr_hash_first(pool, entries);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
+          dag_node_t *child;
+          svn_revnum_t child_rev;
+          apr_int64_t child_mergeinfo;
+
+          svn_pool_clear(iterpool);
+
+          /* Compute CHILD_REV. */
+          SVN_ERR(svn_fs_fs__dag_get_node(&child, fs, dirent->id, iterpool));
+          SVN_ERR(svn_fs_fs__dag_get_revision(&child_rev, child, iterpool));
+
+          if (child_rev == rev)
+            SVN_ERR(verify_node(child, rev, iterpool));
+
+          SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&child_mergeinfo, child));
+          children_mergeinfo += child_mergeinfo;
+        }
+
+      /* Side-effect of issue #4129. */
+      if (children_mergeinfo+has_mergeinfo != mergeinfo_count)
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                                 "Mergeinfo-count discrepancy on '%s': "
+                                 "expected %" APR_INT64_T_FMT "+%d, "
+                                 "counted %" APR_INT64_T_FMT,
+                                 stringify_node(node, iterpool),
+                                 mergeinfo_count, has_mergeinfo,
+                                 children_mergeinfo);
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__verify_root(svn_fs_root_t *root,
+                       apr_pool_t *pool)
+{
+  fs_rev_root_data_t *frd;
+
+  if (root->is_txn_root)
+    /* ### Not implemented */
+    return SVN_NO_ERROR;
+  frd = root->fsap_data;
+
+  /* Recursively verify ROOT_DIR. */
+  SVN_ERR(verify_node(frd->root_dir, root->rev, pool));
+
+  /* Verify explicitly the predecessor of the root. */
+  {
+    const svn_fs_id_t *pred_id;
+    dag_node_t *pred;
+    svn_revnum_t pred_rev;
+
+    /* Only r0 should have no predecessor. */
+    SVN_ERR(svn_fs_fs__dag_get_predecessor_id(&pred_id, frd->root_dir));
+    if (!!pred_id != !!root->rev)
+      return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                               "r%ld's root node's predecessor is "
+                               "unexpectedly '%s'",
+                               root->rev,
+                               (pred_id
+                                ? svn_fs_fs__id_unparse(pred_id, pool)->data
+                                : "(null)"));
+
+    /* Check the predecessor's revision. */
+    if (pred_id)
+      {
+        SVN_ERR(svn_fs_fs__dag_get_node(&pred, root->fs, pred_id, pool));
+        SVN_ERR(svn_fs_fs__dag_get_revision(&pred_rev, pred, pool));
+        if (pred_rev+1 != root->rev)
+          /* Issue #4129. */
+          return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                                   "r%ld's root node's predecessor is r%ld",
+                                   root->rev, pred_rev);
+      }
+  }
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.h?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.h (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_fs_fs/tree.h Wed May 16 20:32:43 2012
@@ -78,6 +78,12 @@ svn_fs_fs__node_created_rev(svn_revnum_t
                             const char *path,
                             apr_pool_t *pool);
 
+/* Verify metadata for ROOT.
+   ### Currently only implemented for revision roots. */
+svn_error_t *
+svn_fs_fs__verify_root(svn_fs_root_t *root,
+                       apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra/compat.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra/compat.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra/compat.c Wed May 16 20:32:43 2012
@@ -141,7 +141,7 @@ prev_log_path(const char **prev_path_p,
               svn_sort__item_t item = APR_ARRAY_IDX(paths,
                                                     i - 1, svn_sort__item_t);
               const char *ch_path = item.key;
-              int len = strlen(ch_path);
+              size_t len = strlen(ch_path);
 
               /* See if our path is the child of this change path.  If
                  not, keep looking.  */

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra/debug_reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra/debug_reporter.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra/debug_reporter.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra/debug_reporter.c Wed May 16 20:32:43 2012
@@ -95,7 +95,7 @@ finish_report(void *report_baton,
               apr_pool_t *pool)
 {
   struct report_baton *rb = report_baton;
-  SVN_ERR(svn_stream_printf(rb->out, pool, "finish_report()\n"));
+  SVN_ERR(svn_stream_puts(rb->out, "finish_report()\n"));
   SVN_ERR(rb->wrapped_reporter->finish_report(rb->wrapped_report_baton, pool));
   return SVN_NO_ERROR;
 }
@@ -105,7 +105,7 @@ abort_report(void *report_baton,
              apr_pool_t *pool)
 {
   struct report_baton *rb = report_baton;
-  SVN_ERR(svn_stream_printf(rb->out, pool, "abort_report()\n"));
+  SVN_ERR(svn_stream_puts(rb->out, "abort_report()\n"));
   SVN_ERR(rb->wrapped_reporter->abort_report(rb->wrapped_report_baton, pool));
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.c Wed May 16 20:32:43 2012
@@ -706,6 +706,39 @@ commit_callback_wrapper(const svn_commit
   return ccwb->original_callback(ci, ccwb->original_baton, pool);
 }
 
+
+/* Some RA layers do not correctly fill in REPOS_ROOT in commit_info, or
+   they are third-party layers conforming to an older commit_info structure.
+   Interpose a utility function to ensure the field is valid.  */
+static void
+remap_commit_callback(svn_commit_callback2_t *callback,
+                      void **callback_baton,
+                      svn_ra_session_t *session,
+                      svn_commit_callback2_t original_callback,
+                      void *original_baton,
+                      apr_pool_t *result_pool)
+{
+  if (original_callback == NULL)
+    {
+      *callback = NULL;
+      *callback_baton = NULL;
+    }
+  else
+    {
+      /* Allocate this in RESULT_POOL, since the callback will be called
+         long after this function has returned. */
+      struct ccw_baton *ccwb = apr_palloc(result_pool, sizeof(*ccwb));
+
+      ccwb->session = session;
+      ccwb->original_callback = original_callback;
+      ccwb->original_baton = original_baton;
+
+      *callback = commit_callback_wrapper;
+      *callback_baton = ccwb;
+    }
+}
+
+
 svn_error_t *svn_ra_get_commit_editor3(svn_ra_session_t *session,
                                        const svn_delta_editor_t **editor,
                                        void **edit_baton,
@@ -716,20 +749,13 @@ svn_error_t *svn_ra_get_commit_editor3(s
                                        svn_boolean_t keep_locks,
                                        apr_pool_t *pool)
 {
-  /* Allocate this in a pool, since the callback will be called long after
-     this function as returned. */
-  struct ccw_baton *ccwb = apr_palloc(pool, sizeof(*ccwb));
-
-  ccwb->original_callback = callback;
-  ccwb->original_baton = callback_baton;
-  ccwb->session = session;
+  remap_commit_callback(&callback, &callback_baton,
+                        session, callback, callback_baton,
+                        pool);
 
   return session->vtable->get_commit_editor(session, editor, edit_baton,
                                             revprop_table,
-                                            callback
-                                                ? commit_callback_wrapper
-                                                : NULL,
-                                            callback ? ccwb : NULL,
+                                            callback, callback_baton,
                                             lock_tokens, keep_locks, pool);
 }
 
@@ -876,6 +902,8 @@ svn_error_t *svn_ra_do_diff3(svn_ra_sess
                              void *diff_baton,
                              apr_pool_t *pool)
 {
+  SVN_ERR_ASSERT(svn_path_is_empty(diff_target)
+                 || svn_path_is_single_path_component(diff_target));
   return session->vtable->do_diff(session,
                                   reporter, report_baton,
                                   revision, diff_target,
@@ -1241,6 +1269,67 @@ svn_ra_get_deleted_rev(svn_ra_session_t 
   return err;
 }
 
+
+svn_error_t *
+svn_ra__get_commit_ev2(svn_editor_t **editor,
+                       svn_ra_session_t *session,
+                       apr_hash_t *revprop_table,
+                       svn_commit_callback2_t callback,
+                       void *callback_baton,
+                       apr_hash_t *lock_tokens,
+                       svn_boolean_t keep_locks,
+                       svn_ra__provide_base_cb_t provide_base_cb,
+                       svn_ra__provide_props_cb_t provide_props_cb,
+                       svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+                       void *cb_baton,
+                       svn_cancel_func_t cancel_func,
+                       void *cancel_baton,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  if (session->vtable->get_commit_ev2 == NULL)
+    {
+      /* The specific RA layer does not have an implementation. Use our
+         default shim over the normal commit editor.  */
+
+      /* Remap for RA layers exposing Ev1.  */
+      remap_commit_callback(&callback, &callback_baton,
+                            session, callback, callback_baton,
+                            result_pool);
+
+      return svn_error_trace(svn_ra__use_commit_shim(
+                               editor,
+                               session,
+                               revprop_table,
+                               callback, callback_baton,
+                               lock_tokens,
+                               keep_locks,
+                               provide_base_cb,
+                               provide_props_cb,
+                               get_copysrc_kind_cb,
+                               cb_baton,
+                               cancel_func, cancel_baton,
+                               result_pool, scratch_pool));
+    }
+
+  /* Note: no need to remap the callback for Ev2. RA layers providing this
+     vtable entry should completely fill in commit_info.  */
+
+  return svn_error_trace(session->vtable->get_commit_ev2(
+                           editor,
+                           session,
+                           revprop_table,
+                           callback, callback_baton,
+                           lock_tokens,
+                           keep_locks,
+                           provide_base_cb,
+                           provide_props_cb,
+                           get_copysrc_kind_cb,
+                           cb_baton,
+                           cancel_func, cancel_baton,
+                           result_pool, scratch_pool));
+}
+
 
 
 svn_error_t *

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.h?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra/ra_loader.h Wed May 16 20:32:43 2012
@@ -32,6 +32,8 @@
 
 #include "svn_ra.h"
 
+#include "private/svn_ra_private.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -293,9 +295,29 @@ typedef struct svn_ra__vtable_t {
                                   svn_revnum_t end_revision,
                                   svn_revnum_t *revision_deleted,
                                   apr_pool_t *pool);
+
+  /* See svn_ra__register_editor_shim_callbacks() */
   svn_error_t *(*register_editor_shim_callbacks)(svn_ra_session_t *session,
                                     svn_delta_shim_callbacks_t *callbacks);
 
+  /* See svn_ra__get_commit_ev2()  */
+  svn_error_t *(*get_commit_ev2)(
+    svn_editor_t **editor,
+    svn_ra_session_t *session,
+    apr_hash_t *revprop_table,
+    svn_commit_callback2_t callback,
+    void *callback_baton,
+    apr_hash_t *lock_tokens,
+    svn_boolean_t keep_locks,
+    svn_ra__provide_base_cb_t provide_base_cb,
+    svn_ra__provide_props_cb_t provide_props_cb,
+    svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+    void *cb_baton,
+    svn_cancel_func_t cancel_func,
+    void *cancel_baton,
+    apr_pool_t *result_pool,
+    apr_pool_t *scratch_pool);
+
 } svn_ra__vtable_t;
 
 /* The RA session object. */
@@ -453,6 +475,29 @@ svn_ra__get_deleted_rev_from_log(svn_ra_
                                  svn_revnum_t *revision_deleted,
                                  apr_pool_t *pool);
 
+
+/* Utility function to provide a shim between a returned Ev2 and an RA
+   provider's Ev1-based commit editor.
+
+   See svn_ra__get_commit_ev2() for parameter semantics.  */
+svn_error_t *
+svn_ra__use_commit_shim(svn_editor_t **editor,
+                        svn_ra_session_t *session,
+                        apr_hash_t *revprop_table,
+                        svn_commit_callback2_t callback,
+                        void *callback_baton,
+                        apr_hash_t *lock_tokens,
+                        svn_boolean_t keep_locks,
+                        svn_ra__provide_base_cb_t provide_base_cb,
+                        svn_ra__provide_props_cb_t provide_props_cb,
+                        svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+                        void *cb_baton,
+                        svn_cancel_func_t cancel_func,
+                        void *cancel_baton,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool);
+
+
 #ifdef __cplusplus
 }
 #endif

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_local/ra_plugin.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_local/ra_plugin.c Wed May 16 20:32:43 2012
@@ -76,8 +76,6 @@ get_username(svn_ra_session_t *session,
              apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  svn_auth_iterstate_t *iterstate;
-  svn_fs_access_t *access_ctx;
 
   /* If we've already found the username don't ask for it again. */
   if (! sess->username)
@@ -88,6 +86,8 @@ get_username(svn_ra_session_t *session,
         {
           void *creds;
           svn_auth_cred_username_t *username_creds;
+          svn_auth_iterstate_t *iterstate;
+
           SVN_ERR(svn_auth_first_credentials(&creds, &iterstate,
                                              SVN_AUTH_CRED_USERNAME,
                                              sess->uuid, /* realmstring */
@@ -118,6 +118,8 @@ get_username(svn_ra_session_t *session,
   */
   if (*sess->username)
     {
+      svn_fs_access_t *access_ctx;
+
       SVN_ERR(svn_fs_create_access(&access_ctx, sess->username,
                                    session->pool));
       SVN_ERR(svn_fs_set_access(sess->fs, access_ctx));
@@ -367,11 +369,12 @@ struct deltify_etc_baton
 {
   svn_fs_t *fs;                     /* the fs to deltify in */
   svn_repos_t *repos;               /* repos for unlocking */
-  const char *fs_path;              /* fs-path part of split session URL */
+  const char *fspath_base;          /* fs-path part of split session URL */
+
   apr_hash_t *lock_tokens;          /* tokens to unlock, if any */
-  apr_pool_t *pool;                 /* pool for scratch work */
-  svn_commit_callback2_t callback;  /* the original callback */
-  void *callback_baton;             /* the original callback's baton */
+
+  svn_commit_callback2_t commit_cb; /* the original callback */
+  void *commit_baton;               /* the original callback's baton */
 };
 
 /* This implements 'svn_commit_callback_t'.  Its invokes the original
@@ -380,60 +383,107 @@ struct deltify_etc_baton
    BATON is 'struct deltify_etc_baton *'. */
 static svn_error_t *
 deltify_etc(const svn_commit_info_t *commit_info,
-            void *baton, apr_pool_t *pool)
+            void *baton,
+            apr_pool_t *scratch_pool)
 {
-  struct deltify_etc_baton *db = baton;
+  struct deltify_etc_baton *deb = baton;
   svn_error_t *err1 = SVN_NO_ERROR;
   svn_error_t *err2;
-  apr_hash_index_t *hi;
-  apr_pool_t *iterpool;
 
   /* Invoke the original callback first, in case someone's waiting to
      know the revision number so they can go off and annotate an
      issue or something. */
-  if (db->callback)
-    err1 = db->callback(commit_info, db->callback_baton, pool);
+  if (deb->commit_cb)
+    err1 = deb->commit_cb(commit_info, deb->commit_baton, scratch_pool);
 
   /* Maybe unlock the paths. */
-  if (db->lock_tokens)
+  if (deb->lock_tokens)
     {
-      iterpool = svn_pool_create(db->pool);
-      for (hi = apr_hash_first(db->pool, db->lock_tokens); hi;
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      apr_hash_index_t *hi;
+
+      for (hi = apr_hash_first(scratch_pool, deb->lock_tokens); hi;
            hi = apr_hash_next(hi))
         {
-          const void *rel_path;
-          void *val;
-          const char *abs_path, *token;
+          const void *relpath = svn__apr_hash_index_key(hi);
+          const char *token = svn__apr_hash_index_val(hi);
+          const char *fspath;
 
           svn_pool_clear(iterpool);
-          apr_hash_this(hi, &rel_path, NULL, &val);
-          token = val;
-          abs_path = svn_fspath__join(db->fs_path, rel_path, iterpool);
+
+          fspath = svn_fspath__join(deb->fspath_base, relpath, iterpool);
+
           /* We may get errors here if the lock was broken or stolen
              after the commit succeeded.  This is fine and should be
              ignored. */
-          svn_error_clear(svn_repos_fs_unlock(db->repos, abs_path, token,
+          svn_error_clear(svn_repos_fs_unlock(deb->repos, fspath, token,
                                               FALSE, iterpool));
         }
+
       svn_pool_destroy(iterpool);
     }
 
   /* But, deltification shouldn't be stopped just because someone's
      random callback failed, so proceed unconditionally on to
      deltification. */
-  err2 = svn_fs_deltify_revision(db->fs, commit_info->revision, db->pool);
+  err2 = svn_fs_deltify_revision(deb->fs, commit_info->revision, scratch_pool);
+
+  return svn_error_compose_create(err1, err2);
+}
+
 
-  /* It's more interesting if the original callback failed, so let
-     that one dominate. */
-  if (err1)
+/* If LOCK_TOKENS is not NULL, then copy all tokens into the access context
+   of FS. The tokens' paths will be prepended with FSPATH_BASE.
+
+   ACCESS_POOL must match (or exceed) the lifetime of the access context
+   that was associated with FS. Typically, this is the session pool.
+
+   Temporary allocations are made in SCRATCH_POOL.  */
+static svn_error_t *
+apply_lock_tokens(svn_fs_t *fs,
+                  const char *fspath_base,
+                  apr_hash_t *lock_tokens,
+                  apr_pool_t *access_pool,
+                  apr_pool_t *scratch_pool)
+{
+  if (lock_tokens)
     {
-      svn_error_clear(err2);
-      return err1;
+      svn_fs_access_t *access_ctx;
+
+      SVN_ERR(svn_fs_get_access(&access_ctx, fs));
+
+      /* If there is no access context, the filesystem will scream if a
+         lock is needed.  */
+      if (access_ctx)
+        {
+          apr_hash_index_t *hi;
+
+          /* Note: we have no use for an iterpool here since the data
+             within the loop is copied into ACCESS_POOL.  */
+
+          for (hi = apr_hash_first(scratch_pool, lock_tokens); hi;
+               hi = apr_hash_next(hi))
+            {
+              const void *relpath = svn__apr_hash_index_key(hi);
+              const char *token = svn__apr_hash_index_val(hi);
+              const char *fspath;
+
+              /* The path needs to live as long as ACCESS_CTX.  */
+              fspath = svn_fspath__join(fspath_base, relpath, access_pool);
+
+              /* The token must live as long as ACCESS_CTX.  */
+              token = apr_pstrdup(access_pool, token);
+
+              SVN_ERR(svn_fs_access_add_lock_token2(access_ctx, fspath,
+                                                    token));
+            }
+        }
     }
 
-  return err2;
+  return SVN_NO_ERROR;
 }
 
+
 /*----------------------------------------------------------------*/
 
 /*** The RA vtable routines ***/
@@ -679,47 +729,24 @@ svn_ra_local__get_commit_editor(svn_ra_s
                                 apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  struct deltify_etc_baton *db = apr_palloc(pool, sizeof(*db));
-  apr_hash_index_t *hi;
-  svn_fs_access_t *fs_access;
+  struct deltify_etc_baton *deb = apr_palloc(pool, sizeof(*deb));
 
-  db->fs = sess->fs;
-  db->repos = sess->repos;
-  db->fs_path = sess->fs_path->data;
+  /* Prepare the baton for deltify_etc()  */
+  deb->fs = sess->fs;
+  deb->repos = sess->repos;
+  deb->fspath_base = sess->fs_path->data;
   if (! keep_locks)
-    db->lock_tokens = lock_tokens;
+    deb->lock_tokens = lock_tokens;
   else
-    db->lock_tokens = NULL;
-  db->pool = pool;
-  db->callback = callback;
-  db->callback_baton = callback_baton;
+    deb->lock_tokens = NULL;
+  deb->commit_cb = callback;
+  deb->commit_baton = callback_baton;
 
   SVN_ERR(get_username(session, pool));
 
   /* If there are lock tokens to add, do so. */
-  if (lock_tokens)
-    {
-      SVN_ERR(svn_fs_get_access(&fs_access, sess->fs));
-
-      /* If there is no access context, the filesystem will scream if a
-         lock is needed. */
-      if (fs_access)
-        {
-          for (hi = apr_hash_first(pool, lock_tokens); hi;
-               hi = apr_hash_next(hi))
-            {
-              void *val;
-              const char *abs_path, *token;
-              const void *key;
-
-              apr_hash_this(hi, &key, NULL, &val);
-              abs_path = svn_fspath__join(sess->fs_path->data, key, pool);
-              token = val;
-              SVN_ERR(svn_fs_access_add_lock_token2(fs_access,
-                                                    abs_path, token));
-            }
-        }
-    }
+  SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
+                            session->pool, pool));
 
   /* Copy the revprops table so we can add the username. */
   revprop_table = apr_hash_copy(pool, revprop_table);
@@ -730,7 +757,7 @@ svn_ra_local__get_commit_editor(svn_ra_s
   return svn_repos_get_commit_editor5
          (editor, edit_baton, sess->repos, NULL,
           svn_path_uri_decode(sess->repos_url, pool), sess->fs_path->data,
-          revprop_table, deltify_etc, db, NULL, NULL, pool);
+          revprop_table, deltify_etc, deb, NULL, NULL, pool);
 }
 
 
@@ -1514,6 +1541,62 @@ svn_ra_local__register_editor_shim_callb
   return SVN_NO_ERROR;
 }
 
+
+static svn_error_t *
+svn_ra_local__get_commit_ev2(svn_editor_t **editor,
+                             svn_ra_session_t *session,
+                             apr_hash_t *revprops,
+                             svn_commit_callback2_t commit_cb,
+                             void *commit_baton,
+                             apr_hash_t *lock_tokens,
+                             svn_boolean_t keep_locks,
+                             svn_ra__provide_base_cb_t provide_base_cb,
+                             svn_ra__provide_props_cb_t provide_props_cb,
+                             svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+                             void *cb_baton,
+                             svn_cancel_func_t cancel_func,
+                             void *cancel_baton,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  svn_ra_local__session_baton_t *sess = session->priv;
+  struct deltify_etc_baton *deb = apr_palloc(result_pool, sizeof(*deb));
+
+  /* NOTE: the RA callbacks are ignored. We pass everything directly to
+     the REPOS editor.  */
+
+  /* Prepare the baton for deltify_etc()  */
+  deb->fs = sess->fs;
+  deb->repos = sess->repos;
+  deb->fspath_base = sess->fs_path->data;
+  if (! keep_locks)
+    deb->lock_tokens = lock_tokens;
+  else
+    deb->lock_tokens = NULL;
+  deb->commit_cb = commit_cb;
+  deb->commit_baton = commit_baton;
+
+  /* Ensure there is a username (and an FS access context) associated with
+     the session and its FS handle.  */
+  SVN_ERR(get_username(session, scratch_pool));
+
+  /* If there are lock tokens to add, do so.  */
+  SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
+                            session->pool, scratch_pool));
+
+  /* Copy the REVPROPS and insert the author/username.  */
+  revprops = apr_hash_copy(scratch_pool, revprops);
+  apr_hash_set(revprops, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING,
+               svn_string_create(sess->username, scratch_pool));
+
+  return svn_error_trace(svn_repos__get_commit_ev2(
+                           editor, sess->repos, NULL /* authz */,
+                           NULL /* authz_repos_name */, NULL /* authz_user */,
+                           revprops,
+                           deltify_etc, deb, cancel_func, cancel_baton,
+                           result_pool, scratch_pool));
+}
+
 /*----------------------------------------------------------------*/
 
 static const svn_version_t *
@@ -1561,7 +1644,8 @@ static const svn_ra__vtable_t ra_local_v
   svn_ra_local__has_capability,
   svn_ra_local__replay_range,
   svn_ra_local__get_deleted_rev,
-  svn_ra_local__register_editor_shim_callbacks
+  svn_ra_local__register_editor_shim_callbacks,
+  svn_ra_local__get_commit_ev2
 };
 
 

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/commit.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/commit.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/commit.c Wed May 16 20:32:43 2012
@@ -737,6 +737,7 @@ static svn_error_t * commit_open_root(vo
          transaction (and, optionally, a corresponding activity). */
       svn_ra_neon__request_t *req;
       const char *header_val;
+      svn_error_t *err;
 
       SVN_ERR(svn_ra_neon__request_create(&req, cc->ras, "POST",
                                           cc->ras->me_resource, dir_pool));
@@ -749,33 +750,39 @@ static svn_error_t * commit_open_root(vo
                             svn_uuid_generate(dir_pool));
 #endif
 
-      SVN_ERR(svn_ra_neon__request_dispatch(NULL, req, NULL, "( create-txn )",
-                                            201, 0, dir_pool));
-
-      /* Check the response headers for either the virtual transaction
-         details, or the real transaction details.  We need to have
-         one or the other of those!  */
-      if ((header_val = ne_get_response_header(req->ne_req,
-                                               SVN_DAV_VTXN_NAME_HEADER)))
-        {
-          cc->txn_url = svn_path_url_add_component2(cc->ras->vtxn_stub,
-                                                    header_val, cc->pool);
-          cc->txn_root_url
-            = svn_path_url_add_component2(cc->ras->vtxn_root_stub,
-                                          header_val, cc->pool);
-        }
-      else if ((header_val = ne_get_response_header(req->ne_req,
-                                                    SVN_DAV_TXN_NAME_HEADER)))
-        {
-          cc->txn_url = svn_path_url_add_component2(cc->ras->txn_stub,
-                                                    header_val, cc->pool);
-          cc->txn_root_url = svn_path_url_add_component2(cc->ras->txn_root_stub,
-                                                         header_val, cc->pool);
+      err = svn_ra_neon__request_dispatch(NULL, req, NULL, "( create-txn )",
+                                          201, 0, dir_pool);
+      if (!err)
+        {
+          /* Check the response headers for either the virtual transaction
+             details, or the real transaction details.  We need to have
+             one or the other of those!  */
+          if ((header_val = ne_get_response_header(req->ne_req,
+                                                   SVN_DAV_VTXN_NAME_HEADER)))
+            {
+              cc->txn_url = svn_path_url_add_component2(cc->ras->vtxn_stub,
+                                                        header_val, cc->pool);
+              cc->txn_root_url
+                = svn_path_url_add_component2(cc->ras->vtxn_root_stub,
+                                              header_val, cc->pool);
+            }
+          else if ((header_val
+                    = ne_get_response_header(req->ne_req,
+                                             SVN_DAV_TXN_NAME_HEADER)))
+            {
+              cc->txn_url = svn_path_url_add_component2(cc->ras->txn_stub,
+                                                        header_val, cc->pool);
+              cc->txn_root_url
+                = svn_path_url_add_component2(cc->ras->txn_root_stub,
+                                              header_val, cc->pool);
+            }
+          else
+            err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                    _("POST request did not return transaction "
+                                      "information"));
         }
-      else
-        return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                                 _("POST request did not return transaction "
-                                   "information"));
+      svn_ra_neon__request_destroy(req);
+      SVN_ERR(err);
 
       root->rsrc = NULL;
       root->txn_root_url = svn_path_url_add_component2(cc->txn_root_url,
@@ -1570,6 +1577,7 @@ svn_error_t * svn_ra_neon__get_commit_ed
   svn_delta_editor_t *commit_editor;
   commit_ctx_t *cc;
   apr_hash_index_t *hi;
+  const char *repos_root;
 
   /* Build the main commit editor's baton. */
   cc = apr_pcalloc(pool, sizeof(*cc));
@@ -1619,7 +1627,10 @@ svn_error_t * svn_ra_neon__get_commit_ed
   *editor = commit_editor;
   *edit_baton = cc;
 
+  SVN_ERR(svn_ra_neon__get_repos_root(session, &repos_root, pool));
+
   SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+                                   repos_root, cc->anchor_relpath,
                                    ras->shim_callbacks, pool, pool));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/fetch.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/fetch.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/fetch.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/fetch.c Wed May 16 20:32:43 2012
@@ -912,8 +912,19 @@ svn_error_t *svn_ra_neon__get_dir(svn_ra
                                      final_url, SVN_RA_NEON__DEPTH_ONE,
                                      NULL, which_props, pool));
 
-      /* Count the number of path components in final_url. */
-      final_url_n_components = svn_path_component_count(final_url);
+      /* In the loop below we will want to skip the effective '.' entry that
+         comes back from SVN_RA_NEON__DEPTH_ONE. To perform this skip we use
+         the component count of the FINAL_URL and compare it to the component
+         count of the keys in RESOURCES.  But this only works if REVISION
+         was a valid revnum and FINAL_URL is a baseline collection (i.e. no
+         scheme://host prefix).  If REVISION was SVN_INVALID_REVNUM then
+         FINAL_URL is a fully qualified URL, so we need to ignore the scheme
+         and host portions. */
+      if (SVN_IS_VALID_REVNUM(revision))
+        final_url_n_components = svn_path_component_count(final_url);
+      else
+        final_url_n_components = svn_path_component_count(
+          svn_path_url_add_component2(ras->root.path, path, pool));
 
       /* Now we have a hash that maps a bunch of url children to resource
          objects.  Each resource object contains the properties of the
@@ -1818,6 +1829,10 @@ start_element(int *elem, void *userdata,
                                    " element"));
       svn_stringbuf_set(rb->namestr, name);
 
+      att = svn_xml_get_attr_value("rev", atts);
+      if (att) /* Not available on older repositories! */
+        crev = SVN_STR_TO_REV(att);
+
       parent_dir = &TOP_DIR(rb);
 
       /* Pool use is a little non-standard here.  When lots of items in the
@@ -1832,8 +1847,8 @@ start_element(int *elem, void *userdata,
       svn_path_add_component(pathbuf, rb->namestr->data);
 
       SVN_ERR((*rb->editor->delete_entry)(pathbuf->data,
-                                          SVN_INVALID_REVNUM,
-                                          TOP_DIR(rb).baton,
+                                          crev,
+                                          parent_dir->baton,
                                           subpool));
       svn_pool_destroy(subpool);
       break;

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/ra_neon.h
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/ra_neon.h?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/ra_neon.h (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/ra_neon.h Wed May 16 20:32:43 2012
@@ -1188,6 +1188,10 @@ svn_error_t *
 svn_ra_neon__register_editor_shim_callbacks(svn_ra_session_t *session,
                                     svn_delta_shim_callbacks_t *callbacks);
 
+svn_error_t *svn_ra_neon__get_repos_root(svn_ra_session_t *session,
+                                         const char **url,
+                                         apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/session.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/session.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/session.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/session.c Wed May 16 20:32:43 2012
@@ -1109,9 +1109,9 @@ static svn_error_t *svn_ra_neon__get_ses
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *svn_ra_neon__get_repos_root(svn_ra_session_t *session,
-                                                const char **url,
-                                                apr_pool_t *pool)
+svn_error_t *svn_ra_neon__get_repos_root(svn_ra_session_t *session,
+                                         const char **url,
+                                         apr_pool_t *pool)
 {
   svn_ra_neon__session_t *ras = session->priv;
 

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/util.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/util.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_neon/util.c Wed May 16 20:32:43 2012
@@ -245,7 +245,15 @@ end_207_element(void *baton, int state,
 
     case ELEM_responsedescription:
       if (b->in_propstat)
-        svn_stringbuf_set(b->propstat_description, b->cdata->data);
+        {
+          const char *data = b->cdata->data;
+
+          /* Remove leading newline added by DEBUG_CR on server */
+          if (*data == '\n')
+              ++data;
+
+            svn_stringbuf_set(b->propstat_description, data);
+        }
       else
         {
           if (! svn_stringbuf_isempty(b->description))

Modified: subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/blame.c?rev=1339349&r1=1339348&r2=1339349&view=diff
==============================================================================
--- subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/fix-rdump-editor/subversion/libsvn_ra_serf/blame.c Wed May 16 20:32:43 2012
@@ -22,9 +22,6 @@
  */
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -39,6 +36,8 @@
 
 #include "svn_private_config.h"
 
+#include "private/svn_string_private.h"
+
 #include "ra_serf.h"
 #include "../libsvn_ra/ra_loader.h"
 
@@ -48,6 +47,7 @@
  */
 typedef enum blame_state_e {
   NONE = 0,
+  INITIAL = 0,
   FILE_REVS_REPORT,
   FILE_REV,
   REV_PROP,
@@ -85,10 +85,7 @@ typedef struct blame_info_t {
 
   /* The currently collected value as we build it up */
   const char *prop_name;
-  const char *prop_attr;
-  apr_size_t prop_attr_len;
-
-  svn_string_t *prop_string;
+  svn_stringbuf_t *prop_value;
 
   /* Merged revision flag */
   svn_boolean_t merged_revision;
@@ -113,6 +110,42 @@ typedef struct blame_context_t {
   void *file_rev_baton;
 } blame_context_t;
 
+
+#if 0
+/* ### we cannot use this yet since the CDATA is unbounded and cannot be
+   ### collected by the parsing context. we need a streamy mechanism for
+   ### this report.  */
+
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t blame_ttable[] = {
+  { INITIAL, S_, "file-revs-report", FILE_REVS_REPORT,
+    FALSE, { NULL }, FALSE, FALSE },
+
+  { FILE_REVS_REPORT, S_, "file-rev", FILE_REV,
+    FALSE, { "path", "rev", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "rev-prop", REV_PROP,
+    TRUE, { "name", "?encoding", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "set-prop", SET_PROP,
+    TRUE, { "name", "?encoding", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "remove-prop", REMOVE_PROP,
+    FALSE, { "name", "?encoding", NULL }, FALSE, TRUE },
+
+  { FILE_REV, D_, "merged-revision", MERGED_REVISION,
+    FALSE, { NULL }, FALSE, FALSE },
+
+  { FILE_REV, D_, "txdelta", TXDELTA,
+    TRUE, { NULL }, FALSE, TRUE },
+
+  { 0 }
+};
+
+#endif
+
+
 
 static blame_info_t *
 push_state(svn_ra_serf__xml_parser_t *parser,
@@ -125,18 +158,16 @@ push_state(svn_ra_serf__xml_parser_t *pa
     {
       blame_info_t *info;
 
-      info = apr_palloc(parser->state->pool, sizeof(*info));
+      info = apr_pcalloc(parser->state->pool, sizeof(*info));
 
       info->pool = parser->state->pool;
 
       info->rev = SVN_INVALID_REVNUM;
-      info->path = NULL;
 
       info->rev_props = apr_hash_make(info->pool);
       info->prop_diffs = apr_array_make(info->pool, 0, sizeof(svn_prop_t));
 
-      info->stream = NULL;
-      info->merged_revision = FALSE;
+      info->prop_value = svn_stringbuf_create_empty(info->pool);
 
       parser->state->private = info;
     }
@@ -144,36 +175,31 @@ push_state(svn_ra_serf__xml_parser_t *pa
   return parser->state->private;
 }
 
+
 static const svn_string_t *
 create_propval(blame_info_t *info)
 {
-  const svn_string_t *s;
-
-  if (!info->prop_attr)
-    {
-      return svn_string_create_empty(info->pool);
-    }
-  else
-    {
-      info->prop_attr = apr_pmemdup(info->pool, info->prop_attr,
-                                    info->prop_attr_len + 1);
-    }
-
-  s = svn_string_ncreate(info->prop_attr, info->prop_attr_len, info->pool);
   if (info->prop_base64)
     {
-      s = svn_base64_decode_string(s, info->pool);
+      const svn_string_t *morph;
+
+      morph = svn_stringbuf__morph_into_string(info->prop_value);
+#ifdef SVN_DEBUG
+      info->prop_value = NULL;  /* morph killed the stringbuf.  */
+#endif
+      return svn_base64_decode_string(morph, info->pool);
     }
-  return s;
+
+  return svn_string_create_from_buf(info->prop_value, info->pool);
 }
 
 static svn_error_t *
 start_blame(svn_ra_serf__xml_parser_t *parser,
-            void *userData,
             svn_ra_serf__dav_props_t name,
-            const char **attrs)
+            const char **attrs,
+            apr_pool_t *scratch_pool)
 {
-  blame_context_t *blame_ctx = userData;
+  blame_context_t *blame_ctx = parser->user_data;
   blame_state_e state;
 
   state = parser->state->current_state;
@@ -240,8 +266,7 @@ start_blame(svn_ra_serf__xml_parser_t *p
         case REMOVE_PROP:
           info->prop_name = apr_pstrdup(info->pool,
                                         svn_xml_get_attr_value("name", attrs));
-          info->prop_attr = NULL;
-          info->prop_attr_len = 0;
+          svn_stringbuf_setempty(info->prop_value);
 
           enc = svn_xml_get_attr_value("encoding", attrs);
           if (enc && strcmp(enc, "base64") == 0)
@@ -266,10 +291,10 @@ start_blame(svn_ra_serf__xml_parser_t *p
 
 static svn_error_t *
 end_blame(svn_ra_serf__xml_parser_t *parser,
-          void *userData,
-          svn_ra_serf__dav_props_t name)
+          svn_ra_serf__dav_props_t name,
+          apr_pool_t *scratch_pool)
 {
-  blame_context_t *blame_ctx = userData;
+  blame_context_t *blame_ctx = parser->user_data;
   blame_state_e state;
   blame_info_t *info;
 
@@ -338,11 +363,11 @@ end_blame(svn_ra_serf__xml_parser_t *par
 
 static svn_error_t *
 cdata_blame(svn_ra_serf__xml_parser_t *parser,
-            void *userData,
             const char *data,
-            apr_size_t len)
+            apr_size_t len,
+            apr_pool_t *scratch_pool)
 {
-  blame_context_t *blame_ctx = userData;
+  blame_context_t *blame_ctx = parser->user_data;
   blame_state_e state;
   blame_info_t *info;
 
@@ -360,8 +385,7 @@ cdata_blame(svn_ra_serf__xml_parser_t *p
     {
       case REV_PROP:
       case SET_PROP:
-        svn_ra_serf__expand_string(&info->prop_attr, &info->prop_attr_len,
-                                   data, len, parser->state->pool);
+        svn_stringbuf_appendbytes(info->prop_value, data, len);
         break;
       case TXDELTA:
         if (info->stream)
@@ -437,8 +461,7 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
-  const char *relative_url, *basecoll_url, *req_url;
-  int status_code;
+  const char *req_url;
   svn_error_t *err;
 
   blame_ctx = apr_pcalloc(pool, sizeof(*blame_ctx));
@@ -451,13 +474,14 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   blame_ctx->include_merged_revisions = include_merged_revisions;
   blame_ctx->done = FALSE;
 
-  SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
-                                         NULL, session->session_url.path,
-                                         end, NULL, pool));
-  req_url = svn_path_url_add_component2(basecoll_url, relative_url, pool);
+  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                      session, NULL /* conn */,
+                                      NULL /* url */, end,
+                                      pool, pool));
 
   handler = apr_pcalloc(pool, sizeof(*handler));
 
+  handler->handler_pool = pool;
   handler->method = "REPORT";
   handler->path = req_url;
   handler->body_type = "text/xml";
@@ -474,7 +498,6 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   parser_ctx->end = end_blame;
   parser_ctx->cdata = cdata_blame;
   parser_ctx->done = &blame_ctx->done;
-  parser_ctx->status_code = &status_code;
 
   handler->response_handler = svn_ra_serf__handle_xml_parser;
   handler->response_baton = parser_ctx;
@@ -484,9 +507,9 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   err = svn_ra_serf__context_run_wait(&blame_ctx->done, session, pool);
 
   err = svn_error_compose_create(
-            svn_ra_serf__error_on_status(status_code,
+            svn_ra_serf__error_on_status(handler->sline.code,
                                          handler->path,
-                                         parser_ctx->location),
+                                         handler->location),
             err);
 
   return svn_error_trace(err);