1251881Speter/**
2251881Speter * @copyright
3251881Speter * ====================================================================
4251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
5251881Speter *    or more contributor license agreements.  See the NOTICE file
6251881Speter *    distributed with this work for additional information
7251881Speter *    regarding copyright ownership.  The ASF licenses this file
8251881Speter *    to you under the Apache License, Version 2.0 (the
9251881Speter *    "License"); you may not use this file except in compliance
10251881Speter *    with the License.  You may obtain a copy of the License at
11251881Speter *
12251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
13251881Speter *
14251881Speter *    Unless required by applicable law or agreed to in writing,
15251881Speter *    software distributed under the License is distributed on an
16251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17251881Speter *    KIND, either express or implied.  See the License for the
18251881Speter *    specific language governing permissions and limitations
19251881Speter *    under the License.
20251881Speter * ====================================================================
21251881Speter * @endcopyright
22251881Speter */
23251881Speter
24251881Speter#include "svn_dirent_uri.h"
25251881Speter#include "svn_hash.h"
26251881Speter#include "svn_path.h"
27251881Speter#include "svn_pools.h"
28251881Speter#include "svn_wc.h"
29251881Speter
30251881Speter#include "wc.h"
31251881Speter
32251881Speter#include "svn_private_config.h"
33251881Speter#include "private/svn_wc_private.h"
34251881Speter
35251881Speter
36251881Speter
37251881Spetersvn_wc_info_t *
38251881Spetersvn_wc_info_dup(const svn_wc_info_t *info,
39251881Speter                apr_pool_t *pool)
40251881Speter{
41251881Speter  svn_wc_info_t *new_info = apr_pmemdup(pool, info, sizeof(*new_info));
42251881Speter
43251881Speter  if (info->changelist)
44251881Speter    new_info->changelist = apr_pstrdup(pool, info->changelist);
45251881Speter  new_info->checksum = svn_checksum_dup(info->checksum, pool);
46251881Speter  if (info->conflicts)
47251881Speter    {
48251881Speter      int i;
49251881Speter
50251881Speter      apr_array_header_t *new_conflicts
51251881Speter        = apr_array_make(pool, info->conflicts->nelts, info->conflicts->elt_size);
52251881Speter      for (i = 0; i < info->conflicts->nelts; i++)
53251881Speter        {
54251881Speter          APR_ARRAY_PUSH(new_conflicts, svn_wc_conflict_description2_t *)
55289180Speter            = svn_wc_conflict_description2_dup(
56251881Speter                APR_ARRAY_IDX(info->conflicts, i,
57251881Speter                              const svn_wc_conflict_description2_t *),
58251881Speter                pool);
59251881Speter        }
60251881Speter      new_info->conflicts = new_conflicts;
61251881Speter    }
62251881Speter  if (info->copyfrom_url)
63251881Speter    new_info->copyfrom_url = apr_pstrdup(pool, info->copyfrom_url);
64251881Speter  if (info->wcroot_abspath)
65251881Speter    new_info->wcroot_abspath = apr_pstrdup(pool, info->wcroot_abspath);
66251881Speter  if (info->moved_from_abspath)
67251881Speter    new_info->moved_from_abspath = apr_pstrdup(pool, info->moved_from_abspath);
68251881Speter  if (info->moved_to_abspath)
69251881Speter    new_info->moved_to_abspath = apr_pstrdup(pool, info->moved_to_abspath);
70251881Speter
71251881Speter  return new_info;
72251881Speter}
73251881Speter
74251881Speter
75251881Speter/* Set *INFO to a new struct, allocated in RESULT_POOL, built from the WC
76251881Speter   metadata of LOCAL_ABSPATH.  Pointer fields are copied by reference, not
77251881Speter   dup'd. */
78251881Speterstatic svn_error_t *
79251881Speterbuild_info_for_node(svn_wc__info2_t **info,
80251881Speter                     svn_wc__db_t *db,
81251881Speter                     const char *local_abspath,
82251881Speter                     svn_node_kind_t kind,
83251881Speter                     apr_pool_t *result_pool,
84251881Speter                     apr_pool_t *scratch_pool)
85251881Speter{
86251881Speter  svn_wc__info2_t *tmpinfo;
87251881Speter  const char *repos_relpath;
88251881Speter  svn_wc__db_status_t status;
89251881Speter  svn_node_kind_t db_kind;
90251881Speter  const char *original_repos_relpath;
91251881Speter  const char *original_repos_root_url;
92251881Speter  const char *original_uuid;
93251881Speter  svn_revnum_t original_revision;
94251881Speter  svn_wc__db_lock_t *lock;
95251881Speter  svn_boolean_t conflicted;
96251881Speter  svn_boolean_t op_root;
97251881Speter  svn_boolean_t have_base;
98251881Speter  svn_boolean_t have_more_work;
99251881Speter  svn_wc_info_t *wc_info;
100251881Speter
101251881Speter  tmpinfo = apr_pcalloc(result_pool, sizeof(*tmpinfo));
102251881Speter  tmpinfo->kind = kind;
103251881Speter
104251881Speter  wc_info = apr_pcalloc(result_pool, sizeof(*wc_info));
105251881Speter  tmpinfo->wc_info = wc_info;
106251881Speter
107251881Speter  wc_info->copyfrom_rev = SVN_INVALID_REVNUM;
108251881Speter
109251881Speter  SVN_ERR(svn_wc__db_read_info(&status, &db_kind, &tmpinfo->rev,
110251881Speter                               &repos_relpath,
111251881Speter                               &tmpinfo->repos_root_URL, &tmpinfo->repos_UUID,
112251881Speter                               &tmpinfo->last_changed_rev,
113251881Speter                               &tmpinfo->last_changed_date,
114251881Speter                               &tmpinfo->last_changed_author,
115251881Speter                               &wc_info->depth, &wc_info->checksum, NULL,
116251881Speter                               &original_repos_relpath,
117251881Speter                               &original_repos_root_url, &original_uuid,
118251881Speter                               &original_revision, &lock,
119251881Speter                               &wc_info->recorded_size,
120251881Speter                               &wc_info->recorded_time,
121251881Speter                               &wc_info->changelist,
122251881Speter                               &conflicted, &op_root, NULL, NULL,
123251881Speter                               &have_base, &have_more_work, NULL,
124251881Speter                               db, local_abspath,
125251881Speter                               result_pool, scratch_pool));
126251881Speter
127251881Speter  if (original_repos_root_url != NULL)
128251881Speter    {
129251881Speter      tmpinfo->repos_root_URL = original_repos_root_url;
130251881Speter      tmpinfo->repos_UUID = original_uuid;
131251881Speter    }
132251881Speter
133251881Speter  if (status == svn_wc__db_status_added)
134251881Speter    {
135251881Speter      /* ### We should also just be fetching the true BASE revision
136251881Speter         ### here, which means copied items would also not have a
137251881Speter         ### revision to display.  But WC-1 wants to show the revision of
138251881Speter         ### copy targets as the copyfrom-rev.  *sigh* */
139251881Speter
140251881Speter      if (original_repos_relpath)
141251881Speter        {
142251881Speter          /* Root or child of copy */
143251881Speter          tmpinfo->rev = original_revision;
144251881Speter
145251881Speter          if (op_root)
146251881Speter            {
147251881Speter              svn_error_t *err;
148251881Speter              wc_info->copyfrom_url =
149251881Speter                    svn_path_url_add_component2(tmpinfo->repos_root_URL,
150251881Speter                                                original_repos_relpath,
151251881Speter                                                result_pool);
152251881Speter
153251881Speter              wc_info->copyfrom_rev = original_revision;
154251881Speter
155251881Speter              err = svn_wc__db_scan_moved(&wc_info->moved_from_abspath,
156251881Speter                                          NULL, NULL, NULL,
157251881Speter                                          db, local_abspath,
158251881Speter                                          result_pool, scratch_pool);
159251881Speter
160251881Speter              if (err)
161251881Speter                {
162251881Speter                   if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
163251881Speter                      return svn_error_trace(err);
164251881Speter                   svn_error_clear(err);
165251881Speter                   wc_info->moved_from_abspath = NULL;
166251881Speter                }
167251881Speter            }
168251881Speter        }
169251881Speter
170251881Speter      /* ### We should be able to avoid both these calls with the information
171251881Speter         from read_info() in most cases */
172251881Speter      if (! op_root)
173251881Speter        wc_info->schedule = svn_wc_schedule_normal;
174251881Speter      else if (! have_more_work && ! have_base)
175251881Speter        wc_info->schedule = svn_wc_schedule_add;
176251881Speter      else
177251881Speter        {
178251881Speter          svn_wc__db_status_t below_working;
179251881Speter          svn_boolean_t have_work;
180251881Speter
181251881Speter          SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work,
182251881Speter                                                &below_working,
183251881Speter                                                db, local_abspath,
184251881Speter                                                scratch_pool));
185251881Speter
186251881Speter          /* If the node is not present or deleted (read: not present
187251881Speter             in working), then the node is not a replacement */
188251881Speter          if (below_working != svn_wc__db_status_not_present
189251881Speter              && below_working != svn_wc__db_status_deleted)
190251881Speter            {
191251881Speter              wc_info->schedule = svn_wc_schedule_replace;
192251881Speter            }
193251881Speter          else
194251881Speter            wc_info->schedule = svn_wc_schedule_add;
195251881Speter        }
196289180Speter      SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath,
197289180Speter                                         &tmpinfo->repos_root_URL,
198289180Speter                                         &tmpinfo->repos_UUID,
199289180Speter                                         db, local_abspath,
200289180Speter                                         result_pool, scratch_pool));
201289180Speter
202289180Speter      tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
203289180Speter                                                 repos_relpath, result_pool);
204251881Speter    }
205251881Speter  else if (status == svn_wc__db_status_deleted)
206251881Speter    {
207289180Speter      svn_wc__db_status_t w_status;
208251881Speter
209289180Speter      SVN_ERR(svn_wc__db_read_pristine_info(&w_status, &tmpinfo->kind,
210251881Speter                                            &tmpinfo->last_changed_rev,
211251881Speter                                            &tmpinfo->last_changed_date,
212251881Speter                                            &tmpinfo->last_changed_author,
213251881Speter                                            &wc_info->depth,
214251881Speter                                            &wc_info->checksum,
215251881Speter                                            NULL, NULL, NULL,
216251881Speter                                            db, local_abspath,
217251881Speter                                            result_pool, scratch_pool));
218251881Speter
219289180Speter      if (w_status == svn_wc__db_status_deleted)
220289180Speter        {
221289180Speter          /* We have a working not-present status. We don't know anything
222289180Speter             about this node, but it *is visible* in STATUS.
223289180Speter
224289180Speter             Let's tell that it is excluded */
225289180Speter
226289180Speter          wc_info->depth = svn_depth_exclude;
227289180Speter          tmpinfo->kind = svn_node_unknown;
228289180Speter        }
229289180Speter
230251881Speter      /* And now fetch the url and revision of what will be deleted */
231251881Speter      SVN_ERR(svn_wc__db_scan_deletion(NULL, &wc_info->moved_to_abspath,
232289180Speter                                       NULL, NULL,
233251881Speter                                       db, local_abspath,
234251881Speter                                       scratch_pool, scratch_pool));
235251881Speter
236289180Speter      SVN_ERR(svn_wc__db_read_repos_info(&tmpinfo->rev, &repos_relpath,
237289180Speter                                         &tmpinfo->repos_root_URL,
238289180Speter                                         &tmpinfo->repos_UUID,
239289180Speter                                         db, local_abspath,
240289180Speter                                         result_pool, scratch_pool));
241251881Speter
242251881Speter      wc_info->schedule = svn_wc_schedule_delete;
243289180Speter      tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
244289180Speter                                                 repos_relpath, result_pool);
245251881Speter    }
246251881Speter  else if (status == svn_wc__db_status_not_present
247251881Speter           || status == svn_wc__db_status_server_excluded)
248251881Speter    {
249251881Speter      *info = NULL;
250251881Speter      return SVN_NO_ERROR;
251251881Speter    }
252289180Speter  else if (status == svn_wc__db_status_excluded && !repos_relpath)
253289180Speter    {
254289180Speter      /* We have a WORKING exclude. Avoid segfault on no repos info */
255289180Speter
256289180Speter      SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath,
257289180Speter                                         &tmpinfo->repos_root_URL,
258289180Speter                                         &tmpinfo->repos_UUID,
259289180Speter                                         db, local_abspath,
260289180Speter                                         result_pool, scratch_pool));
261289180Speter
262289180Speter      wc_info->schedule = svn_wc_schedule_normal;
263289180Speter      tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
264289180Speter                                                 repos_relpath, result_pool);
265289180Speter      tmpinfo->wc_info->depth = svn_depth_exclude;
266289180Speter    }
267251881Speter  else
268251881Speter    {
269251881Speter      /* Just a BASE node. We have all the info we need */
270251881Speter      tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
271251881Speter                                                 repos_relpath,
272251881Speter                                                 result_pool);
273251881Speter      wc_info->schedule = svn_wc_schedule_normal;
274289180Speter
275289180Speter      if (status == svn_wc__db_status_excluded)
276289180Speter        wc_info->depth = svn_depth_exclude;
277251881Speter    }
278251881Speter
279251881Speter  /* A default */
280251881Speter  tmpinfo->size = SVN_INVALID_FILESIZE;
281251881Speter
282251881Speter  SVN_ERR(svn_wc__db_get_wcroot(&tmpinfo->wc_info->wcroot_abspath, db,
283251881Speter                                local_abspath, result_pool, scratch_pool));
284251881Speter
285251881Speter  if (conflicted)
286289180Speter    SVN_ERR(svn_wc__read_conflicts(&wc_info->conflicts, NULL,
287289180Speter                                   db, local_abspath,
288289180Speter                                   FALSE /* create tempfiles */,
289289180Speter                                   FALSE /* only tree conflicts */,
290251881Speter                                   result_pool, scratch_pool));
291251881Speter  else
292251881Speter    wc_info->conflicts = NULL;
293251881Speter
294251881Speter  /* lock stuff */
295251881Speter  if (lock != NULL)
296251881Speter    {
297251881Speter      tmpinfo->lock = apr_pcalloc(result_pool, sizeof(*(tmpinfo->lock)));
298251881Speter      tmpinfo->lock->token         = lock->token;
299251881Speter      tmpinfo->lock->owner         = lock->owner;
300251881Speter      tmpinfo->lock->comment       = lock->comment;
301251881Speter      tmpinfo->lock->creation_date = lock->date;
302251881Speter    }
303251881Speter
304251881Speter  *info = tmpinfo;
305251881Speter  return SVN_NO_ERROR;
306251881Speter}
307251881Speter
308251881Speter
309251881Speter/* Set *INFO to a new struct with minimal content, to be
310251881Speter   used in reporting info for unversioned tree conflict victims. */
311251881Speter/* ### Some fields we could fill out based on the parent dir's entry
312251881Speter       or by looking at an obstructing item. */
313251881Speterstatic svn_error_t *
314251881Speterbuild_info_for_unversioned(svn_wc__info2_t **info,
315251881Speter                           apr_pool_t *pool)
316251881Speter{
317251881Speter  svn_wc__info2_t *tmpinfo = apr_pcalloc(pool, sizeof(*tmpinfo));
318251881Speter  svn_wc_info_t *wc_info = apr_pcalloc(pool, sizeof (*wc_info));
319251881Speter
320251881Speter  tmpinfo->URL                  = NULL;
321251881Speter  tmpinfo->repos_UUID           = NULL;
322251881Speter  tmpinfo->repos_root_URL       = NULL;
323251881Speter  tmpinfo->rev                  = SVN_INVALID_REVNUM;
324251881Speter  tmpinfo->kind                 = svn_node_none;
325251881Speter  tmpinfo->size                 = SVN_INVALID_FILESIZE;
326251881Speter  tmpinfo->last_changed_rev     = SVN_INVALID_REVNUM;
327251881Speter  tmpinfo->last_changed_date    = 0;
328251881Speter  tmpinfo->last_changed_author  = NULL;
329251881Speter  tmpinfo->lock                 = NULL;
330251881Speter
331251881Speter  tmpinfo->wc_info = wc_info;
332251881Speter
333251881Speter  wc_info->copyfrom_rev = SVN_INVALID_REVNUM;
334251881Speter  wc_info->depth = svn_depth_unknown;
335251881Speter  wc_info->recorded_size = SVN_INVALID_FILESIZE;
336251881Speter
337251881Speter  *info = tmpinfo;
338251881Speter  return SVN_NO_ERROR;
339251881Speter}
340251881Speter
341251881Speter/* Callback and baton for crawl_entries() walk over entries files. */
342251881Speterstruct found_entry_baton
343251881Speter{
344251881Speter  svn_wc__info_receiver2_t receiver;
345251881Speter  void *receiver_baton;
346251881Speter  svn_wc__db_t *db;
347251881Speter  svn_boolean_t actual_only;
348251881Speter  svn_boolean_t first;
349251881Speter  /* The set of tree conflicts that have been found but not (yet) visited by
350289180Speter   * the tree walker.  Map of abspath -> empty string. */
351251881Speter  apr_hash_t *tree_conflicts;
352251881Speter  apr_pool_t *pool;
353251881Speter};
354251881Speter
355251881Speter/* Call WALK_BATON->receiver with WALK_BATON->receiver_baton, passing to it
356251881Speter * info about the path LOCAL_ABSPATH.
357251881Speter * An svn_wc__node_found_func_t callback function. */
358251881Speterstatic svn_error_t *
359251881Speterinfo_found_node_callback(const char *local_abspath,
360251881Speter                         svn_node_kind_t kind,
361251881Speter                         void *walk_baton,
362251881Speter                         apr_pool_t *scratch_pool)
363251881Speter{
364251881Speter  struct found_entry_baton *fe_baton = walk_baton;
365251881Speter  svn_wc__info2_t *info;
366251881Speter
367251881Speter  SVN_ERR(build_info_for_node(&info, fe_baton->db, local_abspath,
368251881Speter                               kind, scratch_pool, scratch_pool));
369251881Speter
370251881Speter  if (info == NULL)
371251881Speter    {
372251881Speter      if (!fe_baton->first)
373251881Speter        return SVN_NO_ERROR; /* not present or server excluded descendant */
374251881Speter
375251881Speter      /* If the info root is not found, that is an error */
376251881Speter      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
377251881Speter                               _("The node '%s' was not found."),
378251881Speter                               svn_dirent_local_style(local_abspath,
379251881Speter                                                      scratch_pool));
380251881Speter    }
381251881Speter
382251881Speter  fe_baton->first = FALSE;
383251881Speter
384251881Speter  SVN_ERR_ASSERT(info->wc_info != NULL);
385251881Speter  SVN_ERR(fe_baton->receiver(fe_baton->receiver_baton, local_abspath,
386251881Speter                             info, scratch_pool));
387251881Speter
388251881Speter  /* If this node is a versioned directory, make a note of any tree conflicts
389251881Speter   * on all immediate children.  Some of these may be visited later in this
390251881Speter   * walk, at which point they will be removed from the list, while any that
391251881Speter   * are not visited will remain in the list. */
392251881Speter  if (fe_baton->actual_only && kind == svn_node_dir)
393251881Speter    {
394251881Speter      const apr_array_header_t *victims;
395251881Speter      int i;
396251881Speter
397251881Speter      SVN_ERR(svn_wc__db_read_conflict_victims(&victims,
398251881Speter                                               fe_baton->db, local_abspath,
399251881Speter                                               scratch_pool, scratch_pool));
400251881Speter
401251881Speter      for (i = 0; i < victims->nelts; i++)
402251881Speter        {
403251881Speter          const char *this_basename = APR_ARRAY_IDX(victims, i, const char *);
404251881Speter
405251881Speter          svn_hash_sets(fe_baton->tree_conflicts,
406251881Speter                        svn_dirent_join(local_abspath, this_basename,
407251881Speter                                        fe_baton->pool),
408251881Speter                        "");
409251881Speter        }
410251881Speter    }
411251881Speter
412251881Speter  /* Delete this path which we are currently visiting from the list of tree
413251881Speter   * conflicts.  This relies on the walker visiting a directory before visiting
414251881Speter   * its children. */
415251881Speter  svn_hash_sets(fe_baton->tree_conflicts, local_abspath, NULL);
416251881Speter
417251881Speter  return SVN_NO_ERROR;
418251881Speter}
419251881Speter
420251881Speter
421251881Speter/* Return TRUE iff the subtree at ROOT_ABSPATH, restricted to depth DEPTH,
422251881Speter * would include the path CHILD_ABSPATH of kind CHILD_KIND. */
423251881Speterstatic svn_boolean_t
424251881Speterdepth_includes(const char *root_abspath,
425251881Speter               svn_depth_t depth,
426251881Speter               const char *child_abspath,
427251881Speter               svn_node_kind_t child_kind,
428251881Speter               apr_pool_t *scratch_pool)
429251881Speter{
430251881Speter  const char *parent_abspath = svn_dirent_dirname(child_abspath, scratch_pool);
431251881Speter
432251881Speter  return (depth == svn_depth_infinity
433251881Speter          || ((depth == svn_depth_immediates
434251881Speter               || (depth == svn_depth_files && child_kind == svn_node_file))
435251881Speter              && strcmp(root_abspath, parent_abspath) == 0)
436251881Speter          || strcmp(root_abspath, child_abspath) == 0);
437251881Speter}
438251881Speter
439251881Speter
440251881Spetersvn_error_t *
441251881Spetersvn_wc__get_info(svn_wc_context_t *wc_ctx,
442251881Speter                 const char *local_abspath,
443251881Speter                 svn_depth_t depth,
444251881Speter                 svn_boolean_t fetch_excluded,
445251881Speter                 svn_boolean_t fetch_actual_only,
446251881Speter                 const apr_array_header_t *changelist_filter,
447251881Speter                 svn_wc__info_receiver2_t receiver,
448251881Speter                 void *receiver_baton,
449251881Speter                 svn_cancel_func_t cancel_func,
450251881Speter                 void *cancel_baton,
451251881Speter                 apr_pool_t *scratch_pool)
452251881Speter{
453251881Speter  struct found_entry_baton fe_baton;
454251881Speter  svn_error_t *err;
455251881Speter  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
456251881Speter  apr_hash_index_t *hi;
457251881Speter  const char *repos_root_url = NULL;
458251881Speter  const char *repos_uuid = NULL;
459251881Speter
460251881Speter  fe_baton.receiver = receiver;
461251881Speter  fe_baton.receiver_baton = receiver_baton;
462251881Speter  fe_baton.db = wc_ctx->db;
463251881Speter  fe_baton.actual_only = fetch_actual_only;
464251881Speter  fe_baton.first = TRUE;
465251881Speter  fe_baton.tree_conflicts = apr_hash_make(scratch_pool);
466251881Speter  fe_baton.pool = scratch_pool;
467251881Speter
468251881Speter  err = svn_wc__internal_walk_children(wc_ctx->db, local_abspath,
469251881Speter                                       fetch_excluded,
470251881Speter                                       changelist_filter,
471251881Speter                                       info_found_node_callback,
472251881Speter                                       &fe_baton, depth,
473251881Speter                                       cancel_func, cancel_baton,
474251881Speter                                       iterpool);
475251881Speter
476251881Speter  /* If the target root node is not present, svn_wc__internal_walk_children()
477251881Speter     returns a PATH_NOT_FOUND error and doesn't call the callback.  If there
478251881Speter     is a tree conflict on this node, that is not an error. */
479251881Speter  if (fe_baton.first /* not visited by walk_children */
480251881Speter      && fetch_actual_only
481251881Speter      && err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
482251881Speter    {
483251881Speter      svn_boolean_t tree_conflicted;
484251881Speter      svn_error_t *err2;
485251881Speter
486251881Speter      err2 = svn_wc__internal_conflicted_p(NULL, NULL, &tree_conflicted,
487251881Speter                                           wc_ctx->db, local_abspath,
488251881Speter                                           iterpool);
489251881Speter
490251881Speter      if ((err2 && err2->apr_err == SVN_ERR_WC_PATH_NOT_FOUND))
491251881Speter        {
492251881Speter          svn_error_clear(err2);
493251881Speter          return svn_error_trace(err);
494251881Speter        }
495251881Speter      else if (err2 || !tree_conflicted)
496251881Speter        return svn_error_compose_create(err, err2);
497251881Speter
498251881Speter      svn_error_clear(err);
499251881Speter
500251881Speter      svn_hash_sets(fe_baton.tree_conflicts, local_abspath, "");
501251881Speter    }
502251881Speter  else
503251881Speter    SVN_ERR(err);
504251881Speter
505251881Speter  /* If there are any tree conflicts that we have found but have not reported,
506251881Speter   * send a minimal info struct for each one now. */
507251881Speter  for (hi = apr_hash_first(scratch_pool, fe_baton.tree_conflicts); hi;
508251881Speter       hi = apr_hash_next(hi))
509251881Speter    {
510289180Speter      const char *this_abspath = apr_hash_this_key(hi);
511251881Speter      const svn_wc_conflict_description2_t *tree_conflict;
512251881Speter      svn_wc__info2_t *info;
513289180Speter      const apr_array_header_t *conflicts;
514251881Speter
515251881Speter      svn_pool_clear(iterpool);
516251881Speter
517251881Speter      SVN_ERR(build_info_for_unversioned(&info, iterpool));
518251881Speter
519251881Speter      if (!repos_root_url)
520251881Speter        {
521289180Speter          SVN_ERR(svn_wc__db_read_repos_info(NULL, NULL,
522289180Speter                                             &repos_root_url,
523289180Speter                                             &repos_uuid,
524289180Speter                                             wc_ctx->db,
525289180Speter                                             svn_dirent_dirname(
526257936Speter                                                            this_abspath,
527251881Speter                                                            iterpool),
528289180Speter                                             scratch_pool, iterpool));
529251881Speter        }
530251881Speter
531251881Speter      info->repos_root_URL = repos_root_url;
532251881Speter      info->repos_UUID = repos_uuid;
533251881Speter
534289180Speter      SVN_ERR(svn_wc__read_conflicts(&conflicts, NULL,
535251881Speter                                     wc_ctx->db, this_abspath,
536289180Speter                                     FALSE /* create tempfiles */,
537289180Speter                                     FALSE /* only tree conflicts */,
538251881Speter                                     iterpool, iterpool));
539289180Speter      if (! conflicts || ! conflicts->nelts)
540251881Speter        continue;
541251881Speter
542289180Speter      tree_conflict = APR_ARRAY_IDX(conflicts, 0,
543289180Speter                                    const svn_wc_conflict_description2_t *);
544251881Speter
545251881Speter      if (!depth_includes(local_abspath, depth, tree_conflict->local_abspath,
546251881Speter                          tree_conflict->node_kind, iterpool))
547251881Speter        continue;
548251881Speter
549289180Speter      info->wc_info->conflicts = conflicts;
550251881Speter      SVN_ERR(receiver(receiver_baton, this_abspath, info, iterpool));
551251881Speter    }
552251881Speter  svn_pool_destroy(iterpool);
553251881Speter
554251881Speter  return SVN_NO_ERROR;
555251881Speter}
556