1251881Speter/*
2251881Speter * ambient_depth_filter_editor.c -- provide a svn_delta_editor_t which wraps
3251881Speter *                                  another editor and provides
4251881Speter *                                  *ambient* depth-based filtering
5251881Speter *
6251881Speter * ====================================================================
7251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
8251881Speter *    or more contributor license agreements.  See the NOTICE file
9251881Speter *    distributed with this work for additional information
10251881Speter *    regarding copyright ownership.  The ASF licenses this file
11251881Speter *    to you under the Apache License, Version 2.0 (the
12251881Speter *    "License"); you may not use this file except in compliance
13251881Speter *    with the License.  You may obtain a copy of the License at
14251881Speter *
15251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
16251881Speter *
17251881Speter *    Unless required by applicable law or agreed to in writing,
18251881Speter *    software distributed under the License is distributed on an
19251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20251881Speter *    KIND, either express or implied.  See the License for the
21251881Speter *    specific language governing permissions and limitations
22251881Speter *    under the License.
23251881Speter * ====================================================================
24251881Speter */
25251881Speter
26251881Speter#include "svn_delta.h"
27251881Speter#include "svn_wc.h"
28251881Speter#include "svn_dirent_uri.h"
29251881Speter#include "svn_path.h"
30251881Speter
31251881Speter#include "wc.h"
32251881Speter
33251881Speter/*
34251881Speter     Notes on the general depth-filtering strategy.
35251881Speter     ==============================================
36251881Speter
37251881Speter     When a depth-aware (>= 1.5) client pulls an update from a
38251881Speter     non-depth-aware server, the server may send back too much data,
39251881Speter     because it doesn't hear what the client tells it about the
40251881Speter     "requested depth" of the update (the "foo" in "--depth=foo"), nor
41251881Speter     about the "ambient depth" of each working copy directory.
42251881Speter
43251881Speter     For example, suppose a 1.5 client does this against a 1.4 server:
44251881Speter
45251881Speter       $ svn co --depth=empty -rSOME_OLD_REV http://url/repos/blah/ wc
46251881Speter       $ cd wc
47251881Speter       $ svn up
48251881Speter
49251881Speter     In the initial checkout, the requested depth is 'empty', so the
50251881Speter     depth-filtering editor (see libsvn_delta/depth_filter_editor.c)
51251881Speter     that wraps the main update editor transparently filters out all
52251881Speter     the unwanted calls.
53251881Speter
54251881Speter     In the 'svn up', the requested depth is unspecified, meaning that
55251881Speter     the ambient depth(s) of the working copy should be preserved.
56251881Speter     Since there's only one directory, and its depth is 'empty',
57251881Speter     clearly we should filter out or render no-ops all editor calls
58251881Speter     after open_root(), except maybe for change_dir_prop() on the
59251881Speter     top-level directory.  (Note that the server will have stuff to
60251881Speter     send down, because we checked out at an old revision in the first
61251881Speter     place, to set up this scenario.)
62251881Speter
63251881Speter     The depth-filtering editor won't help us here.  It only filters
64251881Speter     based on the requested depth, it never looks in the working copy
65251881Speter     to get ambient depths.  So the update editor itself will have to
66251881Speter     filter out the unwanted calls -- or better yet, it will have to
67251881Speter     be wrapped in a filtering editor that does the job.
68251881Speter
69251881Speter     This is that filtering editor.
70251881Speter
71251881Speter     Most of the work is done at the moment of baton construction.
72251881Speter     When a file or dir is opened, we create its baton with the
73251881Speter     appropriate ambient depth, either taking the depth directly from
74251881Speter     the corresponding working copy object (if available), or from its
75251881Speter     parent baton.  In the latter case, we don't just copy the parent
76251881Speter     baton's depth, but rather use it to choose the correct depth for
77251881Speter     this child.  The usual depth demotion rules apply, with the
78251881Speter     additional stipulation that as soon as we find a subtree is not
79251881Speter     present at all, due to being omitted for depth reasons, we set the
80251881Speter     ambiently_excluded flag in its baton, which signals that
81251881Speter     all descendant batons should be ignored.
82251881Speter     (In fact, we may just re-use the parent baton, since none of the
83251881Speter     other fields will be used anyway.)
84251881Speter
85251881Speter     See issues #2842 and #2897 for more.
86251881Speter*/
87251881Speter
88251881Speter
89251881Speter/*** Batons, and the Toys That Create Them ***/
90251881Speter
91251881Speterstruct edit_baton
92251881Speter{
93251881Speter  const svn_delta_editor_t *wrapped_editor;
94251881Speter  void *wrapped_edit_baton;
95251881Speter  svn_wc__db_t *db;
96251881Speter  const char *anchor_abspath;
97251881Speter  const char *target;
98251881Speter};
99251881Speter
100251881Speterstruct file_baton
101251881Speter{
102251881Speter  svn_boolean_t ambiently_excluded;
103251881Speter  struct edit_baton *edit_baton;
104251881Speter  void *wrapped_baton;
105251881Speter};
106251881Speter
107251881Speterstruct dir_baton
108251881Speter{
109251881Speter  svn_boolean_t ambiently_excluded;
110251881Speter  svn_depth_t ambient_depth;
111251881Speter  struct edit_baton *edit_baton;
112251881Speter  const char *abspath;
113251881Speter  void *wrapped_baton;
114251881Speter};
115251881Speter
116251881Speter/* Fetch the STATUS, KIND and DEPTH of the base node at LOCAL_ABSPATH.
117251881Speter * If there is no such base node, report 'normal', 'unknown' and 'unknown'
118251881Speter * respectively.
119251881Speter *
120251881Speter * STATUS and/or DEPTH may be NULL if not wanted; KIND must not be NULL.
121251881Speter */
122251881Speterstatic svn_error_t *
123251881Speterambient_read_info(svn_wc__db_status_t *status,
124251881Speter                  svn_node_kind_t *kind,
125251881Speter                  svn_depth_t *depth,
126251881Speter                  svn_wc__db_t *db,
127251881Speter                  const char *local_abspath,
128251881Speter                  apr_pool_t *scratch_pool)
129251881Speter{
130251881Speter  svn_error_t *err;
131251881Speter  SVN_ERR_ASSERT(kind != NULL);
132251881Speter
133251881Speter  err = svn_wc__db_base_get_info(status, kind, NULL, NULL, NULL, NULL,
134251881Speter                                 NULL, NULL, NULL, depth, NULL, NULL,
135251881Speter                                 NULL, NULL, NULL, NULL,
136251881Speter                                 db, local_abspath,
137251881Speter                                 scratch_pool, scratch_pool);
138251881Speter
139251881Speter  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
140251881Speter    {
141251881Speter      svn_error_clear(err);
142251881Speter
143251881Speter      *kind = svn_node_unknown;
144251881Speter      if (status)
145251881Speter        *status = svn_wc__db_status_normal;
146251881Speter      if (depth)
147251881Speter        *depth = svn_depth_unknown;
148251881Speter
149251881Speter      return SVN_NO_ERROR;
150251881Speter    }
151251881Speter  else
152251881Speter    SVN_ERR(err);
153251881Speter
154251881Speter  return SVN_NO_ERROR;
155251881Speter}
156251881Speter
157251881Speter/* */
158251881Speterstatic svn_error_t *
159251881Spetermake_dir_baton(struct dir_baton **d_p,
160251881Speter               const char *path,
161251881Speter               struct edit_baton *eb,
162251881Speter               struct dir_baton *pb,
163251881Speter               svn_boolean_t added,
164251881Speter               apr_pool_t *pool)
165251881Speter{
166251881Speter  struct dir_baton *d;
167251881Speter
168251881Speter  SVN_ERR_ASSERT(path || (! pb));
169251881Speter
170251881Speter  if (pb && pb->ambiently_excluded)
171251881Speter    {
172251881Speter      /* Just re-use the parent baton, since the only field that
173251881Speter         matters is ambiently_excluded. */
174251881Speter      *d_p = pb;
175251881Speter      return SVN_NO_ERROR;
176251881Speter    }
177251881Speter
178251881Speter  /* Okay, no easy out, so allocate and initialize a dir baton. */
179251881Speter  d = apr_pcalloc(pool, sizeof(*d));
180251881Speter
181251881Speter  if (path)
182251881Speter    d->abspath = svn_dirent_join(eb->anchor_abspath, path, pool);
183251881Speter  else
184251881Speter    d->abspath = apr_pstrdup(pool, eb->anchor_abspath);
185251881Speter
186251881Speter  /* The svn_depth_unknown means that: 1) pb is the anchor; 2) there
187251881Speter     is an non-null target, for which we are preparing the baton.
188251881Speter     This enables explicitly pull in the target. */
189251881Speter  if (pb && pb->ambient_depth != svn_depth_unknown)
190251881Speter    {
191251881Speter      svn_boolean_t exclude;
192251881Speter      svn_wc__db_status_t status;
193251881Speter      svn_node_kind_t kind;
194251881Speter      svn_boolean_t exists = TRUE;
195251881Speter
196251881Speter      if (!added)
197251881Speter        {
198251881Speter          SVN_ERR(ambient_read_info(&status, &kind, NULL,
199251881Speter                                    eb->db, d->abspath, pool));
200251881Speter        }
201251881Speter      else
202251881Speter        {
203251881Speter          status = svn_wc__db_status_not_present;
204251881Speter          kind = svn_node_unknown;
205251881Speter        }
206251881Speter
207251881Speter      exists = (kind != svn_node_unknown);
208251881Speter
209251881Speter      if (pb->ambient_depth == svn_depth_empty
210251881Speter          || pb->ambient_depth == svn_depth_files)
211251881Speter        {
212251881Speter          /* This is not a depth upgrade, and the parent directory is
213251881Speter             depth==empty or depth==files.  So if the parent doesn't
214251881Speter             already have an entry for the new dir, then the parent
215251881Speter             doesn't want the new dir at all, thus we should initialize
216251881Speter             it with ambiently_excluded=TRUE. */
217251881Speter          exclude = !exists;
218251881Speter        }
219251881Speter      else
220251881Speter        {
221251881Speter          /* If the parent expect all children by default, only exclude
222251881Speter             it whenever it is explicitly marked as exclude. */
223251881Speter          exclude = exists && (status == svn_wc__db_status_excluded);
224251881Speter        }
225251881Speter      if (exclude)
226251881Speter        {
227251881Speter          d->ambiently_excluded = TRUE;
228251881Speter          *d_p = d;
229251881Speter          return SVN_NO_ERROR;
230251881Speter        }
231251881Speter    }
232251881Speter
233251881Speter  d->edit_baton = eb;
234251881Speter  /* We'll initialize this differently in add_directory and
235251881Speter     open_directory. */
236251881Speter  d->ambient_depth = svn_depth_unknown;
237251881Speter
238251881Speter  *d_p = d;
239251881Speter  return SVN_NO_ERROR;
240251881Speter}
241251881Speter
242251881Speter/* */
243251881Speterstatic svn_error_t *
244251881Spetermake_file_baton(struct file_baton **f_p,
245251881Speter                struct dir_baton *pb,
246251881Speter                const char *path,
247251881Speter                svn_boolean_t added,
248251881Speter                apr_pool_t *pool)
249251881Speter{
250251881Speter  struct file_baton *f = apr_pcalloc(pool, sizeof(*f));
251251881Speter  struct edit_baton *eb = pb->edit_baton;
252251881Speter  svn_wc__db_status_t status;
253251881Speter  svn_node_kind_t kind;
254251881Speter  const char *abspath;
255251881Speter
256251881Speter  SVN_ERR_ASSERT(path);
257251881Speter
258251881Speter  if (pb->ambiently_excluded)
259251881Speter    {
260251881Speter      f->ambiently_excluded = TRUE;
261251881Speter      *f_p = f;
262251881Speter      return SVN_NO_ERROR;
263251881Speter    }
264251881Speter
265251881Speter  abspath = svn_dirent_join(eb->anchor_abspath, path, pool);
266251881Speter
267251881Speter  if (!added)
268251881Speter    {
269251881Speter      SVN_ERR(ambient_read_info(&status, &kind, NULL,
270251881Speter                                eb->db, abspath, pool));
271251881Speter    }
272251881Speter  else
273251881Speter    {
274251881Speter      status = svn_wc__db_status_not_present;
275251881Speter      kind = svn_node_unknown;
276251881Speter    }
277251881Speter
278251881Speter  if (pb->ambient_depth == svn_depth_empty)
279251881Speter    {
280251881Speter      /* This is not a depth upgrade, and the parent directory is
281251881Speter         depth==empty.  So if the parent doesn't
282251881Speter         already have an entry for the file, then the parent
283251881Speter         doesn't want to hear about the file at all. */
284251881Speter
285251881Speter      if (status == svn_wc__db_status_not_present
286251881Speter          || status == svn_wc__db_status_server_excluded
287251881Speter          || status == svn_wc__db_status_excluded
288251881Speter          || kind == svn_node_unknown)
289251881Speter        {
290251881Speter          f->ambiently_excluded = TRUE;
291251881Speter          *f_p = f;
292251881Speter          return SVN_NO_ERROR;
293251881Speter        }
294251881Speter    }
295251881Speter
296251881Speter  /* If pb->ambient_depth == svn_depth_unknown we are pulling
297251881Speter     in new nodes */
298251881Speter  if (pb->ambient_depth != svn_depth_unknown
299251881Speter      && status == svn_wc__db_status_excluded)
300251881Speter    {
301251881Speter      f->ambiently_excluded = TRUE;
302251881Speter      *f_p = f;
303251881Speter      return SVN_NO_ERROR;
304251881Speter    }
305251881Speter
306251881Speter  f->edit_baton = pb->edit_baton;
307251881Speter
308251881Speter  *f_p = f;
309251881Speter  return SVN_NO_ERROR;
310251881Speter}
311251881Speter
312251881Speter
313251881Speter/*** Editor Functions ***/
314251881Speter
315251881Speter/* An svn_delta_editor_t function. */
316251881Speterstatic svn_error_t *
317251881Speterset_target_revision(void *edit_baton,
318251881Speter                    svn_revnum_t target_revision,
319251881Speter                    apr_pool_t *pool)
320251881Speter{
321251881Speter  struct edit_baton *eb = edit_baton;
322251881Speter
323251881Speter  /* Nothing depth-y to filter here. */
324251881Speter return eb->wrapped_editor->set_target_revision(eb->wrapped_edit_baton,
325251881Speter                                                target_revision, pool);
326251881Speter}
327251881Speter
328251881Speter/* An svn_delta_editor_t function. */
329251881Speterstatic svn_error_t *
330251881Speteropen_root(void *edit_baton,
331251881Speter          svn_revnum_t base_revision,
332251881Speter          apr_pool_t *pool,
333251881Speter          void **root_baton)
334251881Speter{
335251881Speter  struct edit_baton *eb = edit_baton;
336251881Speter  struct dir_baton *b;
337251881Speter
338251881Speter  SVN_ERR(make_dir_baton(&b, NULL, eb, NULL, FALSE, pool));
339251881Speter  *root_baton = b;
340251881Speter
341251881Speter  if (b->ambiently_excluded)
342251881Speter    return SVN_NO_ERROR;
343251881Speter
344251881Speter  if (! *eb->target)
345251881Speter    {
346251881Speter      /* For an update with a NULL target, this is equivalent to open_dir(): */
347251881Speter      svn_node_kind_t kind;
348251881Speter      svn_wc__db_status_t status;
349251881Speter      svn_depth_t depth;
350251881Speter
351251881Speter      /* Read the depth from the entry. */
352251881Speter      SVN_ERR(ambient_read_info(&status, &kind, &depth,
353251881Speter                                eb->db, eb->anchor_abspath,
354251881Speter                                pool));
355251881Speter
356251881Speter      if (kind != svn_node_unknown
357251881Speter          && status != svn_wc__db_status_not_present
358251881Speter          && status != svn_wc__db_status_excluded
359251881Speter          && status != svn_wc__db_status_server_excluded)
360251881Speter        {
361251881Speter          b->ambient_depth = depth;
362251881Speter        }
363251881Speter    }
364251881Speter
365251881Speter  return eb->wrapped_editor->open_root(eb->wrapped_edit_baton, base_revision,
366251881Speter                                       pool, &b->wrapped_baton);
367251881Speter}
368251881Speter
369251881Speter/* An svn_delta_editor_t function. */
370251881Speterstatic svn_error_t *
371251881Speterdelete_entry(const char *path,
372251881Speter             svn_revnum_t base_revision,
373251881Speter             void *parent_baton,
374251881Speter             apr_pool_t *pool)
375251881Speter{
376251881Speter  struct dir_baton *pb = parent_baton;
377251881Speter  struct edit_baton *eb = pb->edit_baton;
378251881Speter
379251881Speter  if (pb->ambiently_excluded)
380251881Speter    return SVN_NO_ERROR;
381251881Speter
382251881Speter  if (pb->ambient_depth < svn_depth_immediates)
383251881Speter    {
384251881Speter      /* If the entry we want to delete doesn't exist, that's OK.
385251881Speter         It's probably an old server that doesn't understand
386251881Speter         depths. */
387251881Speter      svn_node_kind_t kind;
388251881Speter      svn_wc__db_status_t status;
389251881Speter      const char *abspath;
390251881Speter
391251881Speter      abspath = svn_dirent_join(eb->anchor_abspath, path, pool);
392251881Speter
393251881Speter      SVN_ERR(ambient_read_info(&status, &kind, NULL,
394251881Speter                                eb->db, abspath, pool));
395251881Speter
396251881Speter      if (kind == svn_node_unknown
397251881Speter          || status == svn_wc__db_status_not_present
398251881Speter          || status == svn_wc__db_status_excluded
399251881Speter          || status == svn_wc__db_status_server_excluded)
400251881Speter        return SVN_NO_ERROR;
401251881Speter    }
402251881Speter
403251881Speter  return eb->wrapped_editor->delete_entry(path, base_revision,
404251881Speter                                          pb->wrapped_baton, pool);
405251881Speter}
406251881Speter
407251881Speter/* An svn_delta_editor_t function. */
408251881Speterstatic svn_error_t *
409251881Speteradd_directory(const char *path,
410251881Speter              void *parent_baton,
411251881Speter              const char *copyfrom_path,
412251881Speter              svn_revnum_t copyfrom_revision,
413251881Speter              apr_pool_t *pool,
414251881Speter              void **child_baton)
415251881Speter{
416251881Speter  struct dir_baton *pb = parent_baton;
417251881Speter  struct edit_baton *eb = pb->edit_baton;
418251881Speter  struct dir_baton *b = NULL;
419251881Speter
420251881Speter  SVN_ERR(make_dir_baton(&b, path, eb, pb, TRUE, pool));
421251881Speter  *child_baton = b;
422251881Speter
423251881Speter  if (b->ambiently_excluded)
424251881Speter    return SVN_NO_ERROR;
425251881Speter
426251881Speter  /* It's not excluded, so what should we treat the ambient depth as
427251881Speter     being? */
428251881Speter  if (strcmp(eb->target, path) == 0)
429251881Speter    {
430251881Speter      /* The target of the edit is being added, so make it
431251881Speter         infinity. */
432251881Speter      b->ambient_depth = svn_depth_infinity;
433251881Speter    }
434251881Speter  else if (pb->ambient_depth == svn_depth_immediates)
435251881Speter    {
436251881Speter      b->ambient_depth = svn_depth_empty;
437251881Speter    }
438251881Speter  else
439251881Speter    {
440251881Speter      /* There may be a requested depth < svn_depth_infinity, but
441251881Speter         that's okay, libsvn_delta/depth_filter_editor.c will filter
442251881Speter         further calls out for us anyway, and the update_editor will
443251881Speter         do the right thing when it creates the directory. */
444251881Speter      b->ambient_depth = svn_depth_infinity;
445251881Speter    }
446251881Speter
447251881Speter  return eb->wrapped_editor->add_directory(path, pb->wrapped_baton,
448251881Speter                                           copyfrom_path,
449251881Speter                                           copyfrom_revision,
450251881Speter                                           pool, &b->wrapped_baton);
451251881Speter}
452251881Speter
453251881Speter/* An svn_delta_editor_t function. */
454251881Speterstatic svn_error_t *
455251881Speteropen_directory(const char *path,
456251881Speter               void *parent_baton,
457251881Speter               svn_revnum_t base_revision,
458251881Speter               apr_pool_t *pool,
459251881Speter               void **child_baton)
460251881Speter{
461251881Speter  struct dir_baton *pb = parent_baton;
462251881Speter  struct edit_baton *eb = pb->edit_baton;
463251881Speter  struct dir_baton *b;
464251881Speter  const char *local_abspath;
465251881Speter  svn_node_kind_t kind;
466251881Speter  svn_wc__db_status_t status;
467251881Speter  svn_depth_t depth;
468251881Speter
469251881Speter  SVN_ERR(make_dir_baton(&b, path, eb, pb, FALSE, pool));
470251881Speter  *child_baton = b;
471251881Speter
472251881Speter  if (b->ambiently_excluded)
473251881Speter    return SVN_NO_ERROR;
474251881Speter
475251881Speter  SVN_ERR(eb->wrapped_editor->open_directory(path, pb->wrapped_baton,
476251881Speter                                             base_revision, pool,
477251881Speter                                             &b->wrapped_baton));
478251881Speter  /* Note that for the update editor, the open_directory above will
479251881Speter     flush the logs of pb's directory, which might be important for
480251881Speter     this svn_wc_entry call. */
481251881Speter
482251881Speter  local_abspath = svn_dirent_join(eb->anchor_abspath, path, pool);
483251881Speter
484251881Speter  SVN_ERR(ambient_read_info(&status, &kind, &depth,
485251881Speter                            eb->db, local_abspath, pool));
486251881Speter
487251881Speter  if (kind != svn_node_unknown
488251881Speter      && status != svn_wc__db_status_not_present
489251881Speter      && status != svn_wc__db_status_excluded
490251881Speter      && status != svn_wc__db_status_server_excluded)
491251881Speter    {
492251881Speter      b->ambient_depth = depth;
493251881Speter    }
494251881Speter
495251881Speter  return SVN_NO_ERROR;
496251881Speter}
497251881Speter
498251881Speter/* An svn_delta_editor_t function. */
499251881Speterstatic svn_error_t *
500251881Speteradd_file(const char *path,
501251881Speter         void *parent_baton,
502251881Speter         const char *copyfrom_path,
503251881Speter         svn_revnum_t copyfrom_revision,
504251881Speter         apr_pool_t *pool,
505251881Speter         void **child_baton)
506251881Speter{
507251881Speter  struct dir_baton *pb = parent_baton;
508251881Speter  struct edit_baton *eb = pb->edit_baton;
509251881Speter  struct file_baton *b = NULL;
510251881Speter
511251881Speter  SVN_ERR(make_file_baton(&b, pb, path, TRUE, pool));
512251881Speter  *child_baton = b;
513251881Speter
514251881Speter  if (b->ambiently_excluded)
515251881Speter    return SVN_NO_ERROR;
516251881Speter
517251881Speter  return eb->wrapped_editor->add_file(path, pb->wrapped_baton,
518251881Speter                                      copyfrom_path, copyfrom_revision,
519251881Speter                                      pool, &b->wrapped_baton);
520251881Speter}
521251881Speter
522251881Speter/* An svn_delta_editor_t function. */
523251881Speterstatic svn_error_t *
524251881Speteropen_file(const char *path,
525251881Speter          void *parent_baton,
526251881Speter          svn_revnum_t base_revision,
527251881Speter          apr_pool_t *pool,
528251881Speter          void **child_baton)
529251881Speter{
530251881Speter  struct dir_baton *pb = parent_baton;
531251881Speter  struct edit_baton *eb = pb->edit_baton;
532251881Speter  struct file_baton *b;
533251881Speter
534251881Speter  SVN_ERR(make_file_baton(&b, pb, path, FALSE, pool));
535251881Speter  *child_baton = b;
536251881Speter  if (b->ambiently_excluded)
537251881Speter    return SVN_NO_ERROR;
538251881Speter
539251881Speter  return eb->wrapped_editor->open_file(path, pb->wrapped_baton,
540251881Speter                                       base_revision, pool,
541251881Speter                                       &b->wrapped_baton);
542251881Speter}
543251881Speter
544251881Speter/* An svn_delta_editor_t function. */
545251881Speterstatic svn_error_t *
546251881Speterapply_textdelta(void *file_baton,
547251881Speter                const char *base_checksum,
548251881Speter                apr_pool_t *pool,
549251881Speter                svn_txdelta_window_handler_t *handler,
550251881Speter                void **handler_baton)
551251881Speter{
552251881Speter  struct file_baton *fb = file_baton;
553251881Speter  struct edit_baton *eb = fb->edit_baton;
554251881Speter
555251881Speter  /* For filtered files, we just consume the textdelta. */
556251881Speter  if (fb->ambiently_excluded)
557251881Speter    {
558251881Speter      *handler = svn_delta_noop_window_handler;
559251881Speter      *handler_baton = NULL;
560251881Speter      return SVN_NO_ERROR;
561251881Speter    }
562251881Speter
563251881Speter  return eb->wrapped_editor->apply_textdelta(fb->wrapped_baton,
564251881Speter                                             base_checksum, pool,
565251881Speter                                             handler, handler_baton);
566251881Speter}
567251881Speter
568251881Speter/* An svn_delta_editor_t function. */
569251881Speterstatic svn_error_t *
570251881Speterclose_file(void *file_baton,
571251881Speter           const char *text_checksum,
572251881Speter           apr_pool_t *pool)
573251881Speter{
574251881Speter  struct file_baton *fb = file_baton;
575251881Speter  struct edit_baton *eb = fb->edit_baton;
576251881Speter
577251881Speter  if (fb->ambiently_excluded)
578251881Speter    return SVN_NO_ERROR;
579251881Speter
580251881Speter  return eb->wrapped_editor->close_file(fb->wrapped_baton,
581251881Speter                                        text_checksum, pool);
582251881Speter}
583251881Speter
584251881Speter/* An svn_delta_editor_t function. */
585251881Speterstatic svn_error_t *
586251881Speterabsent_file(const char *path,
587251881Speter            void *parent_baton,
588251881Speter            apr_pool_t *pool)
589251881Speter{
590251881Speter  struct dir_baton *pb = parent_baton;
591251881Speter  struct edit_baton *eb = pb->edit_baton;
592251881Speter
593251881Speter  if (pb->ambiently_excluded)
594251881Speter    return SVN_NO_ERROR;
595251881Speter
596251881Speter  return eb->wrapped_editor->absent_file(path, pb->wrapped_baton, pool);
597251881Speter}
598251881Speter
599251881Speter/* An svn_delta_editor_t function. */
600251881Speterstatic svn_error_t *
601251881Speterclose_directory(void *dir_baton,
602251881Speter                apr_pool_t *pool)
603251881Speter{
604251881Speter  struct dir_baton *db = dir_baton;
605251881Speter  struct edit_baton *eb = db->edit_baton;
606251881Speter
607251881Speter  if (db->ambiently_excluded)
608251881Speter    return SVN_NO_ERROR;
609251881Speter
610251881Speter  return eb->wrapped_editor->close_directory(db->wrapped_baton, pool);
611251881Speter}
612251881Speter
613251881Speter/* An svn_delta_editor_t function. */
614251881Speterstatic svn_error_t *
615251881Speterabsent_directory(const char *path,
616251881Speter                 void *parent_baton,
617251881Speter                 apr_pool_t *pool)
618251881Speter{
619251881Speter  struct dir_baton *pb = parent_baton;
620251881Speter  struct edit_baton *eb = pb->edit_baton;
621251881Speter
622251881Speter  /* Don't report absent items in filtered directories. */
623251881Speter  if (pb->ambiently_excluded)
624251881Speter    return SVN_NO_ERROR;
625251881Speter
626251881Speter  return eb->wrapped_editor->absent_directory(path, pb->wrapped_baton, pool);
627251881Speter}
628251881Speter
629251881Speter/* An svn_delta_editor_t function. */
630251881Speterstatic svn_error_t *
631251881Speterchange_file_prop(void *file_baton,
632251881Speter                 const char *name,
633251881Speter                 const svn_string_t *value,
634251881Speter                 apr_pool_t *pool)
635251881Speter{
636251881Speter  struct file_baton *fb = file_baton;
637251881Speter  struct edit_baton *eb = fb->edit_baton;
638251881Speter
639251881Speter  if (fb->ambiently_excluded)
640251881Speter    return SVN_NO_ERROR;
641251881Speter
642251881Speter  return eb->wrapped_editor->change_file_prop(fb->wrapped_baton,
643251881Speter                                              name, value, pool);
644251881Speter}
645251881Speter
646251881Speter/* An svn_delta_editor_t function. */
647251881Speterstatic svn_error_t *
648251881Speterchange_dir_prop(void *dir_baton,
649251881Speter                const char *name,
650251881Speter                const svn_string_t *value,
651251881Speter                apr_pool_t *pool)
652251881Speter{
653251881Speter  struct dir_baton *db = dir_baton;
654251881Speter  struct edit_baton *eb = db->edit_baton;
655251881Speter
656251881Speter  if (db->ambiently_excluded)
657251881Speter    return SVN_NO_ERROR;
658251881Speter
659251881Speter  return eb->wrapped_editor->change_dir_prop(db->wrapped_baton,
660251881Speter                                             name, value, pool);
661251881Speter}
662251881Speter
663251881Speter/* An svn_delta_editor_t function. */
664251881Speterstatic svn_error_t *
665251881Speterclose_edit(void *edit_baton,
666251881Speter           apr_pool_t *pool)
667251881Speter{
668251881Speter  struct edit_baton *eb = edit_baton;
669251881Speter  return eb->wrapped_editor->close_edit(eb->wrapped_edit_baton, pool);
670251881Speter}
671251881Speter
672251881Spetersvn_error_t *
673251881Spetersvn_wc__ambient_depth_filter_editor(const svn_delta_editor_t **editor,
674251881Speter                                    void **edit_baton,
675251881Speter                                    svn_wc__db_t *db,
676251881Speter                                    const char *anchor_abspath,
677251881Speter                                    const char *target,
678251881Speter                                    const svn_delta_editor_t *wrapped_editor,
679251881Speter                                    void *wrapped_edit_baton,
680251881Speter                                    apr_pool_t *result_pool)
681251881Speter{
682251881Speter  svn_delta_editor_t *depth_filter_editor;
683251881Speter  struct edit_baton *eb;
684251881Speter
685251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
686251881Speter
687251881Speter  depth_filter_editor = svn_delta_default_editor(result_pool);
688251881Speter  depth_filter_editor->set_target_revision = set_target_revision;
689251881Speter  depth_filter_editor->open_root = open_root;
690251881Speter  depth_filter_editor->delete_entry = delete_entry;
691251881Speter  depth_filter_editor->add_directory = add_directory;
692251881Speter  depth_filter_editor->open_directory = open_directory;
693251881Speter  depth_filter_editor->change_dir_prop = change_dir_prop;
694251881Speter  depth_filter_editor->close_directory = close_directory;
695251881Speter  depth_filter_editor->absent_directory = absent_directory;
696251881Speter  depth_filter_editor->add_file = add_file;
697251881Speter  depth_filter_editor->open_file = open_file;
698251881Speter  depth_filter_editor->apply_textdelta = apply_textdelta;
699251881Speter  depth_filter_editor->change_file_prop = change_file_prop;
700251881Speter  depth_filter_editor->close_file = close_file;
701251881Speter  depth_filter_editor->absent_file = absent_file;
702251881Speter  depth_filter_editor->close_edit = close_edit;
703251881Speter
704251881Speter  eb = apr_pcalloc(result_pool, sizeof(*eb));
705251881Speter  eb->wrapped_editor = wrapped_editor;
706251881Speter  eb->wrapped_edit_baton = wrapped_edit_baton;
707251881Speter  eb->db = db;
708251881Speter  eb->anchor_abspath = anchor_abspath;
709251881Speter  eb->target = target;
710251881Speter
711251881Speter  *editor = depth_filter_editor;
712251881Speter  *edit_baton = eb;
713251881Speter
714251881Speter  return SVN_NO_ERROR;
715251881Speter}
716