You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pr...@apache.org on 2013/02/13 11:21:36 UTC

svn commit: r1445542 [2/16] - in /subversion/branches/verify-keep-going: ./ build/generator/ build/generator/swig/ build/generator/templates/ build/win32/ contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ notes/ notes/api-errata/1.7/ ...

Modified: subversion/branches/verify-keep-going/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/include/private/svn_wc_private.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/include/private/svn_wc_private.h (original)
+++ subversion/branches/verify-keep-going/subversion/include/private/svn_wc_private.h Wed Feb 13 10:21:33 2013
@@ -302,6 +302,12 @@ svn_wc__get_tree_conflict(const svn_wc_c
 /** Record the tree conflict described by @a conflict in the WC for
  * @a conflict->local_abspath.  Use @a scratch_pool for all temporary
  * allocations.
+ *
+ * Returns an SVN_ERR_WC_PATH_UNEXPECTED_STATUS error when
+ * CONFLICT->LOCAL_ABSPATH is already tree conflicted.
+ *
+ * ### This function can't set moved_away, moved_here conflicts for
+ *     any operation, except merges.
  */
 svn_error_t *
 svn_wc__add_tree_conflict(svn_wc_context_t *wc_ctx,
@@ -415,18 +421,21 @@ svn_wc__node_get_children(const apr_arra
 
 
 /**
- * Fetch the repository root information for the working version
- * of the node at @a local_abspath into @a *repos_root_url
- * and @a *repos_uuid. Use @a wc_ctx to access the working copy
- * for @a local_abspath, @a scratch_pool for all temporary allocations,
- * @a result_pool for result allocations. Note: the results will be NULL if
- * the node does not exist or is not under version control. If the node is
- * locally added, return the repository root it will have if committed.
+ * Fetch the repository information for the working version
+ * of the node at @a local_abspath into @a *revision, @a *repos_relpath,
+ * @a *repos_root_url and @a *repos_uuid. Use @a wc_ctx to access the working
+ * copy. Allocate results in @a result_pool.
  *
- * Either output argument may be NULL, indicating no interest.
+ * @a *revision will be set to SVN_INVALID_REVNUM for any shadowed node (including
+ * added and deleted nodes). All other output values will be set to the current
+ * values or those they would have after a commit.
+ *
+ * All output argument may be NULL, indicating no interest.
  */
 svn_error_t *
-svn_wc__node_get_repos_info(const char **repos_root_url,
+svn_wc__node_get_repos_info(svn_revnum_t *revision,
+                            const char **repos_relpath,
+                            const char **repos_root_url,
                             const char **repos_uuid,
                             svn_wc_context_t *wc_ctx,
                             const char *local_abspath,
@@ -517,22 +526,6 @@ svn_wc__node_get_origin(svn_boolean_t *i
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);
 
-
-/**
- * Set @a *repos_relpath to the corresponding repos_relpath for @a
- * local_abspath, using @a wc_ctx. If the node is added, return the
- * repos_relpath it will have in the repository.
- *
- * If @a local_abspath is not in the working copy, return @c
- * SVN_ERR_WC_PATH_NOT_FOUND.
- * */
-svn_error_t *
-svn_wc__node_get_repos_relpath(const char **repos_relpath,
-                               svn_wc_context_t *wc_ctx,
-                               const char *local_abspath,
-                               apr_pool_t *result_pool,
-                               apr_pool_t *scratch_pool);
-
 /**
  * Set @a *is_deleted to TRUE if @a local_abspath is deleted, using
  * @a wc_ctx.  If @a local_abspath is not in the working copy, return
@@ -620,14 +613,14 @@ svn_wc__node_has_working(svn_boolean_t *
 /**
  * Get the repository location of the base node at @a local_abspath.
  *
- * Set *REVISION, *REPOS_RELPATH, *REPOS_ROOT_URL and *REPOS_UUID to the
- * location that this node was checked out at or last updated/switched to,
- * regardless of any uncommitted changes (delete, replace and/or
- * copy-here/move-here).
+ * Set *REVISION, *REPOS_RELPATH, *REPOS_ROOT_URL *REPOS_UUID and *LOCK_TOKEN
+ * to the location that this node was checked out at or last updated/switched
+ * to, regardless of any uncommitted changes (delete, replace and/or copy-here/
+ * move-here).
  *
  * If there is no base node at @a local_abspath (such as when there is a
  * locally added/copied/moved-here node that is not part of a replace),
- * return @c SVN_INVALID_REVNUM/NULL/NULL/NULL.
+ * return @c SVN_INVALID_REVNUM/NULL/NULL/NULL/NULL.
  *
  * All output arguments may be NULL.
  *
@@ -639,6 +632,7 @@ svn_wc__node_get_base(svn_revnum_t *revi
                       const char **repos_relpath,
                       const char **repos_root_url,
                       const char **repos_uuid,
+                      const char **lock_token,
                       svn_wc_context_t *wc_ctx,
                       const char *local_abspath,
                       apr_pool_t *result_pool,
@@ -679,30 +673,6 @@ svn_wc__node_get_pre_ng_status_data(svn_
                                     apr_pool_t *scratch_pool);
 
 /**
- * Fetch lock information (if any) for @a local_abspath using @a wc_ctx:
- *
- *   Set @a *lock_token to the lock token (or NULL)
- *   Set @a *lock_owner to the owner of the lock (or NULL)
- *   Set @a *lock_comment to the comment associated with the lock (or NULL)
- *   Set @a *lock_date to the timestamp of the lock (or 0)
- *
- * Any of the aforementioned return values may be NULL to indicate
- * that the caller doesn't care about those values.
- *
- * If @a local_abspath is not in the working copy, return @c
- * SVN_ERR_WC_PATH_NOT_FOUND.
- */
-svn_error_t *
-svn_wc__node_get_lock_info(const char **lock_token,
-                           const char **lock_owner,
-                           const char **lock_comment,
-                           apr_time_t *lock_date,
-                           svn_wc_context_t *wc_ctx,
-                           const char *local_abspath,
-                           apr_pool_t *result_pool,
-                           apr_pool_t *scratch_pool);
-
-/**
  * Acquire a recursive write lock for @a local_abspath.  If @a lock_anchor
  * is true, determine if @a local_abspath has an anchor that should be locked
  * instead; otherwise, @a local_abspath must be a versioned directory.
@@ -1111,6 +1081,12 @@ svn_wc__get_not_present_descendants(cons
  * If DELETED is not NULL, set *DELETED to TRUE if the node is marked as
  * deleted in the working copy.
  *
+ * If EXCLUDED is not NULL, set *EXCLUDED to TRUE if the node is marked as
+ * user or server excluded.
+ *
+ * If PARENT_DEPTH is not NULL, set *PARENT_DEPTH to the depth stored on the
+ * parent. (Set to svn_depth_unknown if LOCAL_ABSPATH itself exists as node)
+ *
  * All output arguments except OBSTRUCTION_STATE can be NULL to ommit the
  * result.
  *
@@ -1120,6 +1096,8 @@ svn_error_t *
 svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
                                svn_node_kind_t *kind,
                                svn_boolean_t *deleted,
+                               svn_boolean_t *excluded,
+                               svn_depth_t *parent_depth,
                                svn_wc_context_t *wc_ctx,
                                const char *local_abspath,
                                svn_boolean_t no_wcroot_check,
@@ -1712,17 +1690,13 @@ typedef svn_error_t *
                                        apr_pool_t *scratch_pool);
 
 /** Obtains a diff processor that will drive the diff callbacks when it
- * is invoked. The state arguments will be handled by the state processor
- * or ignored if STATE_HANDLER is NULL
+ * is invoked.
  */
 svn_error_t *
-svn_wc__wrap_diff_callbacks(svn_diff_tree_processor_t **diff_processor,
+svn_wc__wrap_diff_callbacks(const svn_diff_tree_processor_t **diff_processor,
                             const svn_wc_diff_callbacks4_t *callbacks,
                             void *callback_baton,
-                            svn_wc__diff_state_handle_t state_handle,
-                            svn_wc__diff_state_close_t state_close,
-                            svn_wc__diff_state_absent_t state_absent,
-                            void *state_baton,
+                            svn_boolean_t walk_deleted_dirs,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool);
 

Modified: subversion/branches/verify-keep-going/subversion/include/svn_auth.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/include/svn_auth.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/include/svn_auth.h (original)
+++ subversion/branches/verify-keep-going/subversion/include/svn_auth.h Wed Feb 13 10:21:33 2013
@@ -590,19 +590,25 @@ svn_auth_get_parameter(svn_auth_baton_t 
 
 /** @brief Indicates whether providers may save passwords to disk in
  * plaintext. Property value can be either SVN_CONFIG_TRUE,
- * SVN_CONFIG_FALSE, or SVN_CONFIG_ASK. */
+ * SVN_CONFIG_FALSE, or SVN_CONFIG_ASK.
+ * @since New in 1.6.
+ */
 #define SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS  SVN_AUTH_PARAM_PREFIX \
                                                   "store-plaintext-passwords"
 
 /** @brief The application doesn't want any providers to save passphrase
  * to disk. Property value is irrelevant; only property's existence
- * matters. */
+ * matters.
+ * @since New in 1.6.
+ */
 #define SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP \
   SVN_AUTH_PARAM_PREFIX "dont-store-ssl-client-cert-pp"
 
 /** @brief Indicates whether providers may save passphrase to disk in
  * plaintext. Property value can be either SVN_CONFIG_TRUE,
- * SVN_CONFIG_FALSE, or SVN_CONFIG_ASK. */
+ * SVN_CONFIG_FALSE, or SVN_CONFIG_ASK.
+ * @since New in 1.6.
+ */
 #define SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT \
   SVN_AUTH_PARAM_PREFIX "store-ssl-client-cert-pp-plaintext"
 
@@ -769,6 +775,39 @@ svn_auth_get_simple_provider2(
   void *prompt_baton,
   apr_pool_t *pool);
 
+/** Callback for svn_auth_cleanup_walk().
+ *
+ * Called for each credential to allow selectively removing credentials.
+ *
+ * @a cred_kind and @a realmstring specify the key of the credential (see
+ * svn_auth_first_credentials()).
+ *
+ * @a provider specifies which provider currently holds the credential.
+ *
+ * Before returning set @a *delete_cred to TRUE to remove the credential from
+ * the cache.
+ *
+ * @since New in 1.8.
+ */
+typedef svn_error_t * (*svn_auth_cleanup_callback)(svn_boolean_t *delete_cred,
+                                                   void *cleanup_baton,
+                                                   const char *cred_kind,
+                                                   const char *realmstring,
+                                                   const char *provider,
+                                                   apr_pool_t *scratch_pool);
+
+/** Call @a cleanup with information describing each currently cached
+ * credential (in providers that support iterating). If the callback
+ * confirms that the credential should be deleted, delete it.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_auth_cleanup_walk(svn_auth_baton_t *auth_baton,
+                      svn_auth_cleanup_callback cleanup,
+                      void *cleanup_baton,
+                      apr_pool_t *scratch_pool);
+
 /** Like svn_auth_get_simple_provider2, but without the ability to
  * call the svn_auth_plaintext_prompt_func_t callback, and the provider
  * always assumes that it is allowed to store the password in plaintext.

Modified: subversion/branches/verify-keep-going/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/include/svn_client.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/include/svn_client.h (original)
+++ subversion/branches/verify-keep-going/subversion/include/svn_client.h Wed Feb 13 10:21:33 2013
@@ -367,7 +367,7 @@ typedef struct svn_client_proplist_item_
  *
  * The #svn_prop_inherited_item_t->path_or_url members of the
  * #svn_prop_inherited_item_t * structures in @a inherited_props are
- * URLs if @a path is a URL or if @path is a working copy path but the
+ * URLs if @a path is a URL or if @a path is a working copy path but the
  * property represented by the structure is above the working copy root (i.e.
  * the inherited property is from the cache).  In all other cases the
  * #svn_prop_inherited_item_t->path_or_url members are absolute working copy
@@ -4264,6 +4264,11 @@ svn_client_resolved(const char *path,
  *   - #svn_wc_conflict_choose_mine_conflict
  *     ###...
  *
+ *   - svn_wc_conflict_choose_unspecified
+ *     invoke @a ctx->conflict_func2 with @a ctx->conflict_baton2 to obtain
+ *     a resolution decision for each conflict.  This can be used to
+ *     implement interactive conflict resolution.
+ *
  * #svn_wc_conflict_choose_theirs_conflict and
  * #svn_wc_conflict_choose_mine_conflict are not legal for binary
  * files or properties.
@@ -4959,7 +4964,7 @@ svn_client_revprop_set(const char *propn
  *
  * The #svn_prop_inherited_item_t->path_or_url members of the
  * #svn_prop_inherited_item_t * structures in @a *inherited_props are
- * URLs if @a target is a URL or if @target is a working copy path but the
+ * URLs if @a target is a URL or if @a target is a working copy path but the
  * property represented by the structure is above the working copy root (i.e.
  * the inherited property is from the cache).  In all other cases the
  * #svn_prop_inherited_item_t->path_or_url members are absolute working copy

Modified: subversion/branches/verify-keep-going/subversion/include/svn_dav.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/include/svn_dav.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/include/svn_dav.h (original)
+++ subversion/branches/verify-keep-going/subversion/include/svn_dav.h Wed Feb 13 10:21:33 2013
@@ -198,6 +198,13 @@ extern "C" {
  * @since New in 1.8.   */
 #define SVN_DAV_ALLOW_BULK_UPDATES "SVN-Allow-Bulk-Updates"
 
+/** Assuming the request target is a Subversion repository resource,
+ * this header is returned in the OPTIONS response to indicate whether
+ * the repository supports the merge tracking feature ("yes") or not
+ * ("no").
+ * @since New in 1.8.  */
+#define SVN_DAV_REPOSITORY_MERGEINFO "SVN-Repository-MergeInfo"
+
 /**
  * @name Fulltext MD5 headers
  *

Modified: subversion/branches/verify-keep-going/subversion/include/svn_hash.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/include/svn_hash.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/include/svn_hash.h (original)
+++ subversion/branches/verify-keep-going/subversion/include/svn_hash.h Wed Feb 13 10:21:33 2013
@@ -240,6 +240,20 @@ svn_hash_from_cstring_keys(apr_hash_t **
                            const apr_array_header_t *keys,
                            apr_pool_t *pool);
 
+/* Shortcut for apr_hash_get() with a const char * key.
+ *
+ * @since New in 1.8.
+ */
+#define svn_hash_gets(ht, key) \
+            apr_hash_get(ht, key, APR_HASH_KEY_STRING)
+
+/* Shortcut for apr_hash_set() with a const char * key.
+ *
+ * @since New in 1.8.
+ */
+#define svn_hash_sets(ht, key, val) \
+            apr_hash_set(ht, key, APR_HASH_KEY_STRING, val)
+
 /** @} */
 
 /** @} */

Modified: subversion/branches/verify-keep-going/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/include/svn_repos.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/include/svn_repos.h (original)
+++ subversion/branches/verify-keep-going/subversion/include/svn_repos.h Wed Feb 13 10:21:33 2013
@@ -3210,7 +3210,8 @@ svn_repos_authz_read(svn_authz_t **authz
  * If @a path or @a groups_path is not a valid authz rule file, then return
  * #SVN_ERR_AUTHZ_INVALID_CONFIG.  The contents of @a *authz_p is then
  * undefined.  If @a must_exist is TRUE, a missing authz or groups file
- * is also an error.
+ * is also an error other than #SVN_ERR_AUTHZ_INVALID_CONFIG (exact error
+ * depends on the access type).
  *
  * If @a path is a repos relative URL then @a repos_root must be set to
  * the root of the repository the authz configuration will be used with.

Modified: subversion/branches/verify-keep-going/subversion/include/svn_wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/include/svn_wc.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/include/svn_wc.h (original)
+++ subversion/branches/verify-keep-going/subversion/include/svn_wc.h Wed Feb 13 10:21:33 2013
@@ -6794,10 +6794,20 @@ typedef enum svn_wc_merge_outcome_t
  * is returned in @a *merge_content_outcome.
  * ### (and what about @a *merge_props_state?)
  *
+ * ### BH: Two kinds of outcome is not how it should be.
+ *
+ * ### For text, we report the outcome as 'merged' if there was some
+ *     incoming change that we dealt with (even if we decided to no-op?)
+ *     but the callers then convert this outcome into a notification
+ *     of 'merged' only if there was already a local modification;
+ *     otherwise they notify it as simply 'updated'.  But for props
+ *     we report a notify state of 'merged' here if there was an
+ *     incoming change regardless of the local-mod state.  Inconsistent.
+ *
  * Use @a scratch_pool for any temporary allocation.
  *
  * @since New in 1.8.
- */ /* ### BH: Two kinds of outcome is not how it should be */
+ */
 svn_error_t *
 svn_wc_merge5(enum svn_wc_merge_outcome_t *merge_content_outcome,
               enum svn_wc_notify_state_t *merge_props_state,

Modified: subversion/branches/verify-keep-going/subversion/libsvn_client/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_client/blame.c?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_client/blame.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_client/blame.c Wed Feb 13 10:21:33 2013
@@ -79,7 +79,6 @@ struct file_rev_baton {
   const char *target;
   svn_client_ctx_t *ctx;
   const svn_diff_file_options_t *diff_options;
-  svn_boolean_t ignore_mime_type;
   /* name of file containing the previous revision of the file */
   const char *last_filename;
   struct rev *rev;     /* the rev for which blame is being assigned
@@ -383,27 +382,6 @@ window_handler(svn_txdelta_window_t *win
   return SVN_NO_ERROR;
 }
 
-/* Throw an SVN_ERR_CLIENT_IS_BINARY_FILE error if PROP_DIFFS indicates a
-   binary MIME type.  Else, return SVN_NO_ERROR. */
-static svn_error_t *
-check_mimetype(const apr_array_header_t *prop_diffs, const char *target,
-               apr_pool_t *pool)
-{
-  int i;
-
-  for (i = 0; i < prop_diffs->nelts; ++i)
-    {
-      const svn_prop_t *prop = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
-      if (strcmp(prop->name, SVN_PROP_MIME_TYPE) == 0
-          && prop->value
-          && svn_mime_type_is_binary(prop->value->data))
-        return svn_error_createf
-          (SVN_ERR_CLIENT_IS_BINARY_FILE, 0,
-           _("Cannot calculate blame information for binary file '%s'"),
-           svn_dirent_local_style(target, pool));
-    }
-  return SVN_NO_ERROR;
-}
 
 /* Calculate and record blame information for one revision of the file,
  * by comparing the file content against the previously seen revision.
@@ -432,10 +410,6 @@ file_rev_handler(void *baton, const char
   /* Clear the current pool. */
   svn_pool_clear(frb->currpool);
 
-  /* If this file has a non-textual mime-type, bail out. */
-  if (! frb->ignore_mime_type)
-    SVN_ERR(check_mimetype(prop_diffs, frb->target, frb->currpool));
-
   if (frb->ctx->notify_func2)
     {
       svn_wc_notify_t *notify
@@ -640,12 +614,43 @@ svn_client_blame5(const char *target,
       (SVN_ERR_CLIENT_BAD_REVISION, NULL,
        _("Start revision must precede end revision"));
 
+  /* We check the mime-type of the yougest revision before getting all
+     the older revisions. */
+  if (!ignore_mime_type)
+    {
+      apr_hash_t *props;
+      apr_hash_index_t *hi;
+
+      SVN_ERR(svn_client_propget5(&props, NULL, SVN_PROP_MIME_TYPE,
+                                  target_abspath_or_url,  peg_revision,
+                                  end, NULL, svn_depth_empty, NULL, ctx,
+                                  pool, pool));
+
+      /* props could be keyed on URLs or paths depending on the
+         peg_revision and end values so avoid using the key. */
+      hi = apr_hash_first(pool, props);
+      if (hi)
+        {
+          svn_string_t *value;
+
+          /* Should only be one value */
+          SVN_ERR_ASSERT(apr_hash_count(props) == 1);
+
+          value = svn__apr_hash_index_val(hi);
+          if (value && svn_mime_type_is_binary(value->data))
+            return svn_error_createf
+              (SVN_ERR_CLIENT_IS_BINARY_FILE, 0,
+               _("Cannot calculate blame information for binary file '%s'"),
+               (svn_path_is_url(target)
+                ? target : svn_dirent_local_style(target, pool)));
+        }
+    }
+
   frb.start_rev = start_revnum;
   frb.end_rev = end_revnum;
   frb.target = target;
   frb.ctx = ctx;
   frb.diff_options = diff_options;
-  frb.ignore_mime_type = ignore_mime_type;
   frb.include_merged_revisions = include_merged_revisions;
   frb.last_filename = NULL;
   frb.last_original_filename = NULL;

Modified: subversion/branches/verify-keep-going/subversion/libsvn_client/cleanup.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_client/cleanup.c?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_client/cleanup.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_client/cleanup.c Wed Feb 13 10:21:33 2013
@@ -38,7 +38,6 @@
 #include "svn_props.h"
 
 #include "svn_private_config.h"
-#include "private/svn_wc_private.h"
 
 
 /*** Code. ***/
@@ -62,308 +61,3 @@ svn_client_cleanup(const char *path,
   svn_io_sleep_for_timestamps(path, scratch_pool);
   return svn_error_trace(err);
 }
-
-
-/* callback baton for fetch_repos_info */
-struct repos_info_baton
-{
-  apr_pool_t *state_pool;
-  svn_client_ctx_t *ctx;
-  const char *last_repos;
-  const char *last_uuid;
-};
-
-/* svn_wc_upgrade_get_repos_info_t implementation for calling
-   svn_wc_upgrade() from svn_client_upgrade() */
-static svn_error_t *
-fetch_repos_info(const char **repos_root,
-                 const char **repos_uuid,
-                 void *baton,
-                 const char *url,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
-{
-  struct repos_info_baton *ri = baton;
-  apr_pool_t *subpool;
-  svn_ra_session_t *ra_session;
-
-  /* The same info is likely to retrieved multiple times (e.g. externals) */
-  if (ri->last_repos && svn_uri__is_ancestor(ri->last_repos, url))
-    {
-      *repos_root = apr_pstrdup(result_pool, ri->last_repos);
-      *repos_uuid = apr_pstrdup(result_pool, ri->last_uuid);
-      return SVN_NO_ERROR;
-    }
-
-  subpool = svn_pool_create(scratch_pool);
-
-  SVN_ERR(svn_client_open_ra_session(&ra_session, url, ri->ctx, subpool));
-
-  SVN_ERR(svn_ra_get_repos_root2(ra_session, repos_root, result_pool));
-  SVN_ERR(svn_ra_get_uuid2(ra_session, repos_uuid, result_pool));
-
-  /* Store data for further calls */
-  ri->last_repos = apr_pstrdup(ri->state_pool, *repos_root);
-  ri->last_uuid = apr_pstrdup(ri->state_pool, *repos_uuid);
-
-  svn_pool_destroy(subpool);
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_client_upgrade(const char *path,
-                   svn_client_ctx_t *ctx,
-                   apr_pool_t *scratch_pool)
-{
-  const char *local_abspath;
-  apr_hash_t *externals;
-  apr_hash_index_t *hi;
-  apr_pool_t *iterpool;
-  apr_pool_t *iterpool2;
-  svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
-  struct repos_info_baton info_baton;
-
-  info_baton.state_pool = scratch_pool;
-  info_baton.ctx = ctx;
-  info_baton.last_repos = NULL;
-  info_baton.last_uuid = NULL;
-
-  if (svn_path_is_url(path))
-    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
-                             _("'%s' is not a local path"), path);
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
-  SVN_ERR(svn_wc_upgrade(ctx->wc_ctx, local_abspath,
-                         fetch_repos_info, &info_baton,
-                         ctx->cancel_func, ctx->cancel_baton,
-                         ctx->notify_func2, ctx->notify_baton2,
-                         scratch_pool));
-
-  /* Now it's time to upgrade the externals too. We do it after the wc
-     upgrade to avoid that errors in the externals causes the wc upgrade to
-     fail. Thanks to caching the performance penalty of walking the wc a
-     second time shouldn't be too severe */
-  SVN_ERR(svn_client_propget5(&externals, NULL, SVN_PROP_EXTERNALS,
-                              local_abspath, &rev, &rev, NULL,
-                              svn_depth_infinity, NULL, ctx,
-                              scratch_pool, scratch_pool));
-
-  iterpool = svn_pool_create(scratch_pool);
-  iterpool2 = svn_pool_create(scratch_pool);
-
-  for (hi = apr_hash_first(scratch_pool, externals); hi;
-       hi = apr_hash_next(hi))
-    {
-      int i;
-      const char *externals_parent_abspath;
-      const char *externals_parent_url;
-      const char *externals_parent_repos_root_url;
-      const char *externals_parent = svn__apr_hash_index_key(hi);
-      svn_string_t *external_desc = svn__apr_hash_index_val(hi);
-      apr_array_header_t *externals_p;
-      svn_error_t *err;
-
-      svn_pool_clear(iterpool);
-      externals_p = apr_array_make(iterpool, 1,
-                                   sizeof(svn_wc_external_item2_t*));
-
-      /* In this loop, an error causes the respective externals definition, or
-       * the external (inner loop), to be skipped, so that upgrade carries on
-       * with the other externals. */
-
-      err = svn_dirent_get_absolute(&externals_parent_abspath,
-                                    externals_parent, iterpool);
-
-      if (!err)
-        err = svn_wc__node_get_url(&externals_parent_url, ctx->wc_ctx,
-                                   externals_parent_abspath,
-                                   iterpool, iterpool);
-      if (!err)
-        err = svn_wc__node_get_repos_info(&externals_parent_repos_root_url,
-                                          NULL,
-                                          ctx->wc_ctx,
-                                          externals_parent_abspath,
-                                          iterpool, iterpool);
-      if (!err)
-        err = svn_wc_parse_externals_description3(
-                  &externals_p, svn_dirent_dirname(path, iterpool),
-                  external_desc->data, FALSE, iterpool);
-      if (err)
-        {
-          svn_wc_notify_t *notify =
-              svn_wc_create_notify(externals_parent,
-                                   svn_wc_notify_failed_external,
-                                   scratch_pool);
-          notify->err = err;
-
-          ctx->notify_func2(ctx->notify_baton2,
-                            notify, scratch_pool);
-
-          svn_error_clear(err);
-
-          /* Next externals definition, please... */
-          continue;
-        }
-
-      for (i = 0; i < externals_p->nelts; i++)
-        {
-          svn_wc_external_item2_t *item;
-          const char *resolved_url;
-          const char *external_abspath;
-          const char *repos_relpath;
-          const char *repos_root_url;
-          const char *repos_uuid;
-          svn_node_kind_t external_kind;
-          svn_revnum_t peg_revision;
-          svn_revnum_t revision;
-
-          item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);
-
-          svn_pool_clear(iterpool2);
-          external_abspath = svn_dirent_join(externals_parent_abspath,
-                                             item->target_dir,
-                                             iterpool2);
-
-          err = svn_wc__resolve_relative_external_url(
-                                              &resolved_url,
-                                              item,
-                                              externals_parent_repos_root_url,
-                                              externals_parent_url,
-                                              scratch_pool, scratch_pool);
-          if (err)
-            goto handle_error;
-
-          /* This is a hack. We only need to call svn_wc_upgrade() on external
-           * dirs, as file externals are upgraded along with their defining
-           * WC.  Reading the kind will throw an exception on an external dir,
-           * saying that the wc must be upgraded.  If it's a file, the lookup
-           * is done in an adm_dir belonging to the defining wc (which has
-           * already been upgraded) and no error is returned.  If it doesn't
-           * exist (external that isn't checked out yet), we'll just get
-           * svn_node_none. */
-          err = svn_wc_read_kind(&external_kind, ctx->wc_ctx,
-                                 external_abspath, FALSE, iterpool2);
-          if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
-            {
-              svn_error_clear(err);
-
-              err = svn_client_upgrade(external_abspath, ctx, iterpool2);
-              if (err)
-                goto handle_error;
-            }
-          else if (err)
-            goto handle_error;
-
-          /* The upgrade of any dir should be done now, get the now reliable
-           * kind. */
-          err = svn_wc_read_kind(&external_kind, ctx->wc_ctx, external_abspath,
-                                 FALSE, iterpool2);
-          if (err)
-            goto handle_error;
-
-          /* Update the EXTERNALS table according to the root URL,
-           * relpath and uuid known in the upgraded external WC. */
-
-          /* We should probably have a function that provides all three
-           * of root URL, repos relpath and uuid at once, but here goes... */
-
-          /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
-           * when the node is not present in the file system.
-           * svn_wc__node_get_repos_info() would try to derive the URL. */
-          err = svn_wc__node_get_repos_relpath(&repos_relpath,
-                                               ctx->wc_ctx,
-                                               external_abspath,
-                                               iterpool2, iterpool2);
-          if (! err)
-            {
-              /* We got a repos relpath from a WC. So also get the root. */
-              err = svn_wc__node_get_repos_info(&repos_root_url,
-                                                &repos_uuid,
-                                                ctx->wc_ctx,
-                                                external_abspath,
-                                                iterpool2, iterpool2);
-              if (err)
-                goto handle_error;
-            }
-          else if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-            {
-              /* The external is not currently checked out. Try to figure out
-               * the URL parts via the defined URL and fetch_repos_info(). */
-              svn_error_clear(err);
-              repos_relpath = NULL;
-              repos_root_url = NULL;
-              repos_uuid = NULL;
-            }
-          else if (err)
-            goto handle_error;
-
-          /* If we haven't got any information from the checked out external,
-           * or if the URL information mismatches the external's definition,
-           * ask fetch_repos_info() to find out the repos root. */
-          if (! repos_relpath || ! repos_root_url
-              || 0 != strcmp(resolved_url,
-                             svn_path_url_add_component2(repos_root_url,
-                                                         repos_relpath,
-                                                         scratch_pool)))
-            {
-              err = fetch_repos_info(&repos_root_url,
-                                     &repos_uuid,
-                                     &info_baton,
-                                     resolved_url,
-                                     scratch_pool, scratch_pool);
-              if (err)
-                goto handle_error;
-
-              repos_relpath = svn_uri_skip_ancestor(repos_root_url,
-                                                    resolved_url,
-                                                    iterpool2);
-
-              /* There's just the URL, no idea what kind the external is.
-               * That's fine, as the external isn't even checked out yet.
-               * The kind will be set during the next 'update'. */
-              external_kind = svn_node_unknown;
-            }
-
-          if (err)
-            goto handle_error;
-
-          peg_revision = (item->peg_revision.kind == svn_opt_revision_number
-                          ? item->peg_revision.value.number
-                          : SVN_INVALID_REVNUM);
-
-          revision = (item->revision.kind == svn_opt_revision_number
-                      ? item->revision.value.number
-                      : SVN_INVALID_REVNUM);
-
-          err = svn_wc__upgrade_add_external_info(ctx->wc_ctx,
-                                                  external_abspath,
-                                                  external_kind,
-                                                  externals_parent,
-                                                  repos_relpath,
-                                                  repos_root_url,
-                                                  repos_uuid,
-                                                  peg_revision,
-                                                  revision,
-                                                  iterpool2);
-handle_error:
-          if (err)
-            {
-              svn_wc_notify_t *notify =
-                  svn_wc_create_notify(external_abspath,
-                                       svn_wc_notify_failed_external,
-                                       scratch_pool);
-              notify->err = err;
-              ctx->notify_func2(ctx->notify_baton2,
-                                notify, scratch_pool);
-              svn_error_clear(err);
-              /* Next external node, please... */
-            }
-        }
-    }
-
-  svn_pool_destroy(iterpool);
-  svn_pool_destroy(iterpool2);
-
-  return SVN_NO_ERROR;
-}

Modified: subversion/branches/verify-keep-going/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_client/client.h?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_client/client.h (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_client/client.h Wed Feb 13 10:21:33 2013
@@ -37,6 +37,7 @@
 
 #include "private/svn_magic.h"
 #include "private/svn_client_private.h"
+#include "private/svn_diff_tree.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -709,40 +710,27 @@ svn_client__get_inheritable_props(apr_ha
    is being driven. REVISION is the revision number of the 'old' side of
    the diff.
 
-   For each deleted directory, if WALK_DELETED_DIRS is true then just call
-   the 'dir_deleted' callback once, otherwise call the 'file_deleted' or
-   'dir_deleted' callback for each individual node in that subtree.
-
    If TEXT_DELTAS is FALSE, then do not expect text deltas from the edit
    drive, nor send the 'before' and 'after' texts to the diff callbacks;
    instead, send empty files to the diff callbacks if there was a change.
    This must be FALSE if the edit producer is not sending text deltas,
    otherwise the file content checksum comparisons will fail.
 
-   If NOTIFY_FUNC is non-null, invoke it with NOTIFY_BATON for each
-   file and directory operated on during the edit.
-
-   If ABSENT_RELPATHS is non-null, collect const char * keys in it with
-   the relative paths marked as absent by the diff driver.
+   EDITOR/EDIT_BATON return the newly created editor and baton.
 
-   EDITOR/EDIT_BATON return the newly created editor and baton. */
+   @since New in 1.8.
+   */
 svn_error_t *
-svn_client__get_diff_editor(const svn_delta_editor_t **editor,
-                            void **edit_baton,
-                            svn_depth_t depth,
-                            svn_ra_session_t *ra_session,
-                            svn_revnum_t revision,
-                            svn_boolean_t walk_deleted_dirs,
-                            svn_boolean_t text_deltas,
-                            apr_hash_t *absent_relpaths,
-                            const svn_wc_diff_callbacks4_t *diff_callbacks,
-                            void *diff_cmd_baton,
-                            svn_cancel_func_t cancel_func,
-                            void *cancel_baton,
-                            svn_wc_notify_func2_t notify_func,
-                            void *notify_baton,
-                            apr_pool_t *result_pool);
-
+svn_client__get_diff_editor2(const svn_delta_editor_t **editor,
+                             void **edit_baton,
+                             svn_ra_session_t *ra_session,
+                             svn_depth_t depth,
+                             svn_revnum_t revision,
+                             svn_boolean_t text_deltas,
+                             const svn_diff_tree_processor_t *processor,
+                             svn_cancel_func_t cancel_func,
+                             void *cancel_baton,
+                             apr_pool_t *result_pool);
 
 /* ---------------------------------------------------------------- */
 

Modified: subversion/branches/verify-keep-going/subversion/libsvn_client/commit_util.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_client/commit_util.c?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_client/commit_util.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_client/commit_util.c Wed Feb 13 10:21:33 2013
@@ -765,7 +765,7 @@ harvest_status_callback(void *status_bat
       svn_revnum_t dir_rev;
 
       if (!copy_mode_root && !status->switched)
-        SVN_ERR(svn_wc__node_get_base(&dir_rev, NULL, NULL, NULL, wc_ctx,
+        SVN_ERR(svn_wc__node_get_base(&dir_rev, NULL, NULL, NULL, NULL, wc_ctx,
                                       svn_dirent_dirname(local_abspath,
                                                          scratch_pool),
                                       scratch_pool, scratch_pool));
@@ -1239,7 +1239,8 @@ harvest_copy_committables(void *baton, v
   /* Read the entry for this SRC. */
   SVN_ERR_ASSERT(svn_dirent_is_absolute(pair->src_abspath_or_url));
 
-  SVN_ERR(svn_wc__node_get_repos_info(&repos_root_url, NULL, btn->ctx->wc_ctx,
+  SVN_ERR(svn_wc__node_get_repos_info(NULL, NULL, &repos_root_url, NULL,
+                                      btn->ctx->wc_ctx,
                                       pair->src_abspath_or_url,
                                       pool, pool));
 

Modified: subversion/branches/verify-keep-going/subversion/libsvn_client/delete.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_client/delete.c?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_client/delete.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_client/delete.c Wed Feb 13 10:21:33 2013
@@ -79,7 +79,14 @@ find_undeletables(void *baton,
     return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
                              _("'%s' is not under version control"),
                              svn_dirent_local_style(local_abspath, pool));
-
+  else if ((status->node_status == svn_wc_status_added
+            || status->node_status == svn_wc_status_replaced)
+           && status->text_status == svn_wc_status_normal
+           && (status->prop_status == svn_wc_status_normal
+               || status->prop_status == svn_wc_status_none))
+    {
+      /* Unmodified copy. Go ahead, remove it */
+    }
   else if (status->node_status != svn_wc_status_normal
            && status->node_status != svn_wc_status_deleted
            && status->node_status != svn_wc_status_missing)

Modified: subversion/branches/verify-keep-going/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_client/deprecated.c?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_client/deprecated.c Wed Feb 13 10:21:33 2013
@@ -2785,7 +2785,8 @@ svn_client_uuid_from_path2(const char **
                            apr_pool_t *scratch_pool)
 {
   return svn_error_trace(
-    svn_wc__node_get_repos_info(NULL, uuid, ctx->wc_ctx, local_abspath,
+      svn_client_get_repos_root(NULL, uuid,
+                                local_abspath, ctx,
                                 result_pool, scratch_pool));
 }
 

Modified: subversion/branches/verify-keep-going/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/verify-keep-going/subversion/libsvn_client/diff.c?rev=1445542&r1=1445541&r2=1445542&view=diff
==============================================================================
--- subversion/branches/verify-keep-going/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/verify-keep-going/subversion/libsvn_client/diff.c Wed Feb 13 10:21:33 2013
@@ -50,6 +50,7 @@
 
 #include "private/svn_wc_private.h"
 #include "private/svn_diff_private.h"
+#include "private/svn_subr_private.h"
 
 #include "svn_private_config.h"
 
@@ -92,9 +93,9 @@ make_repos_relpath(const char **repos_re
                                                       scratch_pool),
                                       scratch_pool));
 
-      err = svn_wc__node_get_repos_relpath(repos_relpath, wc_ctx,
-                                           local_abspath,
-                                           result_pool, scratch_pool);
+      err = svn_wc__node_get_repos_info(NULL, repos_relpath, NULL, NULL,
+                                        wc_ctx, local_abspath,
+                                        result_pool, scratch_pool);
 
       if (!ra_session
           || ! err
@@ -594,6 +595,12 @@ struct diff_cmd_baton {
   /* Whether deletion of a file is summarized versus showing a full diff. */
   svn_boolean_t no_diff_deleted;
 
+  /* Whether to ignore copyfrom information when showing adds */
+  svn_boolean_t no_copyfrom_on_add;
+
+  /* Empty files for creating diffs or NULL if not used yet */
+  const char *empty_file;
+
   svn_wc_context_t *wc_ctx;
 
   /* The RA session used during diffs involving the repository. */
@@ -996,6 +1003,30 @@ diff_file_added(svn_wc_notify_state_t *c
         rev2 = diff_cmd_baton->revnum2;
     }
 
+  if (diff_cmd_baton->no_copyfrom_on_add
+      && (copyfrom_path || SVN_IS_VALID_REVNUM(copyfrom_revision)))
+    {
+      apr_hash_t *empty_hash = apr_hash_make(scratch_pool);
+      apr_array_header_t *new_changes;
+
+      /* Rebase changes on having no left source. */
+      if (!diff_cmd_baton->empty_file)
+        SVN_ERR(svn_io_open_unique_file3(NULL, &diff_cmd_baton->empty_file,
+                                         NULL, svn_io_file_del_on_pool_cleanup,
+                                         diff_cmd_baton->pool, scratch_pool));
+
+      SVN_ERR(svn_prop_diffs(&new_changes,
+                             svn_prop__patch(original_props, prop_changes,
+                                             scratch_pool),
+                             empty_hash,
+                             scratch_pool));
+
+      tmpfile1 = diff_cmd_baton->empty_file;
+      prop_changes = new_changes;
+      original_props = empty_hash;
+      copyfrom_revision = SVN_INVALID_REVNUM;
+    }
+
   if (diff_cmd_baton->no_diff_added)
     {
       const char *index_path = diff_relpath;
@@ -1192,37 +1223,6 @@ static const svn_wc_diff_callbacks4_t di
    the user specifies two dates that resolve to the same revision.  */
 
 
-
-
-/* Helper function: given a working-copy ABSPATH_OR_URL, return its
-   associated url in *URL, allocated in RESULT_POOL.  If ABSPATH_OR_URL is
-   *already* a URL, that's fine, return ABSPATH_OR_URL allocated in
-   RESULT_POOL.
-
-   Use SCRATCH_POOL for temporary allocations. */
-static svn_error_t *
-convert_to_url(const char **url,
-               svn_wc_context_t *wc_ctx,
-               const char *abspath_or_url,
-               apr_pool_t *result_pool,
-               apr_pool_t *scratch_pool)
-{
-  if (svn_path_is_url(abspath_or_url))
-    {
-      *url = apr_pstrdup(result_pool, abspath_or_url);
-      return SVN_NO_ERROR;
-    }
-
-  SVN_ERR(svn_wc__node_get_url(url, wc_ctx, abspath_or_url,
-                               result_pool, scratch_pool));
-  if (! *url)
-    return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
-                             _("Path '%s' has no URL"),
-                             svn_dirent_local_style(abspath_or_url,
-                                                    scratch_pool));
-  return SVN_NO_ERROR;
-}
-
 /** Check if paths PATH_OR_URL1 and PATH_OR_URL2 are urls and if the
  * revisions REVISION1 and REVISION2 are local. If PEG_REVISION is not
  * unspecified, ensure that at least one of the two revisions is not
@@ -1384,24 +1384,25 @@ diff_prepare_repos_repos(const char **ur
 {
   const char *abspath_or_url2;
   const char *abspath_or_url1;
+  const char *repos_root_url;
 
   if (!svn_path_is_url(path_or_url2))
-    SVN_ERR(svn_dirent_get_absolute(&abspath_or_url2, path_or_url2,
-                                    pool));
+    {
+      SVN_ERR(svn_dirent_get_absolute(&abspath_or_url2, path_or_url2, pool));
+      SVN_ERR(svn_wc__node_get_url(url2, ctx->wc_ctx, abspath_or_url2,
+                                   pool, pool));
+    }
   else
-    abspath_or_url2 = path_or_url2;
+    *url2 = abspath_or_url2 = apr_pstrdup(pool, path_or_url2);
 
   if (!svn_path_is_url(path_or_url1))
-    SVN_ERR(svn_dirent_get_absolute(&abspath_or_url1, path_or_url1,
-                                    pool));
+    {
+      SVN_ERR(svn_dirent_get_absolute(&abspath_or_url1, path_or_url1, pool));
+      SVN_ERR(svn_wc__node_get_url(url1, ctx->wc_ctx, abspath_or_url1,
+                                   pool, pool));
+    }
   else
-    abspath_or_url1 = path_or_url1;
-
-  /* Figure out URL1 and URL2. */
-  SVN_ERR(convert_to_url(url1, ctx->wc_ctx, abspath_or_url1,
-                         pool, pool));
-  SVN_ERR(convert_to_url(url2, ctx->wc_ctx, abspath_or_url2,
-                         pool, pool));
+    *url1 = abspath_or_url1 = apr_pstrdup(pool, path_or_url1);
 
   /* We need exactly one BASE_PATH, so we'll let the BASE_PATH
      calculated for PATH_OR_URL2 override the one for PATH_OR_URL1
@@ -1488,18 +1489,23 @@ diff_prepare_repos_repos(const char **ur
   else if (*kind2 == svn_node_none)
     SVN_ERR(check_diff_target_exists(*url2, *rev1, *rev2, *ra_session, pool));
 
+  SVN_ERR(svn_ra_get_repos_root2(*ra_session, &repos_root_url, pool));
+
   /* Choose useful anchors and targets for our two URLs. */
   *anchor1 = *url1;
   *anchor2 = *url2;
   *target1 = "";
   *target2 = "";
 
-  /* If one of the targets is a file, use the parent directory as anchor. */
-  if (*kind1 == svn_node_file || *kind2 == svn_node_file)
+  /* If none of the targets is the repository root open the parent directory
+     to allow describing replacement of the target itself */
+  if (strcmp(*url1, repos_root_url) != 0
+      && strcmp(*url2, repos_root_url) != 0)
     {
       svn_uri_split(anchor1, target1, *url1, pool);
       svn_uri_split(anchor2, target2, *url2, pool);
-      if (*base_path)
+      if (*base_path
+          && (*kind1 == svn_node_file || *kind2 == svn_node_file))
         *base_path = svn_dirent_dirname(*base_path, pool);
       SVN_ERR(svn_ra_reparent(*ra_session, *anchor1, pool));
     }
@@ -1630,300 +1636,6 @@ diff_wc_wc(const char *path1,
   return SVN_NO_ERROR;
 }
 
-/* Create an array of regular properties in PROP_HASH, filtering entry-props
- * and wc-props. Allocate the returned array in RESULT_POOL.
- * Use SCRATCH_POOL for temporary allocations. */
-static apr_array_header_t *
-make_regular_props_array(apr_hash_t *prop_hash,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool)
-{
-  apr_array_header_t *regular_props;
-  apr_hash_index_t *hi;
-
-  regular_props = apr_array_make(result_pool, 0, sizeof(svn_prop_t));
-  for (hi = apr_hash_first(scratch_pool, prop_hash); hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *name = svn__apr_hash_index_key(hi);
-      svn_string_t *value = svn__apr_hash_index_val(hi);
-      svn_prop_kind_t prop_kind = svn_property_kind2(name);
-
-      if (prop_kind == svn_prop_regular_kind)
-        {
-          svn_prop_t *prop = apr_palloc(scratch_pool, sizeof(svn_prop_t));
-
-          prop->name = name;
-          prop->value = value;
-          APR_ARRAY_PUSH(regular_props, svn_prop_t) = *prop;
-        }
-    }
-
-  return regular_props;
-}
-
-/* Create a hash of regular properties from PROP_HASH, filtering entry-props
- * and wc-props. Allocate the returned hash in RESULT_POOL.
- * Use SCRATCH_POOL for temporary allocations. */
-static apr_hash_t *
-make_regular_props_hash(apr_hash_t *prop_hash,
-                        apr_pool_t *result_pool,
-                        apr_pool_t *scratch_pool)
-{
-  apr_hash_t *regular_props;
-  apr_hash_index_t *hi;
-
-  regular_props = apr_hash_make(result_pool);
-  for (hi = apr_hash_first(scratch_pool, prop_hash); hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *name = svn__apr_hash_index_key(hi);
-      svn_string_t *value = svn__apr_hash_index_val(hi);
-      svn_prop_kind_t prop_kind = svn_property_kind2(name);
-
-      if (prop_kind == svn_prop_regular_kind)
-        apr_hash_set(regular_props, name, APR_HASH_KEY_STRING, value);
-    }
-
-  return regular_props;
-}
-
-/* Handle an added or deleted diff target file for a repos<->repos diff.
- *
- * Using the provided diff CALLBACKS and the CALLBACK_BATON, show the file
- * TARGET@PEG_REVISION as added or deleted, depending on SHOW_DELETION.
- * TARGET is a path relative to RA_SESSION's URL.
- * REV1 and REV2 are the revisions being compared.
- * Use SCRATCH_POOL for temporary allocations. */
-static svn_error_t *
-diff_repos_repos_added_or_deleted_file(const char *target,
-                                       svn_revnum_t peg_revision,
-                                       svn_revnum_t rev1,
-                                       svn_revnum_t rev2,
-                                       svn_boolean_t show_deletion,
-                                      const char *empty_file,
-                                       const svn_wc_diff_callbacks4_t
-                                         *callbacks,
-                                       struct diff_cmd_baton *callback_baton,
-                                       svn_ra_session_t *ra_session,
-                                       apr_pool_t *scratch_pool)
-{
-  const char *file_abspath;
-  svn_stream_t *content;
-  apr_hash_t *prop_hash;
-
-  SVN_ERR(svn_stream_open_unique(&content, &file_abspath, NULL,
-                                 svn_io_file_del_on_pool_cleanup,
-                                 scratch_pool, scratch_pool));
-  SVN_ERR(svn_ra_get_file(ra_session, target, peg_revision, content, NULL,
-                          &prop_hash, scratch_pool));
-  SVN_ERR(svn_stream_close(content));
-
-  if (show_deletion)
-    {
-      SVN_ERR(callbacks->file_deleted(NULL, NULL,
-                                      target, file_abspath, empty_file,
-                                      apr_hash_get(prop_hash,
-                                                   SVN_PROP_MIME_TYPE,
-                                                   APR_HASH_KEY_STRING),
-                                      NULL,
-                                      make_regular_props_hash(
-                                        prop_hash, scratch_pool, scratch_pool),
-                                      callback_baton, scratch_pool));
-    }
-  else
-    {
-      SVN_ERR(callbacks->file_added(NULL, NULL, NULL,
-                                    target, empty_file, file_abspath,
-                                    rev1, rev2, NULL,
-                                    apr_hash_get(prop_hash, SVN_PROP_MIME_TYPE,
-                                                 APR_HASH_KEY_STRING),
-                                    NULL, SVN_INVALID_REVNUM,
-                                    make_regular_props_array(prop_hash,
-                                                             scratch_pool,
-                                                             scratch_pool),
-                                    NULL, callback_baton, scratch_pool));
-    }
-    
-  return SVN_NO_ERROR;
-}
-
-/* Handle an added or deleted diff target directory for a repos<->repos diff.
- *
- * Using the provided diff CALLBACKS and the CALLBACK_BATON, show the
- * directory TARGET@PEG_REVISION, and all of its children, as added or deleted,
- * depending on SHOW_DELETION. TARGET is a path relative to RA_SESSION's URL.
- * REV1 and REV2 are the revisions being compared.
- * Use SCRATCH_POOL for temporary allocations. */
-static svn_error_t *
-diff_repos_repos_added_or_deleted_dir(const char *target,
-                                      svn_revnum_t revision,
-                                      svn_revnum_t rev1,
-                                      svn_revnum_t rev2,
-                                      svn_boolean_t show_deletion,
-                                      const char *empty_file,
-                                      const svn_wc_diff_callbacks4_t
-                                        *callbacks,
-                                      struct diff_cmd_baton *callback_baton,
-                                      svn_ra_session_t *ra_session,
-                                      apr_pool_t *scratch_pool)
-{
-  apr_hash_t *dirents;
-  apr_hash_t *props;
-  apr_pool_t *iterpool;
-  apr_hash_index_t *hi;
-
-  SVN_ERR(svn_ra_get_dir2(ra_session, &dirents, NULL, &props,
-                          target, revision, SVN_DIRENT_KIND,
-                          scratch_pool));
-
-  if (show_deletion)
-    SVN_ERR(callbacks->dir_deleted(NULL, NULL, target, callback_baton,
-                                   scratch_pool));
-  else
-    SVN_ERR(callbacks->dir_added(NULL, NULL, NULL, NULL,
-                                 target, revision,
-                                 NULL, SVN_INVALID_REVNUM,
-                                 callback_baton, scratch_pool));
-  if (props)
-    {
-      if (show_deletion)
-        SVN_ERR(callbacks->dir_props_changed(NULL, NULL, target, FALSE,
-                                             apr_array_make(scratch_pool, 0,
-                                                            sizeof(svn_prop_t)),
-                                             make_regular_props_hash(
-                                               props, scratch_pool,
-                                               scratch_pool),
-                                             callback_baton, scratch_pool));
-      else
-        SVN_ERR(callbacks->dir_props_changed(NULL, NULL, target, TRUE,
-                                             make_regular_props_array(
-                                               props, scratch_pool,
-                                               scratch_pool),
-                                             NULL,
-                                             callback_baton, scratch_pool));
-    }
-
-  iterpool = svn_pool_create(scratch_pool);
-  for (hi = apr_hash_first(scratch_pool, dirents); hi; hi = apr_hash_next(hi))
-    {
-      const char *name = svn__apr_hash_index_key(hi);
-      svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
-      const char *child_target;
-
-      svn_pool_clear(iterpool);
-
-      child_target = svn_relpath_join(target, name, iterpool);
-
-      if (dirent->kind == svn_node_dir)
-        SVN_ERR(diff_repos_repos_added_or_deleted_dir(child_target,
-                                                      revision, rev1, rev2,
-                                                      show_deletion,
-                                                      empty_file,
-                                                      callbacks,
-                                                      callback_baton,
-                                                      ra_session,
-                                                      iterpool));
-      else if (dirent->kind == svn_node_file)
-        SVN_ERR(diff_repos_repos_added_or_deleted_file(child_target,
-                                                       revision, rev1, rev2,
-                                                       show_deletion,
-                                                       empty_file,
-                                                       callbacks,
-                                                       callback_baton,
-                                                       ra_session,
-                                                       iterpool));
-    }
-  svn_pool_destroy(iterpool);
-
-  if (!show_deletion)
-    SVN_ERR(callbacks->dir_closed(NULL, NULL, NULL, target, TRUE,
-                                  callback_baton, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
-
-/* Handle an added or deleted diff target for a repos<->repos diff.
- *
- * Using the provided diff CALLBACKS and the CALLBACK_BATON, show
- * TARGET@PEG_REVISION, and all of its children, if any, as added or deleted.
- * TARGET is a path relative to RA_SESSION's URL.
- * REV1 and REV2 are the revisions being compared.
- * Use SCRATCH_POOL for temporary allocations. */
-static svn_error_t *
-diff_repos_repos_added_or_deleted_target(const char *target1,
-                                         const char *target2,
-                                         svn_revnum_t rev1,
-                                         svn_revnum_t rev2,
-                                         svn_node_kind_t kind1,
-                                         svn_node_kind_t kind2,
-                                         const svn_wc_diff_callbacks4_t
-                                           *callbacks,
-                                         struct diff_cmd_baton *callback_baton,
-                                         svn_ra_session_t *ra_session,
-                                         apr_pool_t *scratch_pool)
-{
-  const char *existing_target;
-  svn_revnum_t existing_rev;
-  svn_node_kind_t existing_kind;
-  svn_boolean_t show_deletion;
-  const char *empty_file;
-
-  SVN_ERR_ASSERT(kind1 == svn_node_none || kind2 == svn_node_none);
-
-  /* Are we showing an addition or deletion? */
-  show_deletion = (kind2 == svn_node_none);
-
-  /* Which target is being added/deleted? Is it a file or a directory? */
-  if (show_deletion)
-    {
-      existing_target = target1;
-      existing_rev = rev1;
-      existing_kind = kind1;
-    }
-  else
-    {
-      existing_target = target2;
-      existing_rev = rev2;
-      existing_kind = kind2;
-    }
-
-  /* All file content will be diffed against the empty file. */
-  SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file, NULL,
-                                   svn_io_file_del_on_pool_cleanup,
-                                   scratch_pool, scratch_pool));
-
-  if (existing_kind == svn_node_file)
-    {
-      /* Get file content and show a diff against the empty file. */
-      SVN_ERR(diff_repos_repos_added_or_deleted_file(existing_target,
-                                                     existing_rev,
-                                                     rev1, rev2,
-                                                     show_deletion,
-                                                     empty_file,
-                                                     callbacks,
-                                                     callback_baton,
-                                                     ra_session,
-                                                     scratch_pool));
-    }
-  else
-    {
-      /* Walk the added/deleted tree and show a diff for each child. */
-      SVN_ERR(diff_repos_repos_added_or_deleted_dir(existing_target,
-                                                    existing_rev,
-                                                    rev1, rev2,
-                                                    show_deletion,
-                                                    empty_file,
-                                                    callbacks,
-                                                    callback_baton,
-                                                    ra_session,
-                                                    scratch_pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* Perform a diff between two repository paths.
 
    PATH_OR_URL1 and PATH_OR_URL2 may be either URLs or the working copy paths.
@@ -1954,6 +1666,8 @@ diff_repos_repos(const svn_wc_diff_callb
   const svn_delta_editor_t *diff_editor;
   void *diff_edit_baton;
 
+  const svn_diff_tree_processor_t *diff_processor;
+
   const char *url1;
   const char *url2;
   const char *base_path;
@@ -1975,6 +1689,14 @@ diff_repos_repos(const svn_wc_diff_callb
                                    revision1, revision2, peg_revision,
                                    pool));
 
+  /* Set up the repos_diff editor on BASE_PATH, if available.
+     Otherwise, we just use "". */
+
+  SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
+                                      callbacks, callback_baton,
+                                      TRUE /* walk_deleted_dirs */,
+                                      pool, pool));
+
   /* Get actual URLs. */
   callback_baton->orig_path_1 = url1;
   callback_baton->orig_path_2 = url2;
@@ -1986,21 +1708,41 @@ diff_repos_repos(const svn_wc_diff_callb
   callback_baton->ra_session = ra_session;
   callback_baton->anchor = base_path;
 
-  if (kind1 == svn_node_none || kind2 == svn_node_none)
+  /* The repository can bring in a new working copy, but not delete
+     everything. Luckily our new diff handler can just be reversed. */
+  if (kind2 == svn_node_none)
     {
-      /* One side of the diff does not exist.
-       * Walk the tree that does exist, showing a series of additions
-       * or deletions. */
-      SVN_ERR(diff_repos_repos_added_or_deleted_target(target1, target2,
-                                                       rev1, rev2,
-                                                       kind1, kind2,
-                                                       callbacks,
-                                                       callback_baton,
-                                                       ra_session,
-                                                       pool));
-      return SVN_NO_ERROR;
+      const char *str_tmp;
+      svn_revnum_t rev_tmp;
+
+      str_tmp = url2;
+      url2 = url1;
+      url1 = str_tmp;
+
+      rev_tmp = rev2;
+      rev2 = rev1;
+      rev1 = rev_tmp;
+
+      str_tmp = anchor2;
+      anchor2 = anchor1;
+      anchor1 = str_tmp;
+
+      str_tmp = target2;
+      target2 = target1;
+      target1 = str_tmp;
+
+      diff_processor = svn_diff__tree_processor_reverse_create(diff_processor,
+                                                               NULL, pool);
     }
 
+  /* Filter the first path component using a filter processor, until we fixed
+     the diff processing to handle this directly */
+  if ((kind1 != svn_node_file && kind2 != svn_node_file) && target1[0] != '\0')
+  {
+    diff_processor = svn_diff__tree_processor_filter_create(diff_processor,
+                                                            target1, pool);
+  }
+
   /* Now, we open an extra RA session to the correct anchor
      location for URL1.  This is used during the editor calls to fetch file
      contents.  */
@@ -2008,189 +1750,28 @@ diff_repos_repos(const svn_wc_diff_callb
                                                anchor1, NULL, NULL, FALSE,
                                                TRUE, ctx, pool));
 
-  /* Set up the repos_diff editor on BASE_PATH, if available.
-     Otherwise, we just use "". */
-  SVN_ERR(svn_client__get_diff_editor(
+  SVN_ERR(svn_client__get_diff_editor2(
                 &diff_editor, &diff_edit_baton,
-                depth,
-                extra_ra_session, rev1, TRUE /* walk_deleted_dirs */,
+                extra_ra_session, depth,
+                rev1, 
                 TRUE /* text_deltas */,
-                NULL /* absent relpaths */,
-                callbacks, callback_baton,
+                diff_processor,
                 ctx->cancel_func, ctx->cancel_baton,
-                NULL /* no notify_func */, NULL /* no notify_baton */,
                 pool));
 
   /* We want to switch our txn into URL2 */
-  SVN_ERR(svn_ra_do_diff3
-          (ra_session, &reporter, &reporter_baton, rev2, target1,
-           depth, ignore_ancestry, TRUE /* text_deltas */,
-           url2, diff_editor, diff_edit_baton, pool));
+  SVN_ERR(svn_ra_do_diff3(ra_session, &reporter, &reporter_baton,
+                          rev2, target1,
+                          depth, ignore_ancestry, TRUE /* text_deltas */,
+                          url2, diff_editor, diff_edit_baton, pool));
 
   /* Drive the reporter; do the diff. */
   SVN_ERR(reporter->set_path(reporter_baton, "", rev1,
                              svn_depth_infinity,
                              FALSE, NULL,
                              pool));
-  return reporter->finish_report(reporter_baton, pool);
-}
-
-
-/* Using CALLBACKS, show a REPOS->WC diff for a file TARGET, which in the
- * working copy is at FILE2_ABSPATH. KIND1 is the node kind of the repository
- * target (either svn_node_file or svn_node_none). REV is the revision the
- * working file is diffed against. RA_SESSION points at the URL of the file
- * in the repository and is used to get the file's repository-version content,
- * if necessary. The other parameters are as in diff_repos_wc(). */
-static svn_error_t *
-diff_repos_wc_file_target(const char *target,
-                          const char *file2_abspath,
-                          svn_node_kind_t kind1,
-                          svn_revnum_t rev,
-                          svn_boolean_t reverse,
-                          svn_boolean_t show_copies_as_adds,
-                          const svn_wc_diff_callbacks4_t *callbacks,
-                          void *callback_baton,
-                          svn_ra_session_t *ra_session,
-                          svn_client_ctx_t *ctx,
-                          apr_pool_t *scratch_pool)
-{
-  const char *file1_abspath;
-  svn_stream_t *file1_content;
-  svn_stream_t *file2_content;
-  apr_hash_t *file1_props = NULL;
-  apr_hash_t *file2_props;
-  svn_boolean_t is_copy = FALSE;
-  apr_hash_t *keywords = NULL;
-  svn_string_t *keywords_prop;
-  svn_subst_eol_style_t eol_style;
-  const char *eol_str;
-
-  /* Get content and props of file 1 (the remote file). */
-  SVN_ERR(svn_stream_open_unique(&file1_content, &file1_abspath, NULL,
-                                 svn_io_file_del_on_pool_cleanup,
-                                 scratch_pool, scratch_pool));
-  if (kind1 == svn_node_file)
-    {
-      if (show_copies_as_adds)
-        SVN_ERR(svn_wc__node_get_origin(&is_copy, 
-                                        NULL, NULL, NULL, NULL, NULL,
-                                        ctx->wc_ctx, file2_abspath,
-                                        FALSE, scratch_pool, scratch_pool));
-      /* If showing copies as adds, diff against the empty file. */
-      if (!(show_copies_as_adds && is_copy))
-        SVN_ERR(svn_ra_get_file(ra_session, "", rev, file1_content,
-                                NULL, &file1_props, scratch_pool));
-    }
-
-  SVN_ERR(svn_stream_close(file1_content));
-
-  SVN_ERR(svn_wc_prop_list2(&file2_props, ctx->wc_ctx, file2_abspath,
-                            scratch_pool, scratch_pool));
-
-  /* We might have to create a normalised version of the working file. */
-  svn_subst_eol_style_from_value(&eol_style, &eol_str,
-                                 apr_hash_get(file2_props,
-                                              SVN_PROP_EOL_STYLE,
-                                              APR_HASH_KEY_STRING));
-  keywords_prop = apr_hash_get(file2_props, SVN_PROP_KEYWORDS,
-                               APR_HASH_KEY_STRING);
-  if (keywords_prop)
-    SVN_ERR(svn_subst_build_keywords2(&keywords, keywords_prop->data,
-                                      NULL, NULL, 0, NULL,
-                                      scratch_pool));
-  if (svn_subst_translation_required(eol_style, SVN_SUBST_NATIVE_EOL_STR,
-                                     keywords, FALSE, TRUE))
-    {
-      svn_stream_t *working_content;
-      svn_stream_t *normalized_content;
-
-      SVN_ERR(svn_stream_open_readonly(&working_content, file2_abspath,
-                                       scratch_pool, scratch_pool));
-
-      /* Create a temporary file and copy normalised data into it. */
-      SVN_ERR(svn_stream_open_unique(&file2_content, &file2_abspath, NULL,
-                                     svn_io_file_del_on_pool_cleanup,
-                                     scratch_pool, scratch_pool));
-      normalized_content = svn_subst_stream_translated(
-                             file2_content, SVN_SUBST_NATIVE_EOL_STR,
-                             TRUE, keywords, FALSE, scratch_pool);
-      SVN_ERR(svn_stream_copy3(working_content, normalized_content,
-                               ctx->cancel_func, ctx->cancel_baton,
-                               scratch_pool));
-    }
 
-  if (kind1 == svn_node_file && !(show_copies_as_adds && is_copy))
-    {
-      SVN_ERR(callbacks->file_opened(NULL, NULL, target,
-                                     reverse ? SVN_INVALID_REVNUM : rev,
-                                     callback_baton, scratch_pool));
-
-      if (reverse)
-        SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target,
-                                        file2_abspath, file1_abspath,
-                                        SVN_INVALID_REVNUM, rev,
-                                        apr_hash_get(file2_props,
-                                                     SVN_PROP_MIME_TYPE,
-                                                     APR_HASH_KEY_STRING),
-                                        apr_hash_get(file1_props,
-                                                     SVN_PROP_MIME_TYPE,
-                                                     APR_HASH_KEY_STRING),
-                                        make_regular_props_array(
-                                          file1_props, scratch_pool,
-                                          scratch_pool),
-                                        file2_props,
-                                        callback_baton, scratch_pool));
-      else
-        SVN_ERR(callbacks->file_changed(NULL, NULL, NULL, target,
-                                        file1_abspath, file2_abspath,
-                                        rev, SVN_INVALID_REVNUM,
-                                        apr_hash_get(file1_props,
-                                                     SVN_PROP_MIME_TYPE,
-                                                     APR_HASH_KEY_STRING),
-                                        apr_hash_get(file2_props,
-                                                     SVN_PROP_MIME_TYPE,
-                                                     APR_HASH_KEY_STRING),
-                                        make_regular_props_array(
-                                          file2_props, scratch_pool,
-                                          scratch_pool),
-                                        file1_props,
-                                        callback_baton, scratch_pool));
-    }
-  else
-    {
-      if (reverse)
-        {
-          SVN_ERR(callbacks->file_deleted(NULL, NULL,
-                                          target, file2_abspath, file1_abspath,
-                                          apr_hash_get(file2_props,
-                                                       SVN_PROP_MIME_TYPE,
-                                                       APR_HASH_KEY_STRING),
-                                          NULL,
-                                          make_regular_props_hash(
-                                            file2_props, scratch_pool,
-                                            scratch_pool),
-                                          callback_baton, scratch_pool));
-        }
-      else
-        {
-          SVN_ERR(callbacks->file_added(NULL, NULL, NULL, target,
-                                        file1_abspath, file2_abspath,
-                                        rev, SVN_INVALID_REVNUM,
-                                        NULL,
-                                        apr_hash_get(file2_props,
-                                                     SVN_PROP_MIME_TYPE,
-                                                     APR_HASH_KEY_STRING),
-                                        NULL, SVN_INVALID_REVNUM,
-                                        make_regular_props_array(
-                                          file2_props, scratch_pool,
-                                          scratch_pool),
-                                        NULL,
-                                        callback_baton, scratch_pool));
-        }
-    }
-
-  return SVN_NO_ERROR;
+  return svn_error_trace(reporter->finish_report(reporter_baton, pool));
 }
 
 /* Perform a diff between a repository path and a working-copy path.
@@ -2219,8 +1800,9 @@ diff_repos_wc(const char *path_or_url1,
               void *callback_baton,
               struct diff_cmd_baton *cmd_baton,
               svn_client_ctx_t *ctx,
-              apr_pool_t *pool)
+              apr_pool_t *scratch_pool)
 {
+  apr_pool_t *pool = scratch_pool;
   const char *url1, *anchor, *anchor_url, *target;
   svn_revnum_t rev;
   svn_ra_session_t *ra_session;
@@ -2237,22 +1819,27 @@ diff_repos_wc(const char *path_or_url1,
   svn_node_kind_t kind1;
   svn_node_kind_t kind2;
   svn_boolean_t is_copy;
-  svn_revnum_t copyfrom_rev;
-  const char *copy_source_repos_relpath;
-  const char *copy_source_repos_root_url;
+  svn_revnum_t cf_revision;
+  const char *cf_repos_relpath;
+  const char *cf_repos_root_url;
 
   SVN_ERR_ASSERT(! svn_path_is_url(path2));
 
   if (!svn_path_is_url(path_or_url1))
-    SVN_ERR(svn_dirent_get_absolute(&abspath_or_url1, path_or_url1, pool));
+    {
+      SVN_ERR(svn_dirent_get_absolute(&abspath_or_url1, path_or_url1, pool));
+      SVN_ERR(svn_wc__node_get_url(&url1, ctx->wc_ctx, abspath_or_url1,
+                                   pool, pool));
+    }
   else
-    abspath_or_url1 = path_or_url1;
+    {
+      url1 = path_or_url1;
+      abspath_or_url1 = path_or_url1;
+    }
 
   SVN_ERR(svn_dirent_get_absolute(&abspath2, path2, pool));
 
   /* Convert path_or_url1 to a URL to feed to do_diff. */
-  SVN_ERR(convert_to_url(&url1, ctx->wc_ctx, abspath_or_url1, pool, pool));
-
   SVN_ERR(svn_wc_get_actual_target2(&anchor, &target,
                                     ctx->wc_ctx, path2,
                                     pool, pool));
@@ -2261,10 +1848,7 @@ diff_repos_wc(const char *path_or_url1,
   SVN_ERR(svn_dirent_get_absolute(&anchor_abspath, anchor, pool));
   SVN_ERR(svn_wc__node_get_url(&anchor_url, ctx->wc_ctx, anchor_abspath,
                                pool, pool));
-  if (! anchor_url)
-    return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
-                             _("Directory '%s' has no URL"),
-                             svn_dirent_local_style(anchor, pool));
+  SVN_ERR_ASSERT(anchor_url != NULL);
 
   /* If we are performing a pegged diff, we need to find out what our
      actual URLs will be. */
@@ -2313,32 +1897,14 @@ diff_repos_wc(const char *path_or_url1,
     cmd_baton->revnum2 = rev;
 
   /* Check if our diff target is a copied node. */
-  SVN_ERR(svn_wc__node_get_origin(&is_copy, 
-                                  &copyfrom_rev,
-                                  &copy_source_repos_relpath,
-                                  &copy_source_repos_root_url,
+  SVN_ERR(svn_wc__node_get_origin(&is_copy,
+                                  &cf_revision,
+                                  &cf_repos_relpath,
+                                  &cf_repos_root_url,
                                   NULL, NULL,
                                   ctx->wc_ctx, abspath2,
                                   FALSE, pool, pool));
 
-  /* If both diff targets can be diffed as files, fetch the appropriate
-   * file content from the repository and generate a diff against the
-   * local version of the file.
-   * However, if comparing the repository version of the file to the BASE
-   * tree version we can use the diff editor to transmit a delta instead
-   * of potentially huge file content. */
-  if ((!rev2_is_base || is_copy) &&
-      (kind1 == svn_node_file || kind1 == svn_node_none)
-       && kind2 == svn_node_file)
-    {
-      SVN_ERR(diff_repos_wc_file_target(target, abspath2, kind1, rev,
-                                        reverse, show_copies_as_adds,
-                                        callbacks, callback_baton,
-                                        ra_session, ctx, pool));
-
-      return SVN_NO_ERROR;
-    }
-
   /* Use the diff editor to generate the diff. */
   SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                 SVN_RA_CAPABILITY_DEPTH, pool));
@@ -2347,7 +1913,7 @@ diff_repos_wc(const char *path_or_url1,
                                   anchor_abspath,
                                   target,
                                   depth,
-                                  ignore_ancestry,
+                                  ignore_ancestry || is_copy,
                                   show_copies_as_adds,
                                   use_git_diff_format,
                                   rev2_is_base,
@@ -2366,30 +1932,40 @@ diff_repos_wc(const char *path_or_url1,
 
   if (is_copy)
     {
-      const char *copyfrom_url;
       const char *copyfrom_parent_url;
       const char *copyfrom_basename;
       svn_depth_t copy_depth;
 
       cmd_baton->repos_wc_diff_target_is_copy = TRUE;
 
-      /* We're diffing a locally copied/moved directory.
+      /* We're diffing a locally copied/moved node.
        * Describe the copy source to the reporter instead of the copy itself.
        * Doing the latter would generate a single add_directory() call to the
        * diff editor which results in an unexpected diff (the copy would
        * be shown as deleted). */
 
-      copyfrom_url = apr_pstrcat(pool, copy_source_repos_root_url, "/",
-                                 copy_source_repos_relpath, (char *)NULL);
-      svn_uri_split(&copyfrom_parent_url, &copyfrom_basename,
-                    copyfrom_url, pool);
+      if (cf_repos_relpath[0] == '\0')
+        {
+          copyfrom_parent_url = cf_repos_root_url;
+          copyfrom_basename = "";
+        }
+      else
+        {
+          const char *parent_relpath;
+          svn_relpath_split(&parent_relpath, &copyfrom_basename,
+                            cf_repos_relpath, scratch_pool);
+
+          copyfrom_parent_url = svn_path_url_add_component2(cf_repos_root_url,
+                                                            parent_relpath,
+                                                            scratch_pool);
+        }
       SVN_ERR(svn_ra_reparent(ra_session, copyfrom_parent_url, pool));
 
       /* Tell the RA layer we want a delta to change our txn to URL1 */ 
       SVN_ERR(svn_ra_do_diff3(ra_session,
                               &reporter, &reporter_baton,
                               rev,
-                              copyfrom_basename,
+                              target,
                               diff_depth,
                               ignore_ancestry,
                               TRUE,  /* text_deltas */
@@ -2399,9 +1975,23 @@ diff_repos_wc(const char *path_or_url1,
       /* Report the copy source. */
       SVN_ERR(svn_wc__node_get_depth(&copy_depth, ctx->wc_ctx, abspath2,
                                      pool));
-      SVN_ERR(reporter->set_path(reporter_baton, "", copyfrom_rev,
-                                 copy_depth, FALSE, NULL, pool));
-      
+
+      if (copy_depth == svn_depth_unknown)
+        copy_depth = svn_depth_infinity;
+
+      SVN_ERR(reporter->set_path(reporter_baton, "",
+                                 cf_revision,
+                                 copy_depth, FALSE, NULL, scratch_pool));
+
+      if (strcmp(target, copyfrom_basename) != 0)
+        SVN_ERR(reporter->link_path(reporter_baton, target,
+                                    svn_path_url_add_component2(
+                                                cf_repos_root_url,
+                                                cf_repos_relpath,
+                                                scratch_pool),
+                                    cf_revision,
+                                    copy_depth, FALSE, NULL, scratch_pool));
+
       /* Finish the report to generate the diff. */
       SVN_ERR(reporter->finish_report(reporter_baton, pool));
     }
@@ -2502,6 +2092,7 @@ do_diff(const svn_wc_diff_callbacks4_t *
               SVN_ERR(svn_dirent_get_absolute(&abspath2, path_or_url2, pool));
 
               SVN_ERR(svn_client__arbitrary_nodes_diff(abspath1, abspath2,
+                                                       depth,
                                                        callbacks,
                                                        callback_baton,
                                                        ctx, pool));
@@ -2646,6 +2237,8 @@ diff_summarize_repos_repos(svn_client_di
   const svn_delta_editor_t *diff_editor;
   void *diff_edit_baton;
 
+  const svn_diff_tree_processor_t *diff_processor;
+
   const char *url1;
   const char *url2;
   const char *base_path;
@@ -2669,43 +2262,58 @@ diff_summarize_repos_repos(svn_client_di
                                    revision1, revision2,
                                    peg_revision, pool));
 
-  if (kind1 == svn_node_none || kind2 == svn_node_none)
-    {
-      /* One side of the diff does not exist.
-       * Walk the tree that does exist, showing a series of additions
-       * or deletions. */
-      SVN_ERR(svn_client__get_diff_summarize_callbacks(
-                &callbacks, &callback_baton, target1, FALSE, 
-                summarize_func, summarize_baton, pool));
-      SVN_ERR(diff_repos_repos_added_or_deleted_target(target1, target2,
-                                                       rev1, rev2,
-                                                       kind1, kind2,
-                                                       callbacks,
-                                                       callback_baton,
-                                                       ra_session,
-                                                       pool));
-      return SVN_NO_ERROR;
-    }
-
+  /* Set up the repos_diff editor. */
   SVN_ERR(svn_client__get_diff_summarize_callbacks(
             &callbacks, &callback_baton,
             target1, FALSE, summarize_func, summarize_baton, pool));
 
+  SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
+                                      callbacks, callback_baton,
+                                      TRUE /* walk_deleted_dirs */,
+                                      pool, pool));
+
+
+  /* The repository can bring in a new working copy, but not delete
+     everything. Luckily our new diff handler can just be reversed. */
+  if (kind2 == svn_node_none)
+    {
+      const char *str_tmp;
+      svn_revnum_t rev_tmp;
+
+      str_tmp = url2;
+      url2 = url1;
+      url1 = str_tmp;
+
+      rev_tmp = rev2;
+      rev2 = rev1;
+      rev1 = rev_tmp;
+
+      str_tmp = anchor2;
+      anchor2 = anchor1;
+      anchor1 = str_tmp;
+
+      str_tmp = target2;
+      target2 = target1;
+      target1 = str_tmp;
+
+      diff_processor = svn_diff__tree_processor_reverse_create(diff_processor,
+                                                               NULL, pool);
+    }
+
   /* Now, we open an extra RA session to the correct anchor
      location for URL1.  This is used to get the kind of deleted paths.  */
   SVN_ERR(svn_client__open_ra_session_internal(&extra_ra_session, NULL,
                                                anchor1, NULL, NULL, FALSE,
                                                TRUE, ctx, pool));
 
-  /* Set up the repos_diff editor. */
-  SVN_ERR(svn_client__get_diff_editor(&diff_editor, &diff_edit_baton,
-            depth,
-            extra_ra_session, rev1, TRUE /* walk_deleted_dirs */,
-            FALSE /* text_deltas */,
-            NULL /* absent relpaths */,
-            callbacks, callback_baton,
-            ctx->cancel_func, ctx->cancel_baton,
-            NULL /* notify_func */, NULL /* notify_baton */, pool));
+  SVN_ERR(svn_client__get_diff_editor2(&diff_editor, &diff_edit_baton,
+                                       extra_ra_session,
+                                       depth,
+                                       rev1,
+                                       FALSE /* text_deltas */,
+                                       diff_processor,
+                                       ctx->cancel_func, ctx->cancel_baton,
+                                       pool));
 
   /* We want to switch our txn into URL2 */
   SVN_ERR(svn_ra_do_diff3
@@ -2718,7 +2326,7 @@ diff_summarize_repos_repos(svn_client_di
   SVN_ERR(reporter->set_path(reporter_baton, "", rev1,
                              svn_depth_infinity,
                              FALSE, NULL, pool));
-  return reporter->finish_report(reporter_baton, pool);
+  return svn_error_trace(reporter->finish_report(reporter_baton, pool));
 }
 
 /* This is basically just the guts of svn_client_diff_summarize[_peg]2(). */
@@ -2799,6 +2407,7 @@ do_diff_summarize(svn_client_diff_summar
                      summarize_func, summarize_baton, pool));
 
              SVN_ERR(svn_client__arbitrary_nodes_diff(abspath1, abspath2,
+                                                      depth,
                                                       callbacks,
                                                       callback_baton,
                                                       ctx, pool));
@@ -2971,6 +2580,8 @@ svn_client_diff6(const apr_array_header_
   diff_cmd_baton.use_git_diff_format = use_git_diff_format;
   diff_cmd_baton.no_diff_added = no_diff_added;
   diff_cmd_baton.no_diff_deleted = no_diff_deleted;
+  diff_cmd_baton.no_copyfrom_on_add = show_copies_as_adds;
+
   diff_cmd_baton.wc_ctx = ctx->wc_ctx;
   diff_cmd_baton.ra_session = NULL;
   diff_cmd_baton.anchor = NULL;
@@ -3032,6 +2643,8 @@ svn_client_diff_peg6(const apr_array_hea
   diff_cmd_baton.use_git_diff_format = use_git_diff_format;
   diff_cmd_baton.no_diff_added = no_diff_added;
   diff_cmd_baton.no_diff_deleted = no_diff_deleted;
+  diff_cmd_baton.no_copyfrom_on_add = show_copies_as_adds;
+
   diff_cmd_baton.wc_ctx = ctx->wc_ctx;
   diff_cmd_baton.ra_session = NULL;
   diff_cmd_baton.anchor = NULL;