1251881Speter/*
2251881Speter * diff_pristine.c -- A simple diff walker which compares local files against
3251881Speter *                    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"
44251881Speter#include "props.h"
45251881Speter#include "translate.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  /* Should this diff not compare copied files with their source? */
93251881Speter  svn_boolean_t show_copies_as_adds;
94251881Speter
95251881Speter  /* Hash whose keys are const char * changelist names. */
96251881Speter  apr_hash_t *changelist_hash;
97251881Speter
98251881Speter  /* Cancel function/baton */
99251881Speter  svn_cancel_func_t cancel_func;
100251881Speter  void *cancel_baton;
101251881Speter
102251881Speter  apr_pool_t *pool;
103251881Speter};
104251881Speter
105251881Speter/* Recursively opens directories on the stack in EB, until LOCAL_ABSPATH
106251881Speter   is reached. If RECURSIVE_SKIP is TRUE, don't open LOCAL_ABSPATH itself,
107251881Speter   but create it marked with skip+skip_children.
108251881Speter */
109251881Speterstatic svn_error_t *
110251881Speterensure_state(struct diff_baton *eb,
111251881Speter             const char *local_abspath,
112251881Speter             svn_boolean_t recursive_skip,
113251881Speter             apr_pool_t *scratch_pool)
114251881Speter{
115251881Speter  struct node_state_t *ns;
116251881Speter  apr_pool_t *ns_pool;
117251881Speter  if (!eb->cur)
118251881Speter    {
119262253Speter      const char *relpath;
120262253Speter
121262253Speter      relpath = svn_dirent_skip_ancestor(eb->anchor_abspath, local_abspath);
122262253Speter      if (! relpath)
123251881Speter        return SVN_NO_ERROR;
124251881Speter
125262253Speter      /* Don't recurse on the anchor, as that might loop infinately because
126262253Speter            svn_dirent_dirname("/",...)   -> "/"
127262253Speter            svn_dirent_dirname("C:/",...) -> "C:/" (Windows) */
128262253Speter      if (*relpath)
129262253Speter        SVN_ERR(ensure_state(eb,
130262253Speter                             svn_dirent_dirname(local_abspath,scratch_pool),
131262253Speter                             FALSE,
132262253Speter                             scratch_pool));
133251881Speter    }
134251881Speter  else if (svn_dirent_is_child(eb->cur->local_abspath, local_abspath, NULL))
135251881Speter    SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath,scratch_pool),
136251881Speter                         FALSE,
137251881Speter                         scratch_pool));
138251881Speter  else
139251881Speter    return SVN_NO_ERROR;
140251881Speter
141251881Speter  if (eb->cur && eb->cur->skip_children)
142251881Speter    return SVN_NO_ERROR;
143251881Speter
144251881Speter  ns_pool = svn_pool_create(eb->cur ? eb->cur->pool : eb->pool);
145251881Speter  ns = apr_pcalloc(ns_pool, sizeof(*ns));
146251881Speter
147251881Speter  ns->pool = ns_pool;
148251881Speter  ns->local_abspath = apr_pstrdup(ns_pool, local_abspath);
149251881Speter  ns->relpath = svn_dirent_skip_ancestor(eb->anchor_abspath, ns->local_abspath);
150251881Speter  ns->parent = eb->cur;
151251881Speter  eb->cur = ns;
152251881Speter
153251881Speter  if (recursive_skip)
154251881Speter    {
155251881Speter      ns->skip = TRUE;
156251881Speter      ns->skip_children = TRUE;
157251881Speter      return SVN_NO_ERROR;
158251881Speter    }
159251881Speter
160251881Speter  {
161251881Speter    svn_revnum_t revision;
162251881Speter    svn_error_t *err;
163251881Speter
164251881Speter    err = svn_wc__db_base_get_info(NULL, NULL, &revision, NULL, NULL, NULL,
165251881Speter                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
166251881Speter                                   NULL, NULL, NULL,
167251881Speter                                   eb->db, local_abspath,
168251881Speter                                   scratch_pool, scratch_pool);
169251881Speter
170251881Speter    if (err)
171251881Speter      {
172251881Speter        if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
173251881Speter          return svn_error_trace(err);
174251881Speter        svn_error_clear(err);
175251881Speter
176251881Speter        revision = 0; /* Use original revision? */
177251881Speter      }
178251881Speter    ns->left_src = svn_diff__source_create(revision, ns->pool);
179251881Speter    ns->right_src = svn_diff__source_create(SVN_INVALID_REVNUM, ns->pool);
180251881Speter
181251881Speter    SVN_ERR(eb->processor->dir_opened(&ns->baton, &ns->skip,
182251881Speter                                      &ns->skip_children,
183251881Speter                                      ns->relpath,
184251881Speter                                      ns->left_src,
185251881Speter                                      ns->right_src,
186251881Speter                                      NULL /* copyfrom_source */,
187251881Speter                                      ns->parent ? ns->parent->baton : NULL,
188251881Speter                                      eb->processor,
189251881Speter                                      ns->pool, scratch_pool));
190251881Speter  }
191251881Speter
192251881Speter  return SVN_NO_ERROR;
193251881Speter}
194251881Speter
195251881Speter/* Implements svn_wc_status_func3_t */
196251881Speterstatic svn_error_t *
197251881Speterdiff_status_callback(void *baton,
198251881Speter                     const char *local_abspath,
199251881Speter                     const svn_wc_status3_t *status,
200251881Speter                     apr_pool_t *scratch_pool)
201251881Speter{
202251881Speter  struct diff_baton *eb = baton;
203251881Speter  svn_wc__db_t *db = eb->db;
204251881Speter
205262253Speter  if (! status->versioned)
206262253Speter    return SVN_NO_ERROR; /* unversioned (includes dir externals) */
207262253Speter
208262253Speter  if (status->node_status == svn_wc_status_conflicted
209262253Speter      && status->text_status == svn_wc_status_none
210262253Speter      && status->prop_status == svn_wc_status_none)
211251881Speter    {
212262253Speter      /* Node is an actual only node describing a tree conflict */
213262253Speter      return SVN_NO_ERROR;
214251881Speter    }
215251881Speter
216251881Speter  /* Not text/prop modified, not copied. Easy out */
217251881Speter  if (status->node_status == svn_wc_status_normal && !status->copied)
218251881Speter    return SVN_NO_ERROR;
219251881Speter
220251881Speter  /* Mark all directories where we are no longer inside as closed */
221251881Speter  while (eb->cur
222251881Speter         && !svn_dirent_is_ancestor(eb->cur->local_abspath, local_abspath))
223251881Speter    {
224251881Speter      struct node_state_t *ns = eb->cur;
225251881Speter
226251881Speter      if (!ns->skip)
227251881Speter        {
228251881Speter          if (ns->propchanges)
229251881Speter            SVN_ERR(eb->processor->dir_changed(ns->relpath,
230251881Speter                                               ns->left_src,
231251881Speter                                               ns->right_src,
232251881Speter                                               ns->left_props,
233251881Speter                                               ns->right_props,
234251881Speter                                               ns->propchanges,
235251881Speter                                               ns->baton,
236251881Speter                                               eb->processor,
237251881Speter                                               ns->pool));
238251881Speter          else
239251881Speter            SVN_ERR(eb->processor->dir_closed(ns->relpath,
240251881Speter                                              ns->left_src,
241251881Speter                                              ns->right_src,
242251881Speter                                              ns->baton,
243251881Speter                                              eb->processor,
244251881Speter                                              ns->pool));
245251881Speter        }
246251881Speter      eb->cur = ns->parent;
247251881Speter      svn_pool_clear(ns->pool);
248251881Speter    }
249251881Speter  SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
250251881Speter                       FALSE, scratch_pool));
251251881Speter
252251881Speter  if (eb->cur && eb->cur->skip_children)
253251881Speter    return SVN_NO_ERROR;
254251881Speter
255251881Speter  if (eb->changelist_hash != NULL
256251881Speter      && (!status->changelist
257251881Speter          || ! svn_hash_gets(eb->changelist_hash, status->changelist)))
258251881Speter    return SVN_NO_ERROR; /* Filtered via changelist */
259251881Speter
260251881Speter  /* This code does about the same thing as the inner body of
261251881Speter     walk_local_nodes_diff() in diff_editor.c, except that
262251881Speter     it is already filtered by the status walker, doesn't have to
263251881Speter     account for remote changes (and many tiny other details) */
264251881Speter
265251881Speter  {
266251881Speter    svn_boolean_t repos_only;
267251881Speter    svn_boolean_t local_only;
268251881Speter    svn_wc__db_status_t db_status;
269251881Speter    svn_boolean_t have_base;
270251881Speter    svn_node_kind_t base_kind;
271251881Speter    svn_node_kind_t db_kind = status->kind;
272251881Speter    svn_depth_t depth_below_here = svn_depth_unknown;
273251881Speter
274251881Speter    const char *child_abspath = local_abspath;
275251881Speter    const char *child_relpath = svn_dirent_skip_ancestor(eb->anchor_abspath,
276251881Speter                                                         local_abspath);
277251881Speter
278251881Speter
279251881Speter    repos_only = FALSE;
280251881Speter    local_only = FALSE;
281251881Speter
282251881Speter    /* ### optimize away this call using status info. Should
283251881Speter           be possible in almost every case (except conflict, missing, obst.)*/
284251881Speter    SVN_ERR(svn_wc__db_read_info(&db_status, NULL, NULL, NULL, NULL, NULL,
285251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
286251881Speter                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
287251881Speter                                 NULL, NULL, NULL, NULL,
288251881Speter                                 &have_base, NULL, NULL,
289251881Speter                                 eb->db, local_abspath,
290251881Speter                                 scratch_pool, scratch_pool));
291251881Speter    if (!have_base)
292251881Speter      {
293251881Speter        local_only = TRUE; /* Only report additions */
294251881Speter      }
295251881Speter    else if (db_status == svn_wc__db_status_normal)
296251881Speter      {
297251881Speter        /* Simple diff */
298251881Speter        base_kind = db_kind;
299251881Speter      }
300251881Speter    else if (db_status == svn_wc__db_status_deleted)
301251881Speter      {
302251881Speter        svn_wc__db_status_t base_status;
303251881Speter        repos_only = TRUE;
304251881Speter        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
305251881Speter                                         NULL, NULL, NULL, NULL, NULL,
306251881Speter                                         NULL, NULL, NULL, NULL, NULL,
307251881Speter                                         NULL, NULL, NULL,
308251881Speter                                         eb->db, local_abspath,
309251881Speter                                         scratch_pool, scratch_pool));
310251881Speter
311251881Speter        if (base_status != svn_wc__db_status_normal)
312251881Speter          return SVN_NO_ERROR;
313251881Speter      }
314251881Speter    else
315251881Speter      {
316251881Speter        /* working status is either added or deleted */
317251881Speter        svn_wc__db_status_t base_status;
318251881Speter
319251881Speter        SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, NULL,
320251881Speter                                         NULL, NULL, NULL, NULL, NULL,
321251881Speter                                         NULL, NULL, NULL, NULL, NULL,
322251881Speter                                         NULL, NULL, NULL,
323251881Speter                                         eb->db, local_abspath,
324251881Speter                                         scratch_pool, scratch_pool));
325251881Speter
326251881Speter        if (base_status != svn_wc__db_status_normal)
327251881Speter          local_only = TRUE;
328251881Speter        else if (base_kind != db_kind || !eb->ignore_ancestry)
329251881Speter          {
330251881Speter            repos_only = TRUE;
331251881Speter            local_only = TRUE;
332251881Speter          }
333251881Speter      }
334251881Speter
335251881Speter    if (repos_only)
336251881Speter      {
337251881Speter        /* Report repository form deleted */
338251881Speter        if (base_kind == svn_node_file)
339251881Speter          SVN_ERR(svn_wc__diff_base_only_file(db, child_abspath,
340251881Speter                                              child_relpath,
341251881Speter                                              SVN_INVALID_REVNUM,
342251881Speter                                              eb->processor,
343251881Speter                                              eb->cur ? eb->cur->baton : NULL,
344251881Speter                                              scratch_pool));
345251881Speter        else if (base_kind == svn_node_dir)
346251881Speter          SVN_ERR(svn_wc__diff_base_only_dir(db, child_abspath,
347251881Speter                                             child_relpath,
348251881Speter                                             SVN_INVALID_REVNUM,
349251881Speter                                             depth_below_here,
350251881Speter                                             eb->processor,
351251881Speter                                             eb->cur ? eb->cur->baton : NULL,
352251881Speter                                             eb->cancel_func,
353251881Speter                                             eb->cancel_baton,
354251881Speter                                             scratch_pool));
355251881Speter      }
356251881Speter    else if (!local_only)
357251881Speter      {
358251881Speter        /* Diff base against actual */
359251881Speter        if (db_kind == svn_node_file)
360251881Speter          {
361251881Speter            SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
362251881Speter                                                   child_relpath,
363251881Speter                                                   SVN_INVALID_REVNUM,
364251881Speter                                                   eb->changelist_hash,
365251881Speter                                                   eb->processor,
366251881Speter                                                   eb->cur
367251881Speter                                                        ? eb->cur->baton
368251881Speter                                                        : NULL,
369251881Speter                                                   FALSE,
370251881Speter                                                   eb->cancel_func,
371251881Speter                                                   eb->cancel_baton,
372251881Speter                                                   scratch_pool));
373251881Speter          }
374251881Speter        else if (db_kind == svn_node_dir)
375251881Speter          {
376251881Speter            SVN_ERR(ensure_state(eb, local_abspath, FALSE, scratch_pool));
377251881Speter
378251881Speter            if (status->prop_status != svn_wc_status_none
379251881Speter                && status->prop_status != svn_wc_status_normal)
380251881Speter              {
381251881Speter                apr_array_header_t *propchanges;
382251881Speter                SVN_ERR(svn_wc__db_base_get_props(&eb->cur->left_props,
383251881Speter                                                  eb->db, local_abspath,
384251881Speter                                                  eb->cur->pool,
385251881Speter                                                  scratch_pool));
386251881Speter                SVN_ERR(svn_wc__db_read_props(&eb->cur->right_props,
387251881Speter                                              eb->db, local_abspath,
388251881Speter                                              eb->cur->pool,
389251881Speter                                              scratch_pool));
390251881Speter
391251881Speter                SVN_ERR(svn_prop_diffs(&propchanges,
392251881Speter                                       eb->cur->right_props,
393251881Speter                                       eb->cur->left_props,
394251881Speter                                       eb->cur->pool));
395251881Speter
396251881Speter                eb->cur->propchanges = propchanges;
397251881Speter              }
398251881Speter          }
399251881Speter      }
400251881Speter
401262253Speter    if (local_only && (db_status != svn_wc__db_status_deleted))
402251881Speter      {
403251881Speter        if (db_kind == svn_node_file)
404251881Speter          SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
405251881Speter                                               child_relpath,
406251881Speter                                               eb->processor,
407251881Speter                                               eb->cur ? eb->cur->baton : NULL,
408251881Speter                                               eb->changelist_hash,
409251881Speter                                               FALSE,
410251881Speter                                               eb->cancel_func,
411251881Speter                                               eb->cancel_baton,
412251881Speter                                               scratch_pool));
413251881Speter        else if (db_kind == svn_node_dir)
414251881Speter          SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
415251881Speter                                              child_relpath, depth_below_here,
416251881Speter                                              eb->processor,
417251881Speter                                              eb->cur ? eb->cur->baton : NULL,
418251881Speter                                              eb->changelist_hash,
419251881Speter                                              FALSE,
420251881Speter                                              eb->cancel_func,
421251881Speter                                              eb->cancel_baton,
422251881Speter                                              scratch_pool));
423251881Speter      }
424251881Speter
425251881Speter    if (db_kind == svn_node_dir && (local_only || repos_only))
426251881Speter      SVN_ERR(ensure_state(eb, local_abspath, TRUE /* skip */, scratch_pool));
427251881Speter  }
428251881Speter
429251881Speter  return SVN_NO_ERROR;
430251881Speter}
431251881Speter
432251881Speter
433251881Speter/* Public Interface */
434251881Spetersvn_error_t *
435251881Spetersvn_wc_diff6(svn_wc_context_t *wc_ctx,
436251881Speter             const char *local_abspath,
437251881Speter             const svn_wc_diff_callbacks4_t *callbacks,
438251881Speter             void *callback_baton,
439251881Speter             svn_depth_t depth,
440251881Speter             svn_boolean_t ignore_ancestry,
441251881Speter             svn_boolean_t show_copies_as_adds,
442251881Speter             svn_boolean_t use_git_diff_format,
443251881Speter             const apr_array_header_t *changelist_filter,
444251881Speter             svn_cancel_func_t cancel_func,
445251881Speter             void *cancel_baton,
446251881Speter             apr_pool_t *scratch_pool)
447251881Speter{
448251881Speter  struct diff_baton eb = { 0 };
449251881Speter  svn_node_kind_t kind;
450251881Speter  svn_boolean_t get_all;
451251881Speter  const svn_diff_tree_processor_t *processor;
452251881Speter
453251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
454251881Speter  SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath,
455251881Speter                               FALSE /* allow_missing */,
456251881Speter                               TRUE /* show_deleted */,
457251881Speter                               FALSE /* show_hidden */,
458251881Speter                               scratch_pool));
459251881Speter
460251881Speter  if (kind == svn_node_dir)
461251881Speter    eb.anchor_abspath = local_abspath;
462251881Speter  else
463251881Speter    eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
464251881Speter
465251881Speter  SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
466251881Speter                                      callbacks, callback_baton, TRUE,
467251881Speter                                      scratch_pool, scratch_pool));
468251881Speter
469251881Speter  if (use_git_diff_format)
470251881Speter    show_copies_as_adds = TRUE;
471251881Speter  if (show_copies_as_adds)
472251881Speter    ignore_ancestry = FALSE;
473251881Speter
474251881Speter
475251881Speter
476251881Speter  /*
477251881Speter  if (reverse_order)
478251881Speter    processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool);
479251881Speter   */
480251881Speter
481251881Speter  if (! show_copies_as_adds && !use_git_diff_format)
482251881Speter    processor = svn_diff__tree_processor_copy_as_changed_create(processor,
483251881Speter                                                                scratch_pool);
484251881Speter
485251881Speter  eb.db = wc_ctx->db;
486251881Speter  eb.processor = processor;
487251881Speter  eb.ignore_ancestry = ignore_ancestry;
488251881Speter  eb.show_copies_as_adds = show_copies_as_adds;
489251881Speter  eb.pool = scratch_pool;
490251881Speter
491251881Speter  if (changelist_filter && changelist_filter->nelts)
492251881Speter    SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter,
493251881Speter                                       scratch_pool));
494251881Speter
495251881Speter  if (show_copies_as_adds || use_git_diff_format || !ignore_ancestry)
496251881Speter    get_all = TRUE; /* We need unmodified descendants of copies */
497251881Speter  else
498251881Speter    get_all = FALSE;
499251881Speter
500251881Speter  /* Walk status handles files and directories */
501251881Speter  SVN_ERR(svn_wc__internal_walk_status(wc_ctx->db, local_abspath, depth,
502251881Speter                                       get_all,
503251881Speter                                       TRUE /* no_ignore */,
504251881Speter                                       FALSE /* ignore_text_mods */,
505251881Speter                                       NULL /* ignore_patterns */,
506251881Speter                                       diff_status_callback, &eb,
507251881Speter                                       cancel_func, cancel_baton,
508251881Speter                                       scratch_pool));
509251881Speter
510251881Speter  /* Close the remaining open directories */
511251881Speter  while (eb.cur)
512251881Speter    {
513251881Speter      struct node_state_t *ns = eb.cur;
514251881Speter
515251881Speter      if (!ns->skip)
516251881Speter        {
517251881Speter          if (ns->propchanges)
518251881Speter            SVN_ERR(processor->dir_changed(ns->relpath,
519251881Speter                                           ns->left_src,
520251881Speter                                           ns->right_src,
521251881Speter                                           ns->left_props,
522251881Speter                                           ns->right_props,
523251881Speter                                           ns->propchanges,
524251881Speter                                           ns->baton,
525251881Speter                                           processor,
526251881Speter                                           ns->pool));
527251881Speter          else
528251881Speter            SVN_ERR(processor->dir_closed(ns->relpath,
529251881Speter                                          ns->left_src,
530251881Speter                                          ns->right_src,
531251881Speter                                          ns->baton,
532251881Speter                                          processor,
533251881Speter                                          ns->pool));
534251881Speter        }
535251881Speter      eb.cur = ns->parent;
536251881Speter      svn_pool_clear(ns->pool);
537251881Speter    }
538251881Speter
539251881Speter  return SVN_NO_ERROR;
540251881Speter}
541