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 2011/12/19 19:49:43 UTC

svn commit: r1220893 [7/19] - in /subversion/branches/fs-py: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/ subversion/bindings/javahl/native/ su...

Modified: subversion/branches/fs-py/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_client/relocate.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_client/relocate.c Mon Dec 19 18:49:34 2011
@@ -143,13 +143,9 @@ relocate_externals(const char *local_abs
                    svn_client_ctx_t *ctx,
                    apr_pool_t *scratch_pool)
 {
-  const char *url;
   apr_pool_t *iterpool;
   int i;
 
-  SVN_ERR(svn_client_url_from_path2(&url, local_abspath, ctx,
-                                    scratch_pool, scratch_pool));
-
   /* Parse an externals definition into an array of external items. */
 
   iterpool = svn_pool_create(scratch_pool);
@@ -185,8 +181,8 @@ relocate_externals(const char *local_abs
                                                       ext_item->target_dir,
                                                       iterpool),
                                       iterpool));
-      err = svn_client_root_url_from_path(&target_repos_root_url,
-                                          target_abspath, ctx, iterpool);
+      err = svn_client_get_repos_root(&target_repos_root_url, NULL /* uuid */,
+                                      target_abspath, ctx, iterpool, iterpool);
 
       /* Ignore externals that aren't present in the working copy.
        * This can happen if an external is deleted from disk accidentally,
@@ -248,16 +244,16 @@ svn_client_relocate2(const char *wcroot_
     }
 
   /* Fetch our current root URL. */
-  SVN_ERR(svn_client_root_url_from_path(&old_repos_root_url, local_abspath,
-                                        ctx, pool));
+  SVN_ERR(svn_client_get_repos_root(&old_repos_root_url, NULL /* uuid */,
+                                    local_abspath, ctx, pool, pool));
 
   /* Perform the relocation. */
   SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from_prefix, to_prefix,
                            validator_func, &vb, pool));
 
   /* Now fetch new current root URL. */
-  SVN_ERR(svn_client_root_url_from_path(&new_repos_root_url, local_abspath,
-                                        ctx, pool));
+  SVN_ERR(svn_client_get_repos_root(&new_repos_root_url, NULL /* uuid */,
+                                    local_abspath, ctx, pool, pool));
 
 
   /* Relocate externals, too (if any). */

Modified: subversion/branches/fs-py/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_client/repos_diff.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_client/repos_diff.c Mon Dec 19 18:49:34 2011
@@ -1348,6 +1348,8 @@ svn_client__get_diff_editor(const svn_de
   apr_pool_t *editor_pool = svn_pool_create(result_pool);
   svn_delta_editor_t *tree_editor = svn_delta_default_editor(editor_pool);
   struct edit_baton *eb = apr_pcalloc(editor_pool, sizeof(*eb));
+  svn_delta_shim_callbacks_t *shim_callbacks =
+                                svn_delta_shim_callbacks_default(editor_pool);
 
   eb->pool = editor_pool;
   eb->depth = depth;
@@ -1388,7 +1390,7 @@ svn_client__get_diff_editor(const svn_de
                                             eb->pool));
 
   SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
-                                   NULL, NULL, NULL, NULL,
+                                   shim_callbacks,
                                    result_pool, result_pool));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/fs-py/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_client/status.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_client/status.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_client/status.c Mon Dec 19 18:49:34 2011
@@ -430,7 +430,7 @@ svn_client_status5(svn_revnum_t *result_
                                                       pool));
             }
 
-          if (depth_as_sticky)
+          if (depth_as_sticky || !server_supports_depth)
             status_depth = depth;
           else
             status_depth = svn_depth_unknown; /* Use depth from WC */

Modified: subversion/branches/fs-py/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_client/switch.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_client/switch.c Mon Dec 19 18:49:34 2011
@@ -197,7 +197,7 @@ switch_internal(svn_revnum_t *result_rev
      ### okay? */
   if (! ignore_ancestry)
     {
-      const char *target_url, *yc_path;
+      const char *target_url, *yc_url;
       svn_revnum_t target_rev, yc_rev;
 
       SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, local_abspath,
@@ -206,11 +206,11 @@ switch_internal(svn_revnum_t *result_rev
                                         local_abspath, pool));
       /* ### It would be nice if this function could reuse the existing
              ra session instead of opening two for its own use. */
-      SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_path, &yc_rev,
+      SVN_ERR(svn_client__get_youngest_common_ancestor(NULL, &yc_url, &yc_rev,
                                                        switch_rev_url, revnum,
                                                        target_url, target_rev,
                                                        ctx, pool));
-      if (! (yc_path && SVN_IS_VALID_REVNUM(yc_rev)))
+      if (! (yc_url && SVN_IS_VALID_REVNUM(yc_rev)))
         return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
                                  _("'%s' shares no common ancestry with '%s'"),
                                  switch_url, local_abspath);

