You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2014/02/20 13:57:16 UTC

svn commit: r1570177 - in /subversion/trunk/subversion: include/private/svn_client_private.h include/private/svn_wc_private.h libsvn_client/client.h libsvn_client/diff.c libsvn_client/diff_local.c libsvn_client/diff_summarize.c libsvn_wc/diff_local.c

Author: rhuijben
Date: Thu Feb 20 12:57:15 2014
New Revision: 1570177

URL: http://svn.apache.org/r1570177
Log:
In the libsvn_client diff handling: replace the output argument of the anchor
base argument with a pair of root_relpath and root_is_dir values.

These two booleans should allow cleaning up the remaining 'dual calculations'
of anchors in the diff code.

The diff runner and diff writer have/had deep knowledge about each others
about this handling and covered for bugs on the other side. This is pumbing
in preparation for replacing this with the usage of generic diff driver rules.

* subversion/include/private/svn_client_private.h
  (svn_client__arbitrary_nodes_diff): Move function to client.h

* subversion/include/private/svn_wc_private.h
  (svn_wc__diff7): Update private api.

* subversion/libsvn_client/client.h
  (svn_client__arbitrary_nodes_diff): Move function here and update output
    arguments to new form.

* subversion/libsvn_client/diff.c
  (diff_wc_wc): Update output arguments. Update caller.
  (diff_repos_repos): Update output arguments. Remove filter that isn't
    necessary if our caller wants to do the filtering based on what we
    return.
  (do_diff): Update caller.

  (svn_client_diff6,
   svn_client_diff_peg6): Update caller.

  (svn_client_diff_summarize2,
   svn_client_diff_summarize_peg2): Update caller.

* subversion/libsvn_client/diff_local.c
  (svn_client__arbitrary_nodes_diff): Update output arguments.

* subversion/libsvn_client/diff_summarize.c
  (summarize_baton_t): Remove two variables.
  (ensure_skip_relpath): Remove now unneeded function.
  (send_summary): Update caller.
  (svn_client__get_diff_summarize_callbacks): Pass skip_relpath directly.

* subversion/libsvn_wc/diff_local.c
  (includes): Add wc_db.h. Remove translate.h.
  (svn_wc__diff7): Update argument. Always root at parent directory when we
    can tell the caller about this. (This fixes driving a root replacement)

Modified:
    subversion/trunk/subversion/include/private/svn_client_private.h
    subversion/trunk/subversion/include/private/svn_wc_private.h
    subversion/trunk/subversion/libsvn_client/client.h
    subversion/trunk/subversion/libsvn_client/diff.c
    subversion/trunk/subversion/libsvn_client/diff_local.c
    subversion/trunk/subversion/libsvn_client/diff_summarize.c
    subversion/trunk/subversion/libsvn_wc/diff_local.c

