1251881Speter/*
2299742Sdim * diff_local.c -- A simple diff walker which compares local files against
3299742Sdim *                 their pristine versions.
4251881Speter *
5251881Speter * ====================================================================
6251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
7251881Speter *    or more contributor license agreements.  See the NOTICE file
8251881Speter *    distributed with this work for additional information
9251881Speter *    regarding copyright ownership.  The ASF licenses this file
10251881Speter *    to you under the Apache License, Version 2.0 (the
11251881Speter *    "License"); you may not use this file except in compliance
12251881Speter *    with the License.  You may obtain a copy of the License at
13251881Speter *
14251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
15251881Speter *
16251881Speter *    Unless required by applicable law or agreed to in writing,
17251881Speter *    software distributed under the License is distributed on an
18251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19251881Speter *    KIND, either express or implied.  See the License for the
20251881Speter *    specific language governing permissions and limitations
21251881Speter *    under the License.
22251881Speter * ====================================================================
23251881Speter *
24251881Speter * This is the simple working copy diff algorithm which is used when you
25251881Speter * just use 'svn diff PATH'. It shows what is modified in your working copy
26251881Speter * since a node was checked out or copied but doesn't show most kinds of
27251881Speter * restructuring operations.
28251881Speter *
29251881Speter * You can look at this as another form of the status walker.
30251881Speter */
31251881Speter
32251881Speter#include <apr_hash.h>
33251881Speter
34251881Speter#include "svn_error.h"
35251881Speter#include "svn_pools.h"
36251881Speter#include "svn_dirent_uri.h"
37251881Speter#include "svn_path.h"
38251881Speter#include "svn_hash.h"
39251881Speter
40251881Speter#include "private/svn_wc_private.h"
41251881Speter#include "private/svn_diff_tree.h"
42251881Speter
43251881Speter#include "wc.h"
44299742Sdim#include "wc_db.h"
45251881Speter#include "props.h"
46251881Speter#include "diff.h"
47251881Speter
48251881Speter#include "svn_private_config.h"
49251881Speter
50251881Speter/*-------------------------------------------------------------------------*/
51251881Speter
52251881Speter/* Baton containing the state of a directory
53251881Speter   reported open via a diff processor */
54251881Speterstruct node_state_t
55251881Speter{
56251881Speter  struct node_state_t *parent;
57251881Speter
58251881Speter  apr_pool_t *pool;
59251881Speter
60251881Speter  const char *local_abspath;
61251881Speter  const char *relpath;
62251881Speter  void *baton;
63251881Speter
64251881Speter  svn_diff_source_t *left_src;
65251881Speter  svn_diff_source_t *right_src;
66251881Speter  svn_diff_source_t *copy_src;
67251881Speter
68251881Speter  svn_boolean_t skip;
69251881Speter  svn_boolean_t skip_children;
70251881Speter
71251881Speter  apr_hash_t *left_props;
72251881Speter  apr_hash_t *right_props;
73251881Speter  const apr_array_header_t *propchanges;
74251881Speter};
75251881Speter
76251881Speter/* The diff baton */
77251881Speterstruct diff_baton
78251881Speter{
79251881Speter  /* A wc db. */
80251881Speter  svn_wc__db_t *db;
81251881Speter
82251881Speter  /* Report editor paths relative from this directory */
83251881Speter  const char *anchor_abspath;
84251881Speter
85251881Speter  struct node_state_t *cur;
86251881Speter
87251881Speter  const svn_diff_tree_processor_t *processor;
88251881Speter
89251881Speter  /* Should this diff ignore node ancestry? */
90251881Speter  svn_boolean_t ignore_ancestry;
91251881Speter
92251881Speter  /* Cancel function/baton */
93251881Speter  svn_cancel_func_t cancel_func;
94251881Speter  void *cancel_baton;
95251881Speter
96251881Speter  apr_pool_t *pool;
97251881Speter};
98251881Speter
99251881Speter/* Recursively opens directories on the stack in EB, until LOCAL_ABSPATH
100251881Speter   is reached. If RECURSIVE_SKIP is TRUE, don't open LOCAL_ABSPATH itself,
101251881Speter   but create it marked with skip+skip_children.
102251881Speter */
103251881Speterstatic svn_error_t *
104251881Speterensure_state(struct diff_baton *eb,
105251881Speter             const char *local_abspath,
106251881Speter             svn_boolean_t recursive_skip,
107251881Speter             apr_pool_t *scratch_pool)
108251881Speter{
109251881Speter  struct node_state_t *ns;
110251881Speter  apr_pool_t *ns_pool;
111251881Speter  if (!eb->cur)
112251881Speter    {
113262253Speter      const char *relpath;
114262253Speter
115262253Speter      relpath = svn_dirent_skip_ancestor(eb->anchor_abspath, local_abspath);
116262253Speter      if (! relpath)
117251881Speter        return SVN_NO_ERROR;
118251881Speter
119299742Sdim      /* Don't recurse on the anchor, as that might loop infinitely because
120262253Speter            svn_dirent_dirname("/",...)   -> "/"
121262253Speter            svn_dirent_dirname("C:/",...) -> "C:/" (Windows) */
122262253Speter      if (*relpath)
123262253Speter        SVN_ERR(ensure_state(eb,
124299742Sdim                             svn_dirent_dirname(local_abspath, scratch_pool),
125262253Speter                             FALSE,
126262253Speter                             scratch_pool));
127251881Speter    }
128251881Speter  else if (svn_dirent_is_child(eb->cur->local_abspath, local_abspath, NULL))
129299742Sdim    SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
130251881Speter                         FALSE,
131251881Speter                         scratch_pool));
132251881Speter  else
133251881Speter    return SVN_NO_ERROR;
134251881Speter
135251881Speter  if (eb->cur && eb->cur->skip_children)
136251881Speter    return SVN_NO_ERROR;
137251881Speter
138251881Speter  ns_pool = svn_pool_create(eb->cur ? eb->cur->pool : eb->pool);
139251881Speter  ns = apr_pcalloc(ns_pool, sizeof(*ns));
140251881Speter
141251881Speter  ns->pool = ns_pool;
142251881Speter  ns->local_abspath = apr_pstrdup(ns_pool, local_abspath);
143251881Speter  ns->relpath = svn_dirent_skip_ancestor(eb->anchor_abspath, ns->local_abspath);
144251881Speter  ns->parent = eb->cur;
145251881Speter  eb->cur = ns;
146251881Speter
147251881Speter  if (recursive_skip)
148251881Speter    {
149251881Speter      ns->skip = TRUE;
150251881Speter      ns->skip_children = TRUE;
151251881Speter      return SVN_NO_ERROR;
152251881Speter    }
153251881Speter
154251881Speter  {
155251881Speter    svn_revnum_t revision;
156251881Speter    svn_error_t *err;
157251881Speter
158251881Speter    err = svn_wc__db_base_get_info(NULL, NULL, &revision, NULL, NULL, NULL,
159251881Speter                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
160251881Speter                                   NULL, NULL, NULL,
161251881Speter                                   eb->db, local_abspath,
162251881Speter                                   scratch_pool, scratch_pool);
163251881Speter
164251881Speter    if (err)
165251881Speter      {
166251881Speter        if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
167251881Speter          return svn_error_trace(err);
168251881Speter        svn_error_clear(err);
169251881Speter
170251881Speter        revision = 0; /* Use original revision? */
171251881Speter      }
172251881Speter    ns->left_src = svn_diff__source_create(revision, ns->pool);
173251881Speter    ns->right_src = svn_diff__source_create(SVN_INVALID_REVNUM, ns->pool);
174251881Speter
175251881Speter    SVN_ERR(eb->processor->dir_opened(&ns->baton, &ns->skip,
176251881Speter                                      &ns->skip_children,
177251881Speter                                      ns->relpath,
178251881Speter                                      ns->left_src,
179251881Speter                                      ns->right_src,
180251881Speter                                      NULL /* copyfrom_source */,
181251881Speter                                      ns->parent ? ns->parent->baton : NULL,
182251881Speter                                      eb->processor,
183251881Speter                                      ns->pool, scratch_pool));
184251881Speter  }
185251881Speter
186251881Speter  return SVN_NO_ERROR;
187251881Speter}
188251881Speter
189251881Speter/* Implements svn_wc_status_func3_t */
190251881Speterstatic svn_error_t *
191251881Speterdiff_status_callback(void *baton,
192251881Speter                     const char *local_abspath,
193251881Speter                     const svn_wc_status3_t *status,
194251881Speter                     apr_pool_t *scratch_pool)
195251881Speter{
196251881Speter  struct diff_baton *eb = baton;
197251881Speter  svn_wc__db_t *db = eb->db;
198251881Speter
199262253Speter  if (! status->versioned)
200262253Speter    return SVN_NO_ERROR; /* unversioned (includes dir externals) */
201262253Speter
202262253Speter  if (status->node_status == svn_wc_status_conflicted
203262253Speter      && status->text_status == svn_wc_status_none
204262253Speter      && status->prop_status == svn_wc_status_none)
205251881Speter    {
206262253Speter      /* Node is an actual only node describing a tree conflict */
207262253Speter      return SVN_NO_ERROR;
208251881Speter    }
209251881Speter
210251881Speter  /* Not text/prop modified, not copied. Easy out */
211251881Speter  if (status->node_status == svn_wc_status_normal && !status->copied)
212251881Speter    return SVN_NO_ERROR;
213251881Speter
214251881Speter  /* Mark all directories where we are no longer inside as closed */
215251881Speter  while (eb->cur
216251881Speter         && !svn_dirent_is_ancestor(eb->cur->local_abspath, local_abspath))
217251881Speter    {
218251881Speter      struct node_state_t *ns = eb->cur;
219251881Speter
220251881Speter      if (!ns->skip)
221251881Speter        {
222251881Speter          if (ns->propchanges)
223251881Speter            SVN_ERR(eb->processor->dir_changed(ns->relpath,
224251881Speter                                               ns->left_src,
225251881Speter                                               ns->right_src,
226251881Speter                                               ns->left_props,
227251881Speter                                               ns->right_props,
228251881Speter                                               ns->propchanges,
229251881Speter                                               ns->baton,
230251881Speter                                               eb->processor,
231251881Speter                                               ns->pool));
232251881Speter          else
233251881Speter            SVN_ERR(eb->processor->dir_closed(ns->relpath,
234251881Speter                                              ns->left_src,
235251881Speter                                              ns->right_src,
236251881Speter                                              ns->baton,
237251881Speter                                              eb->processor,
238251881Speter                                              ns->pool));
239251881Speter        }
240251881Speter      eb->cur = ns->parent;
241251881Speter      svn_pool_clear(ns->pool);
242251881Speter    }
243251881Speter  SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
244251881Speter                       FALSE, scratch_pool));
245251881Speter
246251881Speter  if (eb->cur && eb->cur->skip_children)
247251881Speter    return SVN_NO_ERROR;
248251881Speter
249251881Speter  /* This code does about the same thing as the inner body of
250251881Speter     walk_local_nodes_diff() in diff_editor.c, except that
251251881Speter     it is already filtered by the status walker, doesn't have to
252251881Speter     account for remote changes (and many tiny other details) */
253251881Speter
254251881Speter  {
255251881Speter    svn_boolean_t repos_only;
256251881Speter    svn_boolean_t local_only;
257251881Speter    svn_wc__db_status_t db_status;
258251881Speter    svn_boolean_t have_base;
259251881Speter    svn_node_kind_t base_kind;
260251881Speter    svn_node_kind_t db_kind = status->kind;
261251881Speter    svn_depth_t depth_below_here = svn_depth_unknown;
262251881Speter
263251881Speter    const char *child_abspath = local_abspath;
264251881Speter    const char *child_relpath = svn_dirent_skip_ancestor(eb->anchor_abspath,
265251881Speter                                                         local_abspath);
266251881Speter
267251881Speter
268251881Speter    repos_only = FALSE;
269251881Speter    local_only = FALSE;
270251881Speter
271251881Speter    /* ### optimize away this call using status info. Should
272251881Speter           be possible in almost every case (except conflict, missing, obst.)*/
273251881Speter    SVN_ERR(svn_wc__db_read_info(&db_status, NULL, NULL, NULL, NULL, NULL,
274251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
275251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
276251881Speter                                 NULL, NULL, NULL, NULL,
277251881Speter                                 &have_base, NULL, NULL,
278251881Speter                                 eb->db, local_abspath,
279251881Speter                                 scratch_pool, scratch_pool));
280251881Speter    if (!have_base)
281251881Speter      {
282251881Speter        local_only = TRUE; /* Only report additions */
283251881Speter      }
284251881Speter    else if (db_status == svn_wc__db_status_normal)
285251881Speter      {
286251881Speter        /* Simple diff */
287251881Speter        base_kind = db_kind;
288251881Speter      }
289251881Speter    else if (db_status == svn_wc__db_status_deleted)
290251881Speter      {
291251881Speter        svn_wc__db_status_t base_status;
292251881Speter        repos_only = TRUE;
293251881Speter        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
294251881Speter                                         NULL, NULL, NULL, NULL, NULL,
295251881Speter                                         NULL, NULL, NULL, NULL, NULL,
296251881Speter                                         NULL, NULL, NULL,
297251881Speter                                         eb->db, local_abspath,
298251881Speter                                         scratch_pool, scratch_pool));
299251881Speter
300251881Speter        if (base_status != svn_wc__db_status_normal)
301251881Speter          return SVN_NO_ERROR;
302251881Speter      }
303251881Speter    else
304251881Speter      {
305251881Speter        /* working status is either added or deleted */
306251881Speter        svn_wc__db_status_t base_status;
307251881Speter
308251881Speter        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
309251881Speter                                         NULL, NULL, NULL, NULL, NULL,
310251881Speter                                         NULL, NULL, NULL, NULL, NULL,
311251881Speter                                         NULL, NULL, NULL,
312251881Speter                                         eb->db, local_abspath,
313251881Speter                                         scratch_pool, scratch_pool));
314251881Speter
315251881Speter        if (base_status != svn_wc__db_status_normal)
316251881Speter          local_only = TRUE;
317251881Speter        else if (base_kind != db_kind || !eb->ignore_ancestry)
318251881Speter          {
319251881Speter            repos_only = TRUE;
320251881Speter            local_only = TRUE;
321251881Speter          }
322251881Speter      }
323251881Speter
324251881Speter    if (repos_only)
325251881Speter      {
326251881Speter        /* Report repository form deleted */
327251881Speter        if (base_kind == svn_node_file)
328251881Speter          SVN_ERR(svn_wc__diff_base_only_file(db, child_abspath,
329251881Speter                                              child_relpath,
330251881Speter                                              SVN_INVALID_REVNUM,
331251881Speter                                              eb->processor,
332251881Speter                                              eb->cur ? eb->cur->baton : NULL,
333251881Speter                                              scratch_pool));
334251881Speter        else if (base_kind == svn_node_dir)
335251881Speter          SVN_ERR(svn_wc__diff_base_only_dir(db, child_abspath,
336251881Speter                                             child_relpath,
337251881Speter                                             SVN_INVALID_REVNUM,
338251881Speter                                             depth_below_here,
339251881Speter                                             eb->processor,
340251881Speter                                             eb->cur ? eb->cur->baton : NULL,
341251881Speter                                             eb->cancel_func,
342251881Speter                                             eb->cancel_baton,
343251881Speter                                             scratch_pool));
344251881Speter      }
345251881Speter    else if (!local_only)
346251881Speter      {
347251881Speter        /* Diff base against actual */
348251881Speter        if (db_kind == svn_node_file)
349251881Speter          {
350251881Speter            SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
351251881Speter                                                   child_relpath,
352251881Speter                                                   SVN_INVALID_REVNUM,
353251881Speter                                                   eb->processor,
354251881Speter                                                   eb->cur
355251881Speter                                                        ? eb->cur->baton
356251881Speter                                                        : NULL,
357251881Speter                                                   FALSE,
358251881Speter                                                   eb->cancel_func,
359251881Speter                                                   eb->cancel_baton,
360251881Speter                                                   scratch_pool));
361251881Speter          }
362251881Speter        else if (db_kind == svn_node_dir)
363251881Speter          {
364251881Speter            SVN_ERR(ensure_state(eb, local_abspath, FALSE, scratch_pool));
365251881Speter
366251881Speter            if (status->prop_status != svn_wc_status_none
367251881Speter                && status->prop_status != svn_wc_status_normal)
368251881Speter              {
369251881Speter                apr_array_header_t *propchanges;
370251881Speter                SVN_ERR(svn_wc__db_base_get_props(&eb->cur->left_props,
371251881Speter                                                  eb->db, local_abspath,
372251881Speter                                                  eb->cur->pool,
373251881Speter                                                  scratch_pool));
374251881Speter                SVN_ERR(svn_wc__db_read_props(&eb->cur->right_props,
375251881Speter                                              eb->db, local_abspath,
376251881Speter                                              eb->cur->pool,
377251881Speter                                              scratch_pool));
378251881Speter
379251881Speter                SVN_ERR(svn_prop_diffs(&propchanges,
380251881Speter                                       eb->cur->right_props,
381251881Speter                                       eb->cur->left_props,
382251881Speter                                       eb->cur->pool));
383251881Speter
384251881Speter                eb->cur->propchanges = propchanges;
385251881Speter              }
386251881Speter          }
387251881Speter      }
388251881Speter
389262253Speter    if (local_only && (db_status != svn_wc__db_status_deleted))
390251881Speter      {
391251881Speter        if (db_kind == svn_node_file)
392251881Speter          SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
393251881Speter                                               child_relpath,
394251881Speter                                               eb->processor,
395251881Speter                                               eb->cur ? eb->cur->baton : NULL,
396251881Speter                                               FALSE,
397251881Speter                                               eb->cancel_func,
398251881Speter                                               eb->cancel_baton,
399251881Speter                                               scratch_pool));
400251881Speter        else if (db_kind == svn_node_dir)
401251881Speter          SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
402251881Speter                                              child_relpath, depth_below_here,
403251881Speter                                              eb->processor,
404251881Speter                                              eb->cur ? eb->cur->baton : NULL,
405251881Speter                                              FALSE,
406251881Speter                                              eb->cancel_func,
407251881Speter                                              eb->cancel_baton,
408251881Speter                                              scratch_pool));
409251881Speter      }
410251881Speter
411251881Speter    if (db_kind == svn_node_dir && (local_only || repos_only))
412251881Speter      SVN_ERR(ensure_state(eb, local_abspath, TRUE /* skip */, scratch_pool));
413251881Speter  }
414251881Speter
415251881Speter  return SVN_NO_ERROR;
416251881Speter}
417251881Speter
418251881Speter
419251881Speter/* Public Interface */
420251881Spetersvn_error_t *
421299742Sdimsvn_wc__diff7(const char **root_relpath,
422299742Sdim              svn_boolean_t *root_is_dir,
423299742Sdim              svn_wc_context_t *wc_ctx,
424299742Sdim              const char *local_abspath,
425299742Sdim              svn_depth_t depth,
426299742Sdim              svn_boolean_t ignore_ancestry,
427299742Sdim              const apr_array_header_t *changelist_filter,
428299742Sdim              const svn_diff_tree_processor_t *diff_processor,
429299742Sdim              svn_cancel_func_t cancel_func,
430299742Sdim              void *cancel_baton,
431299742Sdim              apr_pool_t *result_pool,
432299742Sdim              apr_pool_t *scratch_pool)
433251881Speter{
434251881Speter  struct diff_baton eb = { 0 };
435251881Speter  svn_node_kind_t kind;
436251881Speter  svn_boolean_t get_all;
437251881Speter
438251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
439251881Speter  SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath,
440251881Speter                               FALSE /* allow_missing */,
441251881Speter                               TRUE /* show_deleted */,
442251881Speter                               FALSE /* show_hidden */,
443251881Speter                               scratch_pool));
444251881Speter
445299742Sdim  eb.anchor_abspath = local_abspath;
446251881Speter
447299742Sdim  if (root_relpath)
448299742Sdim    {
449299742Sdim      svn_boolean_t is_wcroot;
450251881Speter
451299742Sdim      SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot,
452299742Sdim                                   wc_ctx->db, local_abspath, scratch_pool));
453251881Speter
454299742Sdim      if (!is_wcroot)
455299742Sdim        eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
456299742Sdim    }
457299742Sdim  else if (kind != svn_node_dir)
458299742Sdim    eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
459251881Speter
460299742Sdim  if (root_relpath)
461299742Sdim    *root_relpath = apr_pstrdup(result_pool,
462299742Sdim                                svn_dirent_skip_ancestor(eb.anchor_abspath,
463299742Sdim                                                         local_abspath));
464299742Sdim  if (root_is_dir)
465299742Sdim    *root_is_dir = (kind == svn_node_dir);
466251881Speter
467289166Speter  /* Apply changelist filtering to the output */
468289166Speter  if (changelist_filter && changelist_filter->nelts)
469289166Speter    {
470289166Speter      apr_hash_t *changelist_hash;
471289166Speter
472289166Speter      SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
473299742Sdim                                         result_pool));
474299742Sdim      diff_processor = svn_wc__changelist_filter_tree_processor_create(
475299742Sdim                         diff_processor, wc_ctx, local_abspath,
476299742Sdim                         changelist_hash, result_pool);
477289166Speter    }
478289166Speter
479251881Speter  eb.db = wc_ctx->db;
480299742Sdim  eb.processor = diff_processor;
481251881Speter  eb.ignore_ancestry = ignore_ancestry;
482251881Speter  eb.pool = scratch_pool;
483251881Speter
484299742Sdim  if (ignore_ancestry)
485251881Speter    get_all = TRUE; /* We need unmodified descendants of copies */
486251881Speter  else
487251881Speter    get_all = FALSE;
488251881Speter
489251881Speter  /* Walk status handles files and directories */
490251881Speter  SVN_ERR(svn_wc__internal_walk_status(wc_ctx->db, local_abspath, depth,
491251881Speter                                       get_all,
492251881Speter                                       TRUE /* no_ignore */,
493251881Speter                                       FALSE /* ignore_text_mods */,
494251881Speter                                       NULL /* ignore_patterns */,
495251881Speter                                       diff_status_callback, &eb,
496251881Speter                                       cancel_func, cancel_baton,
497251881Speter                                       scratch_pool));
498251881Speter
499251881Speter  /* Close the remaining open directories */
500251881Speter  while (eb.cur)
501251881Speter    {
502251881Speter      struct node_state_t *ns = eb.cur;
503251881Speter
504251881Speter      if (!ns->skip)
505251881Speter        {
506251881Speter          if (ns->propchanges)
507299742Sdim            SVN_ERR(diff_processor->dir_changed(ns->relpath,
508299742Sdim                                                ns->left_src,
509299742Sdim                                                ns->right_src,
510299742Sdim                                                ns->left_props,
511299742Sdim                                                ns->right_props,
512299742Sdim                                                ns->propchanges,
513299742Sdim                                                ns->baton,
514299742Sdim                                                diff_processor,
515299742Sdim                                                ns->pool));
516251881Speter          else
517299742Sdim            SVN_ERR(diff_processor->dir_closed(ns->relpath,
518299742Sdim                                               ns->left_src,
519299742Sdim                                               ns->right_src,
520299742Sdim                                               ns->baton,
521299742Sdim                                               diff_processor,
522299742Sdim                                               ns->pool));
523251881Speter        }
524251881Speter      eb.cur = ns->parent;
525251881Speter      svn_pool_clear(ns->pool);
526251881Speter    }
527251881Speter
528251881Speter  return SVN_NO_ERROR;
529251881Speter}
530299742Sdim
531299742Sdimsvn_error_t *
532299742Sdimsvn_wc_diff6(svn_wc_context_t *wc_ctx,
533299742Sdim             const char *local_abspath,
534299742Sdim             const svn_wc_diff_callbacks4_t *callbacks,
535299742Sdim             void *callback_baton,
536299742Sdim             svn_depth_t depth,
537299742Sdim             svn_boolean_t ignore_ancestry,
538299742Sdim             svn_boolean_t show_copies_as_adds,
539299742Sdim             svn_boolean_t use_git_diff_format,
540299742Sdim             const apr_array_header_t *changelist_filter,
541299742Sdim             svn_cancel_func_t cancel_func,
542299742Sdim             void *cancel_baton,
543299742Sdim             apr_pool_t *scratch_pool)
544299742Sdim{
545299742Sdim  const svn_diff_tree_processor_t *processor;
546299742Sdim
547299742Sdim  SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
548299742Sdim                                      callbacks, callback_baton, TRUE,
549299742Sdim                                      scratch_pool, scratch_pool));
550299742Sdim
551299742Sdim  if (use_git_diff_format)
552299742Sdim    show_copies_as_adds = TRUE;
553299742Sdim  if (show_copies_as_adds)
554299742Sdim    ignore_ancestry = FALSE;
555299742Sdim
556299742Sdim  if (! show_copies_as_adds && !use_git_diff_format)
557299742Sdim    processor = svn_diff__tree_processor_copy_as_changed_create(processor,
558299742Sdim                                                                scratch_pool);
559299742Sdim
560299742Sdim  return svn_error_trace(svn_wc__diff7(NULL, NULL,
561299742Sdim                                       wc_ctx, local_abspath,
562299742Sdim                                       depth,
563299742Sdim                                       ignore_ancestry,
564299742Sdim                                       changelist_filter,
565299742Sdim                                       processor,
566299742Sdim                                       cancel_func, cancel_baton,
567299742Sdim                                       scratch_pool, scratch_pool));
568299742Sdim}
569299742Sdim
570