Modified: subversion/branches/fs-py/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_client/update.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_client/update.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_client/update.c Mon Dec 19 18:49:34 2011
@@ -389,7 +389,9 @@ update_internal(svn_revnum_t *result_rev
      invalid revnum, that means RA will use the latest revision.  */
   SVN_ERR(svn_ra_do_update2(ra_session, &reporter, &report_baton,
                             revnum, target,
-                            depth_is_sticky ? depth : svn_depth_unknown,
+                            (!server_supports_depth || depth_is_sticky
+                             ? depth
+                             : svn_depth_unknown),
                             FALSE, update_editor, update_edit_baton, pool));
 
   /* Drive the reporter structure, describing the revisions within

Modified: subversion/branches/fs-py/subversion/libsvn_client/url.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_client/url.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_client/url.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_client/url.c Mon Dec 19 18:49:34 2011
@@ -61,18 +61,3 @@ svn_client_url_from_path2(const char **u
 
   return SVN_NO_ERROR;
 }
-
-
-svn_error_t *
-svn_client_root_url_from_path(const char **url,
-                              const char *path_or_url,
-                              svn_client_ctx_t *ctx,
-                              apr_pool_t *pool)
-{
-  if (!svn_path_is_url(path_or_url))
-    SVN_ERR(svn_dirent_get_absolute(&path_or_url, path_or_url, pool));
-
-  return svn_error_trace(
-           svn_client__get_repos_root(url, NULL, path_or_url,
-                                      ctx, pool, pool));
-}

Modified: subversion/branches/fs-py/subversion/libsvn_client/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_client/util.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_client/util.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_client/util.c Mon Dec 19 18:49:34 2011
@@ -102,17 +102,15 @@ svn_client__path_relative_to_root(const 
 
       SVN_ERR_ASSERT(repos_relpath != NULL);
     }
-     /* Merge handling passes a root that is not the repos root */
   else if (repos_root != NULL)
     {
-      if (!svn_uri__is_ancestor(repos_root, abspath_or_url))
+      repos_relpath = svn_uri_skip_ancestor(repos_root, abspath_or_url,
+                                            result_pool);
+      if (!repos_relpath)
         return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
                                  _("URL '%s' is not a child of repository "
                                    "root URL '%s'"),
                                  abspath_or_url, repos_root);
-
-      repos_relpath = svn_uri_skip_ancestor(repos_root, abspath_or_url,
-                                            result_pool);
     }
   else
     {
@@ -144,12 +142,12 @@ svn_client__path_relative_to_root(const 
 }
 
 svn_error_t *
-svn_client__get_repos_root(const char **repos_root,
-                           const char **repos_uuid,
-                           const char *abspath_or_url,
-                           svn_client_ctx_t *ctx,
-                           apr_pool_t *result_pool,
-                           apr_pool_t *scratch_pool)
+svn_client_get_repos_root(const char **repos_root,
+                          const char **repos_uuid,
+                          const char *abspath_or_url,
+                          svn_client_ctx_t *ctx,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
   svn_ra_session_t *ra_session;
 

Modified: subversion/branches/fs-py/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_delta/compat.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_delta/compat.c Mon Dec 19 18:49:34 2011
@@ -27,6 +27,7 @@
 #include "svn_sorts.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
+#include "svn_hash.h"
 #include "svn_props.h"
 #include "svn_pools.h"
 
@@ -92,14 +93,39 @@ svn_compat_wrap_file_rev_handler(svn_fil
  * large amount of information in the dir batons, and then process it in the
  * close_directory() handler. */
 
+typedef svn_error_t *(*start_edit_func_t)(
+    void *baton,
+    svn_revnum_t base_revision,
+    apr_pool_t *result_pool,
+    void **root_baton);
+
+typedef svn_error_t *(*target_revision_func_t)(
+    void *baton,
+    svn_revnum_t target_revision,
+    apr_pool_t *scratch_pool);
+
 struct ev2_edit_baton
 {
   svn_editor_t *editor;
   apr_hash_t *paths;
-  svn_revnum_t target_revision;
   apr_pool_t *edit_pool;
+
+  svn_boolean_t *found_abs_paths; /* Did we strip an incoming '/' from the
+                                     paths?  */
+
+  void *root_baton;
+
+  start_edit_func_t start_edit;
+  void *start_edit_baton;
+
   svn_delta_fetch_props_func_t fetch_props_func;
   void *fetch_props_baton;
+
+  target_revision_func_t target_revision_func;
+  void *target_revision_baton;
+
+  svn_delta_fetch_base_func_t fetch_base_func;
+  void *fetch_base_baton;
 };
 
 struct ev2_dir_baton
@@ -112,18 +138,25 @@ struct ev2_file_baton
 {
   struct ev2_edit_baton *eb;
   const char *path;
+  const char *delta_base;
 };
 
-enum action
+enum action_code_t
 {
+  ACTION_MOVE,
+  ACTION_MKDIR,
+  ACTION_COPY,
+  ACTION_PROPSET,
+  ACTION_PUT,
   ACTION_ADD,
   ACTION_DELETE,
-  ACTION_SET_PROP
+  ACTION_ADD_ABSENT,
+  ACTION_SET_TEXT
 };
 
 struct path_action
 {
-  enum action action;
+  enum action_code_t action;
   void *args;
 };
 
@@ -133,10 +166,22 @@ struct prop_args
   const svn_string_t *value;
 };
 
+struct copy_args
+{
+  const char *copyfrom_path;
+  svn_revnum_t copyfrom_rev;
+};
+
+struct path_checksum_args
+{
+  const char *path;
+  svn_checksum_t *checksum;
+};
+
 static svn_error_t *
 add_action(struct ev2_edit_baton *eb,
            const char *path,
-           enum action action,
+           enum action_code_t action,
            void *args)
 {
   struct path_action *p_action;
@@ -168,8 +213,19 @@ process_actions(void *edit_baton,
 {
   struct ev2_edit_baton *eb = edit_baton;
   apr_hash_t *props = NULL;
+  svn_boolean_t need_add = FALSE;
+  apr_array_header_t *children;
+  svn_stream_t *contents = NULL;
+  svn_checksum_t *checksum = NULL;
+  svn_kind_t kind;
   int i;
 
+  if (*path == '/')
+    {
+      path++;
+      *eb->found_abs_paths = TRUE;
+    }
+
   /* Go through all of our actions, populating various datastructures
    * dependent on them. */
   for (i = 0; i < actions->nelts; i++)
@@ -179,7 +235,7 @@ process_actions(void *edit_baton,
 
       switch (action->action)
         {
-          case ACTION_SET_PROP:
+          case ACTION_PROPSET:
             {
               const struct prop_args *p_args = action->args;
 
@@ -212,7 +268,49 @@ process_actions(void *edit_baton,
 
           case ACTION_ADD:
             {
-              /* ### do something  */
+              kind = *((svn_kind_t *) action->args);
+              need_add = TRUE;
+
+              if (kind == svn_kind_dir)
+                {
+                  children = apr_array_make(scratch_pool, 1,
+                                            sizeof(const char *));
+                }
+              else
+                {
+                  /* The default is an empty file. */
+                  contents = svn_stream_empty(scratch_pool);
+                  checksum = svn_checksum_empty_checksum(svn_checksum_sha1,
+                                                         scratch_pool);
+                }
+              break;
+            }
+
+          case ACTION_SET_TEXT:
+            {
+              struct path_checksum_args *pca = action->args;
+
+              SVN_ERR(svn_stream_open_readonly(&contents, pca->path,
+                                               scratch_pool, scratch_pool));
+              checksum = pca->checksum;
+              break;
+            }
+
+          case ACTION_COPY:
+            {
+              struct copy_args *c_args = action->args;
+
+              SVN_ERR(svn_editor_copy(eb->editor, c_args->copyfrom_path,
+                                      c_args->copyfrom_rev, path,
+                                      SVN_INVALID_REVNUM));
+              break;
+            }
+
+          case ACTION_ADD_ABSENT:
+            {
+              kind = *((svn_kind_t *) action->args);
+              SVN_ERR(svn_editor_add_absent(eb->editor, path, kind,
+                                            SVN_INVALID_REVNUM));
               break;
             }
 
@@ -224,13 +322,67 @@ process_actions(void *edit_baton,
   /* We've now got a wholistic view of what has happened to this node,
    * so we can call our own editor APIs on it. */
 
-  if (props)
+  if (need_add)
     {
-      /* We fetched and modified the props in some way. Apply 'em now that
-         we have the new set.  */
-      SVN_ERR(svn_editor_set_props(eb->editor, path, eb->target_revision,
-                                   props, TRUE));
+      if (kind == svn_kind_dir)
+        {
+          SVN_ERR(svn_editor_add_directory(eb->editor, path, children,
+                                           props, SVN_INVALID_REVNUM));
+        }
+      else
+        {
+          SVN_ERR(svn_editor_add_file(eb->editor, path, checksum, contents,
+                                      props, SVN_INVALID_REVNUM));
+        }
+    }
+  else
+    {
+      if (props)
+        {
+          /* We fetched and modified the props in some way. Apply 'em now that
+             we have the new set.  */
+          SVN_ERR(svn_editor_set_props(eb->editor, path, SVN_INVALID_REVNUM,
+                                       props, contents == NULL));
+        }
+
+      if (contents)
+        {
+          /* If we have an content for this node, set it now. */
+          SVN_ERR(svn_editor_set_text(eb->editor, path, SVN_INVALID_REVNUM,
+                                      checksum, contents));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+run_ev2_actions(void *edit_baton,
+                apr_pool_t *scratch_pool)
+{
+  struct ev2_edit_baton *eb = edit_baton;
+  apr_array_header_t *sorted_hash;
+  apr_pool_t *iterpool;
+  int i;
+
+  /* Sort the paths touched by this edit.
+   * Ev2 doesn't really have any particular need for depth-first-ness, but
+   * we want to ensure all parent directories are handled before children in
+   * the case of adds (which does introduce an element of depth-first-ness). */
+  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
+                               scratch_pool);
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < sorted_hash->nelts; i++)
+    {
+      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
+      apr_array_header_t *actions = item->value;
+      const char *path = item->key;
+
+      svn_pool_clear(iterpool);
+      SVN_ERR(process_actions(edit_baton, path, actions, iterpool));
     }
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }
@@ -242,7 +394,8 @@ ev2_set_target_revision(void *edit_baton
 {
   struct ev2_edit_baton *eb = edit_baton;
 
-  eb->target_revision = target_revision;
+  SVN_ERR(eb->target_revision_func(eb->target_revision_baton, target_revision,
+                                   scratch_pool));
   return SVN_NO_ERROR;
 }
 
@@ -259,6 +412,11 @@ ev2_open_root(void *edit_baton,
   db->path = "";
 
   *root_baton = db;
+
+  if (eb->start_edit)
+    SVN_ERR(eb->start_edit(eb->start_edit_baton, base_revision, result_pool,
+                           &eb->root_baton));
+
   return SVN_NO_ERROR;
 }
 
@@ -287,16 +445,29 @@ ev2_add_directory(const char *path,
 {
   struct ev2_dir_baton *pb = parent_baton;
   struct ev2_dir_baton *cb = apr_palloc(result_pool, sizeof(*cb));
-  svn_node_kind_t *kind;
-
-  kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
-  *kind = svn_node_dir;
-  SVN_ERR(add_action(pb->eb, path, ACTION_ADD, kind));
 
   cb->eb = pb->eb;
   cb->path = apr_pstrdup(result_pool, path);
   *child_baton = cb;
 
+  if (!copyfrom_path)
+    {
+      /* A simple add. */
+      svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+
+      *kind = svn_kind_dir;
+      SVN_ERR(add_action(pb->eb, path, ACTION_ADD, kind));
+    }
+  else
+    {
+      /* A copy */
+      struct copy_args *args = apr_palloc(pb->eb->edit_pool, sizeof(*args));
+
+      args->copyfrom_path = apr_pstrdup(pb->eb->edit_pool, copyfrom_path);
+      args->copyfrom_rev = copyfrom_revision;
+      SVN_ERR(add_action(pb->eb, path, ACTION_COPY, args));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -329,7 +500,7 @@ ev2_change_dir_prop(void *dir_baton,
   p_args->name = apr_pstrdup(db->eb->edit_pool, name);
   p_args->value = value ? svn_string_dup(value, db->eb->edit_pool) : NULL;
 
-  SVN_ERR(add_action(db->eb, db->path, ACTION_SET_PROP, p_args));
+  SVN_ERR(add_action(db->eb, db->path, ACTION_PROPSET, p_args));
 
   return SVN_NO_ERROR;
 }
@@ -338,8 +509,6 @@ static svn_error_t *
 ev2_close_directory(void *dir_baton,
                     apr_pool_t *scratch_pool)
 {
-  struct ev2_dir_baton *db = dir_baton;
-
   return SVN_NO_ERROR;
 }
 
@@ -349,6 +518,11 @@ ev2_absent_directory(const char *path,
                      apr_pool_t *scratch_pool)
 {
   struct ev2_dir_baton *pb = parent_baton;
+  svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+  
+  *kind = svn_kind_dir;
+  SVN_ERR(add_action(pb->eb, path, ACTION_ADD_ABSENT, kind));
+
   return SVN_NO_ERROR;
 }
 
@@ -362,15 +536,32 @@ ev2_add_file(const char *path,
 {
   struct ev2_file_baton *fb = apr_palloc(result_pool, sizeof(*fb));
   struct ev2_dir_baton *pb = parent_baton;
-  svn_node_kind_t *kind;
 
   fb->eb = pb->eb;
   fb->path = apr_pstrdup(result_pool, path);
   *file_baton = fb;
 
-  kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
-  *kind = svn_node_file;
-  SVN_ERR(add_action(pb->eb, path, ACTION_ADD, kind));
+  SVN_ERR(fb->eb->fetch_base_func(&fb->delta_base,
+                                  fb->eb->fetch_base_baton,
+                                  path, result_pool, result_pool));
+
+  if (!copyfrom_path)
+    {
+      /* A simple add. */
+      svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+
+      *kind = svn_kind_file;
+      SVN_ERR(add_action(pb->eb, path, ACTION_ADD, kind));
+    }
+  else
+    {
+      /* A copy */
+      struct copy_args *args = apr_palloc(pb->eb->edit_pool, sizeof(*args));
+
+      args->copyfrom_path = apr_pstrdup(pb->eb->edit_pool, copyfrom_path);
+      args->copyfrom_rev = copyfrom_revision;
+      SVN_ERR(add_action(pb->eb, path, ACTION_COPY, args));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -388,10 +579,37 @@ ev2_open_file(const char *path,
   fb->eb = pb->eb;
   fb->path = apr_pstrdup(result_pool, path);
 
+  SVN_ERR(fb->eb->fetch_base_func(&fb->delta_base,
+                                  fb->eb->fetch_base_baton,
+                                  path, result_pool, result_pool));
+
   *file_baton = fb;
   return SVN_NO_ERROR;
 }
 
+struct handler_baton
+{
+  svn_txdelta_window_handler_t apply_handler;
+  void *apply_baton;
+
+  apr_pool_t *pool;
+};
+
+static svn_error_t *
+window_handler(svn_txdelta_window_t *window, void *baton)
+{
+  struct handler_baton *hb = baton;
+  svn_error_t *err;
+
+  err = hb->apply_handler(window, hb->apply_baton);
+  if (window != NULL && !err)
+    return SVN_NO_ERROR;
+
+  svn_pool_destroy(hb->pool);
+
+  return svn_error_trace(err);
+}
+
 
 static svn_error_t *
 ev2_apply_textdelta(void *file_baton,
@@ -401,9 +619,40 @@ ev2_apply_textdelta(void *file_baton,
                     void **handler_baton)
 {
   struct ev2_file_baton *fb = file_baton;
+  apr_pool_t *handler_pool = svn_pool_create(fb->eb->edit_pool);
+  struct handler_baton *hb = apr_pcalloc(handler_pool, sizeof(*hb));
+  svn_stream_t *source;
+  svn_stream_t *target;
+  struct path_checksum_args *pca = apr_pcalloc(fb->eb->edit_pool,
+                                               sizeof(*pca));
+
+  if (! fb->delta_base)
+    source = svn_stream_empty(handler_pool);
+  else
+    SVN_ERR(svn_stream_open_readonly(&source, fb->delta_base, handler_pool,
+                                     result_pool));
+
+  SVN_ERR(svn_stream_open_unique(&target, &pca->path, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 fb->eb->edit_pool, result_pool));
+
+  /* Wrap our target with a checksum'ing stream. */
+  target = svn_stream_checksummed2(target, NULL, &pca->checksum,
+                                   svn_checksum_sha1, TRUE,
+                                   fb->eb->edit_pool);
+
+  svn_txdelta_apply(source, target,
+                    NULL, NULL,
+                    handler_pool,
+                    &hb->apply_handler, &hb->apply_baton);
+
+  hb->pool = handler_pool;
+                    
+  *handler_baton = hb;
+  *handler = window_handler;
+
+  SVN_ERR(add_action(fb->eb, fb->path, ACTION_SET_TEXT, pca));
 
-  *handler_baton = NULL;
-  *handler = svn_delta_noop_window_handler;
   return SVN_NO_ERROR;
 }
 
@@ -419,7 +668,7 @@ ev2_change_file_prop(void *file_baton,
   p_args->name = apr_pstrdup(fb->eb->edit_pool, name);
   p_args->value = value ? svn_string_dup(value, fb->eb->edit_pool) : NULL;
 
-  SVN_ERR(add_action(fb->eb, fb->path, ACTION_SET_PROP, p_args));
+  SVN_ERR(add_action(fb->eb, fb->path, ACTION_PROPSET, p_args));
 
   return SVN_NO_ERROR;
 }
@@ -429,7 +678,6 @@ ev2_close_file(void *file_baton,
                const char *text_checksum,
                apr_pool_t *scratch_pool)
 {
-  struct ev2_file_baton *fb = file_baton;
   return SVN_NO_ERROR;
 }
 
@@ -439,6 +687,11 @@ ev2_absent_file(const char *path,
                 apr_pool_t *scratch_pool)
 {
   struct ev2_dir_baton *pb = parent_baton;
+  svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+  
+  *kind = svn_kind_file;
+  SVN_ERR(add_action(pb->eb, path, ACTION_ADD_ABSENT, kind));
+
   return SVN_NO_ERROR;
 }
 
@@ -447,29 +700,8 @@ ev2_close_edit(void *edit_baton,
                apr_pool_t *scratch_pool)
 {
   struct ev2_edit_baton *eb = edit_baton;
-  apr_array_header_t *sorted_hash;
-  apr_pool_t *iterpool;
-  int i;
-
-  /* Sort the paths touched by this edit.
-   * Ev2 doesn't really have any particular need for depth-first-ness, but
-   * we want to ensure all parent directories are handled before children in
-   * the case of adds (which does introduce an element of depth-first-ness). */
-  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
-                               scratch_pool);
-
-  iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < sorted_hash->nelts; i++)
-    {
-      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
-      apr_array_header_t *actions = item->value;
-      const char *path = item->key;
-
-      svn_pool_clear(iterpool);
-      SVN_ERR(process_actions(edit_baton, path, actions, iterpool));
-    }
-  svn_pool_destroy(iterpool);
 
+  SVN_ERR(run_ev2_actions(edit_baton, scratch_pool));
   return svn_error_trace(svn_editor_complete(eb->editor));
 }
 
@@ -479,16 +711,57 @@ ev2_abort_edit(void *edit_baton,
 {
   struct ev2_edit_baton *eb = edit_baton;
 
+  SVN_ERR(run_ev2_actions(edit_baton, scratch_pool));
   return svn_error_trace(svn_editor_abort(eb->editor));
 }
 
-svn_error_t *
-svn_delta_from_editor(const svn_delta_editor_t **deditor,
-                      void **dedit_baton,
-                      svn_editor_t *editor,
-                      svn_delta_fetch_props_func_t fetch_props_func,
-                      void *fetch_props_baton,
-                      apr_pool_t *pool)
+struct start_edit_baton
+{
+  const svn_delta_editor_t *deditor;
+  void *dedit_baton;
+};
+
+static svn_error_t *
+start_edit_func(void *baton,
+                svn_revnum_t base_revision,
+                apr_pool_t *result_pool,
+                void **root_baton)
+{
+  struct start_edit_baton *seb = baton;
+
+  SVN_ERR(seb->deditor->open_root(seb->dedit_baton, base_revision, result_pool,
+                                  root_baton));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+target_revision_func(void *baton,
+                     svn_revnum_t target_revision,
+                     apr_pool_t *scratch_pool)
+{
+  struct start_edit_baton *seb = baton;
+
+  SVN_ERR(seb->deditor->set_target_revision(seb->dedit_baton, target_revision,
+                                            scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+delta_from_editor(const svn_delta_editor_t **deditor,
+                  void **dedit_baton,
+                  svn_editor_t *editor,
+                  svn_boolean_t *found_abs_paths,
+                  svn_delta_fetch_props_func_t fetch_props_func,
+                  void *fetch_props_baton,
+                  svn_delta_fetch_base_func_t fetch_base_func,
+                  void *fetch_base_baton,
+                  start_edit_func_t start_edit,
+                  void *start_edit_baton,
+                  target_revision_func_t target_revision,
+                  void *target_revision_baton,
+                  apr_pool_t *pool)
 {
   /* Static 'cause we don't want it to be on the stack. */
   static svn_delta_editor_t delta_editor = {
@@ -509,15 +782,26 @@ svn_delta_from_editor(const svn_delta_ed
       ev2_close_edit,
       ev2_abort_edit
     };
-  struct ev2_edit_baton *eb = apr_palloc(pool, sizeof(*eb));
+  struct ev2_edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
 
   eb->editor = editor;
   eb->paths = apr_hash_make(pool);
-  eb->target_revision = SVN_INVALID_REVNUM;
   eb->edit_pool = pool;
+  eb->found_abs_paths = found_abs_paths;
+  *eb->found_abs_paths = FALSE;
+
   eb->fetch_props_func = fetch_props_func;
   eb->fetch_props_baton = fetch_props_baton;
 
+  eb->start_edit = start_edit;
+  eb->start_edit_baton = start_edit_baton;
+
+  eb->fetch_base_func = fetch_base_func;
+  eb->fetch_base_baton = fetch_base_baton;
+
+  eb->target_revision_func = target_revision;
+  eb->target_revision_baton = target_revision_baton;
+
   *dedit_baton = eb;
   *deditor = &delta_editor;
 
@@ -528,32 +812,25 @@ svn_delta_from_editor(const svn_delta_ed
 
 
 
-typedef enum action_code_t {
-  ACTION_MV,
-  ACTION_MKDIR,
-  ACTION_CP,
-  ACTION_PROPSET,
-  ACTION_PUT,
-  ACTION_RM
-} action_code_t;
-
 struct operation {
   enum {
     OP_OPEN,
     OP_DELETE,
     OP_ADD,
     OP_REPLACE,
+    OP_ADD_ABSENT,
     OP_PROPSET           /* only for files for which no other operation is
                             occuring; directories are OP_OPEN with non-empty
                             props */
   } operation;
-  svn_node_kind_t kind;  /* to copy, mkdir, put or set revprops */
-  svn_revnum_t rev;      /* to copy, valid for add and replace */
-  const char *url;       /* to copy, valid for add and replace */
+  svn_kind_t kind;  /* to copy, mkdir, put or set revprops */
+  svn_revnum_t copyfrom_revision;      /* to copy, valid for add and replace */
+  const char *copyfrom_url;       /* to copy, valid for add and replace */
   const char *src_file;  /* for put, the source file for contents */
   apr_hash_t *children;  /* const char *path -> struct operation * */
-  apr_hash_t *props;     /* const char *prop_name ->
+  apr_hash_t *prop_mods; /* const char *prop_name ->
                             const svn_string_t *prop_value */
+  apr_array_header_t *prop_dels; /* const char *prop_name deletions */
   void *baton;           /* as returned by the commit editor */
 };
 
@@ -565,12 +842,18 @@ struct editor_baton
   svn_delta_fetch_kind_func_t fetch_kind_func;
   void *fetch_kind_baton;
 
+  svn_delta_fetch_props_func_t fetch_props_func;
+  void *fetch_props_baton;
+
   struct operation root;
+  svn_boolean_t root_opened;
+  svn_boolean_t *make_abs_paths;
 
   apr_hash_t *paths;
   apr_pool_t *edit_pool;
 };
 
+
 /* Find the operation associated with PATH, which is a single-path
    component representing a child of the path represented by
    OPERATION.  If no such child operation exists, create a new one of
@@ -587,9 +870,10 @@ get_operation(const char *path,
       child = apr_pcalloc(result_pool, sizeof(*child));
       child->children = apr_hash_make(result_pool);
       child->operation = OP_OPEN;
-      child->rev = SVN_INVALID_REVNUM;
-      child->kind = svn_node_dir;
-      child->props = NULL;
+      child->copyfrom_revision = SVN_INVALID_REVNUM;
+      child->kind = svn_kind_dir;
+      child->prop_mods = apr_hash_make(result_pool);
+      child->prop_dels = apr_array_make(result_pool, 1, sizeof(const char *));
       apr_hash_set(operation->children, apr_pstrdup(result_pool, path),
                    APR_HASH_KEY_STRING, child);
     }
@@ -603,9 +887,9 @@ get_operation(const char *path,
       ACTION          URL    REV      SRC-FILE  PROPNAME
       ------------    -----  -------  --------  --------
       ACTION_MKDIR    NULL   invalid  NULL      NULL
-      ACTION_CP       valid  valid    NULL      NULL
+      ACTION_COPY     valid  valid    NULL      NULL
       ACTION_PUT      NULL   invalid  valid     NULL
-      ACTION_RM       NULL   invalid  NULL      NULL
+      ACTION_DELETE   NULL   invalid  NULL      NULL
       ACTION_PROPSET  valid  invalid  NULL      valid
 
    Node type information is obtained for any copy source (to determine
@@ -614,8 +898,9 @@ get_operation(const char *path,
    return an error on non-existent nodes). */
 static svn_error_t *
 build(struct editor_baton *eb,
-      action_code_t action,
+      enum action_code_t action,
       const char *relpath,
+      svn_kind_t kind,
       const char *url,
       svn_revnum_t rev,
       apr_hash_t *props,
@@ -646,43 +931,73 @@ build(struct editor_baton *eb,
   /* Handle property changes. */
   if (props)
     {
-      SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
-                                  relpath, scratch_pool));
+      apr_hash_t *current_props;
+      apr_array_header_t *propdiffs;
+
+      if (kind == svn_kind_unknown)
+        SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
+                                    relpath, scratch_pool));
+      else
+        operation->kind = kind;
+
+      SVN_ERR(eb->fetch_props_func(&current_props, eb->fetch_props_baton,
+                                   relpath, scratch_pool, scratch_pool));
+
+      /* Use the edit pool, since most of the results will need to be
+         persisted. */
+      SVN_ERR(svn_prop_diffs(&propdiffs, props, current_props, eb->edit_pool));
+
+      for (i = 0; i < propdiffs->nelts; i++)
+        {
+          /* Note: the array returned by svn_prop_diffs() is an array of
+             actual structures, not pointers to them. */
+          svn_prop_t *prop = &APR_ARRAY_IDX(propdiffs, i, svn_prop_t);
+          if (!prop->value)
+            APR_ARRAY_PUSH(operation->prop_dels, const char *) = prop->name;
+          else
+            apr_hash_set(operation->prop_mods, prop->name, APR_HASH_KEY_STRING,
+                         prop->value);
+        }
 
       /* If we're not adding this thing ourselves, check for existence.  */
       if (! ((operation->operation == OP_ADD) ||
              (operation->operation == OP_REPLACE)))
         {
-          if ((operation->kind == svn_node_file)
+          if ((operation->kind == svn_kind_file)
                    && (operation->operation == OP_OPEN))
             operation->operation = OP_PROPSET;
         }
-      operation->props = svn_prop_hash_dup(props, eb->edit_pool);
-      if (!operation->rev)
-        operation->rev = rev;
+      if (!operation->copyfrom_revision)
+        operation->copyfrom_revision = rev;
       return SVN_NO_ERROR;
     }
 
-  if (action == ACTION_RM)
+  if (action == ACTION_DELETE)
     operation->operation = OP_DELETE;
 
+  else if (action == ACTION_ADD_ABSENT)
+    operation->operation = OP_ADD_ABSENT;
+
   /* Handle copy operations (which can be adds or replacements). */
-  else if (action == ACTION_CP)
+  else if (action == ACTION_COPY)
     {
       operation->operation =
         operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
 
-      SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
-                                  relpath, scratch_pool));
-      operation->url = url;
-      operation->rev = rev;
+      if (kind == svn_kind_none)
+        SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
+                                    relpath, scratch_pool));
+      else
+        operation->kind = kind;
+      operation->copyfrom_url = url;
+      operation->copyfrom_revision = rev;
     }
   /* Handle mkdir operations (which can be adds or replacements). */
   else if (action == ACTION_MKDIR)
     {
       operation->operation =
         operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
-      operation->kind = svn_node_dir;
+      operation->kind = svn_kind_dir;
     }
   /* Handle put operations (which can be adds, replacements, or opens). */
   else if (action == ACTION_PUT)
@@ -693,17 +1008,15 @@ build(struct editor_baton *eb,
         }
       else
         {
-          SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
-                                      relpath, scratch_pool));
-          if (operation->kind == svn_node_file)
+          if (kind == svn_kind_file)
             operation->operation = OP_OPEN;
-          else if (operation->kind == svn_node_none)
+          else if (kind == svn_kind_none)
             operation->operation = OP_ADD;
           else
             return svn_error_createf(SVN_ERR_BAD_URL, NULL,
                                      "'%s' is not a file", relpath);
         }
-      operation->kind = svn_node_file;
+      operation->kind = svn_kind_file;
       operation->src_file = src_file;
     }
   else
@@ -715,6 +1028,19 @@ build(struct editor_baton *eb,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+ensure_root_opened(struct editor_baton *eb)
+{
+  if (!eb->root_opened)
+    {
+      SVN_ERR(eb->deditor->open_root(eb->dedit_baton, SVN_INVALID_REVNUM,
+                                     eb->edit_pool, &eb->root.baton));
+      eb->root_opened = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* This implements svn_editor_cb_add_directory_t */
 static svn_error_t *
 add_directory_cb(void *baton,
@@ -724,6 +1050,19 @@ add_directory_cb(void *baton,
                  svn_revnum_t replaces_rev,
                  apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(ensure_root_opened(eb));
+
+  SVN_ERR(build(eb, ACTION_MKDIR, relpath, svn_kind_dir,
+                NULL, SVN_INVALID_REVNUM,
+                NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+
+  if (props && apr_hash_count(props) > 0)
+    SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_dir,
+                  NULL, SVN_INVALID_REVNUM, props,
+                  NULL, SVN_INVALID_REVNUM, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -737,6 +1076,28 @@ add_file_cb(void *baton,
             svn_revnum_t replaces_rev,
             apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+  const char *tmp_filename;
+  svn_stream_t *tmp_stream;
+
+  SVN_ERR(ensure_root_opened(eb));
+
+  /* Spool the contents to a tempfile, and provide that to the driver. */
+  SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 eb->edit_pool, scratch_pool));
+  SVN_ERR(svn_stream_copy3(svn_stream_disown(contents, scratch_pool),
+                           tmp_stream, NULL, NULL, scratch_pool));
+
+  SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_none,
+                NULL, SVN_INVALID_REVNUM,
+                NULL, tmp_filename, SVN_INVALID_REVNUM, scratch_pool));
+
+  if (props && apr_hash_count(props) > 0)
+    SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_file,
+                  NULL, SVN_INVALID_REVNUM, props,
+                  NULL, SVN_INVALID_REVNUM, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -749,6 +1110,10 @@ add_symlink_cb(void *baton,
                svn_revnum_t replaces_rev,
                apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(ensure_root_opened(eb));
+
   return SVN_NO_ERROR;
 }
 
@@ -756,10 +1121,18 @@ add_symlink_cb(void *baton,
 static svn_error_t *
 add_absent_cb(void *baton,
               const char *relpath,
-              svn_node_kind_t kind,
+              svn_kind_t kind,
               svn_revnum_t replaces_rev,
               apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(ensure_root_opened(eb));
+
+  SVN_ERR(build(eb, ACTION_ADD_ABSENT, relpath, kind,
+                NULL, SVN_INVALID_REVNUM,
+                NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -774,7 +1147,10 @@ set_props_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(build(eb, ACTION_PROPSET, relpath, NULL, SVN_INVALID_REVNUM,
+  SVN_ERR(ensure_root_opened(eb));
+
+  SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_unknown,
+                NULL, SVN_INVALID_REVNUM,
                 props, NULL, SVN_INVALID_REVNUM, scratch_pool));
 
   return SVN_NO_ERROR;
@@ -789,6 +1165,23 @@ set_text_cb(void *baton,
             svn_stream_t *contents,
             apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+  const char *tmp_filename;
+  svn_stream_t *tmp_stream;
+
+  SVN_ERR(ensure_root_opened(eb));
+
+  /* Spool the contents to a tempfile, and provide that to the driver. */
+  SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 eb->edit_pool, scratch_pool));
+  SVN_ERR(svn_stream_copy3(svn_stream_disown(contents, scratch_pool),
+                           tmp_stream, NULL, NULL, scratch_pool));
+
+  SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_file,
+                NULL, SVN_INVALID_REVNUM,
+                NULL, tmp_filename, SVN_INVALID_REVNUM, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -800,6 +1193,10 @@ set_target_cb(void *baton,
               const char *target,
               apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(ensure_root_opened(eb));
+
   return SVN_NO_ERROR;
 }
 
@@ -810,6 +1207,14 @@ delete_cb(void *baton,
           svn_revnum_t revision,
           apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(ensure_root_opened(eb));
+
+  SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
+                NULL, SVN_INVALID_REVNUM, NULL, NULL, SVN_INVALID_REVNUM,
+                scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -822,6 +1227,14 @@ copy_cb(void *baton,
         svn_revnum_t replaces_rev,
         apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(ensure_root_opened(eb));
+
+  SVN_ERR(build(eb, ACTION_COPY, dst_relpath, svn_kind_unknown,
+                src_relpath, src_revision, NULL, NULL, SVN_INVALID_REVNUM,
+                scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -834,6 +1247,173 @@ move_cb(void *baton,
         svn_revnum_t replaces_rev,
         apr_pool_t *scratch_pool)
 {
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(ensure_root_opened(eb));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+change_props(const svn_delta_editor_t *editor,
+             void *baton,
+             const struct operation *child,
+             apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  if (child->prop_dels)
+    {
+      int i;
+      for (i = 0; i < child->prop_dels->nelts; i++)
+        {
+          const char *prop_name;
+
+          svn_pool_clear(iterpool);
+          prop_name = APR_ARRAY_IDX(child->prop_dels, i, const char *);
+          if (child->kind == svn_kind_dir)
+            SVN_ERR(editor->change_dir_prop(baton, prop_name,
+                                            NULL, iterpool));
+          else
+            SVN_ERR(editor->change_file_prop(baton, prop_name,
+                                             NULL, iterpool));
+        }
+    }
+
+  if (apr_hash_count(child->prop_mods))
+    {
+      apr_hash_index_t *hi;
+      for (hi = apr_hash_first(scratch_pool, child->prop_mods);
+           hi; hi = apr_hash_next(hi))
+        {
+          const char *name = svn__apr_hash_index_key(hi);
+          svn_string_t *val = svn__apr_hash_index_val(hi);
+
+          svn_pool_clear(iterpool);
+          if (child->kind == svn_kind_dir)
+            SVN_ERR(editor->change_dir_prop(baton, name, val, iterpool));
+          else
+            SVN_ERR(editor->change_file_prop(baton, name, val, iterpool));
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+drive_tree(const struct operation *operation,
+           const svn_delta_editor_t *editor,
+           svn_boolean_t *make_abs_paths,
+           apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, operation->children);
+       hi; hi = apr_hash_next(hi))
+    {
+      struct operation *child;
+      const char *path;
+      void *file_baton = NULL;
+
+      svn_pool_clear(iterpool);
+      child = svn__apr_hash_index_val(hi);
+      path = svn__apr_hash_index_key(hi);
+
+      if (path[0] != '/' && *make_abs_paths)
+        path = apr_pstrcat(iterpool, "/", path, NULL);
+
+      /* Deletes are simple -- just delete the thing. */
+      if (child->operation == OP_DELETE)
+        {
+          SVN_ERR(editor->delete_entry(path, SVN_INVALID_REVNUM,
+                                       operation->baton, iterpool));
+        }
+
+      if (child->operation == OP_OPEN || child->operation == OP_PROPSET)
+        {
+          if (child->kind == svn_kind_dir)
+            SVN_ERR(editor->open_directory(path, operation->baton,
+                                           SVN_INVALID_REVNUM,
+                                           iterpool, &child->baton));
+          else
+            SVN_ERR(editor->open_file(path, operation->baton,
+                                      SVN_INVALID_REVNUM,
+                                      iterpool, &file_baton));
+        }
+
+      if (child->operation == OP_ADD)
+        {
+          if (child->kind == svn_kind_dir)
+            SVN_ERR(editor->add_directory(path, operation->baton,
+                                          child->copyfrom_url,
+                                          child->copyfrom_revision,
+                                          iterpool, &child->baton));
+          else
+            SVN_ERR(editor->add_file(path, operation->baton,
+                                     child->copyfrom_url,
+                                     child->copyfrom_revision, iterpool,
+                                     &file_baton));
+        }
+
+      if (child->operation == OP_ADD_ABSENT)
+        {
+          if (child->kind == svn_kind_dir)
+            SVN_ERR(editor->absent_directory(path, operation->baton,
+                                             iterpool));
+          else
+            SVN_ERR(editor->absent_file(path, operation->baton, iterpool));
+        }
+
+      if (child->src_file && file_baton)
+        {
+          /* We need to change textual contents. */
+          svn_txdelta_window_handler_t handler;
+          void *handler_baton;
+          svn_stream_t *contents;
+
+          SVN_ERR(editor->apply_textdelta(file_baton, NULL, iterpool,
+                                          &handler, &handler_baton));
+          SVN_ERR(svn_stream_open_readonly(&contents, child->src_file,
+                                           iterpool, iterpool));
+          SVN_ERR(svn_txdelta_send_stream(contents, handler, handler_baton,
+                                          NULL, iterpool));
+          SVN_ERR(svn_stream_close(contents));
+        }
+
+      /* Only worry about properties and closing the file baton if we've
+         previously opened it. */
+      if (file_baton)
+        {
+          if (child->kind == svn_kind_file)
+            SVN_ERR(change_props(editor, file_baton, child, iterpool));
+          SVN_ERR(editor->close_file(file_baton, NULL, iterpool));
+        }
+
+      /* We *always* open the child directory, so drive the child, change any
+         props, and then close the directory. */
+      if (child->kind == svn_kind_dir
+                   && (child->operation == OP_OPEN
+                    || child->operation == OP_PROPSET
+                    || child->operation == OP_ADD))
+        {
+          SVN_ERR(drive_tree(child, editor, make_abs_paths, iterpool));
+          SVN_ERR(editor->close_directory(child->baton, iterpool));
+        }
+    }
+  svn_pool_destroy(iterpool);
+
+  /* Finally, for this node, if it's a directory, change any props before
+     returning (our caller will close the directory. */
+  if (operation->kind == svn_kind_dir
+                   && (operation->operation == OP_OPEN
+                    || operation->operation == OP_PROPSET
+                    || operation->operation == OP_ADD))
+    {
+      SVN_ERR(change_props(editor, operation->baton, operation, scratch_pool));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -843,26 +1423,24 @@ complete_cb(void *baton,
             apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
-  apr_array_header_t *sorted_hash;
-  int i;
+  svn_error_t *err;
 
-  /* Sort the paths touched by this edit.
-   * Ev2 doesn't really have any particular need for depth-first-ness, but
-   * we want to ensure all parent directories are handled before children in
-   * the case of adds (which does introduce an element of depth-first-ness). */
-  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
-                               scratch_pool);
+  SVN_ERR(ensure_root_opened(eb));
 
-  for (i = 0; i < sorted_hash->nelts; i++)
-    {
-      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
-      const char *path = item->key;
+  /* Drive the tree we've created. */
+  err = drive_tree(&eb->root, eb->deditor, eb->make_abs_paths, scratch_pool);
+  if (!err)
+     {
+       err = eb->deditor->close_directory(eb->root.baton, scratch_pool);
+       err = svn_error_compose_create(err, eb->deditor->close_edit(
+                                                            eb->dedit_baton,
+                                                            scratch_pool));
+     }
 
-      /* ### We should actually do something here, but for now... */
-    }
+  if (err)
+    svn_error_clear(eb->deditor->abort_edit(eb->dedit_baton, scratch_pool));
 
-  return svn_error_trace(eb->deditor->close_edit(eb->dedit_baton,
-                                                 scratch_pool));
+  return svn_error_trace(err);
 }
 
 /* This implements svn_editor_cb_abort_t */
@@ -871,20 +1449,41 @@ abort_cb(void *baton,
          apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
-  return svn_error_trace(eb->deditor->abort_edit(eb->dedit_baton,
-                                                 scratch_pool));
+  svn_error_t *err;
+  svn_error_t *err2;
+
+  /* We still need to drive anything we collected in the editor to this
+     point. */
+
+  /* Drive the tree we've created. */
+  err = drive_tree(&eb->root, eb->deditor, eb->make_abs_paths, scratch_pool);
+
+  err2 = eb->deditor->abort_edit(eb->dedit_baton, scratch_pool);
+
+  if (err2)
+    {
+      if (err)
+        svn_error_clear(err2);
+      else
+        err = err2;
+    }
+
+  return svn_error_trace(err);
 }
 
-svn_error_t *
-svn_editor_from_delta(svn_editor_t **editor_p,
-                      const svn_delta_editor_t *deditor,
-                      void *dedit_baton,
-                      svn_cancel_func_t cancel_func,
-                      void *cancel_baton,
-                      svn_delta_fetch_kind_func_t fetch_kind_func,
-                      void *fetch_kind_baton,
-                      apr_pool_t *result_pool,
-                      apr_pool_t *scratch_pool)
+static svn_error_t *
+editor_from_delta(svn_editor_t **editor_p,
+                  const svn_delta_editor_t *deditor,
+                  void *dedit_baton,
+                  svn_boolean_t *send_abs_paths,
+                  svn_cancel_func_t cancel_func,
+                  void *cancel_baton,
+                  svn_delta_fetch_kind_func_t fetch_kind_func,
+                  void *fetch_kind_baton,
+                  svn_delta_fetch_props_func_t fetch_props_func,
+                  void *fetch_props_baton,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
   svn_editor_t *editor;
   static const svn_editor_cb_many_t editor_cbs = {
@@ -910,12 +1509,18 @@ svn_editor_from_delta(svn_editor_t **edi
 
   eb->fetch_kind_func = fetch_kind_func;
   eb->fetch_kind_baton = fetch_kind_baton;
+  eb->fetch_props_func = fetch_props_func;
+  eb->fetch_props_baton = fetch_props_baton;
 
   eb->root.children = apr_hash_make(result_pool);
-  eb->root.kind = svn_node_dir;
+  eb->root.kind = svn_kind_dir;
   eb->root.operation = OP_OPEN;
-  eb->root.props = NULL;
-  eb->root.rev = SVN_INVALID_REVNUM;
+  eb->root.prop_mods = apr_hash_make(result_pool);
+  eb->root.prop_dels = apr_array_make(result_pool, 1, sizeof(const char *));
+  eb->root.copyfrom_revision = SVN_INVALID_REVNUM;
+
+  eb->root_opened = FALSE;
+  eb->make_abs_paths = send_abs_paths;
 
   SVN_ERR(svn_editor_create(&editor, eb, cancel_func, cancel_baton,
                             result_pool, scratch_pool));
@@ -926,6 +1531,13 @@ svn_editor_from_delta(svn_editor_t **edi
   return SVN_NO_ERROR;
 }
 
+svn_delta_shim_callbacks_t *
+svn_delta_shim_callbacks_default(apr_pool_t *result_pool)
+{
+  svn_delta_shim_callbacks_t *shim_callbacks = apr_pcalloc(result_pool,
+                                                     sizeof(*shim_callbacks));
+  return shim_callbacks;
+}
 
 /* Uncomment below to add editor shims throughout Subversion.  In it's
  * current state, that will likely break The World. */
@@ -936,10 +1548,7 @@ svn_editor__insert_shims(const svn_delta
                          void **dedit_baton_out,
                          const svn_delta_editor_t *deditor_in,
                          void *dedit_baton_in,
-                         svn_delta_fetch_props_func_t fetch_props_func,
-                         void *fetch_props_baton,
-                         svn_delta_fetch_kind_func_t fetch_kind_func,
-                         void *fetch_kind_baton,
+                         svn_delta_shim_callbacks_t *shim_callbacks,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
 {
@@ -952,13 +1561,33 @@ svn_editor__insert_shims(const svn_delta
      wrap that again back into a svn_delta_editor_t.  This introduces
      a lot of overhead. */
   svn_editor_t *editor;
+  struct start_edit_baton *seb = apr_palloc(result_pool, sizeof(*seb));
 
-  SVN_ERR(svn_editor_from_delta(&editor, deditor_in, dedit_baton_in,
-                                NULL, NULL, fetch_kind_func, fetch_kind_baton,
-                                result_pool, scratch_pool));
-  SVN_ERR(svn_delta_from_editor(deditor_out, dedit_baton_out, editor,
-                                fetch_props_func, fetch_props_baton,
-                                result_pool));
+  /* The reason this is a pointer is that we don't know the appropriate
+     value until we start receiving paths.  So process_actions() sets the
+     flag, which drive_tree() later consumes. */
+  svn_boolean_t *found_abs_paths = apr_palloc(result_pool,
+                                              sizeof(*found_abs_paths));
+
+  seb->deditor = deditor_in;
+  seb->dedit_baton = dedit_baton_in;
+
+  SVN_ERR(editor_from_delta(&editor, deditor_in, dedit_baton_in,
+                            found_abs_paths, NULL, NULL,
+                            shim_callbacks->fetch_kind_func,
+                            shim_callbacks->fetch_kind_baton,
+                            shim_callbacks->fetch_props_func,
+                            shim_callbacks->fetch_props_baton,
+                            result_pool, scratch_pool));
+  SVN_ERR(delta_from_editor(deditor_out, dedit_baton_out, editor,
+                            found_abs_paths,
+                            shim_callbacks->fetch_props_func,
+                            shim_callbacks->fetch_props_baton,
+                            shim_callbacks->fetch_base_func,
+                            shim_callbacks->fetch_base_baton,
+                            start_edit_func, seb,
+                            target_revision_func, seb,
+                            result_pool));
 
 #endif
   return SVN_NO_ERROR;

Modified: subversion/branches/fs-py/subversion/libsvn_delta/compose_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_delta/compose_delta.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_delta/compose_delta.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_delta/compose_delta.c Mon Dec 19 18:49:34 2011
@@ -774,7 +774,7 @@ svn_txdelta_compose_windows(const svn_tx
   /* Read the description of the delta composition algorithm in
      notes/fs-improvements.txt before going any further.
      You have been warned. */
-  build_baton.new_data = svn_stringbuf_create("", pool);
+  build_baton.new_data = svn_stringbuf_create_empty(pool);
   for (i = 0; i < window_B->num_ops; ++i)
     {
       const svn_txdelta_op_t *const op = &window_B->ops[i];

Modified: subversion/branches/fs-py/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_delta/editor.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_delta/editor.c Mon Dec 19 18:49:34 2011
@@ -354,7 +354,7 @@ svn_editor_add_symlink(svn_editor_t *edi
 svn_error_t *
 svn_editor_add_absent(svn_editor_t *editor,
                       const char *relpath,
-                      svn_node_kind_t kind,
+                      svn_kind_t kind,
                       svn_revnum_t replaces_rev)
 {
   svn_error_t *err;
@@ -605,7 +605,8 @@ svn_editor_complete(svn_editor_t *editor
 
   err = editor->funcs.cb_complete(editor->baton, editor->scratch_pool);
 #ifdef ENABLE_ORDERING_CHECK
-  editor->finished = TRUE;
+  if (!err)
+    editor->finished = TRUE;
 #endif
   svn_pool_clear(editor->scratch_pool);
   return err;

Modified: subversion/branches/fs-py/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_delta/svndiff.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_delta/svndiff.c Mon Dec 19 18:49:34 2011
@@ -182,9 +182,9 @@ window_handler(svn_txdelta_window_t *win
 {
   struct encoder_baton *eb = baton;
   apr_pool_t *pool = svn_pool_create(eb->pool);
-  svn_stringbuf_t *instructions = svn_stringbuf_create("", pool);
-  svn_stringbuf_t *i1 = svn_stringbuf_create("", pool);
-  svn_stringbuf_t *header = svn_stringbuf_create("", pool);
+  svn_stringbuf_t *instructions = svn_stringbuf_create_empty(pool);
+  svn_stringbuf_t *i1 = svn_stringbuf_create_empty(pool);
+  svn_stringbuf_t *header = svn_stringbuf_create_empty(pool);
   const svn_string_t *newdata;
   unsigned char ibuf[MAX_INSTRUCTION_LEN], *ip;
   const svn_txdelta_op_t *op;
@@ -254,8 +254,8 @@ window_handler(svn_txdelta_window_t *win
   append_encoded_int(header, instructions->len);
   if (eb->version == 1)
     {
-      svn_stringbuf_t *temp = svn_stringbuf_create("", pool);
-      svn_string_t *tempstr = svn_string_create("", pool);
+      svn_stringbuf_t *temp = svn_stringbuf_create_empty(pool);
+      svn_string_t *tempstr = svn_string_create_empty(pool);
       SVN_ERR(zlib_encode(window->new_data->data, window->new_data->len,
                           temp, eb->compression_level));
       tempstr->data = temp->data;
@@ -431,20 +431,24 @@ decode_size(apr_size_t *val,
   return NULL;
 }
 
-/* Decode the possibly-zlib compressed string that is in IN, into OUT.
-   We expect an integer is prepended to IN that specifies the original
-   size, and that if encoded size == original size, that the remaining
-   data is not compressed.  */
+/* Decode the possibly-zlib compressed string of length INLEN that is in
+   IN, into OUT.  We expect an integer is prepended to IN that specifies
+   the original size, and that if encoded size == original size, that the
+   remaining data is not compressed.
+   In that case, we will simply return pointer into IN as data pointer for
+   OUT.  The caller is expected not to modify the contents of OUT.
+   An error is returned if the decoded length exceeds the given LIMIT.
+ */
 static svn_error_t *
-zlib_decode(svn_stringbuf_t *in, svn_stringbuf_t *out, apr_size_t limit)
+zlib_decode(const unsigned char *in, apr_size_t inLen, svn_stringbuf_t *out,
+            apr_size_t limit)
 {
   apr_size_t len;
-  char *oldplace = in->data;
+  const unsigned char *oldplace = in;
 
   /* First thing in the string is the original length.  */
-  in->data = (char *)decode_size(&len, (unsigned char *)in->data,
-                                 (unsigned char *)in->data+in->len);
-  if (in->data == NULL)
+  in = decode_size(&len, in, in + inLen);
+  if (in == NULL)
     return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA, NULL,
                             _("Decompression of svndiff data failed: no size"));
   if (len > limit)
@@ -453,33 +457,36 @@ zlib_decode(svn_stringbuf_t *in, svn_str
                               "size too large"));
   /* We need to subtract the size of the encoded original length off the
    *      still remaining input length.  */
-  in->len -= (in->data - oldplace);
-  if (in->len == len)
+  inLen -= (in - oldplace);
+  if (inLen == len)
     {
-      svn_stringbuf_appendstr(out, in);
+      /* "in" is no longer used but the memory remains allocated for
+       * at least as long as "out" will be used by the caller.
+       */
+      out->data = (char *)in;
+      out->len = len;
+      out->blocksize = len; /* sic! */
+
       return SVN_NO_ERROR;
     }
   else
     {
-      unsigned long zliblen;
+      unsigned long zlen = len;
 
       svn_stringbuf_ensure(out, len);
-
-      zliblen = len;
-      if (uncompress  ((unsigned char *)out->data, &zliblen,
-                       (const unsigned char *)in->data, in->len) != Z_OK)
+      if (uncompress((unsigned char *)out->data, &zlen, in, inLen) != Z_OK)
         return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA,
                                 NULL,
                                 _("Decompression of svndiff data failed"));
 
       /* Zlib should not produce something that has a different size than the
          original length we stored. */
-      if (zliblen != len)
+      if (zlen != len)
         return svn_error_create(SVN_ERR_SVNDIFF_INVALID_COMPRESSED_DATA,
                                 NULL,
                                 _("Size of uncompressed data "
                                   "does not match stored original length"));
-      out->len = zliblen;
+      out->len = zlen;
     }
   return SVN_NO_ERROR;
 }
@@ -627,16 +634,15 @@ decode_window(svn_txdelta_window_t *wind
 
   if (version == 1)
     {
-      svn_stringbuf_t *instin, *ndin;
-      svn_stringbuf_t *instout, *ndout;
+      svn_stringbuf_t *instout = svn_stringbuf_create_empty(pool);
+      svn_stringbuf_t *ndout = svn_stringbuf_create_empty(pool);
 
-      instin = svn_stringbuf_ncreate((const char *)data, insend - data, pool);
-      instout = svn_stringbuf_create("", pool);
-      SVN_ERR(zlib_decode(instin, instout, MAX_INSTRUCTION_SECTION_LEN));
-
-      ndin = svn_stringbuf_ncreate((const char *)insend, newlen, pool);
-      ndout = svn_stringbuf_create("", pool);
-      SVN_ERR(zlib_decode(ndin, ndout, SVN_DELTA_WINDOW_SIZE));
+      /* these may in fact simply return references to insend */
+      
+      SVN_ERR(zlib_decode(insend, newlen, ndout,
+                          SVN_DELTA_WINDOW_SIZE));
+      SVN_ERR(zlib_decode(data, insend - data, instout,
+                          MAX_INSTRUCTION_SECTION_LEN));
 
       newlen = ndout->len;
       data = (unsigned char *)instout->data;
@@ -846,7 +852,7 @@ svn_txdelta_parse_svndiff(svn_txdelta_wi
   db->consumer_baton = handler_baton;
   db->pool = subpool;
   db->subpool = svn_pool_create(subpool);
-  db->buffer = svn_stringbuf_create("", db->subpool);
+  db->buffer = svn_stringbuf_create_empty(db->subpool);
   db->last_sview_offset = 0;
   db->last_sview_len = 0;
   db->header_bytes = 0;

Modified: subversion/branches/fs-py/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_delta/text_delta.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_delta/text_delta.c Mon Dec 19 18:49:34 2011
@@ -150,7 +150,7 @@ compute_window(const char *data, apr_siz
   svn_txdelta_window_t *window;
 
   /* Compute the delta operations. */
-  build_baton.new_data = svn_stringbuf_create("", pool);
+  build_baton.new_data = svn_stringbuf_create_empty(pool);
 
   if (source_len == 0)
     svn_txdelta__insert_op(&build_baton, svn_txdelta_new, 0, target_len, data,

Modified: subversion/branches/fs-py/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_diff/diff_file.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_diff/diff_file.c Mon Dec 19 18:49:34 2011
@@ -470,8 +470,9 @@ find_identical_prefix(svn_boolean_t *rea
          too many for the \r. */
       svn_boolean_t ended_at_nonmatching_newline = FALSE;
       for (i = 0; i < file_len; i++)
-        ended_at_nonmatching_newline = ended_at_nonmatching_newline
-                                       || *file[i].curp == '\n';
+        if (file[i].curp < file[i].endp)
+          ended_at_nonmatching_newline = ended_at_nonmatching_newline
+                                         || *file[i].curp == '\n';
       if (ended_at_nonmatching_newline)
         {
           lines--;
@@ -591,9 +592,9 @@ find_identical_suffix(apr_off_t *suffix_
   had_nl = FALSE;
   while (is_match)
     {
+#if SVN_UNALIGNED_ACCESS_IS_OK
       /* Initialize the minimum pointer positions. */
       const char *min_curp[4];
-#if SVN_UNALIGNED_ACCESS_IS_OK
       svn_boolean_t can_read_word;
 #endif /* SVN_UNALIGNED_ACCESS_IS_OK */
 
@@ -616,6 +617,7 @@ find_identical_suffix(apr_off_t *suffix_
 
       DECREMENT_POINTERS(file_for_suffix, file_len, pool);
 
+#if SVN_UNALIGNED_ACCESS_IS_OK
 
       min_curp[0] = file_for_suffix[0].chunk == suffix_min_chunk0
                   ? file_for_suffix[0].buffer + suffix_min_offset0 + 1
@@ -623,8 +625,6 @@ find_identical_suffix(apr_off_t *suffix_
       for (i = 1; i < file_len; i++)
         min_curp[i] = file_for_suffix[i].buffer + 1;
 
-#if SVN_UNALIGNED_ACCESS_IS_OK
-
       /* Scan quickly by reading with machine-word granularity. */
       for (i = 0, can_read_word = TRUE; i < file_len; i++)
         can_read_word = can_read_word
@@ -1756,9 +1756,9 @@ svn_diff_file_output_unified3(svn_stream
       baton.header_encoding = header_encoding;
       baton.path[0] = original_path;
       baton.path[1] = modified_path;
-      baton.hunk = svn_stringbuf_create("", pool);
+      baton.hunk = svn_stringbuf_create_empty(pool);
       baton.show_c_function = show_c_function;
-      baton.extra_context = svn_stringbuf_create("", pool);
+      baton.extra_context = svn_stringbuf_create_empty(pool);
       baton.extra_skip_match = apr_array_make(pool, 3, sizeof(char **));
 
       c = apr_array_push(baton.extra_skip_match);

Modified: subversion/branches/fs-py/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_diff/diff_memory.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_diff/diff_memory.c Mon Dec 19 18:49:34 2011
@@ -584,7 +584,7 @@ svn_diff_mem_string_output_unified2(svn_
       baton.output_stream = output_stream;
       baton.pool = svn_pool_create(pool);
       baton.header_encoding = header_encoding;
-      baton.hunk = svn_stringbuf_create("", pool);
+      baton.hunk = svn_stringbuf_create_empty(pool);
       baton.hunk_delimiter = hunk_delimiter;
 
       SVN_ERR(svn_utf_cstring_from_utf8_ex2

Modified: subversion/branches/fs-py/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_diff/parse-diff.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_diff/parse-diff.c Mon Dec 19 18:49:34 2011
@@ -396,7 +396,7 @@ hunk_readline_original_or_modified(apr_f
       *eof = TRUE;
       if (eol)
         *eol = NULL;
-      *stringbuf = svn_stringbuf_create("", result_pool);
+      *stringbuf = svn_stringbuf_create_empty(result_pool);
       return SVN_NO_ERROR;
     }
 
@@ -490,7 +490,7 @@ svn_diff_hunk_readline_diff_text(svn_dif
       *eof = TRUE;
       if (eol)
         *eol = NULL;
-      *stringbuf = svn_stringbuf_create("", result_pool);
+      *stringbuf = svn_stringbuf_create_empty(result_pool);
       return SVN_NO_ERROR;
     }
 
@@ -590,11 +590,19 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
   svn_boolean_t eof, in_hunk, hunk_seen;
   apr_off_t pos, last_line;
   apr_off_t start, end;
+  apr_off_t original_end;
+  apr_off_t modified_end;
   svn_linenum_t original_lines;
   svn_linenum_t modified_lines;
   svn_linenum_t leading_context;
   svn_linenum_t trailing_context;
   svn_boolean_t changed_line_seen;
+  enum {
+    noise_line,
+    original_line,
+    modified_line,
+    context_line
+  } last_line_type;
   apr_pool_t *iterpool;
 
   *prop_operation = svn_diff_op_unchanged;
@@ -615,12 +623,17 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
   leading_context = 0;
   trailing_context = 0;
   changed_line_seen = FALSE;
+  original_end = 0;
+  modified_end = 0;
   *hunk = apr_pcalloc(result_pool, sizeof(**hunk));
 
   /* Get current seek position -- APR has no ftell() :( */
   pos = 0;
   SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, scratch_pool));
 
+  /* Start out assuming noise. */
+  last_line_type = noise_line;
+
   iterpool = svn_pool_create(scratch_pool);
   do
     {
@@ -632,17 +645,58 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
       SVN_ERR(readline(apr_file, &line, NULL, &eof, APR_SIZE_MAX,
                        iterpool, iterpool));
 
-      if (! eof)
-        {
-          /* Update line offset for next iteration. */
-          pos = 0;
-          SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, iterpool));
-        }
+      /* Update line offset for next iteration. */
+      pos = 0;
+      SVN_ERR(svn_io_file_seek(apr_file, APR_CUR, &pos, iterpool));
 
       /* Lines starting with a backslash are comments, such as
        * "\ No newline at end of file". */
       if (line->data[0] == '\\')
-        continue;
+        {
+          if (in_hunk &&
+              ((!*is_property &&
+                strcmp(line->data, "\\ No newline at end of file") == 0) ||
+               (*is_property &&
+                strcmp(line->data, "\\ No newline at end of property") == 0)))
+            {
+              char eolbuf[2];
+              apr_size_t len;
+              apr_off_t off;
+              apr_off_t hunk_text_end;
+
+              /* Comment terminates the hunk text and says the hunk text
+               * has no trailing EOL. Snip off trailing EOL which is part
+               * of the patch file but not part of the hunk text. */
+              off = last_line - 2;
+              SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &off, iterpool));
+              len = sizeof(eolbuf);
+              SVN_ERR(svn_io_file_read_full2(apr_file, eolbuf, len, &len,
+                                             &eof, iterpool));
+              if (eolbuf[0] == '\r' && eolbuf[1] == '\n')
+                hunk_text_end = last_line - 2;
+              else if (eolbuf[1] == '\n' || eolbuf[1] == '\r')
+                hunk_text_end = last_line - 1;
+              else
+                hunk_text_end = last_line;
+
+              if (last_line_type == original_line && original_end == 0)
+                original_end = hunk_text_end;
+              else if (last_line_type == modified_line && modified_end == 0)
+                modified_end = hunk_text_end;
+              else if (last_line_type == context_line)
+                {
+                  if (original_end == 0)
+                    original_end = hunk_text_end;
+                  if (modified_end == 0)
+                    modified_end = hunk_text_end;
+                  break;
+                }
+
+              SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &pos, iterpool));
+            }
+
+          continue;
+        }
 
       if (in_hunk)
         {
@@ -673,6 +727,7 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 trailing_context++;
               else
                 leading_context++;
+              last_line_type = context_line;
             }
           else if (original_lines > 0 && c == del)
             {
@@ -686,6 +741,7 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 trailing_context = 0;
 
               original_lines--;
+              last_line_type = original_line;
             }
           else if (modified_lines > 0 && c == add)
             {
@@ -699,13 +755,26 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 trailing_context = 0;
 
               modified_lines--;
+              last_line_type = modified_line;
             }
           else
             {
-              /* The start of the current line marks the first byte
-               * after the hunk text. */
-              end = last_line;
+              if (eof)
+                {
+                  /* The hunk ends at EOF. */
+                  end = pos;
+                }
+              else
+                {
+                  /* The start of the current line marks the first byte
+                   * after the hunk text. */
+                  end = last_line;
+                }
 
+              if (original_end == 0)
+                original_end = end;
+              if (modified_end == 0)
+                modified_end = end;
               break; /* Hunk was empty or has been read. */
             }
         }
@@ -785,10 +854,10 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
       (*hunk)->diff_text_range.end = end;
       (*hunk)->original_text_range.start = start;
       (*hunk)->original_text_range.current = start;
-      (*hunk)->original_text_range.end = end;
+      (*hunk)->original_text_range.end = original_end;
       (*hunk)->modified_text_range.start = start;
       (*hunk)->modified_text_range.current = start;
-      (*hunk)->modified_text_range.end = end;
+      (*hunk)->modified_text_range.end = modified_end;
     }
   else
     /* Something went wrong, just discard the result. */

Modified: subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.c Mon Dec 19 18:49:34 2011
@@ -265,9 +265,8 @@ svn_fs_initialize(apr_pool_t *pool)
     return SVN_NO_ERROR;
 
   common_pool = svn_pool_create(pool);
-#if APR_HAS_THREADS
   SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
-#endif
+
   /* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO
      ### (via libsvn_ra_local say) since the global common_pool will live
      ### longer than the DSO, which gets unloaded when the pool used to
@@ -425,16 +424,72 @@ svn_fs_delete_fs(const char *path, apr_p
 }
 
 svn_error_t *
-svn_fs_hotcopy(const char *src_path, const char *dest_path,
-               svn_boolean_t clean, apr_pool_t *pool)
+svn_fs_hotcopy2(const char *src_path, const char *dst_path,
+                svn_boolean_t clean, svn_boolean_t incremental,
+                svn_cancel_func_t cancel_func, void *cancel_baton,
+                apr_pool_t *scratch_pool)
 {
   fs_library_vtable_t *vtable;
-  const char *fs_type;
+  const char *src_fs_type;
+  svn_fs_t *src_fs;
+  svn_fs_t *dst_fs;
+  const char *dst_fs_type;
+  svn_node_kind_t dst_kind;
+
+  if (strcmp(src_path, dst_path) == 0)
+    return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                             _("Hotcopy source and destination are equal"));
+
+  SVN_ERR(svn_fs_type(&src_fs_type, src_path, scratch_pool));
+  SVN_ERR(get_library_vtable(&vtable, src_fs_type, scratch_pool));
+  src_fs = fs_new(NULL, scratch_pool);
+  dst_fs = fs_new(NULL, scratch_pool);
+
+  SVN_ERR(svn_io_check_path(dst_path, &dst_kind, scratch_pool));
+  if (dst_kind == svn_node_file)
+    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+                             _("'%s' already exists and is a file"),
+                             svn_dirent_local_style(dst_path,
+                                                    scratch_pool));
+  if (dst_kind == svn_node_unknown)
+    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+                             _("'%s' already exists and has an unknown "
+                               "node kind"),
+                             svn_dirent_local_style(dst_path,
+                                                    scratch_pool));
+  if (dst_kind == svn_node_dir)
+    {
+      svn_node_kind_t type_file_kind;
 
-  SVN_ERR(svn_fs_type(&fs_type, src_path, pool));
-  SVN_ERR(get_library_vtable(&vtable, fs_type, pool));
-  SVN_ERR(vtable->hotcopy(src_path, dest_path, clean, pool));
-  return svn_error_trace(write_fs_type(dest_path, fs_type, pool));
+      SVN_ERR(svn_io_check_path(svn_dirent_join(dst_path,
+                                                FS_TYPE_FILENAME,
+                                                scratch_pool),
+                                &type_file_kind, scratch_pool));
+      if (type_file_kind != svn_node_none)
+        {
+          SVN_ERR(svn_fs_type(&dst_fs_type, dst_path, scratch_pool));
+          if (strcmp(src_fs_type, dst_fs_type) != 0)
+            return svn_error_createf(
+                     SVN_ERR_ILLEGAL_TARGET, NULL,
+                     _("The filesystem type of the hotcopy source "
+                       "('%s') does not match the filesystem "
+                       "type of the hotcopy destination ('%s')"),
+                     src_fs_type, dst_fs_type);
+        }
+    }
+
+  SVN_ERR(vtable->hotcopy(src_fs, dst_fs, src_path, dst_path, clean,
+                          incremental, cancel_func, cancel_baton,
+                          scratch_pool));
+  return svn_error_trace(write_fs_type(dst_path, src_fs_type, scratch_pool));
+}
+
+svn_error_t *
+svn_fs_hotcopy(const char *src_path, const char *dest_path,
+               svn_boolean_t clean, apr_pool_t *pool)
+{
+  return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean,
+                                         FALSE, NULL, NULL, pool));
 }
 
 svn_error_t *
@@ -892,6 +947,21 @@ svn_fs_closest_copy(svn_fs_root_t **root
 }
 
 svn_error_t *
+svn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog,
+                      svn_fs_root_t *root,
+                      const apr_array_header_t *paths,
+                      svn_mergeinfo_inheritance_t inherit,
+                      svn_boolean_t include_descendants,
+                      svn_boolean_t adjust_inherited_mergeinfo,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(root->vtable->get_mergeinfo(
+    catalog, root, paths, inherit, include_descendants,
+    adjust_inherited_mergeinfo, result_pool, scratch_pool));
+}
+
+svn_error_t *
 svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
                      svn_fs_root_t *root,
                      const apr_array_header_t *paths,
@@ -902,7 +972,7 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catal
   return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths,
                                                      inherit,
                                                      include_descendants,
-                                                     pool));
+                                                     TRUE, pool, pool));
 }
 
 svn_error_t *

Modified: subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.h?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/fs-py/subversion/libsvn_fs/fs-loader.h Mon Dec 19 18:49:34 2011
@@ -93,8 +93,11 @@ typedef struct fs_library_vtable_t
                             apr_pool_t *pool,
                             apr_pool_t *common_pool);
   svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);
-  svn_error_t *(*hotcopy)(const char *src_path, const char *dest_path,
-                          svn_boolean_t clean, apr_pool_t *pool);
+  svn_error_t *(*hotcopy)(svn_fs_t *src_fs, svn_fs_t *dst_fs,
+                          const char *src_path, const char *dst_path,
+                          svn_boolean_t clean, svn_boolean_t incremental,
+                          svn_cancel_func_t cancel_func, void *cancel_baton,
+                          apr_pool_t *pool);
   const char *(*get_description)(void);
   svn_error_t *(*recover)(svn_fs_t *fs,
                           svn_cancel_func_t cancel_func, void *cancel_baton,
@@ -336,7 +339,9 @@ typedef struct root_vtable_t
                                 const apr_array_header_t *paths,
                                 svn_mergeinfo_inheritance_t inherit,
                                 svn_boolean_t include_descendants,
-                                apr_pool_t *pool);
+                                svn_boolean_t adjust_inherited_mergeinfo,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool);
 } root_vtable_t;
 
 

Modified: subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/changes-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/changes-table.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/changes-table.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/changes-table.c Mon Dec 19 18:49:34 2011
@@ -325,14 +325,14 @@ svn_fs_bdb__changes_fetch(apr_hash_t **c
               /* KEY is the path. */
               const void *hashkey;
               apr_ssize_t klen;
-              apr_hash_this(hi, &hashkey, &klen, NULL);
+              const char *child_relpath;
 
-              /* If we come across our own path, ignore it. */
-              if (strcmp(change->path, hashkey) == 0)
-                continue;
+              apr_hash_this(hi, &hashkey, &klen, NULL);
 
-              /* If we come across a child of our path, remove it. */
-              if (svn_fspath__is_child(change->path, hashkey, subpool))
+              /* If we come across our own path, ignore it.
+                 If we come across a child of our path, remove it. */
+              child_relpath = svn_fspath__skip_ancestor(change->path, hashkey);
+              if (child_relpath && *child_relpath)
                 apr_hash_set(changes, hashkey, klen, NULL);
             }
         }

Modified: subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/env.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/env.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/env.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/env.c Mon Dec 19 18:49:34 2011
@@ -379,7 +379,7 @@ bdb_init_cb(void *baton, apr_pool_t *poo
   bdb_cache_pool = svn_pool_create(pool);
   bdb_cache = apr_hash_make(bdb_cache_pool);
   
-  SVN_ERR(svn_mutex__init(&bdb_cache_lock, APR_HAS_THREADS, bdb_cache_pool));
+  SVN_ERR(svn_mutex__init(&bdb_cache_lock, TRUE, bdb_cache_pool));
   apr_pool_cleanup_register(bdb_cache_pool, NULL, clear_cache,
                             apr_pool_cleanup_null);
 

Modified: subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/locks-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/locks-table.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/locks-table.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_fs_base/bdb/locks-table.c Mon Dec 19 18:49:34 2011
@@ -207,6 +207,7 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
   svn_lock_t *lock;
   svn_error_t *err;
   const char *lookup_path = path;
+  apr_size_t lookup_len;
 
   /* First, try to lookup PATH itself. */
   err = svn_fs_bdb__lock_token_get(&lock_token, fs, path, trail, pool);
@@ -224,7 +225,12 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
     {
       SVN_ERR(get_lock(&lock, fs, path, lock_token, trail, pool));
       if (lock && get_locks_func)
-        SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
+        {
+          SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
+
+          /* Found a lock so PATH is a file and we can ignore depth */
+          return SVN_NO_ERROR;
+        }
     }
 
   /* If we're only looking at PATH itself (depth = empty), stop here. */
@@ -250,11 +256,13 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
 
   if (!svn_fspath__is_root(path, strlen(path)))
     lookup_path = apr_pstrcat(pool, path, "/", (char *)NULL);
+  lookup_len = strlen(lookup_path);
 
   /* As long as the prefix of the returned KEY matches LOOKUP_PATH we
      know it is either LOOKUP_PATH or a decendant thereof.  */
   while ((! db_err)
-         && strncmp(lookup_path, key.data, strlen(lookup_path)) == 0)
+         && lookup_len < key.size
+         && strncmp(lookup_path, key.data, lookup_len) == 0)
     {
       const char *child_path;
 
@@ -274,7 +282,7 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
              same set of results.  So just see if CHILD_PATH is an
              immediate child of PATH.  If not, we don't care about
              this item.   */
-          const char *rel_path = svn_fspath__is_child(path, child_path, subpool);
+          const char *rel_path = svn_fspath__skip_ancestor(path, child_path);
           if (!rel_path || (svn_path_component_count(rel_path) != 1))
             goto loop_it;
         }

Modified: subversion/branches/fs-py/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_fs_base/fs.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_fs_base/fs.c Mon Dec 19 18:49:34 2011
@@ -1165,9 +1165,14 @@ copy_db_file_safely(const char *src_dir,
 
 
 static svn_error_t *
-base_hotcopy(const char *src_path,
+base_hotcopy(svn_fs_t *src_fs,
+             svn_fs_t *dst_fs,
+             const char *src_path,
              const char *dest_path,
              svn_boolean_t clean_logs,
+             svn_boolean_t incremental,
+             svn_cancel_func_t cancel_func,
+             void *cancel_baton,
              apr_pool_t *pool)
 {
   svn_error_t *err;
@@ -1175,6 +1180,11 @@ base_hotcopy(const char *src_path,
   svn_boolean_t log_autoremove = FALSE;
   int format;
 
+  if (incremental)
+    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                             _("BDB repositories do not support incremental "
+                               "hotcopy"));
+
   /* Check the FS format number to be certain that we know how to
      hotcopy this FS.  Pre-1.2 filesystems did not have a format file (you
      could say they were format "0"), so we will error here.  This is not