Modified: subversion/trunk/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1570177&r1=1570176&r2=1570177&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_client_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_client_private.h Thu Feb 20 12:57:15 2014
@@ -236,25 +236,6 @@ svn_client__wc_node_get_origin(svn_clien
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
-/* Produce a diff with depth DEPTH between two files or two directories at
- * LEFT_ABSPATH1 and RIGHT_ABSPATH, using the provided diff callbacks to
- * show changes in files. The files and directories involved may be part of
- * a working copy or they may be unversioned. For versioned files, show
- * property changes, too.
- *
- * If ANCHOR_ABSPATH is not null, set it to the anchor of the diff before
- * the first processor call. (The anchor is LEFT_ABSPATH or an ancestor of it)
- */
-svn_error_t *
-svn_client__arbitrary_nodes_diff(const char **anchor_abspath,
-                                 const char *left_abspath,
-                                 const char *right_abspath,
-                                 svn_depth_t depth,
-                                 const svn_diff_tree_processor_t *diff_processor,
-                                 svn_client_ctx_t *ctx,
-                                 apr_pool_t *result_pool,
-                                 apr_pool_t *scratch_pool);
-
 /* Copy the file or directory on URL in some repository to DST_ABSPATH,
  * copying node information and properties. Resolve URL using PEG_REV and
  * REVISION.

Modified: subversion/trunk/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_wc_private.h?rev=1570177&r1=1570176&r2=1570177&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_wc_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_wc_private.h Thu Feb 20 12:57:15 2014
@@ -1842,11 +1842,15 @@ svn_wc__acquire_write_lock_for_resolve(c
 
 /* The implemementation of svn_wc_diff6(), but reporting to a diff processor
  *
- * If ANCHOR_ABSPATH is not null, set it to the anchor of the diff before
+ * If ROOT_RELPATH is not NULL, set *ROOT_RELPATH to the target of the diff
+ * within the diff namespace. ("" or a single path component).
+ *
+ * If ROOT_IS_FILE is NOT NULL set it 
  * the first processor call. (The anchor is LOCAL_ABSPATH or an ancestor of it)
  */
 svn_error_t *
-svn_wc__diff7(const char **anchor_abspath,
+svn_wc__diff7(const char **root_relpath,
+              svn_boolean_t *root_is_dir,
               svn_wc_context_t *wc_ctx,
               const char *local_abspath,
               svn_depth_t depth,

Modified: subversion/trunk/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/client.h?rev=1570177&r1=1570176&r2=1570177&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/client.h (original)
+++ subversion/trunk/subversion/libsvn_client/client.h Thu Feb 20 12:57:15 2014
@@ -712,8 +712,8 @@ svn_client__get_diff_editor2(const svn_d
 /* Set *DIFF_PROCESSOR to a diff processor that will report a diff summary
    to SUMMARIZE_FUNC.
 
-   ANCHOR_PATH will return a pointer to a string that must be set to the
-   anchor of the operation before the processor is called.
+   P_ROOT_RELPATH will return a pointer to a string that must be set to
+   the root of the operation before the processor is called.
 
    ORIGINAL_PATH specifies the original path and will be used with
    **ANCHOR_PATH to create paths as the user originally provided them
@@ -725,7 +725,7 @@ svn_client__get_diff_editor2(const svn_d
 svn_error_t *
 svn_client__get_diff_summarize_callbacks(
                         const svn_diff_tree_processor_t **diff_processor,
-                        const char ***anchor_path,
+                        const char ***p_root_relpath,
                         svn_client_diff_summarize_func_t summarize_func,
                         void *summarize_baton,
                         const char *original_target,
@@ -1151,6 +1151,25 @@ svn_client__resolve_conflicts(svn_boolea
                               svn_client_ctx_t *ctx,
                               apr_pool_t *scratch_pool);
 
+/* Produce a diff with depth DEPTH between two files or two directories at
+ * LEFT_ABSPATH1 and RIGHT_ABSPATH, using the provided diff callbacks to
+ * show changes in files. The files and directories involved may be part of
+ * a working copy or they may be unversioned. For versioned files, show
+ * property changes, too.
+ *
+ * If ANCHOR_ABSPATH is not null, set it to the anchor of the diff before
+ * the first processor call. (The anchor is LEFT_ABSPATH or an ancestor of it)
+ */
+svn_error_t *
+svn_client__arbitrary_nodes_diff(const char **root_relpath,
+                                 svn_boolean_t *root_is_dir,
+                                 const char *left_abspath,
+                                 const char *right_abspath,
+                                 svn_depth_t depth,
+                                 const svn_diff_tree_processor_t *diff_processor,
+                                 svn_client_ctx_t *ctx,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool);
 
 
 #ifdef __cplusplus

Modified: subversion/trunk/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff.c?rev=1570177&r1=1570176&r2=1570177&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff.c Thu Feb 20 12:57:15 2014
@@ -1581,7 +1581,8 @@ unsupported_diff_error(svn_error_t *chil
 
    All other options are the same as those passed to svn_client_diff6(). */
 static svn_error_t *
-diff_wc_wc(const char **anchor_path,
+diff_wc_wc(const char **root_relpath,
+           svn_boolean_t *root_is_dir,
            struct diff_driver_info_t *ddi,
            const char *path1,
            const svn_opt_revision_t *revision1,
@@ -1626,9 +1627,8 @@ diff_wc_wc(const char **anchor_path,
         ddi->anchor = path1;
     }
 
-  SVN_ERR(svn_wc__diff7(anchor_path, ctx->wc_ctx,
-                        abspath1,
-                        depth,
+  SVN_ERR(svn_wc__diff7(root_relpath, root_is_dir,
+                        ctx->wc_ctx, abspath1, depth,
                         ignore_ancestry, changelists,
                         diff_processor,
                         ctx->cancel_func, ctx->cancel_baton,
@@ -1646,7 +1646,8 @@ diff_wc_wc(const char **anchor_path,
 
    All other options are the same as those passed to svn_client_diff6(). */
 static svn_error_t *
-diff_repos_repos(const char **anchor_path_or_url,
+diff_repos_repos(const char **root_relpath,
+                 svn_boolean_t *root_is_dir,
                  struct diff_driver_info_t *ddi,
                  const char *path_or_url1,
                  const char *path_or_url2,
@@ -1740,11 +1741,14 @@ diff_repos_repos(const char **anchor_pat
 
   /* 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, scratch_pool);
-  }
+  if (root_relpath)
+    *root_relpath = apr_pstrdup(result_pool, target1);
+  else if ((kind1 != svn_node_file && kind2 != svn_node_file)
+           && target1[0] != '\0')
+    {
+      diff_processor = svn_diff__tree_processor_filter_create(
+                                        diff_processor, target1, scratch_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
@@ -1752,24 +1756,6 @@ diff_repos_repos(const char **anchor_pat
   SVN_ERR(svn_ra_dup_session(&extra_ra_session, ra_session, anchor1,
                              scratch_pool, scratch_pool));
 
-  if (anchor_path_or_url)
-    {
-      if (base_path)
-        {
-          *anchor_path_or_url = apr_pstrdup(result_pool, base_path);
-        }
-      else
-        {
-          SVN_ERR(svn_ra_get_session_url(ra_session, anchor_path_or_url,
-                                         scratch_pool));
-
-          *anchor_path_or_url = svn_path_url_add_component2(
-                                                  *anchor_path_or_url,
-                                                  target1,
-                                                  result_pool);
-        }
-    }
-
   if (ddi)
     {
       const char *repos_root_url;
@@ -1821,7 +1807,8 @@ diff_repos_repos(const char **anchor_pat
 
    All other options are the same as those passed to svn_client_diff6(). */
 static svn_error_t *
-diff_repos_wc(const char **anchor_path,
+diff_repos_wc(const char **root_relpath,
+              svn_boolean_t *root_is_dir,
               struct diff_driver_info_t *ddi,
               const char *path_or_url1,
               const svn_opt_revision_t *revision1,
@@ -1878,6 +1865,11 @@ diff_repos_wc(const char **anchor_path,
                                     ctx->wc_ctx, path2,
                                     pool, pool));
 
+  if (root_relpath)
+    *root_relpath = apr_pstrdup(result_pool, target);
+  if (root_is_dir)
+    *root_is_dir = (*target == '\0');
+
   /* Fetch the URL of the anchor directory. */
   SVN_ERR(svn_dirent_get_absolute(&anchor_abspath, anchor, pool));
   SVN_ERR(svn_wc__node_get_url(&anchor_url, ctx->wc_ctx, anchor_abspath,
@@ -1960,9 +1952,6 @@ diff_repos_wc(const char **anchor_path,
   else
     diff_depth = svn_depth_unknown;
 
-  if (anchor_path)
-    *anchor_path = apr_pstrdup(result_pool, anchor_abspath);
-
   if (is_copy)
     {
       const char *copyfrom_parent_url;
@@ -2083,7 +2072,8 @@ diff_repos_wc(const char **anchor_path,
 
 /* This is basically just the guts of svn_client_diff[_summarize][_peg]6(). */
 static svn_error_t *
-do_diff(const char **anchor_path,
+do_diff(const char **root_relpath,
+        svn_boolean_t *root_is_dir,
         diff_driver_info_t *ddi,
         const char *path_or_url1,
         const char *path_or_url2,
@@ -2111,7 +2101,8 @@ do_diff(const char **anchor_path,
       if (is_repos2)
         {
           /* ### Ignores 'show_copies_as_adds'. */
-          SVN_ERR(diff_repos_repos(anchor_path, ddi,
+          SVN_ERR(diff_repos_repos(root_relpath, root_is_dir,
+                                   ddi,
                                    path_or_url1, path_or_url2,
                                    revision1, revision2,
                                    peg_revision, depth, ignore_ancestry,
@@ -2121,7 +2112,7 @@ do_diff(const char **anchor_path,
         }
       else /* path_or_url2 is a working copy path */
         {
-          SVN_ERR(diff_repos_wc(anchor_path, ddi,
+          SVN_ERR(diff_repos_wc(root_relpath, root_is_dir, ddi,
                                 path_or_url1, revision1, peg_revision,
                                 path_or_url2, revision2, FALSE, depth,
                                 ignore_ancestry, changelists,
@@ -2133,7 +2124,7 @@ do_diff(const char **anchor_path,
     {
       if (is_repos2)
         {
-          SVN_ERR(diff_repos_wc(anchor_path, ddi,
+          SVN_ERR(diff_repos_wc(root_relpath, root_is_dir, ddi,
                                 path_or_url2, revision2, peg_revision,
                                 path_or_url1, revision1, TRUE, depth,
                                 ignore_ancestry, changelists,
@@ -2155,7 +2146,7 @@ do_diff(const char **anchor_path,
 
               /* ### What about ddi? */
 
-              SVN_ERR(svn_client__arbitrary_nodes_diff(anchor_path,
+              SVN_ERR(svn_client__arbitrary_nodes_diff(root_relpath, root_is_dir,
                                                        abspath1, abspath2,
                                                        depth,
                                                        diff_processor,
@@ -2164,7 +2155,7 @@ do_diff(const char **anchor_path,
             }
           else
             {
-              SVN_ERR(diff_wc_wc(anchor_path, ddi,
+              SVN_ERR(diff_wc_wc(root_relpath, root_is_dir, ddi,
                                  path_or_url1, revision1,
                                  path_or_url2, revision2,
                                  depth, ignore_ancestry, changelists,
@@ -2356,7 +2347,7 @@ svn_client_diff6(const apr_array_header_
   if (show_copies_as_adds || use_git_diff_format)
     ignore_ancestry = FALSE;
 
-  return svn_error_trace(do_diff(NULL, &diff_cmd_baton.ddi,
+  return svn_error_trace(do_diff(NULL, NULL, &diff_cmd_baton.ddi,
                                  path_or_url1, path_or_url2,
                                  revision1, revision2, &peg_revision,
                                  depth, ignore_ancestry, changelists,
@@ -2439,7 +2430,7 @@ svn_client_diff_peg6(const apr_array_hea
   if (show_copies_as_adds || use_git_diff_format)
     ignore_ancestry = FALSE;
 
-  return svn_error_trace(do_diff(NULL, &diff_cmd_baton.ddi,
+  return svn_error_trace(do_diff(NULL, NULL, &diff_cmd_baton.ddi,
                                  path_or_url, path_or_url,
                                  start_revision, end_revision, peg_revision,
                                  depth, ignore_ancestry, changelists,
@@ -2462,17 +2453,17 @@ svn_client_diff_summarize2(const char *p
 {
   const svn_diff_tree_processor_t *diff_processor;
   svn_opt_revision_t peg_revision;
-  const char **anchor_path;
+  const char **p_root_relpath;
 
   /* We will never do a pegged diff from here. */
   peg_revision.kind = svn_opt_revision_unspecified;
 
   SVN_ERR(svn_client__get_diff_summarize_callbacks(
-                     &diff_processor, &anchor_path,
+                     &diff_processor, &p_root_relpath,
                      summarize_func, summarize_baton,
                      path_or_url1, pool, pool));
 
-  return svn_error_trace(do_diff(anchor_path, NULL,
+  return svn_error_trace(do_diff(p_root_relpath, NULL, NULL,
                                  path_or_url1, path_or_url2,
                                  revision1, revision2, &peg_revision,
                                  depth, ignore_ancestry, changelists,
@@ -2494,14 +2485,14 @@ svn_client_diff_summarize_peg2(const cha
                                apr_pool_t *pool)
 {
   const svn_diff_tree_processor_t *diff_processor;
-  const char **anchor_path;
+  const char **p_root_relpath;
 
   SVN_ERR(svn_client__get_diff_summarize_callbacks(
-                     &diff_processor, &anchor_path,
+                     &diff_processor, &p_root_relpath,
                      summarize_func, summarize_baton,
                      path_or_url, pool, pool));
 
-  return svn_error_trace(do_diff(anchor_path, NULL,
+  return svn_error_trace(do_diff(p_root_relpath, NULL, NULL,
                                  path_or_url, path_or_url,
                                  start_revision, end_revision, peg_revision,
                                  depth, ignore_ancestry, changelists,

Modified: subversion/trunk/subversion/libsvn_client/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff_local.c?rev=1570177&r1=1570176&r2=1570177&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff_local.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff_local.c Thu Feb 20 12:57:15 2014
@@ -575,7 +575,8 @@ do_dir_diff(const char *left_abspath,
 }
 
 svn_error_t *
-svn_client__arbitrary_nodes_diff(const char **anchor_abspath,
+svn_client__arbitrary_nodes_diff(const char **root_relpath,
+                                 svn_boolean_t *root_is_dir,
                                  const char *left_abspath,
                                  const char *right_abspath,
                                  svn_depth_t depth,
@@ -603,15 +604,23 @@ svn_client__arbitrary_nodes_diff(const c
     {
       left_root_abspath = left_abspath;
       right_root_abspath = right_abspath;
+
+      if (root_relpath)
+        *root_relpath = "";
+      if (root_is_dir)
+        *root_is_dir = TRUE;
     }
   else
     {
-      left_root_abspath = svn_dirent_dirname(left_abspath, scratch_pool);
+      svn_dirent_split(&left_root_abspath, root_relpath, left_abspath,
+                       scratch_pool);
       right_root_abspath = svn_dirent_dirname(right_abspath, scratch_pool);
-    }
 
-  if (anchor_abspath)
-    *anchor_abspath = apr_pstrdup(result_pool, left_root_abspath);
+      if (root_relpath)
+        *root_relpath = apr_pstrdup(result_pool, *root_relpath);
+      if (root_is_dir)
+        *root_is_dir = FALSE;
+    }
 
   if (left_kind == svn_node_dir && right_kind == svn_node_dir)
     {

Modified: subversion/trunk/subversion/libsvn_client/diff_summarize.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/diff_summarize.c?rev=1570177&r1=1570176&r2=1570177&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/diff_summarize.c (original)
+++ subversion/trunk/subversion/libsvn_client/diff_summarize.c Thu Feb 20 12:57:15 2014
@@ -39,8 +39,6 @@ struct summarize_baton_t {
   apr_pool_t *baton_pool; /* For allocating skip_path */
 
   /* The target path of the diff, relative to the anchor; "" if target == anchor. */
-  const char *original_target;
-  const char *anchor_path;
   const char *skip_relpath;
 
   /* The summarize callback passed down from the API */
@@ -50,29 +48,6 @@ struct summarize_baton_t {
   void *summarize_func_baton;
 };
 
-/* Calculate skip_relpath from original_target and anchor_path */
-static APR_INLINE void
-ensure_skip_relpath(struct summarize_baton_t *b)
-{
-  if (b->skip_relpath)
-    return;
-
-  if (svn_path_is_url(b->original_target))
-    {
-      b->skip_relpath = svn_uri_skip_ancestor(b->anchor_path,
-                                              b->original_target,
-                                              b->baton_pool);
-    }
-  else
-    {
-      b->skip_relpath = svn_dirent_skip_ancestor(b->anchor_path,
-                                                 b->original_target);
-    }
-
-  if (!b->skip_relpath)
-    b->skip_relpath = "";
-}
-
 /* Call B->summarize_func with B->summarize_func_baton, passing it a
  * summary object composed from PATH (but made to be relative to the target
  * of the diff), SUMMARIZE_KIND, PROP_CHANGED (or FALSE if the action is an
@@ -92,8 +67,6 @@ send_summary(struct summarize_baton_t *b
 
   /* PATH is relative to the anchor of the diff, but SUM->path needs to be
      relative to the target of the diff. */
-  ensure_skip_relpath(b);
-
   sum->path = svn_relpath_skip_ancestor(b->skip_relpath, path);
   sum->summarize_kind = summarize_kind;
   if (summarize_kind == svn_client_diff_summarize_kind_modified
@@ -293,7 +266,7 @@ diff_file_deleted(const char *relpath,
 svn_error_t *
 svn_client__get_diff_summarize_callbacks(
                         const svn_diff_tree_processor_t **diff_processor,
-                        const char ***anchor_path,
+                        const char ***p_root_relpath,
                         svn_client_diff_summarize_func_t summarize_func,
                         void *summarize_baton,
                         const char *original_target,
@@ -303,11 +276,9 @@ svn_client__get_diff_summarize_callbacks
   svn_diff_tree_processor_t *dp;
   struct summarize_baton_t *b = apr_pcalloc(result_pool, sizeof(*b));
 
-  *anchor_path = &b->anchor_path;
   b->baton_pool = result_pool;
   b->summarize_func = summarize_func;
   b->summarize_func_baton = summarize_baton;
-  b->original_target = apr_pstrdup(result_pool, original_target);
 
   dp = svn_diff__tree_processor_create(b, result_pool);
 
@@ -322,6 +293,7 @@ svn_client__get_diff_summarize_callbacks
   dp->dir_added = diff_dir_added;
 
   *diff_processor = dp;
+  *p_root_relpath = &b->skip_relpath;
 
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/diff_local.c?rev=1570177&r1=1570176&r2=1570177&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/trunk/subversion/libsvn_wc/diff_local.c Thu Feb 20 12:57:15 2014
@@ -42,8 +42,8 @@
 #include "private/svn_diff_tree.h"
 
 #include "wc.h"
+#include "wc_db.h"
 #include "props.h"
-#include "translate.h"
 #include "diff.h"
 
 /*-------------------------------------------------------------------------*/
@@ -428,7 +428,8 @@ diff_status_callback(void *baton,
 
 /* Public Interface */
 svn_error_t *
-svn_wc__diff7(const char **anchor_abspath,
+svn_wc__diff7(const char **root_relpath,
+              svn_boolean_t *root_is_dir,
               svn_wc_context_t *wc_ctx,
               const char *local_abspath,
               svn_depth_t depth,
@@ -451,13 +452,27 @@ svn_wc__diff7(const char **anchor_abspat
                                FALSE /* show_hidden */,
                                scratch_pool));
 
-  if (kind == svn_node_dir)
-    eb.anchor_abspath = local_abspath;
-  else
+  eb.anchor_abspath = local_abspath;
+
+  if (root_relpath)
+    {
+      svn_boolean_t is_wcroot;
+
+      SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot,
+                                   wc_ctx->db, local_abspath, scratch_pool));
+
+      if (!is_wcroot)
+        eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+    }
+  else if (kind != svn_node_dir)
     eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
 
-  if (anchor_abspath)
-    *anchor_abspath = apr_pstrdup(result_pool, eb.anchor_abspath);
+  if (root_relpath)
+    *root_relpath = apr_pstrdup(result_pool,
+                                svn_dirent_skip_ancestor(eb.anchor_abspath,
+                                                         local_abspath));
+  if (root_is_dir)
+    *root_is_dir = (kind == svn_node_dir);
 
   eb.db = wc_ctx->db;
   eb.processor = diff_processor;
@@ -544,7 +559,7 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
     processor = svn_diff__tree_processor_copy_as_changed_create(processor,
                                                                 scratch_pool);
 
-  return svn_error_trace(svn_wc__diff7(NULL,
+  return svn_error_trace(svn_wc__diff7(NULL, NULL,
                                        wc_ctx, local_abspath,
                                        depth,
                                        ignore_ancestry,