]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/subversion/subversion/libsvn_client/merge.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / subversion / subversion / libsvn_client / merge.c
1 /*
2  * merge.c: merging
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23
24 /* ==================================================================== */
25
26
27 \f
28 /*** Includes ***/
29
30 #include <assert.h>
31 #include <apr_strings.h>
32 #include <apr_tables.h>
33 #include <apr_hash.h>
34 #include "svn_types.h"
35 #include "svn_hash.h"
36 #include "svn_wc.h"
37 #include "svn_delta.h"
38 #include "svn_diff.h"
39 #include "svn_mergeinfo.h"
40 #include "svn_client.h"
41 #include "svn_string.h"
42 #include "svn_error.h"
43 #include "svn_dirent_uri.h"
44 #include "svn_path.h"
45 #include "svn_io.h"
46 #include "svn_utf.h"
47 #include "svn_pools.h"
48 #include "svn_config.h"
49 #include "svn_props.h"
50 #include "svn_time.h"
51 #include "svn_sorts.h"
52 #include "svn_subst.h"
53 #include "svn_ra.h"
54 #include "client.h"
55 #include "mergeinfo.h"
56
57 #include "private/svn_opt_private.h"
58 #include "private/svn_wc_private.h"
59 #include "private/svn_mergeinfo_private.h"
60 #include "private/svn_fspath.h"
61 #include "private/svn_ra_private.h"
62 #include "private/svn_client_private.h"
63 #include "private/svn_subr_private.h"
64
65 #include "svn_private_config.h"
66
67
68 /*-----------------------------------------------------------------------*/
69 \f
70 /* MERGEINFO MERGE SOURCE NORMALIZATION
71  *
72  * Nearly any helper function herein that accepts two URL/revision
73  * pairs (or equivalent struct merge_source_t) expects one of two things
74  * to be true:
75  *
76  *    1.  that mergeinfo is not being recorded at all for this
77  *        operation, or
78  *
79  *    2.  that the pairs represent two locations along a single line
80  *        of version history such that there are no copies in the
81  *        history of the object between the locations when treating
82  *        the oldest of the two locations as non-inclusive.  In other
83  *        words, if there is a copy at all between them, there is only
84  *        one copy and its source was the oldest of the two locations.
85  *
86  * We use svn_ra_get_location_segments() to split a given range of
87  * revisions across an object's history into several which obey these
88  * rules.  For example, an extract from the log of Subversion's own
89  * /subversion/tags/1.4.5 directory shows the following copies between
90  * r859500 and r866500 (omitting the '/subversion' prefix for clarity):
91  *
92  *    r859598:
93  *      A /branches/1.4.x  (from /trunk:859597)
94  *
95  *    r865417:
96  *      A /tags/1.4.4      (from /branches/1.4.x:865262)
97  *    # Notice that this copy leaves a gap between 865262 and 865417.
98  *
99  *    r866420:
100  *      A /branches/1.4.5  (from /tags/1.4.4:866419)
101  *
102  *    r866425:
103  *      D /branches/1.4.5
104  *      A /tags/1.4.5      (from /branches/1.4.5:866424)
105  *
106  * In graphical form:
107  *
108  *                859500 859597 865262        866419 866424 866500
109  *                  .      .      .             .      .      .
110  *    trunk       ------------------------------------------------
111  *                         \      .             .      .
112  *    branches/1.4.x        A-------------------------------------
113  *                          .     \______       .      .
114  *                          .            \      .      .
115  *    tags/1.4.4            .             A-----------------------
116  *                          .             .     \      .
117  *    branches/1.4.5        .             .      A------D
118  *                          .             .      .     \.
119  *    tags/1.4.5            .             .      .      A---------
120  *                          .             .      .      .
121  *                       859598        865417 866420 866425
122  *
123  * A merge of the difference between r859500 and r866500 of this directory
124  * gets split into sequential merges of the following location pairs.
125  *
126  *                859500 859597 865262 865416 866419 866424 866500
127  *                  .      .      .      .      .      .      .
128  *    trunk         (======]      .      .      .      .      .
129  *                                .      .      .      .      .
130  *    trunk                (      .      .      .      .      .
131  *    branches/1.4.x        ======]      .      .      .      .
132  *                                       .      .      .      .
133  *    branches/1.4.x              (      .      .      .      .
134  *    tags/1.4.4                   =============]      .      .
135  *    implicit_src_gap            (======]      .      .      .
136  *                                              .      .      .
137  *    tags/1.4.4                                (      .      .
138  *    branches/1.4.5                             ======]      .
139  *                                                     .      .
140  *    branches/1.4.5                                   (      .
141  *    tags/1.4.5                                        ======]
142  *
143  * which are represented in merge_source_t as:
144  *
145  *    [/trunk:859500, /trunk:859597]
146  *    (recorded in svn:mergeinfo as /trunk:859501-859597)
147  *
148  *    [/trunk:859597, /branches/1.4.x:865262]
149  *    (recorded in svn:mergeinfo as /branches/1.4.x:859598-865262)
150  *
151  *    [/branches/1.4.x:865262, /tags/1.4.4@866419]
152  *    (recorded in svn:mergeinfo as /tags/1.4.4:865263-866419)
153  *    (and there is a gap, the revision range [865262, 865416])
154  *
155  *    [/tags/1.4.4@866419, /branches/1.4.5@866424]
156  *    (recorded in svn:mergeinfo as /branches/1.4.5:866420-866424)
157  *
158  *    [/branches/1.4.5@866424, /tags/1.4.5@866500]
159  *    (recorded in svn:mergeinfo as /tags/1.4.5:866425-866500)
160  *
161  * Our helper functions would then operate on one of these location
162  * pairs at a time.
163  */
164
165 /* WHICH SVN_CLIENT_MERGE* API DO I WANT?
166  *
167  * libsvn_client has three public merge APIs; they are all wrappers
168  * around the do_merge engine.  Which one to use depends on the number
169  * of URLs passed as arguments and whether or not specific merge
170  * ranges (-c/-r) are specified.
171  *
172  *                 1 URL                        2 URLs
173  * +----+--------------------------------+---------------------+
174  * | -c |       mergeinfo-driven         |                     |
175  * | or |        cherrypicking           |                     |
176  * | -r |    (svn_client_merge_peg)      |                     |
177  * |----+--------------------------------+                     |
178  * |    |       mergeinfo-driven         |     unsupported     |
179  * |    |  'cherry harvest', i.e. merge  |                     |
180  * |    |  all revisions from URL that   |                     |
181  * | no |  have not already been merged  |                     |
182  * | -c |    (svn_client_merge_peg)      |                     |
183  * | or +--------------------------------+---------------------+
184  * | -r |      mergeinfo-driven          |   mergeinfo-writing |
185  * |    |        whole-branch            |    diff-and-apply   |
186  * |    |       heuristic merge          |  (svn_client_merge) |
187  * |    | (svn_client_merge_reintegrate) |                     |
188  * +----+--------------------------------+---------------------+
189  *
190  *
191  */
192
193 /* THE CHILDREN_WITH_MERGEINFO ARRAY
194  *
195  * Many of the helper functions in this file pass around an
196  * apr_array_header_t *CHILDREN_WITH_MERGEINFO.  This is a depth first
197  * sorted array filled with svn_client__merge_path_t * describing the
198  * merge target and any of its subtrees which have explicit mergeinfo
199  * or otherwise need special attention during a merge.
200  *
201  * During mergeinfo unaware merges, CHILDREN_WITH_MERGEINFO contains
202  * contains only one element (added by do_mergeinfo_unaware_dir_merge)
203  * describing a contiguous range to be merged to the WC merge target.
204  *
205  * During mergeinfo aware merges CHILDREN_WITH_MERGEINFO is created
206  * by get_mergeinfo_paths() and outside of that function and its helpers
207  * should always meet the criteria dictated in get_mergeinfo_paths()'s doc
208  * string.  The elements of CHILDREN_WITH_MERGEINFO should never be NULL.
209  *
210  * For clarification on mergeinfo aware vs. mergeinfo unaware merges, see
211  * the doc string for HONOR_MERGEINFO().
212  */
213
214
215 /*-----------------------------------------------------------------------*/
216 \f
217 /*** Repos-Diff Editor Callbacks ***/
218
219 /* */
220 typedef struct merge_source_t
221 {
222   /* "left" side URL and revision (inclusive iff youngest) */
223   const svn_client__pathrev_t *loc1;
224
225   /* "right" side URL and revision (inclusive iff youngest) */
226   const svn_client__pathrev_t *loc2;
227
228   /* True iff LOC1 is an ancestor of LOC2 or vice-versa (history-wise). */
229   svn_boolean_t ancestral;
230 } merge_source_t;
231
232 /* Description of the merge target root node (a WC working node) */
233 typedef struct merge_target_t
234 {
235   /* Absolute path to the WC node */
236   const char *abspath;
237
238   /* The repository location of the base node of the target WC.  If the node
239    * is locally added, then URL & REV are NULL & SVN_INVALID_REVNUM.
240    * REPOS_ROOT_URL and REPOS_UUID are always valid. */
241   svn_client__pathrev_t loc;
242
243 } merge_target_t;
244
245 typedef struct merge_cmd_baton_t {
246   svn_boolean_t force_delete;         /* Delete a file/dir even if modified */
247   svn_boolean_t dry_run;
248   svn_boolean_t record_only;          /* Whether to merge only mergeinfo
249                                          differences. */
250   svn_boolean_t same_repos;           /* Whether the merge source repository
251                                          is the same repository as the
252                                          target.  Defaults to FALSE if DRY_RUN
253                                          is TRUE.*/
254   svn_boolean_t mergeinfo_capable;    /* Whether the merge source server
255                                          is capable of Merge Tracking. */
256   svn_boolean_t ignore_mergeinfo;     /* Don't honor mergeinfo; see
257                                          doc string of do_merge().  FALSE if
258                                          MERGE_SOURCE->ancestral is FALSE. */
259   svn_boolean_t diff_ignore_ancestry; /* Diff unrelated nodes as if related; see
260                                          doc string of do_merge().  FALSE if
261                                          MERGE_SOURCE->ancestral is FALSE. */
262   svn_boolean_t reintegrate_merge;    /* Whether this is a --reintegrate
263                                          merge or not. */
264   const merge_target_t *target;       /* Description of merge target node */
265
266   /* The left and right URLs and revs.  The value of this field changes to
267      reflect the merge_source_t *currently* being merged by do_merge(). */
268   merge_source_t merge_source;
269
270   /* Rangelist containing single range which describes the gap, if any,
271      in the natural history of the merge source currently being processed.
272      See http://subversion.tigris.org/issues/show_bug.cgi?id=3432.
273      Updated during each call to do_directory_merge().  May be NULL if there
274      is no gap. */
275   svn_rangelist_t *implicit_src_gap;
276
277   svn_client_ctx_t *ctx;              /* Client context for callbacks, etc. */
278
279   /* The list of any paths which remained in conflict after a
280      resolution attempt was made.  We track this in-memory, rather
281      than just using WC entry state, since the latter doesn't help us
282      when in dry_run mode.
283      ### And because we only want to resolve conflicts that were
284          generated by this merge, not pre-existing ones? */
285   apr_hash_t *conflicted_paths;
286
287   /* A list of absolute paths which had no explicit mergeinfo prior to the
288      merge but got explicit mergeinfo added by the merge.  This is populated
289      by merge_change_props() and is allocated in POOL so it is subject to the
290      lifetime limitations of POOL.  Is NULL if no paths are found which
291      meet the criteria or DRY_RUN is true. */
292   apr_hash_t *paths_with_new_mergeinfo;
293
294   /* A list of absolute paths whose mergeinfo doesn't need updating after
295      the merge. This can be caused by the removal of mergeinfo by the merge
296      or by deleting the node itself.  This is populated by merge_change_props()
297      and the delete callbacks and is allocated in POOL so it is subject to the
298      lifetime limitations of POOL.  Is NULL if no paths are found which
299      meet the criteria or DRY_RUN is true. */
300   apr_hash_t *paths_with_deleted_mergeinfo;
301
302   /* The list of absolute skipped paths, which should be examined and
303      cleared after each invocation of the callback.  The paths
304      are absolute.  Is NULL if MERGE_B->MERGE_SOURCE->ancestral and
305      MERGE_B->REINTEGRATE_MERGE are both false. */
306   apr_hash_t *skipped_abspaths;
307
308   /* The list of absolute merged paths.  Unused if MERGE_B->MERGE_SOURCE->ancestral
309      and MERGE_B->REINTEGRATE_MERGE are both false. */
310   apr_hash_t *merged_abspaths;
311
312   /* A hash of (const char *) absolute WC paths mapped to the same which
313      represent the roots of subtrees added by the merge. */
314   apr_hash_t *added_abspaths;
315
316   /* A list of tree conflict victim absolute paths which may be NULL. */
317   apr_hash_t *tree_conflicted_abspaths;
318
319   /* The diff3_cmd in ctx->config, if any, else null.  We could just
320      extract this as needed, but since more than one caller uses it,
321      we just set it up when this baton is created. */
322   const char *diff3_cmd;
323   const apr_array_header_t *merge_options;
324
325   /* Array of file extension patterns to preserve as extensions in
326      generated conflict files. */
327   const apr_array_header_t *ext_patterns;
328
329   /* RA sessions used throughout a merge operation.  Opened/re-parented
330      as needed.
331
332      NOTE: During the actual merge editor drive, RA_SESSION1 is used
333      for the primary editing and RA_SESSION2 for fetching additional
334      information -- as necessary -- from the repository.  So during
335      this phase of the merge, you *must not* reparent RA_SESSION1; use
336      (temporarily reparenting if you must) RA_SESSION2 instead.  */
337   svn_ra_session_t *ra_session1;
338   svn_ra_session_t *ra_session2;
339
340   /* During the merge, *USE_SLEEP is set to TRUE if a sleep will be required
341      afterwards to ensure timestamp integrity, or unchanged if not. */
342   svn_boolean_t *use_sleep;
343
344   /* Pool which has a lifetime limited to one iteration over a given
345      merge source, i.e. it is cleared on every call to do_directory_merge()
346      or do_file_merge() in do_merge(). */
347   apr_pool_t *pool;
348
349
350   /* State for notify_merge_begin() */
351   struct notify_begin_state_t
352   {
353     /* Cache of which abspath was last notified. */
354     const char *last_abspath;
355
356     /* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global
357        comment) or a similar list for single-file-merges */
358     const apr_array_header_t *nodes_with_mergeinfo;
359   } notify_begin;
360
361 } merge_cmd_baton_t;
362
363
364 /* Return TRUE iff we should be taking account of mergeinfo in deciding what
365    changes to merge, for the merge described by MERGE_B.  Specifically, that
366    is if the merge source server is capable of merge tracking, the left-side
367    merge source is an ancestor of the right-side (or vice-versa), the merge
368    source is in the same repository as the merge target, and we are not
369    ignoring mergeinfo. */
370 #define HONOR_MERGEINFO(merge_b) ((merge_b)->mergeinfo_capable      \
371                                   && (merge_b)->merge_source.ancestral  \
372                                   && (merge_b)->same_repos          \
373                                   && (! (merge_b)->ignore_mergeinfo))
374
375
376 /* Return TRUE iff we should be recording mergeinfo for the merge described
377    by MERGE_B.  Specifically, that is if we are honoring mergeinfo and the
378    merge is not a dry run.  */
379 #define RECORD_MERGEINFO(merge_b) (HONOR_MERGEINFO(merge_b) \
380                                    && !(merge_b)->dry_run)
381
382
383 /*-----------------------------------------------------------------------*/
384 \f
385 /*** Utilities ***/
386
387 /* Return TRUE iff the session URL of RA_SESSION is equal to URL.  Useful in
388  * asserting preconditions. */
389 static svn_boolean_t
390 session_url_is(svn_ra_session_t *ra_session,
391                const char *url,
392                apr_pool_t *scratch_pool)
393 {
394   const char *session_url;
395   svn_error_t *err
396     = svn_ra_get_session_url(ra_session, &session_url, scratch_pool);
397
398   SVN_ERR_ASSERT_NO_RETURN(! err);
399   return strcmp(url, session_url) == 0;
400 }
401
402 /* Return a new merge_source_t structure, allocated in RESULT_POOL,
403  * initialized with deep copies of LOC1 and LOC2 and ANCESTRAL. */
404 static merge_source_t *
405 merge_source_create(const svn_client__pathrev_t *loc1,
406                     const svn_client__pathrev_t *loc2,
407                     svn_boolean_t ancestral,
408                     apr_pool_t *result_pool)
409 {
410   merge_source_t *s
411     = apr_palloc(result_pool, sizeof(*s));
412
413   s->loc1 = svn_client__pathrev_dup(loc1, result_pool);
414   s->loc2 = svn_client__pathrev_dup(loc2, result_pool);
415   s->ancestral = ancestral;
416   return s;
417 }
418
419 /* Return a deep copy of SOURCE, allocated in RESULT_POOL. */
420 static merge_source_t *
421 merge_source_dup(const merge_source_t *source,
422                  apr_pool_t *result_pool)
423 {
424   merge_source_t *s = apr_palloc(result_pool, sizeof(*s));
425
426   s->loc1 = svn_client__pathrev_dup(source->loc1, result_pool);
427   s->loc2 = svn_client__pathrev_dup(source->loc2, result_pool);
428   s->ancestral = source->ancestral;
429   return s;
430 }
431
432 /* Return SVN_ERR_UNSUPPORTED_FEATURE if URL is not inside the repository
433    of LOCAL_ABSPATH.  Use SCRATCH_POOL for temporary allocations. */
434 static svn_error_t *
435 check_repos_match(const merge_target_t *target,
436                   const char *local_abspath,
437                   const char *url,
438                   apr_pool_t *scratch_pool)
439 {
440   if (!svn_uri__is_ancestor(target->loc.repos_root_url, url))
441     return svn_error_createf(
442         SVN_ERR_UNSUPPORTED_FEATURE, NULL,
443          _("URL '%s' of '%s' is not in repository '%s'"),
444          url, svn_dirent_local_style(local_abspath, scratch_pool),
445          target->loc.repos_root_url);
446
447   return SVN_NO_ERROR;
448 }
449
450 /* Return TRUE iff the repository of LOCATION1 is the same as
451  * that of LOCATION2.  If STRICT_URLS is true, the URLs must
452  * match (and the UUIDs, just to be sure), otherwise just the UUIDs must
453  * match and the URLs can differ (a common case is http versus https). */
454 static svn_boolean_t
455 is_same_repos(const svn_client__pathrev_t *location1,
456               const svn_client__pathrev_t *location2,
457               svn_boolean_t strict_urls)
458 {
459   if (strict_urls)
460     return (strcmp(location1->repos_root_url, location2->repos_root_url) == 0
461             && strcmp(location1->repos_uuid, location2->repos_uuid) == 0);
462   else
463     return (strcmp(location1->repos_uuid, location2->repos_uuid) == 0);
464 }
465
466 /* If the repository identified of LOCATION1 is not the same as that
467  * of LOCATION2, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES
468  * error mentioning PATH1 and PATH2. For STRICT_URLS, see is_same_repos().
469  */
470 static svn_error_t *
471 check_same_repos(const svn_client__pathrev_t *location1,
472                  const char *path1,
473                  const svn_client__pathrev_t *location2,
474                  const char *path2,
475                  svn_boolean_t strict_urls,
476                  apr_pool_t *scratch_pool)
477 {
478   if (! is_same_repos(location1, location2, strict_urls))
479     return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
480                              _("'%s' must be from the same repository as "
481                                "'%s'"), path1, path2);
482   return SVN_NO_ERROR;
483 }
484
485 /* Store LOCAL_ABSPATH in PATH_HASH after duplicating it into the pool
486    containing PATH_HASH. */
487 static APR_INLINE void
488 store_path(apr_hash_t *path_hash, const char *local_abspath)
489 {
490   const char *dup_path = apr_pstrdup(apr_hash_pool_get(path_hash),
491                                      local_abspath);
492
493   svn_hash_sets(path_hash, dup_path, dup_path);
494 }
495
496 /* Store LOCAL_ABSPATH in *PATH_HASH_P after duplicating it into the pool
497    containing *PATH_HASH_P.  If *PATH_HASH_P is NULL, then first set
498    *PATH_HASH_P to a new hash allocated from POOL.  */
499 static APR_INLINE void
500 alloc_and_store_path(apr_hash_t **path_hash_p,
501                      const char *local_abspath,
502                      apr_pool_t *pool)
503 {
504   if (! *path_hash_p)
505     *path_hash_p = apr_hash_make(pool);
506   store_path(*path_hash_p, local_abspath);
507 }
508
509 /* Return whether any WC path was put in conflict by the merge
510    operation corresponding to MERGE_B. */
511 static APR_INLINE svn_boolean_t
512 is_path_conflicted_by_merge(merge_cmd_baton_t *merge_b)
513 {
514   return (merge_b->conflicted_paths &&
515           apr_hash_count(merge_b->conflicted_paths) > 0);
516 }
517
518 /* Return a state indicating whether the WC metadata matches the
519  * node kind on disk of the local path LOCAL_ABSPATH.
520  * Use MERGE_B to determine the dry-run details; particularly, if a dry run
521  * noted that it deleted this path, assume matching node kinds (as if both
522  * kinds were svn_node_none).
523  *
524  *   - Return svn_wc_notify_state_inapplicable if the node kind matches.
525  *   - Return 'obstructed' if there is a node on disk where none or a
526  *     different kind is expected, or if the disk node cannot be read.
527  *   - Return 'missing' if there is no node on disk but one is expected.
528  *     Also return 'missing' for server-excluded nodes (not here due to
529  *     authz or other reasons determined by the server).
530  *
531  * Optionally return a bit more info for interested users.
532  **/
533 static svn_error_t *
534 perform_obstruction_check(svn_wc_notify_state_t *obstruction_state,
535                           svn_boolean_t *deleted,
536                           svn_boolean_t *excluded,
537                           svn_node_kind_t *kind,
538                           svn_depth_t *parent_depth,
539                           const merge_cmd_baton_t *merge_b,
540                           const char *local_abspath,
541                           apr_pool_t *scratch_pool)
542 {
543   svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx;
544   svn_node_kind_t wc_kind;
545   svn_boolean_t check_root;
546
547   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
548
549   *obstruction_state = svn_wc_notify_state_inapplicable;
550
551   if (deleted)
552     *deleted = FALSE;
553   if (kind)
554     *kind = svn_node_none;
555
556   if (kind == NULL)
557     kind = &wc_kind;
558
559   check_root = ! strcmp(local_abspath, merge_b->target->abspath);
560
561   SVN_ERR(svn_wc__check_for_obstructions(obstruction_state,
562                                          kind,
563                                          deleted,
564                                          excluded,
565                                          parent_depth,
566                                          wc_ctx, local_abspath,
567                                          check_root,
568                                          scratch_pool));
569   return SVN_NO_ERROR;
570 }
571
572 /* Create *LEFT and *RIGHT conflict versions for conflict victim
573  * at VICTIM_ABSPATH, with kind NODE_KIND, using information obtained
574  * from MERGE_SOURCE and TARGET.
575  * Allocate returned conflict versions in RESULT_POOL. */
576 static svn_error_t *
577 make_conflict_versions(const svn_wc_conflict_version_t **left,
578                        const svn_wc_conflict_version_t **right,
579                        const char *victim_abspath,
580                        svn_node_kind_t node_kind,
581                        const merge_source_t *merge_source,
582                        const merge_target_t *target,
583                        apr_pool_t *result_pool,
584                        apr_pool_t *scratch_pool)
585 {
586   const char *child = svn_dirent_skip_ancestor(target->abspath,
587                                                victim_abspath);
588   const char *left_relpath, *right_relpath;
589
590   SVN_ERR_ASSERT(child != NULL);
591   left_relpath = svn_client__pathrev_relpath(merge_source->loc1,
592                                              scratch_pool);
593   right_relpath = svn_client__pathrev_relpath(merge_source->loc2,
594                                               scratch_pool);
595
596   *left = svn_wc_conflict_version_create2(
597             merge_source->loc1->repos_root_url,
598             merge_source->loc1->repos_uuid,
599             svn_relpath_join(left_relpath, child, scratch_pool),
600             merge_source->loc1->rev, node_kind, result_pool);
601
602   *right = svn_wc_conflict_version_create2(
603              merge_source->loc2->repos_root_url,
604              merge_source->loc2->repos_uuid,
605              svn_relpath_join(right_relpath, child, scratch_pool),
606              merge_source->loc2->rev, node_kind, result_pool);
607
608   return SVN_NO_ERROR;
609 }
610
611 /* Helper for filter_self_referential_mergeinfo()
612
613    *MERGEINFO is a non-empty, non-null collection of mergeinfo.
614
615    Remove all mergeinfo from *MERGEINFO that describes revision ranges
616    greater than REVISION.  Put a copy of any removed mergeinfo, allocated
617    in POOL, into *YOUNGER_MERGEINFO.
618
619    If no mergeinfo is removed from *MERGEINFO then *YOUNGER_MERGEINFO is set
620    to NULL.  If all mergeinfo is removed from *MERGEINFO then *MERGEINFO is
621    set to NULL.
622    */
623 static svn_error_t*
624 split_mergeinfo_on_revision(svn_mergeinfo_t *younger_mergeinfo,
625                             svn_mergeinfo_t *mergeinfo,
626                             svn_revnum_t revision,
627                             apr_pool_t *pool)
628 {
629   apr_hash_index_t *hi;
630   apr_pool_t *iterpool = svn_pool_create(pool);
631
632   *younger_mergeinfo = NULL;
633   for (hi = apr_hash_first(pool, *mergeinfo); hi; hi = apr_hash_next(hi))
634     {
635       int i;
636       const char *merge_source_path = svn__apr_hash_index_key(hi);
637       svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
638
639       svn_pool_clear(iterpool);
640
641       for (i = 0; i < rangelist->nelts; i++)
642         {
643           svn_merge_range_t *range =
644             APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
645           if (range->end <= revision)
646             {
647               /* This entirely of this range is as old or older than
648                  REVISION, so leave it in *MERGEINFO. */
649               continue;
650             }
651           else
652             {
653               /* Since the rangelists in svn_mergeinfo_t's are sorted in
654                  increasing order we know that part or all of *this* range
655                  and *all* of the remaining ranges in *RANGELIST are younger
656                  than REVISION.  Remove the younger rangelists from
657                  *MERGEINFO and put them in *YOUNGER_MERGEINFO. */
658               int j;
659               svn_rangelist_t *younger_rangelist =
660                 apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
661
662               for (j = i; j < rangelist->nelts; j++)
663                 {
664                   svn_merge_range_t *younger_range = svn_merge_range_dup(
665                     APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *), pool);
666
667                   /* REVISION might intersect with the first range where
668                      range->end > REVISION.  If that is the case then split
669                      the current range into two, putting the younger half
670                      into *YOUNGER_MERGEINFO and leaving the older half in
671                      *MERGEINFO. */
672                   if (j == i && range->start + 1 <= revision)
673                     younger_range->start = range->end = revision;
674
675                   APR_ARRAY_PUSH(younger_rangelist, svn_merge_range_t *) =
676                     younger_range;
677                 }
678
679               /* So far we've only been manipulating rangelists, now we
680                  actually create *YOUNGER_MERGEINFO and then remove the older
681                  ranges from *MERGEINFO */
682               if (!(*younger_mergeinfo))
683                 *younger_mergeinfo = apr_hash_make(pool);
684               svn_hash_sets(*younger_mergeinfo, merge_source_path,
685                             younger_rangelist);
686               SVN_ERR(svn_mergeinfo_remove2(mergeinfo, *younger_mergeinfo,
687                                             *mergeinfo, TRUE, pool, iterpool));
688               break; /* ...out of for (i = 0; i < rangelist->nelts; i++) */
689             }
690         }
691     }
692
693   svn_pool_destroy(iterpool);
694
695   return SVN_NO_ERROR;
696 }
697
698
699 /* Make a copy of PROPCHANGES (array of svn_prop_t) into *TRIMMED_PROPCHANGES,
700    omitting any svn:mergeinfo changes.  */
701 static svn_error_t *
702 omit_mergeinfo_changes(apr_array_header_t **trimmed_propchanges,
703                        const apr_array_header_t *propchanges,
704                        apr_pool_t *result_pool)
705 {
706   int i;
707
708   *trimmed_propchanges = apr_array_make(result_pool,
709                                         propchanges->nelts,
710                                         sizeof(svn_prop_t));
711
712   for (i = 0; i < propchanges->nelts; ++i)
713     {
714       const svn_prop_t *change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
715
716       /* If this property is not svn:mergeinfo, then copy it.  */
717       if (strcmp(change->name, SVN_PROP_MERGEINFO) != 0)
718         APR_ARRAY_PUSH(*trimmed_propchanges, svn_prop_t) = *change;
719     }
720
721   return SVN_NO_ERROR;
722 }
723
724
725 /* Helper for merge_props_changed().
726
727    *PROPS is an array of svn_prop_t structures representing regular properties
728    to be added to the working copy TARGET_ABSPATH.
729
730    The merge source and target are assumed to be in the same repository.
731
732    Filter out mergeinfo property additions to TARGET_ABSPATH when
733    those additions refer to the same line of history as TARGET_ABSPATH as
734    described below.
735
736    Examine the added mergeinfo, looking at each range (or single rev)
737    of each source path.  If a source_path/range refers to the same line of
738    history as TARGET_ABSPATH (pegged at its base revision), then filter out
739    that range.  If the entire rangelist for a given path is filtered then
740    filter out the path as well.
741
742    RA_SESSION is an open RA session to the repository
743    in which both the source and target live, else RA_SESSION is not used. It
744    may be temporarily reparented as needed by this function.
745
746    Use CTX for any further client operations.
747
748    If any filtering occurs, set outgoing *PROPS to a shallow copy (allocated
749    in POOL) of incoming *PROPS minus the filtered mergeinfo. */
750 static svn_error_t *
751 filter_self_referential_mergeinfo(apr_array_header_t **props,
752                                   const char *target_abspath,
753                                   svn_ra_session_t *ra_session,
754                                   svn_client_ctx_t *ctx,
755                                   apr_pool_t *pool)
756 {
757   apr_array_header_t *adjusted_props;
758   int i;
759   apr_pool_t *iterpool;
760   svn_boolean_t is_copy;
761   const char *repos_relpath;
762   svn_client__pathrev_t target_base;
763
764   /* If PATH itself has been added there is no need to filter. */
765   SVN_ERR(svn_wc__node_get_origin(&is_copy,  &target_base.rev, &repos_relpath,
766                                   &target_base.repos_root_url,
767                                   &target_base.repos_uuid, NULL,
768                                   ctx->wc_ctx, target_abspath, FALSE,
769                                   pool, pool));
770
771   if (is_copy || !repos_relpath)
772     return SVN_NO_ERROR; /* A copy or a local addition */
773
774   target_base.url = svn_path_url_add_component2(target_base.repos_root_url,
775                                                 repos_relpath, pool);
776
777   adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t));
778   iterpool = svn_pool_create(pool);
779   for (i = 0; i < (*props)->nelts; ++i)
780     {
781       svn_prop_t *prop = &APR_ARRAY_IDX((*props), i, svn_prop_t);
782
783       svn_mergeinfo_t mergeinfo, younger_mergeinfo;
784       svn_mergeinfo_t filtered_mergeinfo = NULL;
785       svn_mergeinfo_t filtered_younger_mergeinfo = NULL;
786       svn_error_t *err;
787
788       /* If this property isn't mergeinfo or is NULL valued (i.e. prop removal)
789          or empty mergeinfo it does not require any special handling.  There
790          is nothing to filter out of empty mergeinfo and the concept of
791          filtering doesn't apply if we are trying to remove mergeinfo
792          entirely.  */
793       if ((strcmp(prop->name, SVN_PROP_MERGEINFO) != 0)
794           || (! prop->value)       /* Removal of mergeinfo */
795           || (! prop->value->len)) /* Empty mergeinfo */
796         {
797           APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
798           continue;
799         }
800
801       svn_pool_clear(iterpool);
802
803       /* Non-empty mergeinfo; filter self-referential mergeinfo out. */
804
805       /* Parse the incoming mergeinfo to allow easier manipulation. */
806       err = svn_mergeinfo_parse(&mergeinfo, prop->value->data, iterpool);
807
808       if (err)
809         {
810           /* Issue #3896: If we can't parse it, we certainly can't
811              filter it. */
812           if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
813             {
814               svn_error_clear(err);
815               APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
816               continue;
817             }
818           else
819             {
820               return svn_error_trace(err);
821             }
822         }
823
824       /* The working copy target PATH is at BASE_REVISION.  Divide the
825          incoming mergeinfo into two groups.  One where all revision ranges
826          are as old or older than BASE_REVISION and one where all revision
827          ranges are younger.
828
829          Note: You may be wondering why we do this.
830
831          For the incoming mergeinfo "older" than target's base revision we
832          can filter out self-referential mergeinfo efficiently using
833          svn_client__get_history_as_mergeinfo().  We simply look at PATH's
834          natural history as mergeinfo and remove that from any incoming
835          mergeinfo.
836
837          For mergeinfo "younger" than the base revision we can't use
838          svn_ra_get_location_segments() to look into PATH's future
839          history.  Instead we must use svn_client__repos_locations() and
840          look at each incoming source/range individually and see if PATH
841          at its base revision and PATH at the start of the incoming range
842          exist on the same line of history.  If they do then we can filter
843          out the incoming range.  But since we have to do this for each
844          range there is a substantial performance penalty to pay if the
845          incoming ranges are not contiguous, i.e. we call
846          svn_client__repos_locations for each discrete range and incur
847          the cost of a roundtrip communication with the repository. */
848       SVN_ERR(split_mergeinfo_on_revision(&younger_mergeinfo,
849                                           &mergeinfo,
850                                           target_base.rev,
851                                           iterpool));
852
853       /* Filter self-referential mergeinfo from younger_mergeinfo. */
854       if (younger_mergeinfo)
855         {
856           apr_hash_index_t *hi;
857           const char *merge_source_root_url;
858
859           SVN_ERR(svn_ra_get_repos_root2(ra_session,
860                                          &merge_source_root_url, iterpool));
861
862           for (hi = apr_hash_first(iterpool, younger_mergeinfo);
863                hi; hi = apr_hash_next(hi))
864             {
865               int j;
866               const char *source_path = svn__apr_hash_index_key(hi);
867               svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
868               const char *merge_source_url;
869               svn_rangelist_t *adjusted_rangelist =
870                 apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *));
871
872               merge_source_url =
873                     svn_path_url_add_component2(merge_source_root_url,
874                                                 source_path + 1, iterpool);
875
876               for (j = 0; j < rangelist->nelts; j++)
877                 {
878                   svn_error_t *err2;
879                   svn_client__pathrev_t *start_loc;
880                   svn_merge_range_t *range =
881                     APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *);
882
883                   /* Because the merge source normalization code
884                      ensures mergeinfo refers to real locations on
885                      the same line of history, there's no need to
886                      look at the whole range, just the start. */
887
888                   /* Check if PATH@BASE_REVISION exists at
889                      RANGE->START on the same line of history.
890                      (start+1 because RANGE->start is not inclusive.) */
891                   err2 = svn_client__repos_location(&start_loc, ra_session,
892                                                     &target_base,
893                                                     range->start + 1,
894                                                     ctx, iterpool, iterpool);
895                   if (err2)
896                     {
897                       if (err2->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES
898                           || err2->apr_err == SVN_ERR_FS_NOT_FOUND
899                           || err2->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
900                         {
901                           /* PATH@BASE_REVISION didn't exist at
902                              RANGE->START + 1 or is unrelated to the
903                              resource PATH@RANGE->START.  Some of the
904                              requested revisions may not even exist in
905                              the repository; a real possibility since
906                              mergeinfo is hand editable.  In all of these
907                              cases clear and ignore the error and don't
908                              do any filtering.
909
910                              Note: In this last case it is possible that
911                              we will allow self-referential mergeinfo to
912                              be applied, but fixing it here is potentially
913                              very costly in terms of finding what part of
914                              a range is actually valid.  Simply allowing
915                              the merge to proceed without filtering the
916                              offending range seems the least worst
917                              option. */
918                           svn_error_clear(err2);
919                           err2 = NULL;
920                           APR_ARRAY_PUSH(adjusted_rangelist,
921                                          svn_merge_range_t *) = range;
922                         }
923                       else
924                         {
925                           return svn_error_trace(err2);
926                         }
927                      }
928                   else
929                     {
930                       /* PATH@BASE_REVISION exists on the same
931                          line of history at RANGE->START and RANGE->END.
932                          Now check that PATH@BASE_REVISION's path
933                          names at RANGE->START and RANGE->END are the same.
934                          If the names are not the same then the mergeinfo
935                          describing PATH@RANGE->START through
936                          PATH@RANGE->END actually belong to some other
937                          line of history and we want to record this
938                          mergeinfo, not filter it. */
939                       if (strcmp(start_loc->url, merge_source_url) != 0)
940                         {
941                           APR_ARRAY_PUSH(adjusted_rangelist,
942                                          svn_merge_range_t *) = range;
943                         }
944                     }
945                     /* else no need to add, this mergeinfo is
946                        all on the same line of history. */
947                 } /* for (j = 0; j < rangelist->nelts; j++) */
948
949               /* Add any rangelists for source_path that are not
950                  self-referential. */
951               if (adjusted_rangelist->nelts)
952                 {
953                   if (!filtered_younger_mergeinfo)
954                     filtered_younger_mergeinfo = apr_hash_make(iterpool);
955                   svn_hash_sets(filtered_younger_mergeinfo, source_path,
956                                 adjusted_rangelist);
957                 }
958
959             } /* Iteration over each merge source in younger_mergeinfo. */
960         } /* if (younger_mergeinfo) */
961
962       /* Filter self-referential mergeinfo from "older" mergeinfo. */
963       if (mergeinfo)
964         {
965           svn_mergeinfo_t implicit_mergeinfo;
966
967           SVN_ERR(svn_client__get_history_as_mergeinfo(
968             &implicit_mergeinfo, NULL,
969             &target_base, target_base.rev, SVN_INVALID_REVNUM,
970             ra_session, ctx, iterpool));
971
972           /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */
973           SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo,
974                                         implicit_mergeinfo,
975                                         mergeinfo, TRUE, iterpool, iterpool));
976         }
977
978       /* Combine whatever older and younger filtered mergeinfo exists
979          into filtered_mergeinfo. */
980       if (filtered_mergeinfo && filtered_younger_mergeinfo)
981         SVN_ERR(svn_mergeinfo_merge2(filtered_mergeinfo,
982                                      filtered_younger_mergeinfo, iterpool,
983                                      iterpool));
984       else if (filtered_younger_mergeinfo)
985         filtered_mergeinfo = filtered_younger_mergeinfo;
986
987       /* If there is any incoming mergeinfo remaining after filtering
988          then put it in adjusted_props. */
989       if (filtered_mergeinfo && apr_hash_count(filtered_mergeinfo))
990         {
991           /* Convert filtered_mergeinfo to a svn_prop_t and put it
992              back in the array. */
993           svn_string_t *filtered_mergeinfo_str;
994           svn_prop_t *adjusted_prop = apr_pcalloc(pool,
995                                                   sizeof(*adjusted_prop));
996           SVN_ERR(svn_mergeinfo_to_string(&filtered_mergeinfo_str,
997                                           filtered_mergeinfo,
998                                           pool));
999           adjusted_prop->name = SVN_PROP_MERGEINFO;
1000           adjusted_prop->value = filtered_mergeinfo_str;
1001           APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *adjusted_prop;
1002         }
1003     }
1004   svn_pool_destroy(iterpool);
1005
1006   *props = adjusted_props;
1007   return SVN_NO_ERROR;
1008 }
1009
1010 /* Prepare a set of property changes PROPCHANGES to be used for a merge
1011    operation on LOCAL_ABSPATH.
1012
1013    Remove all non-regular prop-changes (entry-props and WC-props).
1014    Remove all non-mergeinfo prop-changes if it's a record-only merge.
1015    Remove self-referential mergeinfo (### in some cases...)
1016    Remove foreign-repository mergeinfo (### in some cases...)
1017
1018    Store the resulting property changes in *PROP_UPDATES.
1019    Store information on where mergeinfo is updated in MERGE_B.
1020
1021    Used for both file and directory property merges. */
1022 static svn_error_t *
1023 prepare_merge_props_changed(const apr_array_header_t **prop_updates,
1024                             const char *local_abspath,
1025                             const apr_array_header_t *propchanges,
1026                             merge_cmd_baton_t *merge_b,
1027                             apr_pool_t *result_pool,
1028                             apr_pool_t *scratch_pool)
1029 {
1030   apr_array_header_t *props;
1031
1032   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
1033
1034   /* We only want to merge "regular" version properties:  by
1035      definition, 'svn merge' shouldn't touch any data within .svn/  */
1036   SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props,
1037                                result_pool));
1038
1039   /* If we are only applying mergeinfo changes then we need to do
1040      additional filtering of PROPS so it contains only mergeinfo changes. */
1041   if (merge_b->record_only && props->nelts)
1042     {
1043       apr_array_header_t *mergeinfo_props =
1044         apr_array_make(result_pool, 1, sizeof(svn_prop_t));
1045       int i;
1046
1047       for (i = 0; i < props->nelts; i++)
1048         {
1049           svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
1050
1051           if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0)
1052             {
1053               APR_ARRAY_PUSH(mergeinfo_props, svn_prop_t) = *prop;
1054               break;
1055             }
1056         }
1057       props = mergeinfo_props;
1058     }
1059
1060   if (props->nelts)
1061     {
1062       /* Issue #3383: We don't want mergeinfo from a foreign repos.
1063
1064          If this is a merge from a foreign repository we must strip all
1065          incoming mergeinfo (including mergeinfo deletions). */
1066       if (! merge_b->same_repos)
1067         SVN_ERR(omit_mergeinfo_changes(&props, props, result_pool));
1068
1069       /* If this is a forward merge then don't add new mergeinfo to
1070          PATH that is already part of PATH's own history, see
1071          http://svn.haxx.se/dev/archive-2008-09/0006.shtml.  If the
1072          merge sources are not ancestral then there is no concept of a
1073          'forward' or 'reverse' merge and we filter unconditionally. */
1074       if (merge_b->merge_source.loc1->rev < merge_b->merge_source.loc2->rev
1075           || !merge_b->merge_source.ancestral)
1076         {
1077           if (HONOR_MERGEINFO(merge_b) || merge_b->reintegrate_merge)
1078             SVN_ERR(filter_self_referential_mergeinfo(&props,
1079                                                       local_abspath,
1080                                                       merge_b->ra_session2,
1081                                                       merge_b->ctx,
1082                                                       result_pool));
1083         }
1084     }
1085   *prop_updates = props;
1086
1087   /* Make a record in BATON if we find a PATH where mergeinfo is added
1088      where none existed previously or PATH is having its existing
1089      mergeinfo deleted. */
1090   if (props->nelts)
1091     {
1092       int i;
1093
1094       for (i = 0; i < props->nelts; ++i)
1095         {
1096           svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
1097
1098           if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0)
1099             {
1100               /* Does LOCAL_ABSPATH have any pristine mergeinfo? */
1101               svn_boolean_t has_pristine_mergeinfo = FALSE;
1102               apr_hash_t *pristine_props;
1103
1104               SVN_ERR(svn_wc_get_pristine_props(&pristine_props,
1105                                                 merge_b->ctx->wc_ctx,
1106                                                 local_abspath,
1107                                                 scratch_pool,
1108                                                 scratch_pool));
1109
1110               if (pristine_props
1111                   && svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO))
1112                 has_pristine_mergeinfo = TRUE;
1113
1114               if (!has_pristine_mergeinfo && prop->value)
1115                 {
1116                   alloc_and_store_path(&merge_b->paths_with_new_mergeinfo,
1117                                        local_abspath, merge_b->pool);
1118                 }
1119               else if (has_pristine_mergeinfo && !prop->value)
1120                 {
1121                   alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo,
1122                                        local_abspath, merge_b->pool);
1123                 }
1124             }
1125         }
1126     }
1127
1128   return SVN_NO_ERROR;
1129 }
1130
1131 #define CONFLICT_REASON_NONE       ((svn_wc_conflict_reason_t)-1)
1132 #define CONFLICT_REASON_SKIP       ((svn_wc_conflict_reason_t)-2)
1133 #define CONFLICT_REASON_SKIP_WC    ((svn_wc_conflict_reason_t)-3)
1134
1135 /* Baton used for testing trees for being editted while performing tree
1136    conflict detection for incoming deletes */
1137 struct dir_delete_baton_t
1138 {
1139   /* Reference to dir baton of directory that is the root of the deletion */
1140   struct merge_dir_baton_t *del_root;
1141
1142   /* Boolean indicating that some edit is found. Allows avoiding more work */
1143   svn_boolean_t found_edit;
1144
1145   /* A list of paths that are compared. Kept up to date until FOUND_EDIT is
1146      set to TRUE */
1147   apr_hash_t *compared_abspaths;
1148 };
1149
1150 /* Baton for the merge_dir_*() functions. Initialized in merge_dir_opened() */
1151 struct merge_dir_baton_t
1152 {
1153   /* Reference to the parent baton, unless the parent is the anchor, in which
1154      case PARENT_BATON is NULL */
1155   struct merge_dir_baton_t *parent_baton;
1156
1157   /* The pool containing this baton. Use for RESULT_POOL for storing in this
1158      baton */
1159   apr_pool_t *pool;
1160
1161   /* This directory doesn't have a representation in the working copy, so any
1162      operation on it will be skipped and possibly cause a tree conflict on the
1163      shadow root */
1164   svn_boolean_t shadowed;
1165
1166   /* This node or one of its descendants received operational changes from the
1167      merge. If this node is the shadow root its tree conflict status has been
1168      applied */
1169   svn_boolean_t edited;
1170
1171   /* If a tree conflict will be installed once edited, it's reason. If a skip
1172      should be produced its reason. Otherwise CONFLICT_REASON_NONE for no tree
1173      conflict.
1174
1175      Special values:
1176        CONFLICT_REASON_SKIP:
1177             The node will be skipped with content and property state as stored in
1178             SKIP_REASON.
1179
1180        CONFLICT_REASON_SKIP_WC:
1181             The node will be skipped as an obstructing working copy.
1182    */
1183   svn_wc_conflict_reason_t tree_conflict_reason;
1184   svn_wc_conflict_action_t tree_conflict_action;
1185
1186   /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to
1187      add to the notification */
1188   svn_wc_notify_state_t skip_reason;
1189
1190   /* TRUE if the node was added by this merge. Otherwise FALSE */
1191   svn_boolean_t added;
1192   svn_boolean_t add_is_replace; /* Add is second part of replace */
1193
1194   /* TRUE if we are taking over an existing directory as addition, otherwise
1195      FALSE. */
1196   svn_boolean_t add_existing;
1197
1198   /* NULL, or an hashtable mapping const char * local_abspaths to
1199      const char *kind mapping, containing deleted nodes that still need a delete
1200      notification (which may be a replaced notification if the node is not just
1201      deleted) */
1202   apr_hash_t *pending_deletes;
1203
1204   /* NULL, or an hashtable mapping const char * LOCAL_ABSPATHs to
1205      a const svn_wc_conflict_description2_t * instance, describing the just
1206      installed conflict */
1207   apr_hash_t *new_tree_conflicts;
1208
1209   /* If not NULL, a reference to the information of the delete test that is
1210      currently in progress. Allocated in the root-directory baton, referenced
1211      from all descendants */
1212   struct dir_delete_baton_t *delete_state;
1213 };
1214
1215 /* Baton for the merge_dir_*() functions. Initialized in merge_file_opened() */
1216 struct merge_file_baton_t
1217 {
1218   /* Reference to the parent baton, unless the parent is the anchor, in which
1219      case PARENT_BATON is NULL */
1220   struct merge_dir_baton_t *parent_baton;
1221
1222   /* This file doesn't have a representation in the working copy, so any
1223      operation on it will be skipped and possibly cause a tree conflict
1224      on the shadow root */
1225   svn_boolean_t shadowed;
1226
1227   /* This node received operational changes from the merge. If this node
1228      is the shadow root its tree conflict status has been applied */
1229   svn_boolean_t edited;
1230
1231   /* If a tree conflict will be installed once edited, it's reason. If a skip
1232      should be produced its reason. Some special values are defined. See the
1233      merge_tree_baton_t for an explanation. */
1234   svn_wc_conflict_reason_t tree_conflict_reason;
1235   svn_wc_conflict_action_t tree_conflict_action;
1236
1237   /* When TREE_CONFLICT_REASON is CONFLICT_REASON_SKIP, the skip state to
1238      add to the notification */
1239   svn_wc_notify_state_t skip_reason;
1240
1241   /* TRUE if the node was added by this merge. Otherwise FALSE */
1242   svn_boolean_t added;
1243   svn_boolean_t add_is_replace; /* Add is second part of replace */
1244 };
1245
1246 /* Forward declaration */
1247 static svn_error_t *
1248 notify_merge_begin(merge_cmd_baton_t *merge_b,
1249                    const char *local_abspath,
1250                    svn_boolean_t delete_action,
1251                    apr_pool_t *scratch_pool);
1252
1253 /* Record the skip for future processing and (later) produce the
1254    skip notification */
1255 static svn_error_t *
1256 record_skip(merge_cmd_baton_t *merge_b,
1257             const char *local_abspath,
1258             svn_node_kind_t kind,
1259             svn_wc_notify_action_t action,
1260             svn_wc_notify_state_t state,
1261             apr_pool_t *scratch_pool)
1262 {
1263   if (merge_b->record_only)
1264     return SVN_NO_ERROR; /* ### Why? - Legacy compatibility */
1265
1266   if (merge_b->merge_source.ancestral
1267       || merge_b->reintegrate_merge)
1268     {
1269       store_path(merge_b->skipped_abspaths, local_abspath);
1270     }
1271
1272   if (merge_b->ctx->notify_func2)
1273     {
1274       svn_wc_notify_t *notify;
1275
1276       SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1277
1278       notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
1279       notify->kind = kind;
1280       notify->content_state = notify->prop_state = state;
1281
1282       (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify,
1283                                     scratch_pool);
1284     }
1285   return SVN_NO_ERROR;
1286 }
1287
1288 /* Record a tree conflict in the WC, unless this is a dry run or a record-
1289  * only merge, or if a tree conflict is already flagged for the VICTIM_PATH.
1290  * (The latter can happen if a merge-tracking-aware merge is doing multiple
1291  * editor drives because of a gap in the range of eligible revisions.)
1292  *
1293  * The tree conflict, with its victim specified by VICTIM_PATH, is
1294  * assumed to have happened during a merge using merge baton MERGE_B.
1295  *
1296  * NODE_KIND must be the node kind of "old" and "theirs" and "mine";
1297  * this function cannot cope with node kind clashes.
1298  * ACTION and REASON correspond to the fields
1299  * of the same names in svn_wc_tree_conflict_description_t.
1300  */
1301 static svn_error_t *
1302 record_tree_conflict(merge_cmd_baton_t *merge_b,
1303                      const char *local_abspath,
1304                      struct merge_dir_baton_t *parent_baton,
1305                      svn_node_kind_t node_kind,
1306                      svn_wc_conflict_action_t action,
1307                      svn_wc_conflict_reason_t reason,
1308                      const svn_wc_conflict_description2_t *existing_conflict,
1309                      svn_boolean_t notify_tc,
1310                      apr_pool_t *scratch_pool)
1311 {
1312   svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx;
1313
1314   if (merge_b->record_only)
1315     return SVN_NO_ERROR;
1316
1317   if (merge_b->merge_source.ancestral
1318       || merge_b->reintegrate_merge)
1319     {
1320       store_path(merge_b->tree_conflicted_abspaths, local_abspath);
1321     }
1322
1323   alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
1324                        merge_b->pool);
1325
1326   if (!merge_b->dry_run)
1327     {
1328        svn_wc_conflict_description2_t *conflict;
1329        const svn_wc_conflict_version_t *left;
1330        const svn_wc_conflict_version_t *right;
1331        apr_pool_t *result_pool = parent_baton ? parent_baton->pool
1332                                               : scratch_pool;
1333
1334       if (reason == svn_wc_conflict_reason_deleted)
1335         {
1336           const char *moved_to_abspath;
1337
1338           SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
1339                                               wc_ctx, local_abspath,
1340                                               scratch_pool, scratch_pool));
1341
1342           if (moved_to_abspath)
1343             {
1344               /* Local abspath itself has been moved away. If only a
1345                  descendant is moved away, we call the node itself deleted */
1346               reason = svn_wc_conflict_reason_moved_away;
1347             }
1348         }
1349       else if (reason == svn_wc_conflict_reason_added)
1350         {
1351           const char *moved_from_abspath;
1352           SVN_ERR(svn_wc__node_was_moved_here(&moved_from_abspath, NULL,
1353                                               wc_ctx, local_abspath,
1354                                               scratch_pool, scratch_pool));
1355           if (moved_from_abspath)
1356             reason = svn_wc_conflict_reason_moved_here;
1357         }
1358
1359       SVN_ERR(make_conflict_versions(&left, &right, local_abspath, node_kind,
1360                                      &merge_b->merge_source, merge_b->target,
1361                                      result_pool, scratch_pool));
1362
1363       /* Fix up delete of file, add of dir replacement (or other way around) */
1364       if (existing_conflict != NULL && existing_conflict->src_left_version)
1365           left = existing_conflict->src_left_version;
1366
1367       conflict = svn_wc_conflict_description_create_tree2(
1368                         local_abspath, node_kind, svn_wc_operation_merge,
1369                         left, right, result_pool);
1370
1371       conflict->action = action;
1372       conflict->reason = reason;
1373
1374       /* May return SVN_ERR_WC_PATH_UNEXPECTED_STATUS */
1375       if (existing_conflict)
1376         SVN_ERR(svn_wc__del_tree_conflict(wc_ctx, local_abspath,
1377                                           scratch_pool));
1378
1379       SVN_ERR(svn_wc__add_tree_conflict(merge_b->ctx->wc_ctx, conflict,
1380                                         scratch_pool));
1381
1382       if (parent_baton)
1383         {
1384           if (! parent_baton->new_tree_conflicts)
1385             parent_baton->new_tree_conflicts = apr_hash_make(result_pool);
1386
1387           svn_hash_sets(parent_baton->new_tree_conflicts,
1388                         apr_pstrdup(result_pool, local_abspath),
1389                         conflict);
1390         }
1391
1392       /* ### TODO: Store in parent baton */
1393     }
1394
1395   /* On a replacement we currently get two tree conflicts */
1396   if (merge_b->ctx->notify_func2 && notify_tc)
1397     {
1398       svn_wc_notify_t *notify;
1399
1400       SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1401
1402       notify = svn_wc_create_notify(local_abspath, svn_wc_notify_tree_conflict,
1403                                     scratch_pool);
1404       notify->kind = node_kind;
1405
1406       (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify,
1407                                     scratch_pool);
1408     }
1409
1410   return SVN_NO_ERROR;
1411 }
1412
1413 /* Record the add for future processing and produce the
1414    update_add notification
1415  */
1416 static svn_error_t *
1417 record_update_add(merge_cmd_baton_t *merge_b,
1418                   const char *local_abspath,
1419                   svn_node_kind_t kind,
1420                   svn_boolean_t notify_replaced,
1421                   apr_pool_t *scratch_pool)
1422 {
1423   if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
1424     {
1425       store_path(merge_b->merged_abspaths, local_abspath);
1426     }
1427
1428   if (merge_b->ctx->notify_func2)
1429     {
1430       svn_wc_notify_t *notify;
1431       svn_wc_notify_action_t action = svn_wc_notify_update_add;
1432
1433       SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1434
1435       if (notify_replaced)
1436         action = svn_wc_notify_update_replace;
1437
1438       notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
1439       notify->kind = kind;
1440
1441       (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify,
1442                                     scratch_pool);
1443     }
1444
1445   return SVN_NO_ERROR;
1446 }
1447
1448 /* Record the update for future processing and produce the
1449    update_update notification */
1450 static svn_error_t *
1451 record_update_update(merge_cmd_baton_t *merge_b,
1452                      const char *local_abspath,
1453                      svn_node_kind_t kind,
1454                      svn_wc_notify_state_t content_state,
1455                      svn_wc_notify_state_t prop_state,
1456                      apr_pool_t *scratch_pool)
1457 {
1458   if (merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
1459     {
1460       store_path(merge_b->merged_abspaths, local_abspath);
1461     }
1462
1463   if (merge_b->ctx->notify_func2)
1464     {
1465       svn_wc_notify_t *notify;
1466
1467       SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
1468
1469       notify = svn_wc_create_notify(local_abspath, svn_wc_notify_update_update,
1470                                     scratch_pool);
1471       notify->kind = kind;
1472       notify->content_state = content_state;
1473       notify->prop_state = prop_state;
1474
1475       (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify,
1476                                     scratch_pool);
1477     }
1478
1479   return SVN_NO_ERROR;
1480 }
1481
1482 /* Record the delete for future processing and for (later) producing the
1483    update_delete notification */
1484 static svn_error_t *
1485 record_update_delete(merge_cmd_baton_t *merge_b,
1486                      struct merge_dir_baton_t *parent_db,
1487                      const char *local_abspath,
1488                      svn_node_kind_t kind,
1489                      apr_pool_t *scratch_pool)
1490 {
1491   /* Update the lists of merged, skipped, tree-conflicted and added paths. */
1492   if (merge_b->merge_source.ancestral
1493       || merge_b->reintegrate_merge)
1494     {
1495       /* Issue #4166: If a previous merge added NOTIFY_ABSPATH, but we
1496          are now deleting it, then remove it from the list of added
1497          paths. */
1498       svn_hash_sets(merge_b->added_abspaths, local_abspath, NULL);
1499       store_path(merge_b->merged_abspaths, local_abspath);
1500     }
1501
1502   SVN_ERR(notify_merge_begin(merge_b, local_abspath, TRUE, scratch_pool));
1503
1504   if (parent_db)
1505     {
1506       const char *dup_abspath = apr_pstrdup(parent_db->pool, local_abspath);
1507
1508       if (!parent_db->pending_deletes)
1509         parent_db->pending_deletes = apr_hash_make(parent_db->pool);
1510
1511       svn_hash_sets(parent_db->pending_deletes, dup_abspath,
1512                     svn_node_kind_to_word(kind));
1513     }
1514
1515   return SVN_NO_ERROR;
1516 }
1517
1518 /* Notify the pending 'D'eletes, that were waiting to see if a matching 'A'dd
1519    might make them a 'R'eplace. */
1520 static svn_error_t *
1521 handle_pending_notifications(merge_cmd_baton_t *merge_b,
1522                              struct merge_dir_baton_t *db,
1523                              apr_pool_t *scratch_pool)
1524 {
1525   if (merge_b->ctx->notify_func2 && db->pending_deletes)
1526     {
1527       apr_hash_index_t *hi;
1528
1529       for (hi = apr_hash_first(scratch_pool, db->pending_deletes);
1530            hi;
1531            hi = apr_hash_next(hi))
1532         {
1533           const char *del_abspath = svn__apr_hash_index_key(hi);
1534           svn_wc_notify_t *notify;
1535
1536           notify = svn_wc_create_notify(del_abspath,
1537                                         svn_wc_notify_update_delete,
1538                                         scratch_pool);
1539           notify->kind = svn_node_kind_from_word(
1540                                     svn__apr_hash_index_val(hi));
1541
1542           (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2,
1543                                         notify, scratch_pool);
1544         }
1545
1546       db->pending_deletes = NULL;
1547     }
1548   return SVN_NO_ERROR;
1549 }
1550
1551 /* Helper function for the merge_dir_*() and merge_file_*() functions.
1552
1553    Installs and notifies pre-recorded tree conflicts and skips for
1554    ancestors of operational merges
1555  */
1556 static svn_error_t *
1557 mark_dir_edited(merge_cmd_baton_t *merge_b,
1558                 struct merge_dir_baton_t *db,
1559                 const char *local_abspath,
1560                 apr_pool_t *scratch_pool)
1561 {
1562   /* ### Too much common code with mark_file_edited */
1563   if (db->edited)
1564     return SVN_NO_ERROR;
1565
1566   if (db->parent_baton && !db->parent_baton->edited)
1567     {
1568       const char *dir_abspath = svn_dirent_dirname(local_abspath,
1569                                                    scratch_pool);
1570
1571       SVN_ERR(mark_dir_edited(merge_b, db->parent_baton, dir_abspath,
1572                               scratch_pool));
1573     }
1574
1575   db->edited = TRUE;
1576
1577   if (! db->shadowed)
1578     return SVN_NO_ERROR; /* Easy out */
1579
1580   if (db->parent_baton
1581       && db->parent_baton->delete_state
1582       && db->tree_conflict_reason != CONFLICT_REASON_NONE)
1583     {
1584       db->parent_baton->delete_state->found_edit = TRUE;
1585     }
1586   else if (db->tree_conflict_reason == CONFLICT_REASON_SKIP
1587            || db->tree_conflict_reason == CONFLICT_REASON_SKIP_WC)
1588     {
1589       /* open_directory() decided not to flag a tree conflict, but
1590          for clarity we produce a skip for this node that
1591          most likely isn't touched by the merge itself */
1592
1593       if (merge_b->ctx->notify_func2)
1594         {
1595           svn_wc_notify_t *notify;
1596
1597           SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
1598                                      scratch_pool));
1599
1600           notify = svn_wc_create_notify(
1601                             local_abspath,
1602                             (db->tree_conflict_reason == CONFLICT_REASON_SKIP)
1603                                 ? svn_wc_notify_skip
1604                                 : svn_wc_notify_update_skip_obstruction,
1605                             scratch_pool);
1606           notify->kind = svn_node_dir;
1607           notify->content_state = notify->prop_state = db->skip_reason;
1608
1609           (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2,
1610                                         notify,
1611                                         scratch_pool);
1612         }
1613
1614       if (merge_b->merge_source.ancestral
1615           || merge_b->reintegrate_merge)
1616         {
1617           store_path(merge_b->skipped_abspaths, local_abspath);
1618         }
1619     }
1620   else if (db->tree_conflict_reason != CONFLICT_REASON_NONE)
1621     {
1622       /* open_directory() decided that a tree conflict should be raised */
1623
1624       SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton,
1625                                    svn_node_dir, db->tree_conflict_action,
1626                                    db->tree_conflict_reason,
1627                                    NULL, TRUE,
1628                                    scratch_pool));
1629     }
1630
1631   return SVN_NO_ERROR;
1632 }
1633
1634 /* Helper function for the merge_file_*() functions.
1635
1636    Installs and notifies pre-recorded tree conflicts and skips for
1637    ancestors of operational merges
1638  */
1639 static svn_error_t *
1640 mark_file_edited(merge_cmd_baton_t *merge_b,
1641                  struct merge_file_baton_t *fb,
1642                  const char *local_abspath,
1643                  apr_pool_t *scratch_pool)
1644 {
1645   /* ### Too much common code with mark_dir_edited */
1646   if (fb->edited)
1647     return SVN_NO_ERROR;
1648
1649   if (fb->parent_baton && !fb->parent_baton->edited)
1650     {
1651       const char *dir_abspath = svn_dirent_dirname(local_abspath,
1652                                                    scratch_pool);
1653
1654       SVN_ERR(mark_dir_edited(merge_b, fb->parent_baton, dir_abspath,
1655                               scratch_pool));
1656     }
1657
1658   fb->edited = TRUE;
1659
1660   if (! fb->shadowed)
1661     return SVN_NO_ERROR; /* Easy out */
1662
1663   if (fb->parent_baton
1664       && fb->parent_baton->delete_state
1665       && fb->tree_conflict_reason != CONFLICT_REASON_NONE)
1666     {
1667       fb->parent_baton->delete_state->found_edit = TRUE;
1668     }
1669   else if (fb->tree_conflict_reason == CONFLICT_REASON_SKIP
1670            || fb->tree_conflict_reason == CONFLICT_REASON_SKIP_WC)
1671     {
1672       /* open_directory() decided not to flag a tree conflict, but
1673          for clarity we produce a skip for this node that
1674          most likely isn't touched by the merge itself */
1675
1676       if (merge_b->ctx->notify_func2)
1677         {
1678           svn_wc_notify_t *notify;
1679
1680           SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
1681                                      scratch_pool));
1682
1683           notify = svn_wc_create_notify(local_abspath, svn_wc_notify_skip,
1684                                         scratch_pool);
1685           notify->kind = svn_node_file;
1686           notify->content_state = notify->prop_state = fb->skip_reason;
1687
1688           (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2,
1689                                         notify,
1690                                         scratch_pool);
1691         }
1692
1693       if (merge_b->merge_source.ancestral
1694           || merge_b->reintegrate_merge)
1695         {
1696           store_path(merge_b->skipped_abspaths, local_abspath);
1697         }
1698     }
1699   else if (fb->tree_conflict_reason != CONFLICT_REASON_NONE)
1700     {
1701       /* open_file() decided that a tree conflict should be raised */
1702
1703       SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton,
1704                                    svn_node_file, fb->tree_conflict_action,
1705                                    fb->tree_conflict_reason,
1706                                    NULL, TRUE,
1707                                    scratch_pool));
1708     }
1709
1710   return SVN_NO_ERROR;
1711 }
1712
1713 /* An svn_diff_tree_processor_t function.
1714
1715    Called before either merge_file_changed(), merge_file_added(),
1716    merge_file_deleted() or merge_file_closed(), unless it sets *SKIP to TRUE.
1717
1718    When *SKIP is TRUE, the diff driver avoids work on getting the details
1719    for the closing callbacks.
1720  */
1721 static svn_error_t *
1722 merge_file_opened(void **new_file_baton,
1723                   svn_boolean_t *skip,
1724                   const char *relpath,
1725                   const svn_diff_source_t *left_source,
1726                   const svn_diff_source_t *right_source,
1727                   const svn_diff_source_t *copyfrom_source,
1728                   void *dir_baton,
1729                   const struct svn_diff_tree_processor_t *processor,
1730                   apr_pool_t *result_pool,
1731                   apr_pool_t *scratch_pool)
1732 {
1733   merge_cmd_baton_t *merge_b = processor->baton;
1734   struct merge_dir_baton_t *pdb = dir_baton;
1735   struct merge_file_baton_t *fb;
1736   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
1737                                               relpath, scratch_pool);
1738
1739   fb = apr_pcalloc(result_pool, sizeof(*fb));
1740   fb->tree_conflict_reason = CONFLICT_REASON_NONE;
1741   fb->tree_conflict_action = svn_wc_conflict_action_edit;
1742   fb->skip_reason = svn_wc_notify_state_unknown;
1743
1744   *new_file_baton = fb;
1745
1746   if (pdb)
1747     {
1748       fb->parent_baton = pdb;
1749       fb->shadowed = pdb->shadowed;
1750       fb->skip_reason = pdb->skip_reason;
1751     }
1752
1753   if (fb->shadowed)
1754     {
1755       /* An ancestor is tree conflicted. Nothing to do here. */
1756     }
1757   else if (left_source != NULL)
1758     {
1759       /* Node is expected to be a file, which will be changed or deleted. */
1760       svn_node_kind_t kind;
1761       svn_boolean_t is_deleted;
1762       svn_boolean_t excluded;
1763       svn_depth_t parent_depth;
1764
1765       if (! right_source)
1766         fb->tree_conflict_action = svn_wc_conflict_action_delete;
1767
1768       {
1769         svn_wc_notify_state_t obstr_state;
1770
1771         SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded,
1772                                           &kind, &parent_depth,
1773                                           merge_b, local_abspath,
1774                                           scratch_pool));
1775
1776         if (obstr_state != svn_wc_notify_state_inapplicable)
1777           {
1778             fb->shadowed = TRUE;
1779             fb->tree_conflict_reason = CONFLICT_REASON_SKIP;
1780             fb->skip_reason = obstr_state;
1781             return SVN_NO_ERROR;
1782           }
1783
1784         if (is_deleted)
1785           kind = svn_node_none;
1786       }
1787
1788       if (kind == svn_node_none)
1789         {
1790           fb->shadowed = TRUE;
1791
1792           /* If this is not the merge target and the parent is too shallow to
1793              contain this directory, and the directory is not present
1794              via exclusion or depth filtering, skip it instead of recording
1795              a tree conflict.
1796
1797              Non-inheritable mergeinfo will be recorded, allowing
1798              future merges into non-shallow working copies to merge
1799              changes we missed this time around. */
1800           if (pdb && (excluded
1801                       || (parent_depth != svn_depth_unknown &&
1802                           parent_depth < svn_depth_files)))
1803             {
1804                 fb->shadowed = TRUE;
1805
1806                 fb->tree_conflict_reason = CONFLICT_REASON_SKIP;
1807                 fb->skip_reason = svn_wc_notify_state_missing;
1808                 return SVN_NO_ERROR;
1809             }
1810
1811           if (is_deleted)
1812             fb->tree_conflict_reason = svn_wc_conflict_reason_deleted;
1813           else
1814             fb->tree_conflict_reason = svn_wc_conflict_reason_missing;
1815
1816           /* ### Similar to directory */
1817           *skip = TRUE;
1818           SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1819           return SVN_NO_ERROR;
1820           /* ### /Similar */
1821         }
1822       else if (kind != svn_node_file)
1823         {
1824           fb->shadowed = TRUE;
1825
1826           fb->tree_conflict_reason = svn_wc_conflict_reason_obstructed;
1827
1828           /* ### Similar to directory */
1829           *skip = TRUE;
1830           SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1831           return SVN_NO_ERROR;
1832           /* ### /Similar */
1833         }
1834
1835       if (! right_source)
1836         {
1837           /* We want to delete the directory */
1838           fb->tree_conflict_action = svn_wc_conflict_action_delete;
1839           SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1840
1841           if (fb->shadowed)
1842             {
1843               return SVN_NO_ERROR; /* Already set a tree conflict */
1844             }
1845
1846           /* Comparison mode to verify for delete tree conflicts? */
1847           if (pdb && pdb->delete_state
1848               && pdb->delete_state->found_edit)
1849             {
1850               /* Earlier nodes found a conflict. Done. */
1851               *skip = TRUE;
1852             }
1853         }
1854     }
1855   else
1856     {
1857       const svn_wc_conflict_description2_t *old_tc = NULL;
1858
1859       /* The node doesn't exist pre-merge: We have an addition */
1860       fb->added = TRUE;
1861       fb->tree_conflict_action = svn_wc_conflict_action_add;
1862
1863       if (pdb && pdb->pending_deletes
1864           && svn_hash_gets(pdb->pending_deletes, local_abspath))
1865         {
1866           fb->add_is_replace = TRUE;
1867           fb->tree_conflict_action = svn_wc_conflict_action_replace;
1868
1869           svn_hash_sets(pdb->pending_deletes, local_abspath, NULL);
1870         }
1871
1872       if (pdb
1873           && pdb->new_tree_conflicts
1874           && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath)))
1875         {
1876           fb->tree_conflict_action = svn_wc_conflict_action_replace;
1877           fb->tree_conflict_reason = old_tc->reason;
1878
1879           /* Update the tree conflict to store that this is a replace */
1880           SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb,
1881                                        svn_node_file,
1882                                        fb->tree_conflict_action,
1883                                        fb->tree_conflict_reason,
1884                                        old_tc, FALSE,
1885                                        scratch_pool));
1886
1887           if (old_tc->reason == svn_wc_conflict_reason_deleted
1888               || old_tc->reason == svn_wc_conflict_reason_moved_away)
1889             {
1890               /* Issue #3806: Incoming replacements on local deletes produce
1891                  inconsistent result.
1892
1893                  In this specific case we can continue applying the add part
1894                  of the replacement. */
1895             }
1896           else
1897             {
1898               *skip = TRUE;
1899
1900               return SVN_NO_ERROR;
1901             }
1902         }
1903       else if (! (merge_b->dry_run
1904                   && ((pdb && pdb->added) || fb->add_is_replace)))
1905         {
1906           svn_wc_notify_state_t obstr_state;
1907           svn_node_kind_t kind;
1908           svn_boolean_t is_deleted;
1909
1910           SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL,
1911                                             &kind, NULL,
1912                                             merge_b, local_abspath,
1913                                             scratch_pool));
1914
1915           if (obstr_state != svn_wc_notify_state_inapplicable)
1916             {
1917               /* Skip the obstruction */
1918               fb->shadowed = TRUE;
1919               fb->tree_conflict_reason = CONFLICT_REASON_SKIP;
1920               fb->skip_reason = obstr_state;
1921             }
1922           else if (kind != svn_node_none && !is_deleted)
1923             {
1924               /* Set a tree conflict */
1925               fb->shadowed = TRUE;
1926               fb->tree_conflict_reason = svn_wc_conflict_reason_obstructed;
1927             }
1928         }
1929
1930       /* Handle pending conflicts */
1931       SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1932     }
1933
1934   return SVN_NO_ERROR;
1935 }
1936
1937 /* An svn_diff_tree_processor_t function.
1938  *
1939  * Called after merge_file_opened() when a node receives only text and/or
1940  * property changes between LEFT_SOURCE and RIGHT_SOURCE.
1941  *
1942  * left_file and right_file can be NULL when the file is not modified.
1943  * left_props and right_props are always available.
1944  */
1945 static svn_error_t *
1946 merge_file_changed(const char *relpath,
1947                   const svn_diff_source_t *left_source,
1948                   const svn_diff_source_t *right_source,
1949                   const char *left_file,
1950                   const char *right_file,
1951                   /*const*/ apr_hash_t *left_props,
1952                   /*const*/ apr_hash_t *right_props,
1953                   svn_boolean_t file_modified,
1954                   const apr_array_header_t *prop_changes,
1955                   void *file_baton,
1956                   const struct svn_diff_tree_processor_t *processor,
1957                   apr_pool_t *scratch_pool)
1958 {
1959   merge_cmd_baton_t *merge_b = processor->baton;
1960   struct merge_file_baton_t *fb = file_baton;
1961   svn_client_ctx_t *ctx = merge_b->ctx;
1962   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
1963                                               relpath, scratch_pool);
1964   const svn_wc_conflict_version_t *left;
1965   const svn_wc_conflict_version_t *right;
1966   svn_wc_notify_state_t text_state;
1967   svn_wc_notify_state_t property_state;
1968
1969   SVN_ERR_ASSERT(local_abspath && svn_dirent_is_absolute(local_abspath));
1970   SVN_ERR_ASSERT(!left_file || svn_dirent_is_absolute(left_file));
1971   SVN_ERR_ASSERT(!right_file || svn_dirent_is_absolute(right_file));
1972
1973   SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
1974
1975   if (fb->shadowed)
1976     {
1977       if (fb->tree_conflict_reason == CONFLICT_REASON_NONE)
1978         {
1979           /* We haven't notified for this node yet: report a skip */
1980           SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
1981                               svn_wc_notify_update_shadowed_update,
1982                               fb->skip_reason, scratch_pool));
1983         }
1984
1985       return SVN_NO_ERROR;
1986     }
1987
1988   /* This callback is essentially no more than a wrapper around
1989      svn_wc_merge5().  Thank goodness that all the
1990      diff-editor-mechanisms are doing the hard work of getting the
1991      fulltexts! */
1992
1993   property_state = svn_wc_notify_state_unchanged;
1994   text_state = svn_wc_notify_state_unchanged;
1995
1996   SVN_ERR(prepare_merge_props_changed(&prop_changes, local_abspath,
1997                                       prop_changes, merge_b,
1998                                       scratch_pool, scratch_pool));
1999
2000   SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
2001                                  svn_node_file, &merge_b->merge_source, merge_b->target,
2002                                  scratch_pool, scratch_pool));
2003
2004   /* Do property merge now, if we are not going to perform a text merge */
2005   if ((merge_b->record_only || !left_file) && prop_changes->nelts)
2006     {
2007       SVN_ERR(svn_wc_merge_props3(&property_state, ctx->wc_ctx, local_abspath,
2008                                   left, right,
2009                                   left_props, prop_changes,
2010                                   merge_b->dry_run,
2011                                   NULL, NULL,
2012                                   ctx->cancel_func, ctx->cancel_baton,
2013                                   scratch_pool));
2014       if (property_state == svn_wc_notify_state_conflicted)
2015         {
2016           alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
2017                                merge_b->pool);
2018         }
2019     }
2020
2021   /* Easy out: We are only applying mergeinfo differences. */
2022   if (merge_b->record_only)
2023     {
2024       /* NO-OP */
2025     }
2026   else if (left_file)
2027     {
2028       svn_boolean_t has_local_mods;
2029       enum svn_wc_merge_outcome_t content_outcome;
2030       const char *target_label;
2031       const char *left_label;
2032       const char *right_label;
2033       const char *path_ext = "";
2034
2035       if (merge_b->ext_patterns && merge_b->ext_patterns->nelts)
2036         {
2037           svn_path_splitext(NULL, &path_ext, local_abspath, scratch_pool);
2038           if (! (*path_ext
2039                  && svn_cstring_match_glob_list(path_ext,
2040                                                 merge_b->ext_patterns)))
2041             {
2042               path_ext = "";
2043             }
2044         }
2045
2046       /* xgettext: the '.working', '.merge-left.r%ld' and
2047          '.merge-right.r%ld' strings are used to tag onto a file
2048          name in case of a merge conflict */
2049
2050       target_label = apr_psprintf(scratch_pool, _(".working%s%s"),
2051                                   *path_ext ? "." : "", path_ext);
2052       left_label = apr_psprintf(scratch_pool,
2053                                 _(".merge-left.r%ld%s%s"),
2054                                 left_source->revision,
2055                                 *path_ext ? "." : "", path_ext);
2056       right_label = apr_psprintf(scratch_pool,
2057                                  _(".merge-right.r%ld%s%s"),
2058                                  right_source->revision,
2059                                  *path_ext ? "." : "", path_ext);
2060
2061       SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx,
2062                                       local_abspath, FALSE, scratch_pool));
2063
2064       /* Do property merge and text merge in one step so that keyword expansion
2065          takes into account the new property values. */
2066       SVN_ERR(svn_wc_merge5(&content_outcome, &property_state, ctx->wc_ctx,
2067                             left_file, right_file, local_abspath,
2068                             left_label, right_label, target_label,
2069                             left, right,
2070                             merge_b->dry_run, merge_b->diff3_cmd,
2071                             merge_b->merge_options,
2072                             left_props, prop_changes,
2073                             NULL, NULL,
2074                             ctx->cancel_func,
2075                             ctx->cancel_baton,
2076                             scratch_pool));
2077
2078       if (content_outcome == svn_wc_merge_conflict
2079           || property_state == svn_wc_notify_state_conflicted)
2080         {
2081           alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
2082                                merge_b->pool);
2083         }
2084
2085       if (content_outcome == svn_wc_merge_conflict)
2086         text_state = svn_wc_notify_state_conflicted;
2087       else if (has_local_mods
2088                && content_outcome != svn_wc_merge_unchanged)
2089         text_state = svn_wc_notify_state_merged;
2090       else if (content_outcome == svn_wc_merge_merged)
2091         text_state = svn_wc_notify_state_changed;
2092       else if (content_outcome == svn_wc_merge_no_merge)
2093         text_state = svn_wc_notify_state_missing;
2094       else /* merge_outcome == svn_wc_merge_unchanged */
2095         text_state = svn_wc_notify_state_unchanged;
2096     }
2097
2098   if (text_state == svn_wc_notify_state_conflicted
2099       || text_state == svn_wc_notify_state_merged
2100       || text_state == svn_wc_notify_state_changed
2101       || property_state == svn_wc_notify_state_conflicted
2102       || property_state == svn_wc_notify_state_merged
2103       || property_state == svn_wc_notify_state_changed)
2104     {
2105       SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file,
2106                                    text_state, property_state,
2107                                    scratch_pool));
2108     }
2109
2110   return SVN_NO_ERROR;
2111 }
2112
2113 /* An svn_diff_tree_processor_t function.
2114  *
2115  * Called after merge_file_opened() when a node doesn't exist in LEFT_SOURCE,
2116  * but does in RIGHT_SOURCE.
2117  *
2118  * When a node is replaced instead of just added a separate opened+deleted will
2119  * be invoked before the current open+added.
2120  */
2121 static svn_error_t *
2122 merge_file_added(const char *relpath,
2123                  const svn_diff_source_t *copyfrom_source,
2124                  const svn_diff_source_t *right_source,
2125                  const char *copyfrom_file,
2126                  const char *right_file,
2127                  /*const*/ apr_hash_t *copyfrom_props,
2128                  /*const*/ apr_hash_t *right_props,
2129                  void *file_baton,
2130                  const struct svn_diff_tree_processor_t *processor,
2131                  apr_pool_t *scratch_pool)
2132 {
2133   merge_cmd_baton_t *merge_b = processor->baton;
2134   struct merge_file_baton_t *fb = file_baton;
2135   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2136                                               relpath, scratch_pool);
2137   apr_hash_t *pristine_props;
2138   apr_hash_t *new_props;
2139
2140   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
2141
2142   SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
2143
2144   if (fb->shadowed)
2145     {
2146       if (fb->tree_conflict_reason == CONFLICT_REASON_NONE)
2147         {
2148           /* We haven't notified for this node yet: report a skip */
2149           SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
2150                               svn_wc_notify_update_shadowed_add,
2151                               fb->skip_reason, scratch_pool));
2152         }
2153
2154       return SVN_NO_ERROR;
2155     }
2156
2157   /* Easy out: We are only applying mergeinfo differences. */
2158   if (merge_b->record_only)
2159     {
2160       return SVN_NO_ERROR;
2161     }
2162
2163   if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
2164       && ( !fb->parent_baton || !fb->parent_baton->added))
2165     {
2166       /* Store the roots of added subtrees */
2167       store_path(merge_b->added_abspaths, local_abspath);
2168     }
2169
2170   if (!merge_b->dry_run)
2171     {
2172       const char *copyfrom_url;
2173       svn_revnum_t copyfrom_rev;
2174       svn_stream_t *new_contents, *pristine_contents;
2175
2176       /* If this is a merge from the same repository as our
2177          working copy, we handle adds as add-with-history.
2178          Otherwise, we'll use a pure add. */
2179       if (merge_b->same_repos)
2180         {
2181           const char *child =
2182             svn_dirent_skip_ancestor(merge_b->target->abspath,
2183                                      local_abspath);
2184           SVN_ERR_ASSERT(child != NULL);
2185           copyfrom_url = svn_path_url_add_component2(
2186                                        merge_b->merge_source.loc2->url,
2187                                        child, scratch_pool);
2188           copyfrom_rev = right_source->revision;
2189           SVN_ERR(check_repos_match(merge_b->target, local_abspath,
2190                                     copyfrom_url, scratch_pool));
2191           SVN_ERR(svn_stream_open_readonly(&pristine_contents,
2192                                            right_file,
2193                                            scratch_pool,
2194                                            scratch_pool));
2195           new_contents = NULL; /* inherit from new_base_contents */
2196
2197           pristine_props = right_props; /* Includes last_* information */
2198           new_props = NULL; /* No local changes */
2199
2200           if (svn_hash_gets(pristine_props, SVN_PROP_MERGEINFO))
2201             {
2202               alloc_and_store_path(&merge_b->paths_with_new_mergeinfo,
2203                                    local_abspath, merge_b->pool);
2204             }
2205         }
2206       else
2207         {
2208           apr_array_header_t *regular_props;
2209
2210           copyfrom_url = NULL;
2211           copyfrom_rev = SVN_INVALID_REVNUM;
2212
2213           pristine_contents = svn_stream_empty(scratch_pool);
2214           SVN_ERR(svn_stream_open_readonly(&new_contents, right_file,
2215                                            scratch_pool, scratch_pool));
2216
2217           pristine_props = apr_hash_make(scratch_pool); /* Local addition */
2218
2219           /* We don't want any foreign properties */
2220           SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props,
2221                                                               scratch_pool),
2222                                        NULL, NULL, &regular_props,
2223                                        scratch_pool));
2224
2225           new_props = svn_prop_array_to_hash(regular_props, scratch_pool);
2226
2227           /* Issue #3383: We don't want mergeinfo from a foreign repository. */
2228           svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL);
2229         }
2230
2231       /* Do everything like if we had called 'svn cp PATH1 PATH2'. */
2232       SVN_ERR(svn_wc_add_repos_file4(merge_b->ctx->wc_ctx,
2233                                       local_abspath,
2234                                       pristine_contents,
2235                                       new_contents,
2236                                       pristine_props, new_props,
2237                                       copyfrom_url, copyfrom_rev,
2238                                       merge_b->ctx->cancel_func,
2239                                       merge_b->ctx->cancel_baton,
2240                                       scratch_pool));
2241
2242       /* Caller must call svn_sleep_for_timestamps() */
2243       *merge_b->use_sleep = TRUE;
2244     }
2245
2246   SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_file,
2247                             fb->add_is_replace, scratch_pool));
2248
2249   return SVN_NO_ERROR;
2250 }
2251
2252 /* Compare the two sets of properties PROPS1 and PROPS2, ignoring the
2253  * "svn:mergeinfo" property, and noticing only "normal" props. Set *SAME to
2254  * true if the rest of the properties are identical or false if they differ.
2255  */
2256 static svn_error_t *
2257 properties_same_p(svn_boolean_t *same,
2258                   apr_hash_t *props1,
2259                   apr_hash_t *props2,
2260                   apr_pool_t *scratch_pool)
2261 {
2262   apr_array_header_t *prop_changes;
2263   int i, diffs;
2264
2265   /* Examine the properties that differ */
2266   SVN_ERR(svn_prop_diffs(&prop_changes, props1, props2, scratch_pool));
2267   diffs = 0;
2268   for (i = 0; i < prop_changes->nelts; i++)
2269     {
2270       const char *pname = APR_ARRAY_IDX(prop_changes, i, svn_prop_t).name;
2271
2272       /* Count the properties we're interested in; ignore the rest */
2273       if (svn_wc_is_normal_prop(pname)
2274           && strcmp(pname, SVN_PROP_MERGEINFO) != 0)
2275         diffs++;
2276     }
2277   *same = (diffs == 0);
2278   return SVN_NO_ERROR;
2279 }
2280
2281 /* Compare the file OLDER_ABSPATH (together with its normal properties in
2282  * ORIGINAL_PROPS which may also contain WC props and entry props) with the
2283  * versioned file MINE_ABSPATH (together with its versioned properties).
2284  * Set *SAME to true if they are the same or false if they differ, ignoring
2285  * the "svn:mergeinfo" property, and ignoring differences in keyword
2286  * expansion and end-of-line style. */
2287 static svn_error_t *
2288 files_same_p(svn_boolean_t *same,
2289              const char *older_abspath,
2290              apr_hash_t *original_props,
2291              const char *mine_abspath,
2292              svn_wc_context_t *wc_ctx,
2293              apr_pool_t *scratch_pool)
2294 {
2295   apr_hash_t *working_props;
2296
2297   SVN_ERR(svn_wc_prop_list2(&working_props, wc_ctx, mine_abspath,
2298                             scratch_pool, scratch_pool));
2299
2300   /* Compare the properties */
2301   SVN_ERR(properties_same_p(same, original_props, working_props,
2302                             scratch_pool));
2303   if (*same)
2304     {
2305       svn_stream_t *mine_stream;
2306       svn_stream_t *older_stream;
2307       svn_opt_revision_t working_rev = { svn_opt_revision_working, { 0 } };
2308
2309       /* Compare the file content, translating 'mine' to 'normal' form. */
2310       if (svn_prop_get_value(working_props, SVN_PROP_SPECIAL) != NULL)
2311         SVN_ERR(svn_subst_read_specialfile(&mine_stream, mine_abspath,
2312                                            scratch_pool, scratch_pool));
2313       else
2314         SVN_ERR(svn_client__get_normalized_stream(&mine_stream, wc_ctx,
2315                                                   mine_abspath, &working_rev,
2316                                                   FALSE, TRUE, NULL, NULL,
2317                                                   scratch_pool, scratch_pool));
2318
2319       SVN_ERR(svn_stream_open_readonly(&older_stream, older_abspath,
2320                                        scratch_pool, scratch_pool));
2321
2322       SVN_ERR(svn_stream_contents_same2(same, mine_stream, older_stream,
2323                                         scratch_pool));
2324
2325     }
2326
2327   return SVN_NO_ERROR;
2328 }
2329
2330 /* An svn_diff_tree_processor_t function.
2331  *
2332  * Called after merge_file_opened() when a node does exist in LEFT_SOURCE, but
2333  * no longer exists (or is replaced) in RIGHT_SOURCE.
2334  *
2335  * When a node is replaced instead of just added a separate opened+added will
2336  * be invoked after the current open+deleted.
2337  */
2338 static svn_error_t *
2339 merge_file_deleted(const char *relpath,
2340                    const svn_diff_source_t *left_source,
2341                    const char *left_file,
2342                    /*const*/ apr_hash_t *left_props,
2343                    void *file_baton,
2344                    const struct svn_diff_tree_processor_t *processor,
2345                    apr_pool_t *scratch_pool)
2346 {
2347   merge_cmd_baton_t *merge_b = processor->baton;
2348   struct merge_file_baton_t *fb = file_baton;
2349   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2350                                               relpath, scratch_pool);
2351   svn_boolean_t same;
2352
2353   SVN_ERR(mark_file_edited(merge_b, fb, local_abspath, scratch_pool));
2354
2355   if (fb->shadowed)
2356     {
2357       if (fb->tree_conflict_reason == CONFLICT_REASON_NONE)
2358         {
2359           /* We haven't notified for this node yet: report a skip */
2360           SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
2361                               svn_wc_notify_update_shadowed_delete,
2362                               fb->skip_reason, scratch_pool));
2363         }
2364
2365       return SVN_NO_ERROR;
2366     }
2367
2368   /* Easy out: We are only applying mergeinfo differences. */
2369   if (merge_b->record_only)
2370     {
2371       return SVN_NO_ERROR;
2372     }
2373
2374   /* If the files are identical, attempt deletion */
2375   if (merge_b->force_delete)
2376     same = TRUE;
2377   else
2378     SVN_ERR(files_same_p(&same, left_file, left_props,
2379                          local_abspath, merge_b->ctx->wc_ctx,
2380                          scratch_pool));
2381
2382   if (fb->parent_baton
2383       && fb->parent_baton->delete_state)
2384     {
2385       if (same)
2386         {
2387           /* Note that we checked this file */
2388           store_path(fb->parent_baton->delete_state->compared_abspaths,
2389                      local_abspath);
2390         }
2391       else
2392         {
2393           /* We found some modification. Parent should raise a tree conflict */
2394           fb->parent_baton->delete_state->found_edit = TRUE;
2395         }
2396
2397       return SVN_NO_ERROR;
2398     }
2399   else if (same)
2400     {
2401       if (!merge_b->dry_run)
2402         SVN_ERR(svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath,
2403                                FALSE /* keep_local */, FALSE /* unversioned */,
2404                                merge_b->ctx->cancel_func,
2405                                merge_b->ctx->cancel_baton,
2406                                NULL, NULL /* no notify */,
2407                                scratch_pool));
2408
2409       /* Record that we might have deleted mergeinfo */
2410       alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo,
2411                            local_abspath, merge_b->pool);
2412
2413       /* And notify the deletion */
2414       SVN_ERR(record_update_delete(merge_b, fb->parent_baton, local_abspath,
2415                                    svn_node_file, scratch_pool));
2416     }
2417   else
2418     {
2419       /* The files differ, so raise a conflict instead of deleting */
2420
2421       /* This is use case 5 described in the paper attached to issue
2422        * #2282.  See also notes/tree-conflicts/detection.txt
2423        */
2424       SVN_ERR(record_tree_conflict(merge_b, local_abspath, fb->parent_baton,
2425                                    svn_node_file,
2426                                    svn_wc_conflict_action_delete,
2427                                    svn_wc_conflict_reason_edited,
2428                                    NULL, TRUE,
2429                                    scratch_pool));
2430     }
2431
2432   return SVN_NO_ERROR;
2433 }
2434
2435 /* An svn_diff_tree_processor_t function.
2436
2437    Called before either merge_dir_changed(), merge_dir_added(),
2438    merge_dir_deleted() or merge_dir_closed(), unless it sets *SKIP to TRUE.
2439
2440    After this call and before the close call, all descendants will receive
2441    their changes, unless *SKIP_CHILDREN is set to TRUE.
2442
2443    When *SKIP is TRUE, the diff driver avoids work on getting the details
2444    for the closing callbacks.
2445
2446    The SKIP and SKIP_DESCENDANTS work independantly.
2447  */
2448 static svn_error_t *
2449 merge_dir_opened(void **new_dir_baton,
2450                  svn_boolean_t *skip,
2451                  svn_boolean_t *skip_children,
2452                  const char *relpath,
2453                  const svn_diff_source_t *left_source,
2454                  const svn_diff_source_t *right_source,
2455                  const svn_diff_source_t *copyfrom_source,
2456                  void *parent_dir_baton,
2457                  const struct svn_diff_tree_processor_t *processor,
2458                  apr_pool_t *result_pool,
2459                  apr_pool_t *scratch_pool)
2460 {
2461   merge_cmd_baton_t *merge_b = processor->baton;
2462   struct merge_dir_baton_t *db;
2463   struct merge_dir_baton_t *pdb = parent_dir_baton;
2464
2465   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2466                                               relpath, scratch_pool);
2467
2468   db = apr_pcalloc(result_pool, sizeof(*db));
2469   db->pool = result_pool;
2470   db->tree_conflict_reason = CONFLICT_REASON_NONE;
2471   db->tree_conflict_action = svn_wc_conflict_action_edit;
2472   db->skip_reason = svn_wc_notify_state_unknown;
2473
2474   *new_dir_baton = db;
2475
2476   if (pdb)
2477     {
2478       db->parent_baton = pdb;
2479       db->shadowed = pdb->shadowed;
2480       db->skip_reason = pdb->skip_reason;
2481     }
2482
2483   if (db->shadowed)
2484     {
2485       /* An ancestor is tree conflicted. Nothing to do here. */
2486       if (! left_source)
2487         db->added = TRUE;
2488     }
2489   else if (left_source != NULL)
2490     {
2491       /* Node is expected to be a directory. */
2492       svn_node_kind_t kind;
2493       svn_boolean_t is_deleted;
2494       svn_boolean_t excluded;
2495       svn_depth_t parent_depth;
2496
2497       if (! right_source)
2498           db->tree_conflict_action = svn_wc_conflict_action_delete;
2499
2500       /* Check for an obstructed or missing node on disk. */
2501       {
2502         svn_wc_notify_state_t obstr_state;
2503         SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &excluded,
2504                                           &kind, &parent_depth,
2505                                           merge_b, local_abspath,
2506                                           scratch_pool));
2507
2508         if (obstr_state != svn_wc_notify_state_inapplicable)
2509           {
2510             db->shadowed = TRUE;
2511
2512             if (obstr_state == svn_wc_notify_state_obstructed)
2513               {
2514                 svn_boolean_t is_wcroot;
2515
2516                 SVN_ERR(svn_wc_check_root(&is_wcroot, NULL, NULL,
2517                                         merge_b->ctx->wc_ctx,
2518                                         local_abspath, scratch_pool));
2519
2520                 if (is_wcroot)
2521                   {
2522                     db->tree_conflict_reason = CONFLICT_REASON_SKIP_WC;
2523                     return SVN_NO_ERROR;
2524                   }
2525               }
2526
2527             db->tree_conflict_reason = CONFLICT_REASON_SKIP;
2528             db->skip_reason = obstr_state;
2529
2530             if (! right_source)
2531               {
2532                 *skip = *skip_children = TRUE;
2533                 SVN_ERR(mark_dir_edited(merge_b, db, local_abspath,
2534                                         scratch_pool));
2535               }
2536
2537             return SVN_NO_ERROR;
2538           }
2539
2540         if (is_deleted)
2541           kind = svn_node_none;
2542       }
2543
2544       if (kind == svn_node_none)
2545         {
2546           db->shadowed = TRUE;
2547
2548           /* If this is not the merge target and the parent is too shallow to
2549              contain this directory, and the directory is not presen
2550              via exclusion or depth filtering, skip it instead of recording
2551              a tree conflict.
2552
2553              Non-inheritable mergeinfo will be recorded, allowing
2554              future merges into non-shallow working copies to merge
2555              changes we missed this time around. */
2556           if (pdb && (excluded
2557                       || (parent_depth != svn_depth_unknown &&
2558                           parent_depth < svn_depth_immediates)))
2559             {
2560               db->shadowed = TRUE;
2561
2562               db->tree_conflict_reason = CONFLICT_REASON_SKIP;
2563               db->skip_reason = svn_wc_notify_state_missing;
2564
2565               return SVN_NO_ERROR;
2566             }
2567
2568           if (is_deleted)
2569             db->tree_conflict_reason = svn_wc_conflict_reason_deleted;
2570           else
2571             db->tree_conflict_reason = svn_wc_conflict_reason_missing;
2572
2573           /* ### To avoid breaking tests */
2574           *skip = TRUE;
2575           *skip_children = TRUE;
2576           SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2577           return SVN_NO_ERROR;
2578           /* ### /avoid breaking tests */
2579         }
2580       else if (kind != svn_node_dir)
2581         {
2582           db->shadowed = TRUE;
2583
2584           db->tree_conflict_reason = svn_wc_conflict_reason_obstructed;
2585
2586           /* ### To avoid breaking tests */
2587           *skip = TRUE;
2588           *skip_children = TRUE;
2589           SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2590           return SVN_NO_ERROR;
2591           /* ### /avoid breaking tests */
2592         }
2593
2594       if (! right_source)
2595         {
2596           /* We want to delete the directory */
2597           /* Mark PB edited now? */
2598           db->tree_conflict_action = svn_wc_conflict_action_delete;
2599           SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2600
2601           if (db->shadowed)
2602             {
2603               *skip_children = TRUE;
2604               return SVN_NO_ERROR; /* Already set a tree conflict */
2605             }
2606
2607           db->delete_state = (pdb != NULL) ? pdb->delete_state : NULL;
2608
2609           if (db->delete_state && db->delete_state->found_edit)
2610             {
2611               /* A sibling found a conflict. Done. */
2612               *skip = TRUE;
2613               *skip_children = TRUE;
2614             }
2615           else if (merge_b->force_delete)
2616             {
2617               /* No comparison necessary */
2618               *skip_children = TRUE;
2619             }
2620           else if (! db->delete_state)
2621             {
2622               /* Start descendant comparison */
2623               db->delete_state = apr_pcalloc(db->pool,
2624                                              sizeof(*db->delete_state));
2625
2626               db->delete_state->del_root = db;
2627               db->delete_state->compared_abspaths = apr_hash_make(db->pool);
2628             }
2629         }
2630     }
2631   else
2632     {
2633       const svn_wc_conflict_description2_t *old_tc = NULL;
2634
2635       /* The node doesn't exist pre-merge: We have an addition */
2636       db->added = TRUE;
2637       db->tree_conflict_action = svn_wc_conflict_action_add;
2638
2639       if (pdb && pdb->pending_deletes
2640           && svn_hash_gets(pdb->pending_deletes, local_abspath))
2641         {
2642           db->add_is_replace = TRUE;
2643           db->tree_conflict_action = svn_wc_conflict_action_replace;
2644
2645           svn_hash_sets(pdb->pending_deletes, local_abspath, NULL);
2646         }
2647
2648       if (pdb
2649           && pdb->new_tree_conflicts
2650           && (old_tc = svn_hash_gets(pdb->new_tree_conflicts, local_abspath)))
2651         {
2652           db->tree_conflict_action = svn_wc_conflict_action_replace;
2653           db->tree_conflict_reason = old_tc->reason;
2654
2655           if (old_tc->reason == svn_wc_conflict_reason_deleted
2656              || old_tc->reason == svn_wc_conflict_reason_moved_away)
2657             {
2658               /* Issue #3806: Incoming replacements on local deletes produce
2659                  inconsistent result.
2660
2661                  In this specific case we can continue applying the add part
2662                  of the replacement. */
2663             }
2664           else
2665             {
2666               *skip = TRUE;
2667               *skip_children = TRUE;
2668
2669               /* Update the tree conflict to store that this is a replace */
2670               SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb,
2671                                            svn_node_dir,
2672                                            db->tree_conflict_action,
2673                                            db->tree_conflict_reason,
2674                                            old_tc, FALSE,
2675                                            scratch_pool));
2676
2677               return SVN_NO_ERROR;
2678             }
2679         }
2680
2681       if (! (merge_b->dry_run
2682              && ((pdb && pdb->added) || db->add_is_replace)))
2683         {
2684           svn_wc_notify_state_t obstr_state;
2685           svn_node_kind_t kind;
2686           svn_boolean_t is_deleted;
2687
2688           SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, NULL,
2689                                             &kind, NULL,
2690                                             merge_b, local_abspath,
2691                                             scratch_pool));
2692
2693           /* In this case of adding a directory, we have an exception to the
2694            * usual "skip if it's inconsistent" rule. If the directory exists
2695            * on disk unexpectedly, we simply make it versioned, because we can
2696            * do so without risk of destroying data. Only skip if it is
2697            * versioned but unexpectedly missing from disk, or is unversioned
2698            * but obstructed by a node of the wrong kind. */
2699           if (obstr_state == svn_wc_notify_state_obstructed
2700               && (is_deleted || kind == svn_node_none))
2701             {
2702               svn_node_kind_t disk_kind;
2703
2704               SVN_ERR(svn_io_check_path(local_abspath, &disk_kind,
2705                                         scratch_pool));
2706
2707               if (disk_kind == svn_node_dir)
2708                 {
2709                   obstr_state = svn_wc_notify_state_inapplicable;
2710                   db->add_existing = TRUE; /* Take over existing directory */
2711                 }
2712             }
2713
2714           if (obstr_state != svn_wc_notify_state_inapplicable)
2715             {
2716               /* Skip the obstruction */
2717               db->shadowed = TRUE;
2718               db->tree_conflict_reason = CONFLICT_REASON_SKIP;
2719               db->skip_reason = obstr_state;
2720             }
2721           else if (kind != svn_node_none && !is_deleted)
2722             {
2723               /* Set a tree conflict */
2724               db->shadowed = TRUE;
2725               db->tree_conflict_reason = svn_wc_conflict_reason_obstructed;
2726             }
2727         }
2728
2729       /* Handle pending conflicts */
2730       SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2731
2732       if (db->shadowed)
2733         {
2734           /* Notified and done. Skip children? */
2735         }
2736       else if (merge_b->record_only)
2737         {
2738           /* Ok, we are done for this node and its descendants */
2739           *skip = TRUE;
2740           *skip_children = TRUE;
2741         }
2742       else if (! merge_b->dry_run)
2743         {
2744           /* Create the directory on disk, to allow descendants to be added */
2745           if (! db->add_existing)
2746             SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT,
2747                                     scratch_pool));
2748
2749           if (old_tc)
2750             {
2751               /* svn_wc_add4 and svn_wc_add_from_disk2 can't add a node
2752                  over an existing tree conflict */
2753
2754               /* ### These functions should take some tree conflict argument
2755                      and allow overwriting the tc when one is passed */
2756
2757               SVN_ERR(svn_wc__del_tree_conflict(merge_b->ctx->wc_ctx,
2758                                                 local_abspath,
2759                                                 scratch_pool));
2760             }
2761
2762           if (merge_b->same_repos)
2763             {
2764               const char *original_url;
2765
2766               original_url = svn_path_url_add_component2(
2767                                         merge_b->merge_source.loc2->url,
2768                                         relpath, scratch_pool);
2769
2770               /* Limitation (aka HACK):
2771                  We create a newly added directory with an original URL and
2772                  revision as that in the repository, but without its properties
2773                  and children.
2774
2775                  When the merge is cancelled before the final dir_added(), the
2776                  copy won't really represent the in-repository state of the node.
2777                */
2778               SVN_ERR(svn_wc_add4(merge_b->ctx->wc_ctx, local_abspath,
2779                                   svn_depth_infinity,
2780                                   original_url,
2781                                   right_source->revision,
2782                                   merge_b->ctx->cancel_func,
2783                                   merge_b->ctx->cancel_baton,
2784                                   NULL, NULL /* no notify! */,
2785                                   scratch_pool));
2786             }
2787           else
2788             {
2789               SVN_ERR(svn_wc_add_from_disk2(merge_b->ctx->wc_ctx, local_abspath,
2790                                             apr_hash_make(scratch_pool),
2791                                             NULL, NULL /* no notify! */,
2792                                             scratch_pool));
2793             }
2794
2795           if (old_tc != NULL)
2796             {
2797               /* ### Should be atomic with svn_wc_add(4|_from_disk2)() */
2798               SVN_ERR(record_tree_conflict(merge_b, local_abspath, pdb,
2799                                            svn_node_dir,
2800                                            db->tree_conflict_action,
2801                                            db->tree_conflict_reason,
2802                                            old_tc, FALSE,
2803                                            scratch_pool));
2804             }
2805         }
2806
2807       if (! db->shadowed && !merge_b->record_only)
2808         SVN_ERR(record_update_add(merge_b, local_abspath, svn_node_dir,
2809                                   db->add_is_replace, scratch_pool));
2810     }
2811   return SVN_NO_ERROR;
2812 }
2813
2814 /* An svn_diff_tree_processor_t function.
2815  *
2816  * Called after merge_dir_opened() when a node exists in both the left and
2817  * right source, but has its properties changed inbetween.
2818  *
2819  * After the merge_dir_opened() but before the call to this merge_dir_changed()
2820  * function all descendants will have been updated.
2821  */
2822 static svn_error_t *
2823 merge_dir_changed(const char *relpath,
2824                   const svn_diff_source_t *left_source,
2825                   const svn_diff_source_t *right_source,
2826                   /*const*/ apr_hash_t *left_props,
2827                   /*const*/ apr_hash_t *right_props,
2828                   const apr_array_header_t *prop_changes,
2829                   void *dir_baton,
2830                   const struct svn_diff_tree_processor_t *processor,
2831                   apr_pool_t *scratch_pool)
2832 {
2833   merge_cmd_baton_t *merge_b = processor->baton;
2834   struct merge_dir_baton_t *db = dir_baton;
2835   const apr_array_header_t *props;
2836   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2837                                               relpath, scratch_pool);
2838
2839   SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
2840
2841   SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2842
2843   if (db->shadowed)
2844     {
2845       if (db->tree_conflict_reason == CONFLICT_REASON_NONE)
2846         {
2847           /* We haven't notified for this node yet: report a skip */
2848           SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
2849                               svn_wc_notify_update_shadowed_update,
2850                               db->skip_reason, scratch_pool));
2851         }
2852
2853       return SVN_NO_ERROR;
2854     }
2855
2856   SVN_ERR(prepare_merge_props_changed(&props, local_abspath, prop_changes,
2857                                       merge_b, scratch_pool, scratch_pool));
2858
2859   if (props->nelts)
2860     {
2861       const svn_wc_conflict_version_t *left;
2862       const svn_wc_conflict_version_t *right;
2863       svn_client_ctx_t *ctx = merge_b->ctx;
2864       svn_wc_notify_state_t prop_state;
2865
2866       SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
2867                                      svn_node_dir, &merge_b->merge_source,
2868                                      merge_b->target,
2869                                      scratch_pool, scratch_pool));
2870
2871       SVN_ERR(svn_wc_merge_props3(&prop_state, ctx->wc_ctx, local_abspath,
2872                                   left, right,
2873                                   left_props, props,
2874                                   merge_b->dry_run,
2875                                   NULL, NULL,
2876                                   ctx->cancel_func, ctx->cancel_baton,
2877                                   scratch_pool));
2878
2879       if (prop_state == svn_wc_notify_state_conflicted)
2880         {
2881           alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
2882                                merge_b->pool);
2883         }
2884
2885       if (prop_state == svn_wc_notify_state_conflicted
2886           || prop_state == svn_wc_notify_state_merged
2887           || prop_state == svn_wc_notify_state_changed)
2888         {
2889           SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file,
2890                                        svn_wc_notify_state_inapplicable,
2891                                        prop_state, scratch_pool));
2892         }
2893     }
2894
2895   return SVN_NO_ERROR;
2896 }
2897
2898
2899 /* An svn_diff_tree_processor_t function.
2900  *
2901  * Called after merge_dir_opened() when a node doesn't exist in LEFT_SOURCE,
2902  * but does in RIGHT_SOURCE. After the merge_dir_opened() but before the call
2903  * to this merge_dir_added() function all descendants will have been added.
2904  *
2905  * When a node is replaced instead of just added a separate opened+deleted will
2906  * be invoked before the current open+added.
2907  */
2908 static svn_error_t *
2909 merge_dir_added(const char *relpath,
2910                 const svn_diff_source_t *copyfrom_source,
2911                 const svn_diff_source_t *right_source,
2912                 /*const*/ apr_hash_t *copyfrom_props,
2913                 /*const*/ apr_hash_t *right_props,
2914                 void *dir_baton,
2915                 const struct svn_diff_tree_processor_t *processor,
2916                 apr_pool_t *scratch_pool)
2917 {
2918   merge_cmd_baton_t *merge_b = processor->baton;
2919   struct merge_dir_baton_t *db = dir_baton;
2920   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
2921                                               relpath, scratch_pool);
2922
2923   /* For consistency; usually a no-op from _dir_added() */
2924   SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
2925   SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
2926
2927   if (db->shadowed)
2928     {
2929       if (db->tree_conflict_reason == CONFLICT_REASON_NONE)
2930         {
2931           /* We haven't notified for this node yet: report a skip */
2932           SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
2933                               svn_wc_notify_update_shadowed_add,
2934                               db->skip_reason, scratch_pool));
2935         }
2936
2937       return SVN_NO_ERROR;
2938     }
2939
2940   SVN_ERR_ASSERT(
2941                  db->edited                  /* Marked edited from merge_open_dir() */
2942                  && ! merge_b->record_only /* Skip details from merge_open_dir() */
2943                  );
2944
2945   if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
2946       && ( !db->parent_baton || !db->parent_baton->added))
2947     {
2948       /* Store the roots of added subtrees */
2949       store_path(merge_b->added_abspaths, local_abspath);
2950     }
2951
2952   if (merge_b->same_repos)
2953     {
2954       /* When the directory was added in merge_dir_added() we didn't update its
2955          pristine properties. Instead we receive the property changes later and
2956          apply them in this function.
2957
2958          If we would apply them as changes (such as before fixing issue #3405),
2959          we would see the unmodified properties as local changes, and the
2960          pristine properties would be out of sync with what the repository
2961          expects for this directory.
2962
2963          Instead of doing that we now simply set the properties as the pristine
2964          properties via a private libsvn_wc api.
2965       */
2966
2967       const char *copyfrom_url;
2968       svn_revnum_t copyfrom_rev;
2969       const char *parent_abspath;
2970       const char *child;
2971
2972       /* Creating a hash containing regular and entry props */
2973       apr_hash_t *new_pristine_props = right_props;
2974
2975       parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
2976       child = svn_dirent_is_child(merge_b->target->abspath, local_abspath, NULL);
2977       SVN_ERR_ASSERT(child != NULL);
2978
2979       copyfrom_url = svn_path_url_add_component2(merge_b->merge_source.loc2->url,
2980                                                  child, scratch_pool);
2981       copyfrom_rev = right_source->revision;
2982
2983       SVN_ERR(check_repos_match(merge_b->target, parent_abspath, copyfrom_url,
2984                                 scratch_pool));
2985
2986       if (!merge_b->dry_run)
2987         {
2988           SVN_ERR(svn_wc__complete_directory_add(merge_b->ctx->wc_ctx,
2989                                                 local_abspath,
2990                                                 new_pristine_props,
2991                                                 copyfrom_url, copyfrom_rev,
2992                                                 scratch_pool));
2993         }
2994
2995       if (svn_hash_gets(new_pristine_props, SVN_PROP_MERGEINFO))
2996         {
2997           alloc_and_store_path(&merge_b->paths_with_new_mergeinfo,
2998                                local_abspath, merge_b->pool);
2999         }
3000     }
3001   else
3002     {
3003       apr_array_header_t *regular_props;
3004       apr_hash_t *new_props;
3005       svn_wc_notify_state_t prop_state;
3006
3007       SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props,
3008                                                           scratch_pool),
3009                                    NULL, NULL, &regular_props, scratch_pool));
3010
3011       new_props = svn_prop_array_to_hash(regular_props, scratch_pool);
3012
3013       svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL);
3014
3015       /* ### What is the easiest way to set new_props on LOCAL_ABSPATH?
3016
3017          ### This doesn't need a merge as we just added the node
3018          ### (or installed a tree conflict and skipped this node)*/
3019
3020       SVN_ERR(svn_wc_merge_props3(&prop_state, merge_b->ctx->wc_ctx,
3021                                   local_abspath,
3022                                   NULL, NULL,
3023                                   apr_hash_make(scratch_pool),
3024                                   svn_prop_hash_to_array(new_props,
3025                                                          scratch_pool),
3026                                   merge_b->dry_run,
3027                                   NULL, NULL,
3028                                   merge_b->ctx->cancel_func,
3029                                   merge_b->ctx->cancel_baton,
3030                                   scratch_pool));
3031       if (prop_state == svn_wc_notify_state_conflicted)
3032         {
3033           alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
3034                                merge_b->pool);
3035         }
3036     }
3037
3038   return SVN_NO_ERROR;
3039 }
3040
3041 /* Helper for merge_dir_deleted. Implement svn_wc_status_func4_t */
3042 static svn_error_t *
3043 verify_touched_by_del_check(void *baton,
3044                             const char *local_abspath,
3045                             const svn_wc_status3_t *status,
3046                             apr_pool_t *scratch_pool)
3047 {
3048   struct dir_delete_baton_t *delb = baton;
3049
3050   if (svn_hash_gets(delb->compared_abspaths, local_abspath))
3051     return SVN_NO_ERROR;
3052
3053   switch (status->node_status)
3054     {
3055       case svn_wc_status_deleted:
3056       case svn_wc_status_ignored:
3057       case svn_wc_status_none:
3058         return SVN_NO_ERROR;
3059
3060       default:
3061         delb->found_edit = TRUE;
3062         return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
3063     }
3064 }
3065
3066 /* An svn_diff_tree_processor_t function.
3067  *
3068  * Called after merge_dir_opened() when a node existed only in the left source.
3069  *
3070  * After the merge_dir_opened() but before the call to this merge_dir_deleted()
3071  * function all descendants that existed in left_source will have been deleted.
3072  *
3073  * If this node is replaced, an _opened() followed by a matching _add() will
3074  * be invoked after this function.
3075  */
3076 static svn_error_t *
3077 merge_dir_deleted(const char *relpath,
3078                   const svn_diff_source_t *left_source,
3079                   /*const*/ apr_hash_t *left_props,
3080                   void *dir_baton,
3081                   const struct svn_diff_tree_processor_t *processor,
3082                   apr_pool_t *scratch_pool)
3083 {
3084   merge_cmd_baton_t *merge_b = processor->baton;
3085   struct merge_dir_baton_t *db = dir_baton;
3086   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
3087                                               relpath, scratch_pool);
3088   svn_boolean_t same;
3089   apr_hash_t *working_props;
3090
3091   SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
3092   SVN_ERR(mark_dir_edited(merge_b, db, local_abspath, scratch_pool));
3093
3094   if (db->shadowed)
3095     {
3096       if (db->tree_conflict_reason == CONFLICT_REASON_NONE)
3097         {
3098           /* We haven't notified for this node yet: report a skip */
3099           SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
3100                               svn_wc_notify_update_shadowed_delete,
3101                               db->skip_reason, scratch_pool));
3102         }
3103
3104       return SVN_NO_ERROR;
3105     }
3106
3107   /* Easy out: We are only applying mergeinfo differences. */
3108   if (merge_b->record_only)
3109     {
3110       return SVN_NO_ERROR;
3111     }
3112
3113   SVN_ERR(svn_wc_prop_list2(&working_props,
3114                             merge_b->ctx->wc_ctx, local_abspath,
3115                             scratch_pool, scratch_pool));
3116
3117   if (merge_b->force_delete)
3118     {
3119       /* In this legacy mode we just assume that a directory delete
3120          matches any directory. db->delete_state is NULL */
3121       same = TRUE;
3122     }
3123   else
3124     {
3125       struct dir_delete_baton_t *delb;
3126
3127       /* Compare the properties */
3128       SVN_ERR(properties_same_p(&same, left_props, working_props,
3129                                 scratch_pool));
3130       delb = db->delete_state;
3131       assert(delb != NULL);
3132
3133       if (! same)
3134         {
3135           delb->found_edit = TRUE;
3136         }
3137       else
3138         {
3139           store_path(delb->compared_abspaths, local_abspath);
3140         }
3141
3142       if (delb->del_root != db)
3143         return SVN_NO_ERROR;
3144
3145       if (delb->found_edit)
3146         same = FALSE;
3147       else
3148         {
3149           apr_array_header_t *ignores;
3150           svn_error_t *err;
3151           same = TRUE;
3152
3153           SVN_ERR(svn_wc_get_default_ignores(&ignores, merge_b->ctx->config,
3154                                              scratch_pool));
3155
3156           /* None of the descendants was modified, but maybe there are
3157              descendants we haven't walked?
3158
3159              Note that we aren't interested in changes, as we already verified
3160              changes in the paths touched by the merge. And the existence of
3161              other paths is enough to mark the directory edited */
3162           err = svn_wc_walk_status(merge_b->ctx->wc_ctx, local_abspath,
3163                                    svn_depth_infinity, TRUE /* get-all */,
3164                                    FALSE /* no-ignore */,
3165                                    TRUE /* ignore-text-mods */, ignores,
3166                                    verify_touched_by_del_check, delb,
3167                                    merge_b->ctx->cancel_func,
3168                                    merge_b->ctx->cancel_baton,
3169                                    scratch_pool);
3170
3171           if (err)
3172             {
3173               if (err->apr_err != SVN_ERR_CEASE_INVOCATION)
3174                 return svn_error_trace(err);
3175
3176               svn_error_clear(err);
3177             }
3178
3179           same = ! delb->found_edit;
3180         }
3181     }
3182
3183   if (same && !merge_b->dry_run)
3184     {
3185       svn_error_t *err;
3186
3187       err = svn_wc_delete4(merge_b->ctx->wc_ctx, local_abspath,
3188                            FALSE /* keep_local */, FALSE /* unversioned */,
3189                            merge_b->ctx->cancel_func,
3190                            merge_b->ctx->cancel_baton,
3191                            NULL, NULL /* no notify */,
3192                            scratch_pool);
3193
3194       if (err)
3195         {
3196           if (err->apr_err != SVN_ERR_WC_LEFT_LOCAL_MOD)
3197             return svn_error_trace(err);
3198
3199           svn_error_clear(err);
3200           same = FALSE;
3201         }
3202     }
3203
3204   if (! same)
3205     {
3206       /* If the attempt to delete an existing directory failed,
3207        * the directory has local modifications (e.g. locally added
3208        * files, or property changes). Flag a tree conflict. */
3209
3210       /* This handles use case 5 described in the paper attached to issue
3211        * #2282.  See also notes/tree-conflicts/detection.txt
3212        */
3213       SVN_ERR(record_tree_conflict(merge_b, local_abspath, db->parent_baton,
3214                                    svn_node_dir,
3215                                    svn_wc_conflict_action_delete,
3216                                    svn_wc_conflict_reason_edited,
3217                                    NULL, TRUE,
3218                                    scratch_pool));
3219     }
3220   else
3221     {
3222       /* Record that we might have deleted mergeinfo */
3223       if (working_props
3224           && svn_hash_gets(working_props, SVN_PROP_MERGEINFO))
3225         {
3226           alloc_and_store_path(&merge_b->paths_with_deleted_mergeinfo,
3227                                local_abspath, merge_b->pool);
3228         }
3229
3230       SVN_ERR(record_update_delete(merge_b, db->parent_baton, local_abspath,
3231                                    svn_node_dir, scratch_pool));
3232     }
3233
3234   return SVN_NO_ERROR;
3235 }
3236
3237 /* An svn_diff_tree_processor_t function.
3238  *
3239  * Called after merge_dir_opened() when a node itself didn't change between
3240  * the left and right source.
3241  *
3242  * After the merge_dir_opened() but before the call to this merge_dir_closed()
3243  * function all descendants will have been processed.
3244  */
3245 static svn_error_t *
3246 merge_dir_closed(const char *relpath,
3247                  const svn_diff_source_t *left_source,
3248                  const svn_diff_source_t *right_source,
3249                  void *dir_baton,
3250                  const struct svn_diff_tree_processor_t *processor,
3251                  apr_pool_t *scratch_pool)
3252 {
3253   merge_cmd_baton_t *merge_b = processor->baton;
3254   struct merge_dir_baton_t *db = dir_baton;
3255
3256   SVN_ERR(handle_pending_notifications(merge_b, db, scratch_pool));
3257
3258   return SVN_NO_ERROR;
3259 }
3260
3261 /* An svn_diff_tree_processor_t function.
3262
3263    Called when the diff driver wants to report an absent path.
3264
3265    In case of merges this happens when the diff encounters a server-excluded
3266    path.
3267
3268    We register a skipped path, which will make parent mergeinfo non-
3269    inheritable. This ensures that a future merge might see these skipped
3270    changes as eligable for merging.
3271
3272    For legacy reasons we also notify the path as skipped.
3273  */
3274 static svn_error_t *
3275 merge_node_absent(const char *relpath,
3276                   void *dir_baton,
3277                   const svn_diff_tree_processor_t *processor,
3278                   apr_pool_t *scratch_pool)
3279 {
3280   merge_cmd_baton_t *merge_b = processor->baton;
3281
3282   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
3283                                               relpath, scratch_pool);
3284
3285   SVN_ERR(record_skip(merge_b, local_abspath, svn_node_unknown,
3286                       svn_wc_notify_skip, svn_wc_notify_state_missing,
3287                       scratch_pool));
3288
3289   return SVN_NO_ERROR;
3290 }
3291
3292 /*-----------------------------------------------------------------------*/
3293 \f
3294 /*** Merge Notification ***/
3295
3296
3297 /* Finds a nearest ancestor in CHILDREN_WITH_MERGEINFO for LOCAL_ABSPATH. If
3298    PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO
3299    where child->abspath == PATH is considered PATH's ancestor.  If FALSE,
3300    then child->abspath must be a proper ancestor of PATH.
3301
3302    CHILDREN_WITH_MERGEINFO is expected to be sorted in Depth first
3303    order of path. */
3304 static svn_client__merge_path_t *
3305 find_nearest_ancestor(const apr_array_header_t *children_with_mergeinfo,
3306                       svn_boolean_t path_is_own_ancestor,
3307                       const char *local_abspath)
3308 {
3309   int i;
3310
3311   SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL);
3312
3313   for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--)
3314     {
3315       svn_client__merge_path_t *child =
3316         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
3317
3318       if (svn_dirent_is_ancestor(child->abspath, local_abspath)
3319           && (path_is_own_ancestor
3320               || strcmp(child->abspath, local_abspath) != 0))
3321         return child;
3322     }
3323   return NULL;
3324 }
3325
3326 /* Find the highest level path in a merge target (possibly the merge target
3327    itself) to use in a merge notification header.
3328
3329    Return the svn_client__merge_path_t * representing the most distant
3330    ancestor in CHILDREN_WITH_MERGEINFO of LOCAL_ABSPATH where said
3331    ancestor's first remaining ranges element (per the REMAINING_RANGES
3332    member of the ancestor) intersect with the first remaining ranges element
3333    for every intermediate ancestor svn_client__merge_path_t * of
3334    LOCAL_ABSPATH.  If no such ancestor is found return NULL.
3335
3336    If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO
3337    represent a forward merge, then set *START to the oldest revision found
3338    in any of the intersecting ancestors and *END to the youngest revision
3339    found.  If the remaining ranges of the elements in CHILDREN_WITH_MERGEINFO
3340    represent a reverse merge, then set *START to the youngest revision
3341    found and *END to the oldest revision found.  If no ancestors are found
3342    then set *START and *END to SVN_INVALID_REVNUM.
3343
3344    If PATH_IS_OWN_ANCESTOR is TRUE then a child in CHILDREN_WITH_MERGEINFO
3345    where child->abspath == PATH is considered PATH's ancestor.  If FALSE,
3346    then child->abspath must be a proper ancestor of PATH.
3347
3348    See the CHILDREN_WITH_MERGEINFO ARRAY global comment for more
3349    information. */
3350 static svn_client__merge_path_t *
3351 find_nearest_ancestor_with_intersecting_ranges(
3352   svn_revnum_t *start,
3353   svn_revnum_t *end,
3354   const apr_array_header_t *children_with_mergeinfo,
3355   svn_boolean_t path_is_own_ancestor,
3356   const char *local_abspath)
3357 {
3358   int i;
3359   svn_client__merge_path_t *nearest_ancestor = NULL;
3360
3361   *start = SVN_INVALID_REVNUM;
3362   *end = SVN_INVALID_REVNUM;
3363
3364   SVN_ERR_ASSERT_NO_RETURN(children_with_mergeinfo != NULL);
3365
3366   for (i = children_with_mergeinfo->nelts - 1; i >= 0 ; i--)
3367     {
3368       svn_client__merge_path_t *child =
3369         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
3370
3371       if (svn_dirent_is_ancestor(child->abspath, local_abspath)
3372           && (path_is_own_ancestor
3373               || strcmp(child->abspath, local_abspath) != 0))
3374         {
3375           if (nearest_ancestor == NULL)
3376             {
3377               /* Found an ancestor. */
3378               nearest_ancestor = child;
3379
3380               if (child->remaining_ranges)
3381                 {
3382                   svn_merge_range_t *r1 = APR_ARRAY_IDX(
3383                     child->remaining_ranges, 0, svn_merge_range_t *);
3384                   *start = r1->start;
3385                   *end = r1->end;
3386                 }
3387               else
3388                 {
3389                   /* If CHILD->REMAINING_RANGES is null then LOCAL_ABSPATH
3390                      is inside an absent subtree in the merge target. */
3391                   *start = SVN_INVALID_REVNUM;
3392                   *end = SVN_INVALID_REVNUM;
3393                   break;
3394                 }
3395             }
3396           else
3397             {
3398               /* We'e found another ancestor for LOCAL_ABSPATH.  Do its
3399                  first remaining range intersect with the previously
3400                  found ancestor? */
3401               svn_merge_range_t *r1 =
3402                 APR_ARRAY_IDX(nearest_ancestor->remaining_ranges, 0,
3403                               svn_merge_range_t *);
3404               svn_merge_range_t *r2 =
3405                 APR_ARRAY_IDX(child->remaining_ranges, 0,
3406                               svn_merge_range_t *);
3407
3408               if (r1 && r2)
3409                 {
3410                   svn_merge_range_t range1;
3411                   svn_merge_range_t range2;
3412                   svn_boolean_t reverse_merge = r1->start > r2->end;
3413
3414                   /* Flip endpoints if this is a reverse merge. */
3415                   if (reverse_merge)
3416                     {
3417                       range1.start = r1->end;
3418                       range1.end = r1->start;
3419                       range2.start = r2->end;
3420                       range2.end = r2->start;
3421                     }
3422                   else
3423                     {
3424                       range1.start = r1->start;
3425                       range1.end = r1->end;
3426                       range2.start = r2->start;
3427                       range2.end = r2->end;
3428                     }
3429
3430                   if (range1.start < range2.end && range2.start < range1.end)
3431                     {
3432                       *start = reverse_merge ?
3433                         MAX(r1->start, r2->start) : MIN(r1->start, r2->start);
3434                       *end = reverse_merge ?
3435                         MIN(r1->end, r2->end) : MAX(r1->end, r2->end);
3436                       nearest_ancestor = child;
3437                     }
3438                 }
3439             }
3440         }
3441     }
3442   return nearest_ancestor;
3443 }
3444
3445 /* Notify that we're starting to record mergeinfo for the merge of the
3446  * revision range RANGE into TARGET_ABSPATH.  RANGE should be null if the
3447  * merge sources are not from the same URL.
3448  *
3449  * This calls the client's notification receiver (as found in the client
3450  * context), with a WC abspath.
3451  */
3452 static void
3453 notify_mergeinfo_recording(const char *target_abspath,
3454                            const svn_merge_range_t *range,
3455                            svn_client_ctx_t *ctx,
3456                            apr_pool_t *pool)
3457 {
3458   if (ctx->notify_func2)
3459     {
3460       svn_wc_notify_t *n = svn_wc_create_notify(
3461         target_abspath, svn_wc_notify_merge_record_info_begin, pool);
3462
3463       n->merge_range = range ? svn_merge_range_dup(range, pool) : NULL;
3464       ctx->notify_func2(ctx->notify_baton2, n, pool);
3465     }
3466 }
3467
3468 /* Notify that we're completing the merge into TARGET_ABSPATH.
3469  *
3470  * This calls the client's notification receiver (as found in the client
3471  * context), with a WC abspath.
3472  */
3473 static void
3474 notify_merge_completed(const char *target_abspath,
3475                        svn_client_ctx_t *ctx,
3476                        apr_pool_t *pool)
3477 {
3478   if (ctx->notify_func2)
3479     {
3480       svn_wc_notify_t *n
3481         = svn_wc_create_notify(target_abspath, svn_wc_notify_merge_completed,
3482                                pool);
3483       ctx->notify_func2(ctx->notify_baton2, n, pool);
3484     }
3485 }
3486
3487 /* Is the notification the result of a real operative merge? */
3488 #define IS_OPERATIVE_NOTIFICATION(notify)  \
3489                     (notify->content_state == svn_wc_notify_state_conflicted \
3490                      || notify->content_state == svn_wc_notify_state_merged  \
3491                      || notify->content_state == svn_wc_notify_state_changed \
3492                      || notify->prop_state == svn_wc_notify_state_conflicted \
3493                      || notify->prop_state == svn_wc_notify_state_merged     \
3494                      || notify->prop_state == svn_wc_notify_state_changed    \
3495                      || notify->action == svn_wc_notify_update_add \
3496                      || notify->action == svn_wc_notify_tree_conflict)
3497
3498
3499 /* Remove merge source gaps from range used for merge notifications.
3500    See http://subversion.tigris.org/issues/show_bug.cgi?id=4138
3501
3502    If IMPLICIT_SRC_GAP is not NULL then it is a rangelist containing a
3503    single range (see the implicit_src_gap member of merge_cmd_baton_t).
3504    RANGE describes a (possibly reverse) merge.
3505
3506    If IMPLICIT_SRC_GAP is not NULL and it's sole range intersects with
3507    the older revision in *RANGE, then remove IMPLICIT_SRC_GAP's range
3508    from *RANGE. */
3509 static void
3510 remove_source_gap(svn_merge_range_t *range,
3511                   apr_array_header_t *implicit_src_gap)
3512 {
3513   if (implicit_src_gap)
3514     {
3515       svn_merge_range_t *gap_range =
3516         APR_ARRAY_IDX(implicit_src_gap, 0, svn_merge_range_t *);
3517       if (range->start < range->end)
3518         {
3519           if (gap_range->start == range->start)
3520             range->start = gap_range->end;
3521         }
3522       else /* Reverse merge */
3523         {
3524           if (gap_range->start == range->end)
3525             range->end = gap_range->end;
3526         }
3527     }
3528 }
3529
3530 /* Notify that we're starting a merge
3531  *
3532  * This calls the client's notification receiver (as found in the client
3533  * context), with a WC abspath.
3534  */
3535 static svn_error_t *
3536 notify_merge_begin(merge_cmd_baton_t *merge_b,
3537                    const char *local_abspath,
3538                    svn_boolean_t delete_action,
3539                    apr_pool_t *scratch_pool)
3540 {
3541   svn_wc_notify_t *notify;
3542   svn_merge_range_t n_range =
3543     {SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE};
3544   const char *notify_abspath;
3545
3546   if (! merge_b->ctx->notify_func2)
3547     return SVN_NO_ERROR;
3548
3549   /* If our merge sources are ancestors of one another... */
3550   if (merge_b->merge_source.ancestral)
3551     {
3552       const svn_client__merge_path_t *child;
3553       /* Find NOTIFY->PATH's nearest ancestor in
3554          NOTIFY->CHILDREN_WITH_MERGEINFO.  Normally we consider a child in
3555          NOTIFY->CHILDREN_WITH_MERGEINFO representing PATH to be an
3556          ancestor of PATH, but if this is a deletion of PATH then the
3557          notification must be for a proper ancestor of PATH.  This ensures
3558          we don't get notifications like:
3559
3560            --- Merging rX into 'PARENT/CHILD'
3561            D    PARENT/CHILD
3562
3563          But rather:
3564
3565            --- Merging rX into 'PARENT'
3566            D    PARENT/CHILD
3567       */
3568
3569       child = find_nearest_ancestor_with_intersecting_ranges(
3570         &(n_range.start), &(n_range.end),
3571         merge_b->notify_begin.nodes_with_mergeinfo,
3572         ! delete_action, local_abspath);
3573
3574       if (!child && delete_action)
3575         {
3576           /* Triggered by file replace in single-file-merge */
3577           child = find_nearest_ancestor(merge_b->notify_begin.nodes_with_mergeinfo,
3578                                         TRUE, local_abspath);
3579         }
3580
3581       assert(child != NULL); /* Should always find the merge anchor */
3582
3583       if (! child)
3584         return SVN_NO_ERROR;
3585
3586       if (merge_b->notify_begin.last_abspath != NULL
3587           && strcmp(child->abspath, merge_b->notify_begin.last_abspath) == 0)
3588         {
3589           /* Don't notify the same merge again */
3590           return SVN_NO_ERROR;
3591         }
3592
3593       merge_b->notify_begin.last_abspath = child->abspath;
3594
3595       if (child->absent || child->remaining_ranges->nelts == 0
3596           || !SVN_IS_VALID_REVNUM(n_range.start))
3597         {
3598           /* No valid information for an header */
3599           return SVN_NO_ERROR;
3600         }
3601
3602       notify_abspath = child->abspath;
3603     }
3604   else
3605     {
3606       if (merge_b->notify_begin.last_abspath)
3607         return SVN_NO_ERROR; /* already notified */
3608
3609       notify_abspath = merge_b->target->abspath;
3610       /* Store something in last_abspath. Any value would do */
3611       merge_b->notify_begin.last_abspath = merge_b->target->abspath;
3612     }
3613
3614   notify = svn_wc_create_notify(notify_abspath,
3615                                 merge_b->same_repos
3616                                       ? svn_wc_notify_merge_begin
3617                                       : svn_wc_notify_foreign_merge_begin,
3618                                 scratch_pool);
3619
3620   if (SVN_IS_VALID_REVNUM(n_range.start))
3621     {
3622       /* If the merge source has a gap, then don't mention
3623          those gap revisions in the notification. */
3624       remove_source_gap(&n_range, merge_b->implicit_src_gap);
3625       notify->merge_range = &n_range;
3626     }
3627   else
3628     {
3629       notify->merge_range = NULL;
3630     }
3631
3632   (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify,
3633                                 scratch_pool);
3634
3635   return SVN_NO_ERROR;
3636 }
3637
3638 /* Set *OUT_RANGELIST to the intersection of IN_RANGELIST with the simple
3639  * (inheritable) revision range REV1:REV2, according to CONSIDER_INHERITANCE.
3640  * If REV1 is equal to REV2, the result is an empty rangelist, otherwise
3641  * REV1 must be less than REV2.
3642  *
3643  * Note: If CONSIDER_INHERITANCE is FALSE, the effect is to treat any non-
3644  * inheritable input ranges as if they were inheritable.  If it is TRUE, the
3645  * effect is to discard any non-inheritable input ranges.  Therefore the
3646  * ranges in *OUT_RANGELIST will always be inheritable. */
3647 static svn_error_t *
3648 rangelist_intersect_range(svn_rangelist_t **out_rangelist,
3649                           const svn_rangelist_t *in_rangelist,
3650                           svn_revnum_t rev1,
3651                           svn_revnum_t rev2,
3652                           svn_boolean_t consider_inheritance,
3653                           apr_pool_t *result_pool,
3654                           apr_pool_t *scratch_pool)
3655 {
3656   SVN_ERR_ASSERT(rev1 <= rev2);
3657
3658   if (rev1 < rev2)
3659     {
3660       svn_rangelist_t *simple_rangelist =
3661         svn_rangelist__initialize(rev1, rev2, TRUE, scratch_pool);
3662
3663       SVN_ERR(svn_rangelist_intersect(out_rangelist,
3664                                       simple_rangelist, in_rangelist,
3665                                       consider_inheritance, result_pool));
3666     }
3667   else
3668     {
3669       *out_rangelist = apr_array_make(result_pool, 0,
3670                                       sizeof(svn_merge_range_t *));
3671     }
3672   return SVN_NO_ERROR;
3673 }
3674
3675 /* Helper for fix_deleted_subtree_ranges().  Like fix_deleted_subtree_ranges()
3676    this function should only be called when honoring mergeinfo.
3677
3678    CHILD, PARENT, REVISION1, REVISION2, and RA_SESSION are all cascaded from
3679    fix_deleted_subtree_ranges() -- see that function for more information on
3680    each.
3681
3682    If PARENT is not the merge target then PARENT must have already have been
3683    processed by this function as a child.  Specifically, this means that
3684    PARENT->REMAINING_RANGES must already be populated -- it can be an empty
3685    rangelist but cannot be NULL.
3686
3687    PRIMARY_URL is the merge source url of CHILD at the younger of REVISION1
3688    and REVISION2.
3689
3690    Since this function is only invoked for subtrees of the merge target, the
3691    guarantees afforded by normalize_merge_sources() don't apply - see the
3692    'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file.
3693    Therefore it is possible that PRIMARY_URL@REVISION1 and
3694    PRIMARY_URL@REVISION2 don't describe the endpoints of an unbroken line of
3695    history.  The purpose of this helper is to identify these cases of broken
3696    history and adjust CHILD->REMAINING_RANGES in such a way we don't later try
3697    to describe nonexistent path/revisions to the merge report editor -- see
3698    drive_merge_report_editor().
3699
3700    If PRIMARY_URL@REVISION1 and PRIMARY_URL@REVISION2 describe an unbroken
3701    line of history then do nothing and leave CHILD->REMAINING_RANGES as-is.
3702
3703    If neither PRIMARY_URL@REVISION1 nor PRIMARY_URL@REVISION2 exist then
3704    there is nothing to merge to CHILD->ABSPATH so set CHILD->REMAINING_RANGES
3705    equal to PARENT->REMAINING_RANGES.  This will cause the subtree to
3706    effectively ignore CHILD -- see 'Note: If the first svn_merge_range_t...'
3707    in drive_merge_report_editor()'s doc string.
3708
3709    If PRIMARY_URL@REVISION1 *xor* PRIMARY_URL@REVISION2 exist then we take the
3710    subset of REVISION1:REVISION2 in CHILD->REMAINING_RANGES at which
3711    PRIMARY_URL doesn't exist and set that subset equal to
3712    PARENT->REMAINING_RANGES' intersection with that non-existent range.  Why?
3713    Because this causes CHILD->REMAINING_RANGES to be identical to
3714    PARENT->REMAINING_RANGES for revisions between REVISION1 and REVISION2 at
3715    which PRIMARY_URL doesn't exist.  As mentioned above this means that
3716    drive_merge_report_editor() won't attempt to describe these non-existent
3717    subtree path/ranges to the reporter (which would break the merge).
3718
3719    If the preceding paragraph wasn't terribly clear then what follows spells
3720    out this function's behavior a bit more explicitly:
3721
3722    For forward merges (REVISION1 < REVISION2)
3723
3724      If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then
3725      find the revision 'N' in which PRIMARY_URL@REVISION1 was deleted.  Leave
3726      the subset of CHILD->REMAINING_RANGES that intersects with
3727      REVISION1:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES
3728      that intersects with (N - 1):REVISION2 equal to PARENT->REMAINING_RANGES'
3729      intersection with (N - 1):REVISION2.
3730
3731      If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does,
3732      then find the revision 'M' in which PRIMARY_URL@REVISION2 came into
3733      existence.  Leave the subset of CHILD->REMAINING_RANGES that intersects with
3734      (M - 1):REVISION2 as-is and set the subset of CHILD->REMAINING_RANGES
3735      that intersects with REVISION1:(M - 1) equal to PARENT->REMAINING_RANGES'
3736      intersection with REVISION1:(M - 1).
3737
3738    For reverse merges (REVISION1 > REVISION2)
3739
3740      If PRIMARY_URL@REVISION1 exists but PRIMARY_URL@REVISION2 doesn't, then
3741      find the revision 'N' in which PRIMARY_URL@REVISION1 came into existence.
3742      Leave the subset of CHILD->REMAINING_RANGES that intersects with
3743      REVISION2:(N - 1) as-is and set the subset of CHILD->REMAINING_RANGES
3744      that intersects with (N - 1):REVISION1 equal to PARENT->REMAINING_RANGES'
3745      intersection with (N - 1):REVISION1.
3746
3747      If PRIMARY_URL@REVISION1 doesn't exist but PRIMARY_URL@REVISION2 does,
3748      then find the revision 'M' in which PRIMARY_URL@REVISION2 came into
3749      existence.  Leave the subset of CHILD->REMAINING_RANGES that intersects with
3750      REVISION2:(M - 1) as-is and set the subset of CHILD->REMAINING_RANGES
3751      that intersects with (M - 1):REVISION1 equal to PARENT->REMAINING_RANGES'
3752      intersection with REVISION1:(M - 1).
3753
3754    SCRATCH_POOL is used for all temporary allocations.  Changes to CHILD are
3755    allocated in RESULT_POOL. */
3756 static svn_error_t *
3757 adjust_deleted_subtree_ranges(svn_client__merge_path_t *child,
3758                               svn_client__merge_path_t *parent,
3759                               svn_revnum_t revision1,
3760                               svn_revnum_t revision2,
3761                               const char *primary_url,
3762                               svn_ra_session_t *ra_session,
3763                               svn_client_ctx_t *ctx,
3764                               apr_pool_t *result_pool,
3765                               apr_pool_t *scratch_pool)
3766 {
3767   svn_boolean_t is_rollback = revision2 < revision1;
3768   svn_revnum_t younger_rev = is_rollback ? revision1 : revision2;
3769   svn_revnum_t peg_rev = younger_rev;
3770   svn_revnum_t older_rev = is_rollback ? revision2 : revision1;
3771   apr_array_header_t *segments;
3772   svn_error_t *err;
3773
3774   SVN_ERR_ASSERT(parent->remaining_ranges);
3775
3776   err = svn_client__repos_location_segments(&segments, ra_session,
3777                                             primary_url, peg_rev,
3778                                             younger_rev, older_rev, ctx,
3779                                             scratch_pool);
3780
3781   /* If PRIMARY_URL@peg_rev doesn't exist then
3782       svn_client__repos_location_segments() typically returns an
3783       SVN_ERR_FS_NOT_FOUND error, but if it doesn't exist for a
3784       forward merge over ra_neon then we get SVN_ERR_RA_DAV_REQUEST_FAILED.
3785       http://subversion.tigris.org/issues/show_bug.cgi?id=3137 fixed some of
3786       the cases where different RA layers returned different error codes to
3787       signal the "path not found"...but it looks like there is more to do.
3788
3789       ### Do we still need to special case for ra_neon (since it no longer
3790           exists)? */
3791   if (err)
3792     {
3793       if (err->apr_err == SVN_ERR_FS_NOT_FOUND
3794           || err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
3795         {
3796           /* PRIMARY_URL@peg_rev doesn't exist.  Check if PRIMARY_URL@older_rev
3797              exists, if neither exist then the editor can simply ignore this
3798              subtree. */
3799           const char *rel_source_path;  /* PRIMARY_URL relative to RA_SESSION */
3800           svn_node_kind_t kind;
3801
3802           svn_error_clear(err);
3803           err = NULL;
3804
3805           SVN_ERR(svn_ra_get_path_relative_to_session(
3806                     ra_session, &rel_source_path, primary_url, scratch_pool));
3807
3808           SVN_ERR(svn_ra_check_path(ra_session, rel_source_path,
3809                                     older_rev, &kind, scratch_pool));
3810           if (kind == svn_node_none)
3811             {
3812               /* Neither PRIMARY_URL@peg_rev nor PRIMARY_URL@older_rev exist,
3813                  so there is nothing to merge.  Set CHILD->REMAINING_RANGES
3814                  identical to PARENT's. */
3815               child->remaining_ranges =
3816                 svn_rangelist_dup(parent->remaining_ranges, scratch_pool);
3817             }
3818           else
3819             {
3820               svn_rangelist_t *deleted_rangelist;
3821               svn_revnum_t rev_primary_url_deleted;
3822
3823               /* PRIMARY_URL@older_rev exists, so it was deleted at some
3824                  revision prior to peg_rev, find that revision. */
3825               SVN_ERR(svn_ra_get_deleted_rev(ra_session, rel_source_path,
3826                                              older_rev, younger_rev,
3827                                              &rev_primary_url_deleted,
3828                                              scratch_pool));
3829
3830               /* PRIMARY_URL@older_rev exists and PRIMARY_URL@peg_rev doesn't,
3831                  so svn_ra_get_deleted_rev() should always find the revision
3832                  PRIMARY_URL@older_rev was deleted. */
3833               SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev_primary_url_deleted));
3834
3835               /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and
3836                  PARENT->REMAINING_RANGES so both will work with the
3837                  svn_rangelist_* APIs below. */
3838               if (is_rollback)
3839                 {
3840                   /* svn_rangelist_reverse operates in place so it's safe
3841                      to use our scratch_pool. */
3842                   SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
3843                                                 scratch_pool));
3844                   SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
3845                                                 scratch_pool));
3846                 }
3847
3848               /* Find the intersection of CHILD->REMAINING_RANGES with the
3849                  range over which PRIMARY_URL@older_rev exists (ending at
3850                  the youngest revision at which it still exists). */
3851               SVN_ERR(rangelist_intersect_range(&child->remaining_ranges,
3852                                                 child->remaining_ranges,
3853                                                 older_rev,
3854                                                 rev_primary_url_deleted - 1,
3855                                                 FALSE,
3856                                                 scratch_pool, scratch_pool));
3857
3858               /* Merge into CHILD->REMAINING_RANGES the intersection of
3859                  PARENT->REMAINING_RANGES with the range beginning when
3860                  PRIMARY_URL@older_rev was deleted until younger_rev. */
3861               SVN_ERR(rangelist_intersect_range(&deleted_rangelist,
3862                                                 parent->remaining_ranges,
3863                                                 rev_primary_url_deleted - 1,
3864                                                 peg_rev,
3865                                                 FALSE,
3866                                                 scratch_pool, scratch_pool));
3867               SVN_ERR(svn_rangelist_merge2(child->remaining_ranges,
3868                                            deleted_rangelist, scratch_pool,
3869                                            scratch_pool));
3870
3871               /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES
3872                  to reverse order if necessary. */
3873               if (is_rollback)
3874                 {
3875                   SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
3876                                                 scratch_pool));
3877                   SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
3878                                                 scratch_pool));
3879                 }
3880             }
3881         }
3882       else
3883         {
3884           return svn_error_trace(err);
3885         }
3886     }
3887   else /* PRIMARY_URL@peg_rev exists. */
3888     {
3889       svn_rangelist_t *non_existent_rangelist;
3890       svn_location_segment_t *segment =
3891         APR_ARRAY_IDX(segments, (segments->nelts - 1),
3892                       svn_location_segment_t *);
3893
3894       /* We know PRIMARY_URL@peg_rev exists as the call to
3895          svn_client__repos_location_segments() succeeded.  If there is only
3896          one segment that starts at oldest_rev then we know that
3897          PRIMARY_URL@oldest_rev:PRIMARY_URL@peg_rev describes an unbroken
3898          line of history, so there is nothing more to adjust in
3899          CHILD->REMAINING_RANGES. */
3900       if (segment->range_start == older_rev)
3901         {
3902           return SVN_NO_ERROR;
3903         }
3904
3905       /* If this is a reverse merge reorder CHILD->REMAINING_RANGES and
3906          PARENT->REMAINING_RANGES so both will work with the
3907          svn_rangelist_* APIs below. */
3908       if (is_rollback)
3909         {
3910           SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
3911                                         scratch_pool));
3912           SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
3913                                         scratch_pool));
3914         }
3915
3916       /* Intersect CHILD->REMAINING_RANGES with the range where PRIMARY_URL
3917          exists.  Since segment doesn't span older_rev:peg_rev we know
3918          PRIMARY_URL@peg_rev didn't come into existence until
3919          segment->range_start + 1. */
3920       SVN_ERR(rangelist_intersect_range(&child->remaining_ranges,
3921                                         child->remaining_ranges,
3922                                         segment->range_start, peg_rev,
3923                                         FALSE, scratch_pool, scratch_pool));
3924
3925       /* Merge into CHILD->REMAINING_RANGES the intersection of
3926          PARENT->REMAINING_RANGES with the range before PRIMARY_URL@peg_rev
3927          came into existence. */
3928       SVN_ERR(rangelist_intersect_range(&non_existent_rangelist,
3929                                         parent->remaining_ranges,
3930                                         older_rev, segment->range_start,
3931                                         FALSE, scratch_pool, scratch_pool));
3932       SVN_ERR(svn_rangelist_merge2(child->remaining_ranges,
3933                                    non_existent_rangelist, scratch_pool,
3934                                    scratch_pool));
3935
3936       /* Return CHILD->REMAINING_RANGES and PARENT->REMAINING_RANGES
3937          to reverse order if necessary. */
3938       if (is_rollback)
3939         {
3940           SVN_ERR(svn_rangelist_reverse(child->remaining_ranges,
3941                                         scratch_pool));
3942           SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges,
3943                                         scratch_pool));
3944         }
3945     }
3946
3947   /* Make a lasting copy of CHILD->REMAINING_RANGES using POOL. */
3948   child->remaining_ranges = svn_rangelist_dup(child->remaining_ranges,
3949                                               result_pool);
3950   return SVN_NO_ERROR;
3951 }
3952
3953 /* Helper for do_directory_merge().
3954
3955    SOURCE is cascaded from the argument of the same name in
3956    do_directory_merge().  TARGET is the merge target.  RA_SESSION is the
3957    session for the younger of SOURCE->loc1 and SOURCE->loc2.
3958
3959    Adjust the subtrees in CHILDREN_WITH_MERGEINFO so that we don't
3960    later try to describe invalid paths in drive_merge_report_editor().
3961    This function is just a thin wrapper around
3962    adjust_deleted_subtree_ranges(), which see for further details.
3963
3964    SCRATCH_POOL is used for all temporary allocations.  Changes to
3965    CHILDREN_WITH_MERGEINFO are allocated in RESULT_POOL.
3966 */
3967 static svn_error_t *
3968 fix_deleted_subtree_ranges(const merge_source_t *source,
3969                            const merge_target_t *target,
3970                            svn_ra_session_t *ra_session,
3971                            apr_array_header_t *children_with_mergeinfo,
3972                            svn_client_ctx_t *ctx,
3973                            apr_pool_t *result_pool,
3974                            apr_pool_t *scratch_pool)
3975 {
3976   int i;
3977   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
3978   svn_boolean_t is_rollback = source->loc2->rev < source->loc1->rev;
3979
3980   assert(session_url_is(ra_session,
3981                         (is_rollback ? source->loc1 : source->loc2)->url,
3982                         scratch_pool));
3983
3984   /* CHILDREN_WITH_MERGEINFO is sorted in depth-first order, so
3985      start at index 1 to examine only subtrees. */
3986   for (i = 1; i < children_with_mergeinfo->nelts; i++)
3987     {
3988       svn_client__merge_path_t *child =
3989         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
3990       svn_client__merge_path_t *parent;
3991       svn_rangelist_t *deleted_rangelist, *added_rangelist;
3992
3993       SVN_ERR_ASSERT(child);
3994       if (child->absent)
3995         continue;
3996
3997       svn_pool_clear(iterpool);
3998
3999       /* Find CHILD's parent. */
4000       parent = find_nearest_ancestor(children_with_mergeinfo,
4001                                      FALSE, child->abspath);
4002
4003       /* Since CHILD is a subtree then its parent must be in
4004          CHILDREN_WITH_MERGEINFO, see the global comment
4005          'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
4006       SVN_ERR_ASSERT(parent);
4007
4008       /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
4009          so it will work with the svn_rangelist_diff API. */
4010       if (is_rollback)
4011         {
4012           SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
4013           SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool));
4014         }
4015
4016       SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
4017                                  child->remaining_ranges,
4018                                  parent->remaining_ranges,
4019                                  TRUE, iterpool));
4020
4021       if (is_rollback)
4022         {
4023           SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
4024           SVN_ERR(svn_rangelist_reverse(parent->remaining_ranges, iterpool));
4025         }
4026
4027       /* If CHILD is the merge target we then know that SOURCE is provided
4028          by normalize_merge_sources() -- see 'MERGEINFO MERGE SOURCE
4029          NORMALIZATION'.  Due to this normalization we know that SOURCE
4030          describes an unbroken line of history such that the entire range
4031          described by SOURCE can potentially be merged to CHILD.
4032
4033          But if CHILD is a subtree we don't have the same guarantees about
4034          SOURCE as we do for the merge target.  SOURCE->loc1 and/or
4035          SOURCE->loc2 might not exist.
4036
4037          If one or both doesn't exist, then adjust CHILD->REMAINING_RANGES
4038          such that we don't later try to describe invalid subtrees in
4039          drive_merge_report_editor(), as that will break the merge.
4040          If CHILD has the same remaining ranges as PARENT however, then
4041          there is no need to make these adjustments, since
4042          drive_merge_report_editor() won't attempt to describe CHILD in this
4043          case, see the 'Note' in drive_merge_report_editor's docstring. */
4044       if (deleted_rangelist->nelts || added_rangelist->nelts)
4045         {
4046           const char *child_primary_source_url;
4047           const char *child_repos_src_path =
4048             svn_dirent_is_child(target->abspath, child->abspath, iterpool);
4049
4050           /* This loop is only processing subtrees, so CHILD->ABSPATH
4051              better be a proper child of the merge target. */
4052           SVN_ERR_ASSERT(child_repos_src_path);
4053
4054           child_primary_source_url =
4055             svn_path_url_add_component2((source->loc1->rev < source->loc2->rev)
4056                                         ? source->loc2->url : source->loc1->url,
4057                                         child_repos_src_path, iterpool);
4058
4059           SVN_ERR(adjust_deleted_subtree_ranges(child, parent,
4060                                                 source->loc1->rev,
4061                                                 source->loc2->rev,
4062                                                 child_primary_source_url,
4063                                                 ra_session,
4064                                                 ctx, result_pool, iterpool));
4065         }
4066     }
4067
4068   svn_pool_destroy(iterpool);
4069   return SVN_NO_ERROR;
4070 }
4071
4072 /*-----------------------------------------------------------------------*/
4073 \f
4074 /*** Determining What Remains To Be Merged ***/
4075
4076 /* Get explicit and/or implicit mergeinfo for the working copy path
4077    TARGET_ABSPATH.
4078
4079    If RECORDED_MERGEINFO is not NULL then set *RECORDED_MERGEINFO
4080    to TARGET_ABSPATH's explicit or inherited mergeinfo as dictated by
4081    INHERIT.
4082
4083    If IMPLICIT_MERGEINFO is not NULL then set *IMPLICIT_MERGEINFO
4084    to TARGET_ABSPATH's implicit mergeinfo (a.k.a. natural history).
4085
4086    If both RECORDED_MERGEINFO and IMPLICIT_MERGEINFO are not NULL and
4087    *RECORDED_MERGEINFO is inherited, then *IMPLICIT_MERGEINFO will be
4088    removed from *RECORDED_MERGEINFO.
4089
4090    If INHERITED is not NULL set *INHERITED to TRUE if *RECORDED_MERGEINFO
4091    is inherited rather than explicit.  If RECORDED_MERGEINFO is NULL then
4092    INHERITED is ignored.
4093
4094
4095    If IMPLICIT_MERGEINFO is not NULL then START and END are limits on
4096    the natural history sought, must both be valid revision numbers, and
4097    START must be greater than END.  If TARGET_ABSPATH's base revision
4098    is older than START, then the base revision is used as the younger
4099    bound in place of START.
4100
4101    RA_SESSION is an RA session open to the repository in which TARGET_ABSPATH
4102    lives.  It may be temporarily reparented as needed by this function.
4103
4104    Allocate *RECORDED_MERGEINFO and *IMPLICIT_MERGEINFO in RESULT_POOL.
4105    Use SCRATCH_POOL for any temporary allocations. */
4106 static svn_error_t *
4107 get_full_mergeinfo(svn_mergeinfo_t *recorded_mergeinfo,
4108                    svn_mergeinfo_t *implicit_mergeinfo,
4109                    svn_boolean_t *inherited,
4110                    svn_mergeinfo_inheritance_t inherit,
4111                    svn_ra_session_t *ra_session,
4112                    const char *target_abspath,
4113                    svn_revnum_t start,
4114                    svn_revnum_t end,
4115                    svn_client_ctx_t *ctx,
4116                    apr_pool_t *result_pool,
4117                    apr_pool_t *scratch_pool)
4118 {
4119   /* First, we get the real mergeinfo. */
4120   if (recorded_mergeinfo)
4121     {
4122       SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(recorded_mergeinfo,
4123                                                     inherited,
4124                                                     NULL /* from_repos */,
4125                                                     FALSE,
4126                                                     inherit, ra_session,
4127                                                     target_abspath,
4128                                                     ctx, result_pool));
4129     }
4130
4131   if (implicit_mergeinfo)
4132     {
4133       svn_client__pathrev_t *target;
4134
4135       /* Assert that we have sane input. */
4136       SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(start) && SVN_IS_VALID_REVNUM(end)
4137                      && (start > end));
4138
4139       /* Retrieve the origin (original_*) of the node, or just the
4140          url if the node was not copied. */
4141       SVN_ERR(svn_client__wc_node_get_origin(&target, target_abspath, ctx,
4142                                              scratch_pool, scratch_pool));
4143
4144       if (! target)
4145         {
4146           /* We've been asked to operate on a locally added target, so its
4147            * implicit mergeinfo is empty. */
4148           *implicit_mergeinfo = apr_hash_make(result_pool);
4149         }
4150       else if (target->rev <= end)
4151         {
4152           /* We're asking about a range outside our natural history
4153              altogether.  That means our implicit mergeinfo is empty. */
4154           *implicit_mergeinfo = apr_hash_make(result_pool);
4155         }
4156       else
4157         {
4158           /* Fetch so-called "implicit mergeinfo" (that is, natural
4159              history). */
4160
4161           /* Do not ask for implicit mergeinfo from TARGET_ABSPATH's future.
4162              TARGET_ABSPATH might not even exist, and even if it does the
4163              working copy is *at* TARGET_REV so its implicit history ends
4164              at TARGET_REV! */
4165           if (target->rev < start)
4166             start = target->rev;
4167
4168           /* Fetch the implicit mergeinfo. */
4169           SVN_ERR(svn_client__get_history_as_mergeinfo(implicit_mergeinfo,
4170                                                        NULL,
4171                                                        target, start, end,
4172                                                        ra_session, ctx,
4173                                                        result_pool));
4174         }
4175     } /*if (implicit_mergeinfo) */
4176
4177   return SVN_NO_ERROR;
4178 }
4179
4180 /* Helper for ensure_implicit_mergeinfo().
4181
4182    PARENT, CHILD, REVISION1, REVISION2 and CTX
4183    are all cascaded from the arguments of the same names in
4184    ensure_implicit_mergeinfo().  PARENT and CHILD must both exist, i.e.
4185    this function should never be called where CHILD is the merge target.
4186
4187    If PARENT->IMPLICIT_MERGEINFO is NULL, obtain it from the server.
4188
4189    Set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from
4190    PARENT->IMPLICIT_MERGEINFO.  CHILD->IMPLICIT_MERGEINFO is allocated
4191    in RESULT_POOL.
4192
4193    RA_SESSION is an RA session open to the repository that contains CHILD.
4194    It may be temporarily reparented by this function.
4195    */
4196 static svn_error_t *
4197 inherit_implicit_mergeinfo_from_parent(svn_client__merge_path_t *parent,
4198                                        svn_client__merge_path_t *child,
4199                                        svn_revnum_t revision1,
4200                                        svn_revnum_t revision2,
4201                                        svn_ra_session_t *ra_session,
4202                                        svn_client_ctx_t *ctx,
4203                                        apr_pool_t *result_pool,
4204                                        apr_pool_t *scratch_pool)
4205 {
4206   const char *path_diff;
4207
4208   /* This only works on subtrees! */
4209   SVN_ERR_ASSERT(parent);
4210   SVN_ERR_ASSERT(child);
4211
4212   /* While PARENT must exist, it is possible we've deferred
4213      getting its implicit mergeinfo.  If so get it now. */
4214   if (!parent->implicit_mergeinfo)
4215     SVN_ERR(get_full_mergeinfo(NULL, &(parent->implicit_mergeinfo),
4216                                NULL, svn_mergeinfo_inherited,
4217                                ra_session, child->abspath,
4218                                MAX(revision1, revision2),
4219                                MIN(revision1, revision2),
4220                                ctx, result_pool, scratch_pool));
4221
4222   /* Let CHILD inherit PARENT's implicit mergeinfo. */
4223
4224   path_diff = svn_dirent_is_child(parent->abspath, child->abspath,
4225                                   scratch_pool);
4226   /* PARENT->PATH better be an ancestor of CHILD->ABSPATH! */
4227   SVN_ERR_ASSERT(path_diff);
4228
4229   SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(
4230             &child->implicit_mergeinfo, parent->implicit_mergeinfo,
4231             path_diff, result_pool, scratch_pool));
4232   child->implicit_mergeinfo = svn_mergeinfo_dup(child->implicit_mergeinfo,
4233                                                 result_pool);
4234   return SVN_NO_ERROR;
4235 }
4236
4237 /* Helper of filter_merged_revisions().
4238
4239    If we have deferred obtaining CHILD->IMPLICIT_MERGEINFO, then get
4240    it now, allocating it in RESULT_POOL.  If CHILD_INHERITS_PARENT is true
4241    then set CHILD->IMPLICIT_MERGEINFO to the mergeinfo inherited from
4242    PARENT->IMPLICIT_MERGEINFO, otherwise contact the repository.  Use
4243    SCRATCH_POOL for all temporary allocations.
4244
4245    RA_SESSION is an RA session open to the repository that contains CHILD.
4246    It may be temporarily reparented by this function.
4247
4248    PARENT, CHILD, REVISION1, REVISION2 and
4249    CTX are all cascaded from the arguments of the same name in
4250    filter_merged_revisions() and the same conditions for that function
4251    hold here. */
4252 static svn_error_t *
4253 ensure_implicit_mergeinfo(svn_client__merge_path_t *parent,
4254                           svn_client__merge_path_t *child,
4255                           svn_boolean_t child_inherits_parent,
4256                           svn_revnum_t revision1,
4257                           svn_revnum_t revision2,
4258                           svn_ra_session_t *ra_session,
4259                           svn_client_ctx_t *ctx,
4260                           apr_pool_t *result_pool,
4261                           apr_pool_t *scratch_pool)
4262 {
4263   /* If we haven't already found CHILD->IMPLICIT_MERGEINFO then
4264      contact the server to get it. */
4265
4266   if (child->implicit_mergeinfo)
4267     return SVN_NO_ERROR;
4268
4269   if (child_inherits_parent)
4270     SVN_ERR(inherit_implicit_mergeinfo_from_parent(parent,
4271                                                    child,
4272                                                    revision1,
4273                                                    revision2,
4274                                                    ra_session,
4275                                                    ctx,
4276                                                    result_pool,
4277                                                    scratch_pool));
4278   else
4279     SVN_ERR(get_full_mergeinfo(NULL,
4280                                &(child->implicit_mergeinfo),
4281                                NULL, svn_mergeinfo_inherited,
4282                                ra_session, child->abspath,
4283                                MAX(revision1, revision2),
4284                                MIN(revision1, revision2),
4285                                ctx, result_pool, scratch_pool));
4286
4287   return SVN_NO_ERROR;
4288 }
4289
4290 /* Helper for calculate_remaining_ranges().
4291
4292    Initialize CHILD->REMAINING_RANGES to a rangelist representing the
4293    requested merge of REVISION1:REVISION2 from MERGEINFO_PATH to
4294    CHILD->ABSPATH.
4295
4296    For forward merges remove any ranges from CHILD->REMAINING_RANGES that
4297    have already been merged to CHILD->ABSPATH per TARGET_MERGEINFO or
4298    CHILD->IMPLICIT_MERGEINFO.  For reverse merges remove any ranges from
4299    CHILD->REMAINING_RANGES that have not already been merged to CHILD->ABSPATH
4300    per TARGET_MERGEINFO or CHILD->IMPLICIT_MERGEINFO.  If we have deferred
4301    obtaining CHILD->IMPLICIT_MERGEINFO and it is necessary to use it for
4302    these calculations, then get it from the server, allocating it in
4303    RESULT_POOL.
4304
4305    CHILD represents a working copy path which is the merge target or one of
4306    the target's subtrees.  If not NULL, PARENT is CHILD's nearest path-wise
4307    ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'.
4308
4309    If the function needs to consider CHILD->IMPLICIT_MERGEINFO and
4310    CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the
4311    mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO.  Otherwise contact
4312    the repository for CHILD->IMPLICIT_MERGEINFO.
4313
4314    NOTE: If PARENT is present then this function must have previously been
4315    called for PARENT, i.e. if populate_remaining_ranges() is calling this
4316    function for a set of svn_client__merge_path_t* the calls must be made
4317    in depth-first order.
4318
4319    MERGEINFO_PATH is the merge source relative to the repository root.
4320
4321    REVISION1 and REVISION2 describe the merge range requested from
4322    MERGEINFO_PATH.
4323
4324    TARGET_RANGELIST is the portion of CHILD->ABSPATH's explicit or inherited
4325    mergeinfo that intersects with the merge history described by
4326    MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2.  TARGET_RANGELIST
4327    should be NULL if there is no explicit or inherited mergeinfo on
4328    CHILD->ABSPATH or an empty list if CHILD->ABSPATH has empty mergeinfo or
4329    explicit mergeinfo that exclusively describes non-intersecting history
4330    with MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2.
4331
4332    SCRATCH_POOL is used for all temporary allocations.
4333
4334    NOTE: This should only be called when honoring mergeinfo.
4335
4336    NOTE: Like calculate_remaining_ranges() if PARENT is present then this
4337    function must have previously been called for PARENT.
4338 */
4339 static svn_error_t *
4340 filter_merged_revisions(svn_client__merge_path_t *parent,
4341                         svn_client__merge_path_t *child,
4342                         const char *mergeinfo_path,
4343                         svn_rangelist_t *target_rangelist,
4344                         svn_revnum_t revision1,
4345                         svn_revnum_t revision2,
4346                         svn_boolean_t child_inherits_implicit,
4347                         svn_ra_session_t *ra_session,
4348                         svn_client_ctx_t *ctx,
4349                         apr_pool_t *result_pool,
4350                         apr_pool_t *scratch_pool)
4351 {
4352   svn_rangelist_t *requested_rangelist,
4353     *target_implicit_rangelist, *explicit_rangelist;
4354
4355   /* Convert REVISION1 and REVISION2 to a rangelist.
4356
4357      Note: Talking about a requested merge range's inheritability
4358      doesn't make much sense, but as we are using svn_merge_range_t
4359      to describe it we need to pick *something*.  Since all the
4360      rangelist manipulations in this function either don't consider
4361      inheritance by default or we are requesting that they don't (i.e.
4362      svn_rangelist_remove and svn_rangelist_intersect) then we could
4363      set the inheritability as FALSE, it won't matter either way. */
4364   requested_rangelist = svn_rangelist__initialize(revision1, revision2,
4365                                                   TRUE, scratch_pool);
4366
4367   /* Now filter out revisions that have already been merged to CHILD. */
4368
4369   if (revision1 > revision2) /* This is a reverse merge. */
4370     {
4371       svn_rangelist_t *added_rangelist, *deleted_rangelist;
4372
4373       /* The revert range and will need to be reversed for
4374          our svn_rangelist_* APIs to work properly. */
4375       SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool));
4376
4377       /* Set EXPLICIT_RANGELIST to the list of source-range revs that are
4378          already recorded as merged to target. */
4379       if (target_rangelist)
4380         {
4381           /* Return the intersection of the revs which are both already
4382              represented by CHILD's explicit or inherited mergeinfo.
4383
4384              We don't consider inheritance when determining intersecting
4385              ranges.  If we *did* consider inheritance, then our calculation
4386              would be wrong.  For example, if the CHILD->REMAINING_RANGES is
4387              5:3 and TARGET_RANGELIST is r5* (non-inheritable) then the
4388              intersection would be r4.  And that would be wrong as we clearly
4389              want to reverse merge both r4 and r5 in this case.  Ignoring the
4390              ranges' inheritance results in an intersection of r4-5.
4391
4392              You might be wondering about CHILD's children, doesn't the above
4393              imply that we will reverse merge r4-5 from them?  Nope, this is
4394              safe to do because any path whose parent has non-inheritable
4395              ranges is always considered a subtree with differing mergeinfo
4396              even if that path has no explicit mergeinfo prior to the
4397              merge -- See condition 3 in the doc string for
4398              merge.c:get_mergeinfo_paths(). */
4399           SVN_ERR(svn_rangelist_intersect(&explicit_rangelist,
4400                                           target_rangelist,
4401                                           requested_rangelist,
4402                                           FALSE, scratch_pool));
4403         }
4404       else
4405         {
4406           explicit_rangelist =
4407             apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *));
4408         }
4409
4410       /* Was any part of the requested reverse merge not accounted for in
4411          CHILD's explicit or inherited mergeinfo? */
4412       SVN_ERR(svn_rangelist_diff(&deleted_rangelist, &added_rangelist,
4413                                  requested_rangelist, explicit_rangelist,
4414                                  FALSE, scratch_pool));
4415
4416       if (deleted_rangelist->nelts == 0)
4417         {
4418           /* The whole of REVISION1:REVISION2 was represented in CHILD's
4419              explicit/inherited mergeinfo, allocate CHILD's remaining
4420              ranges in POOL and then we are done. */
4421           SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool));
4422           child->remaining_ranges = svn_rangelist_dup(requested_rangelist,
4423                                                       result_pool);
4424         }
4425       else /* We need to check CHILD's implicit mergeinfo. */
4426         {
4427           svn_rangelist_t *implicit_rangelist;
4428
4429           SVN_ERR(ensure_implicit_mergeinfo(parent,
4430                                             child,
4431                                             child_inherits_implicit,
4432                                             revision1,
4433                                             revision2,
4434                                             ra_session,
4435                                             ctx,
4436                                             result_pool,
4437                                             scratch_pool));
4438
4439           target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo,
4440                                                     mergeinfo_path);
4441
4442           if (target_implicit_rangelist)
4443             SVN_ERR(svn_rangelist_intersect(&implicit_rangelist,
4444                                             target_implicit_rangelist,
4445                                             requested_rangelist,
4446                                             FALSE, scratch_pool));
4447           else
4448             implicit_rangelist = apr_array_make(scratch_pool, 0,
4449                                                 sizeof(svn_merge_range_t *));
4450
4451           SVN_ERR(svn_rangelist_merge2(implicit_rangelist,
4452                                        explicit_rangelist, scratch_pool,
4453                                        scratch_pool));
4454           SVN_ERR(svn_rangelist_reverse(implicit_rangelist, scratch_pool));
4455           child->remaining_ranges = svn_rangelist_dup(implicit_rangelist,
4456                                                       result_pool);
4457         }
4458     }
4459   else /* This is a forward merge */
4460     {
4461       /* Set EXPLICIT_RANGELIST to the list of source-range revs that are
4462          NOT already recorded as merged to target. */
4463       if (target_rangelist)
4464         {
4465           /* See earlier comment preceding svn_rangelist_intersect() for
4466              why we don't consider inheritance here. */
4467           SVN_ERR(svn_rangelist_remove(&explicit_rangelist,
4468                                        target_rangelist,
4469                                        requested_rangelist, FALSE,
4470                                        scratch_pool));
4471         }
4472       else
4473         {
4474           explicit_rangelist = svn_rangelist_dup(requested_rangelist,
4475                                                  scratch_pool);
4476         }
4477
4478       if (explicit_rangelist->nelts == 0)
4479         {
4480           child->remaining_ranges =
4481             apr_array_make(result_pool, 0, sizeof(svn_merge_range_t *));
4482         }
4483       else
4484 /* ### TODO:  Which evil shall we choose?
4485    ###
4486    ### If we allow all forward-merges not already found in recorded
4487    ### mergeinfo, we destroy the ability to, say, merge the whole of a
4488    ### branch to the trunk while automatically ignoring the revisions
4489    ### common to both.  That's bad.
4490    ###
4491    ### If we allow only forward-merges not found in either recorded
4492    ### mergeinfo or implicit mergeinfo (natural history), then the
4493    ### previous scenario works great, but we can't reverse-merge a
4494    ### previous change made to our line of history and then remake it
4495    ### (because the reverse-merge will leave no mergeinfo trace, and
4496    ### the remake-it attempt will still find the original change in
4497    ### natural mergeinfo.  But you know, that we happen to use 'merge'
4498    ### for revision undoing is somewhat unnatural anyway, so I'm
4499    ### finding myself having little interest in caring too much about
4500    ### this.  That said, if we had a way of storing reverse merge
4501    ### ranges, we'd be in good shape either way.
4502 */
4503 #ifdef SVN_MERGE__ALLOW_ALL_FORWARD_MERGES_FROM_SELF
4504         {
4505           /* ### Don't consider implicit mergeinfo. */
4506           child->remaining_ranges = svn_rangelist_dup(explicit_rangelist,
4507                                                       pool);
4508         }
4509 #else
4510         {
4511           /* Based on CHILD's TARGET_MERGEINFO there are ranges to merge.
4512              Check CHILD's implicit mergeinfo to see if these remaining
4513              ranges are represented there. */
4514           SVN_ERR(ensure_implicit_mergeinfo(parent,
4515                                             child,
4516                                             child_inherits_implicit,
4517                                             revision1,
4518                                             revision2,
4519                                             ra_session,
4520                                             ctx,
4521                                             result_pool,
4522                                             scratch_pool));
4523
4524           target_implicit_rangelist = svn_hash_gets(child->implicit_mergeinfo,
4525                                                     mergeinfo_path);
4526           if (target_implicit_rangelist)
4527             SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges),
4528                                          target_implicit_rangelist,
4529                                          explicit_rangelist,
4530                                          FALSE, result_pool));
4531           else
4532             child->remaining_ranges = svn_rangelist_dup(explicit_rangelist,
4533                                                         result_pool);
4534         }
4535 #endif
4536     }
4537
4538   return SVN_NO_ERROR;
4539 }
4540
4541 /* Helper for do_file_merge and do_directory_merge (by way of
4542    populate_remaining_ranges() for the latter).
4543
4544    Determine what portions of SOURCE have already
4545    been merged to CHILD->ABSPATH and populate CHILD->REMAINING_RANGES with
4546    the ranges that still need merging.
4547
4548    SOURCE and CTX are all cascaded from the caller's arguments of the same
4549    names.  Note that this means SOURCE adheres to the requirements noted in
4550    `MERGEINFO MERGE SOURCE NORMALIZATION'.
4551
4552    CHILD represents a working copy path which is the merge target or one of
4553    the target's subtrees.  If not NULL, PARENT is CHILD's nearest path-wise
4554    ancestor - see 'THE CHILDREN_WITH_MERGEINFO ARRAY'.  TARGET_MERGEINFO is
4555    the working mergeinfo on CHILD.
4556
4557    RA_SESSION is the session for the younger of SOURCE->loc1 and
4558    SOURCE->loc2.
4559
4560    If the function needs to consider CHILD->IMPLICIT_MERGEINFO and
4561    CHILD_INHERITS_IMPLICIT is true, then set CHILD->IMPLICIT_MERGEINFO to the
4562    mergeinfo inherited from PARENT->IMPLICIT_MERGEINFO.  Otherwise contact
4563    the repository for CHILD->IMPLICIT_MERGEINFO.
4564
4565    If not null, IMPLICIT_SRC_GAP is the gap, if any, in the natural history
4566    of SOURCE, see merge_cmd_baton_t.implicit_src_gap.
4567
4568    SCRATCH_POOL is used for all temporary allocations.  Changes to CHILD and
4569    PARENT are made in RESULT_POOL.
4570
4571    NOTE: This should only be called when honoring mergeinfo.
4572
4573    NOTE: If PARENT is present then this function must have previously been
4574    called for PARENT, i.e. if populate_remaining_ranges() is calling this
4575    function for a set of svn_client__merge_path_t* the calls must be made
4576    in depth-first order.
4577
4578    NOTE: When performing reverse merges, return
4579    SVN_ERR_CLIENT_NOT_READY_TO_MERGE if both locations in SOURCE and
4580    CHILD->ABSPATH are all on the same line of history but CHILD->ABSPATH's
4581    base revision is older than the SOURCE->rev1:rev2 range, see comment re
4582    issue #2973 below.
4583 */
4584 static svn_error_t *
4585 calculate_remaining_ranges(svn_client__merge_path_t *parent,
4586                            svn_client__merge_path_t *child,
4587                            const merge_source_t *source,
4588                            svn_mergeinfo_t target_mergeinfo,
4589                            const apr_array_header_t *implicit_src_gap,
4590                            svn_boolean_t child_inherits_implicit,
4591                            svn_ra_session_t *ra_session,
4592                            svn_client_ctx_t *ctx,
4593                            apr_pool_t *result_pool,
4594                            apr_pool_t *scratch_pool)
4595 {
4596   const svn_client__pathrev_t *primary_src
4597     = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1;
4598   const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src,
4599                                                           scratch_pool);
4600   /* Intersection of TARGET_MERGEINFO and the merge history
4601      described by SOURCE. */
4602   svn_rangelist_t *target_rangelist;
4603   svn_revnum_t child_base_revision;
4604
4605   /* Since this function should only be called when honoring mergeinfo and
4606    * SOURCE adheres to the requirements noted in 'MERGEINFO MERGE SOURCE
4607    * NORMALIZATION', SOURCE must be 'ancestral'. */
4608   SVN_ERR_ASSERT(source->ancestral);
4609
4610   /* Determine which of the requested ranges to consider merging... */
4611
4612   /* Set TARGET_RANGELIST to the portion of TARGET_MERGEINFO that refers
4613      to SOURCE (excluding any gap in SOURCE): first get all ranges from
4614      TARGET_MERGEINFO that refer to the path of SOURCE, and then prune
4615      any ranges that lie in the gap in SOURCE.
4616
4617      ### [JAF] In fact, that may still leave some ranges that lie entirely
4618      outside the range of SOURCE; it seems we don't care about that.  */
4619   if (target_mergeinfo)
4620     target_rangelist = svn_hash_gets(target_mergeinfo, mergeinfo_path);
4621   else
4622     target_rangelist = NULL;
4623   if (implicit_src_gap && target_rangelist)
4624     {
4625       /* Remove any mergeinfo referring to the 'gap' in SOURCE, as that
4626          mergeinfo doesn't really refer to SOURCE at all but instead
4627          refers to locations that are non-existent or on a different
4628          line of history.  (Issue #3242.) */
4629       SVN_ERR(svn_rangelist_remove(&target_rangelist,
4630                                    implicit_src_gap, target_rangelist,
4631                                    FALSE, result_pool));
4632     }
4633
4634   /* Initialize CHILD->REMAINING_RANGES and filter out revisions already
4635      merged (or, in the case of reverse merges, ranges not yet merged). */
4636   SVN_ERR(filter_merged_revisions(parent, child, mergeinfo_path,
4637                                   target_rangelist,
4638                                   source->loc1->rev, source->loc2->rev,
4639                                   child_inherits_implicit,
4640                                   ra_session, ctx, result_pool,
4641                                   scratch_pool));
4642
4643   /* Issue #2973 -- from the continuing series of "Why, since the advent of
4644      merge tracking, allowing merges into mixed rev and locally modified
4645      working copies isn't simple and could be considered downright evil".
4646
4647      If reverse merging a range to the WC path represented by CHILD, from
4648      that path's own history, where the path inherits no locally modified
4649      mergeinfo from its WC parents (i.e. there is no uncommitted merge to
4650      the WC), and the path's base revision is older than the range, then
4651      the merge will always be a no-op.  This is because we only allow reverse
4652      merges of ranges in the path's explicit or natural mergeinfo and a
4653      reverse merge from the path's future history obviously isn't going to be
4654      in either, hence the no-op.
4655
4656      The problem is two-fold.  First, in a mixed rev WC, the change we
4657      want to revert might actually be to some child of the target path
4658      which is at a younger base revision.  Sure, we can merge directly
4659      to that child or update the WC or even use --ignore-ancestry and then
4660      successfully run the reverse merge, but that gets to the second
4661      problem: Those courses of action are not very obvious.  Before 1.5 if
4662      a user committed a change that didn't touch the commit target, then
4663      immediately decided to revert that change via a reverse merge it would
4664      just DTRT.  But with the advent of merge tracking the user gets a no-op.
4665
4666      So in the name of user friendliness, return an error suggesting a helpful
4667      course of action.
4668   */
4669   SVN_ERR(svn_wc__node_get_base(NULL, &child_base_revision,
4670                                 NULL, NULL, NULL, NULL,
4671                                 ctx->wc_ctx, child->abspath,
4672                                 TRUE /* ignore_enoent */,
4673                                 FALSE /* show_hidden */,
4674                                 scratch_pool, scratch_pool));
4675   /* If CHILD has no base revision then it hasn't been committed yet, so it
4676      can't have any "future" history. */
4677   if (SVN_IS_VALID_REVNUM(child_base_revision)
4678       && ((child->remaining_ranges)->nelts == 0) /* Inoperative merge */
4679       && (source->loc2->rev < source->loc1->rev)     /* Reverse merge */
4680       && (child_base_revision <= source->loc2->rev))  /* From CHILD's future */
4681     {
4682       /* Hmmm, an inoperative reverse merge from the "future".  If it is
4683          from our own future return a helpful error. */
4684       svn_error_t *err;
4685       svn_client__pathrev_t *start_loc;
4686
4687       err = svn_client__repos_location(&start_loc,
4688                                        ra_session,
4689                                        source->loc1,
4690                                        child_base_revision,
4691                                        ctx, scratch_pool, scratch_pool);
4692       if (err)
4693         {
4694           if (err->apr_err == SVN_ERR_FS_NOT_FOUND
4695               || err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES)
4696             svn_error_clear(err);
4697           else
4698             return svn_error_trace(err);
4699         }
4700       else
4701         {
4702           const char *url;
4703
4704           SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child->abspath,
4705                                        scratch_pool, scratch_pool));
4706           if (strcmp(start_loc->url, url) == 0)
4707             return svn_error_create(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL,
4708                                     _("Cannot reverse-merge a range from a "
4709                                       "path's own future history; try "
4710                                       "updating first"));
4711         }
4712     }
4713
4714   return SVN_NO_ERROR;
4715 }
4716
4717 /* Helper for populate_remaining_ranges().
4718
4719    SOURCE is cascaded from the arguments of the same name in
4720    populate_remaining_ranges().
4721
4722    Note: The following comments assume a forward merge, i.e.
4723    SOURCE->loc1->rev < SOURCE->loc2->rev.  If this is a reverse merge then
4724    all the following comments still apply, but with SOURCE->loc1 switched
4725    with SOURCE->loc2.
4726
4727    Like populate_remaining_ranges(), SOURCE must adhere to the restrictions
4728    documented in 'MERGEINFO MERGE SOURCE NORMALIZATION'.  These restrictions
4729    allow for a *single* gap in SOURCE, GAP_REV1:GAP_REV2 exclusive:inclusive
4730    (where SOURCE->loc1->rev == GAP_REV1 <= GAP_REV2 < SOURCE->loc2->rev),
4731    if SOURCE->loc2->url@(GAP_REV2+1) was copied from SOURCE->loc1.  If such
4732    a gap exists, set *GAP_START and *GAP_END to the starting and ending
4733    revisions of the gap.  Otherwise set both to SVN_INVALID_REVNUM.
4734
4735    For example, if the natural history of URL@2:URL@9 is 'trunk/:2,7-9' this
4736    would indicate that trunk@7 was copied from trunk@2.  This function would
4737    return GAP_START:GAP_END of 2:6 in this case.  Note that a path 'trunk'
4738    might exist at r3-6, but it would not be on the same line of history as
4739    trunk@9.
4740
4741    ### GAP_START is basically redundant, as (if there is a gap at all) it is
4742    necessarily the older revision of SOURCE.
4743
4744    RA_SESSION is an open RA session to the repository in which SOURCE lives.
4745 */
4746 static svn_error_t *
4747 find_gaps_in_merge_source_history(svn_revnum_t *gap_start,
4748                                   svn_revnum_t *gap_end,
4749                                   const merge_source_t *source,
4750                                   svn_ra_session_t *ra_session,
4751                                   svn_client_ctx_t *ctx,
4752                                   apr_pool_t *scratch_pool)
4753 {
4754   svn_mergeinfo_t implicit_src_mergeinfo;
4755   svn_revnum_t old_rev = MIN(source->loc1->rev, source->loc2->rev);
4756   const svn_client__pathrev_t *primary_src
4757     = (source->loc1->rev < source->loc2->rev) ? source->loc2 : source->loc1;
4758   const char *merge_src_fspath = svn_client__pathrev_fspath(primary_src,
4759                                                             scratch_pool);
4760   svn_rangelist_t *rangelist;
4761
4762   SVN_ERR_ASSERT(source->ancestral);
4763
4764   /* Start by assuming there is no gap. */
4765   *gap_start = *gap_end = SVN_INVALID_REVNUM;
4766
4767   /* Easy out: There can't be a gap between adjacent revisions. */
4768   if (abs(source->loc1->rev - source->loc2->rev) == 1)
4769     return SVN_NO_ERROR;
4770
4771   /* Get SOURCE as mergeinfo. */
4772   SVN_ERR(svn_client__get_history_as_mergeinfo(&implicit_src_mergeinfo, NULL,
4773                                                primary_src,
4774                                                primary_src->rev, old_rev,
4775                                                ra_session,
4776                                                ctx, scratch_pool));
4777
4778   rangelist = svn_hash_gets(implicit_src_mergeinfo, merge_src_fspath);
4779
4780   if (!rangelist) /* ### Can we ever not find a rangelist? */
4781     return SVN_NO_ERROR;
4782
4783   /* A gap in natural history can result from either a copy or
4784      a rename.  If from a copy then history as mergeinfo will look
4785      something like this:
4786
4787        '/trunk:X,Y-Z'
4788
4789      If from a rename it will look like this:
4790
4791        '/trunk_old_name:X'
4792        '/trunk_new_name:Y-Z'
4793
4794     In both cases the gap, if it exists, is M-N, where M = X + 1 and
4795     N = Y - 1.
4796
4797     Note that per the rules of 'MERGEINFO MERGE SOURCE NORMALIZATION' we
4798     should never have multiple gaps, e.g. if we see anything like the
4799     following then something is quite wrong:
4800
4801         '/trunk_old_name:A,B-C'
4802         '/trunk_new_name:D-E'
4803   */
4804
4805   if (rangelist->nelts > 1) /* Copy */
4806     {
4807       const svn_merge_range_t *gap;
4808       /* As mentioned above, multiple gaps *shouldn't* be possible. */
4809       SVN_ERR_ASSERT(apr_hash_count(implicit_src_mergeinfo) == 1);
4810
4811       gap = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1,
4812                           const svn_merge_range_t *);
4813
4814       *gap_start = MIN(source->loc1->rev, source->loc2->rev);
4815       *gap_end = gap->start;
4816
4817       /* ### Issue #4132:
4818          ### This assertion triggers in merge_tests.py svnmucc_abuse_1()
4819          ### when a node is replaced by an older copy of itself.
4820
4821          BH: I think we should review this and the 'rename' case to find
4822              out which behavior we really want, and if we can really
4823              determine what happened this way. */
4824       SVN_ERR_ASSERT(*gap_start < *gap_end);
4825     }
4826   else if (apr_hash_count(implicit_src_mergeinfo) > 1) /* Rename */
4827     {
4828       svn_rangelist_t *requested_rangelist =
4829         svn_rangelist__initialize(MIN(source->loc1->rev, source->loc2->rev),
4830                                   MAX(source->loc1->rev, source->loc2->rev),
4831                                   TRUE, scratch_pool);
4832       svn_rangelist_t *implicit_rangelist =
4833         apr_array_make(scratch_pool, 2, sizeof(svn_merge_range_t *));
4834       svn_rangelist_t *gap_rangelist;
4835
4836       SVN_ERR(svn_rangelist__merge_many(implicit_rangelist,
4837                                         implicit_src_mergeinfo,
4838                                         scratch_pool, scratch_pool));
4839       SVN_ERR(svn_rangelist_remove(&gap_rangelist, implicit_rangelist,
4840                                    requested_rangelist, FALSE,
4841                                    scratch_pool));
4842
4843       /* If there is anything left it is the gap. */
4844       if (gap_rangelist->nelts)
4845         {
4846           svn_merge_range_t *gap_range =
4847             APR_ARRAY_IDX(gap_rangelist, 0, svn_merge_range_t *);
4848
4849           *gap_start = gap_range->start;
4850           *gap_end = gap_range->end;
4851         }
4852     }
4853
4854   SVN_ERR_ASSERT(*gap_start == MIN(source->loc1->rev, source->loc2->rev)
4855                  || (*gap_start == SVN_INVALID_REVNUM
4856                      && *gap_end == SVN_INVALID_REVNUM));
4857   return SVN_NO_ERROR;
4858 }
4859
4860 /* Helper for do_directory_merge().
4861
4862    For each (svn_client__merge_path_t *) child in CHILDREN_WITH_MERGEINFO,
4863    populate that child's 'remaining_ranges' list with (### ... what?),
4864    and populate that child's 'implicit_mergeinfo' with its implicit
4865    mergeinfo (natural history).  CHILDREN_WITH_MERGEINFO is expected
4866    to be sorted in depth first order and each child must be processed in
4867    that order.  The inheritability of all calculated ranges is TRUE.
4868
4869    If mergeinfo is being honored (based on MERGE_B -- see HONOR_MERGEINFO()
4870    for how this is determined), this function will actually try to be
4871    intelligent about populating remaining_ranges list.  Otherwise, it
4872    will claim that each child has a single remaining range, from
4873    SOURCE->rev1, to SOURCE->rev2.
4874    ### We also take the short-cut if doing record-only.  Why?
4875
4876    SCRATCH_POOL is used for all temporary allocations.  Changes to
4877    CHILDREN_WITH_MERGEINFO are made in RESULT_POOL.
4878
4879    Note that if SOURCE->rev1 > SOURCE->rev2, then each child's remaining_ranges
4880    member does not adhere to the API rules for rangelists described in
4881    svn_mergeinfo.h -- See svn_client__merge_path_t.
4882
4883    See `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements
4884    around SOURCE.
4885 */
4886 static svn_error_t *
4887 populate_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
4888                           const merge_source_t *source,
4889                           svn_ra_session_t *ra_session,
4890                           merge_cmd_baton_t *merge_b,
4891                           apr_pool_t *result_pool,
4892                           apr_pool_t *scratch_pool)
4893 {
4894   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
4895   int i;
4896   svn_revnum_t gap_start, gap_end;
4897
4898   /* If we aren't honoring mergeinfo or this is a --record-only merge,
4899      we'll make quick work of this by simply adding dummy SOURCE->rev1:rev2
4900      ranges for all children. */
4901   if (! HONOR_MERGEINFO(merge_b) || merge_b->record_only)
4902     {
4903       for (i = 0; i < children_with_mergeinfo->nelts; i++)
4904         {
4905           svn_client__merge_path_t *child =
4906             APR_ARRAY_IDX(children_with_mergeinfo, i,
4907                           svn_client__merge_path_t *);
4908
4909           svn_pool_clear(iterpool);
4910
4911           /* Issue #3646 'record-only merges create self-referential
4912              mergeinfo'.  Get the merge target's implicit mergeinfo (natural
4913              history).  We'll use it later to avoid setting self-referential
4914              mergeinfo -- see filter_natural_history_from_mergeinfo(). */
4915           if (i == 0) /* First item is always the merge target. */
4916             {
4917               SVN_ERR(get_full_mergeinfo(NULL, /* child->pre_merge_mergeinfo */
4918                                          &(child->implicit_mergeinfo),
4919                                          NULL, /* child->inherited_mergeinfo */
4920                                          svn_mergeinfo_inherited, ra_session,
4921                                          child->abspath,
4922                                          MAX(source->loc1->rev,
4923                                              source->loc2->rev),
4924                                          MIN(source->loc1->rev,
4925                                              source->loc2->rev),
4926                                          merge_b->ctx, result_pool,
4927                                          iterpool));
4928             }
4929           else
4930             {
4931               /* Issue #3443 - Subtrees of the merge target can inherit
4932                  their parent's implicit mergeinfo in most cases. */
4933               svn_client__merge_path_t *parent
4934                 = find_nearest_ancestor(children_with_mergeinfo,
4935                                         FALSE, child->abspath);
4936               svn_boolean_t child_inherits_implicit;
4937
4938               /* If CHILD is a subtree then its parent must be in
4939                  CHILDREN_WITH_MERGEINFO, see the global comment
4940                  'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
4941               SVN_ERR_ASSERT(parent);
4942
4943               child_inherits_implicit = (parent && !child->switched);
4944               SVN_ERR(ensure_implicit_mergeinfo(parent, child,
4945                                                 child_inherits_implicit,
4946                                                 source->loc1->rev,
4947                                                 source->loc2->rev,
4948                                                 ra_session, merge_b->ctx,
4949                                                 result_pool, iterpool));
4950             }
4951
4952           child->remaining_ranges = svn_rangelist__initialize(source->loc1->rev,
4953                                                               source->loc2->rev,
4954                                                               TRUE,
4955                                                               result_pool);
4956         }
4957       svn_pool_destroy(iterpool);
4958       return SVN_NO_ERROR;
4959     }
4960
4961   /* If, in the merge source's history, there was a copy from an older
4962      revision, then SOURCE->loc2->url won't exist at some range M:N, where
4963      SOURCE->loc1->rev < M < N < SOURCE->loc2->rev. The rules of 'MERGEINFO
4964      MERGE SOURCE NORMALIZATION' allow this, but we must ignore these gaps
4965      when calculating what ranges remain to be merged from SOURCE. If we
4966      don't and try to merge any part of SOURCE->loc2->url@M:N we would
4967      break the editor since no part of that actually exists.  See
4968      http://svn.haxx.se/dev/archive-2008-11/0618.shtml.
4969
4970      Find the gaps in the merge target's history, if any.  Eventually
4971      we will adjust CHILD->REMAINING_RANGES such that we don't describe
4972      non-existent paths to the editor. */
4973   SVN_ERR(find_gaps_in_merge_source_history(&gap_start, &gap_end,
4974                                             source,
4975                                             ra_session, merge_b->ctx,
4976                                             iterpool));
4977
4978   /* Stash any gap in the merge command baton, we'll need it later when
4979      recording mergeinfo describing this merge. */
4980   if (SVN_IS_VALID_REVNUM(gap_start) && SVN_IS_VALID_REVNUM(gap_end))
4981     merge_b->implicit_src_gap = svn_rangelist__initialize(gap_start, gap_end,
4982                                                           TRUE, result_pool);
4983
4984   for (i = 0; i < children_with_mergeinfo->nelts; i++)
4985     {
4986       svn_client__merge_path_t *child =
4987         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
4988       const char *child_repos_path
4989         = svn_dirent_skip_ancestor(merge_b->target->abspath, child->abspath);
4990       merge_source_t child_source;
4991       svn_client__merge_path_t *parent = NULL;
4992       svn_boolean_t child_inherits_implicit;
4993
4994       svn_pool_clear(iterpool);
4995
4996       /* If the path is absent don't do subtree merge either. */
4997       SVN_ERR_ASSERT(child);
4998       if (child->absent)
4999         continue;
5000
5001       SVN_ERR_ASSERT(child_repos_path != NULL);
5002       child_source.loc1 = svn_client__pathrev_join_relpath(
5003                             source->loc1, child_repos_path, iterpool);
5004       child_source.loc2 = svn_client__pathrev_join_relpath(
5005                             source->loc2, child_repos_path, iterpool);
5006       /* ### Is the child 'ancestral' over the same revision range?  It's
5007        * not necessarily true that a child is 'ancestral' if the parent is,
5008        * nor that it's not if the parent is not.  However, here we claim
5009        * that it is.  Before we had this 'ancestral' field that we need to
5010        * set explicitly, the claim was implicit.  Either way, the impact is
5011        * that we might pass calculate_remaining_ranges() a source that is
5012        * not in fact 'ancestral' (despite its 'ancestral' field being true),
5013        * contrary to its doc-string. */
5014       child_source.ancestral = source->ancestral;
5015
5016       /* Get the explicit/inherited mergeinfo for CHILD.  If CHILD is the
5017          merge target then also get its implicit mergeinfo.  Otherwise defer
5018          this until we know it is absolutely necessary, since it requires an
5019          expensive round trip communication with the server. */
5020       SVN_ERR(get_full_mergeinfo(
5021         child->pre_merge_mergeinfo ? NULL : &(child->pre_merge_mergeinfo),
5022         /* Get implicit only for merge target. */
5023         (i == 0) ? &(child->implicit_mergeinfo) : NULL,
5024         &(child->inherited_mergeinfo),
5025         svn_mergeinfo_inherited, ra_session,
5026         child->abspath,
5027         MAX(source->loc1->rev, source->loc2->rev),
5028         MIN(source->loc1->rev, source->loc2->rev),
5029         merge_b->ctx, result_pool, iterpool));
5030
5031       /* If CHILD isn't the merge target find its parent. */
5032       if (i > 0)
5033         {
5034           parent = find_nearest_ancestor(children_with_mergeinfo,
5035                                          FALSE, child->abspath);
5036           /* If CHILD is a subtree then its parent must be in
5037              CHILDREN_WITH_MERGEINFO, see the global comment
5038              'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
5039           SVN_ERR_ASSERT(parent);
5040         }
5041
5042       /* Issue #3443 - Can CHILD inherit PARENT's implicit mergeinfo, saving
5043          us from having to ask the repos?  The only time we can't do this is if
5044          CHILD is the merge target and so there is no PARENT to inherit from
5045          or if CHILD is the root of a switched subtree, in which case PARENT
5046          exists but is not CHILD's repository parent. */
5047       child_inherits_implicit = (parent && !child->switched);
5048
5049       SVN_ERR(calculate_remaining_ranges(parent, child,
5050                                          &child_source,
5051                                          child->pre_merge_mergeinfo,
5052                                          merge_b->implicit_src_gap,
5053                                          child_inherits_implicit,
5054                                          ra_session,
5055                                          merge_b->ctx, result_pool,
5056                                          iterpool));
5057
5058       /* Deal with any gap in SOURCE's natural history.
5059
5060          If the gap is a proper subset of CHILD->REMAINING_RANGES then we can
5061          safely ignore it since we won't describe this path/rev pair.
5062
5063          If the gap exactly matches or is a superset of a range in
5064          CHILD->REMAINING_RANGES then we must remove that range so we don't
5065          attempt to describe non-existent paths via the reporter, this will
5066          break the editor and our merge.
5067
5068          If the gap adjoins or overlaps a range in CHILD->REMAINING_RANGES
5069          then we must *add* the gap so we span the missing revisions. */
5070       if (child->remaining_ranges->nelts
5071           && merge_b->implicit_src_gap)
5072         {
5073           int j;
5074           svn_boolean_t proper_subset = FALSE;
5075           svn_boolean_t overlaps_or_adjoins = FALSE;
5076
5077           /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
5078               so it will work with the svn_rangelist_* APIs below. */
5079           if (source->loc1->rev > source->loc2->rev)
5080             SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
5081
5082           for (j = 0; j < child->remaining_ranges->nelts; j++)
5083             {
5084               svn_merge_range_t *range
5085                 = APR_ARRAY_IDX(child->remaining_ranges, j, svn_merge_range_t *);
5086
5087               if ((range->start <= gap_start && gap_end < range->end)
5088                   || (range->start < gap_start && gap_end <= range->end))
5089                 {
5090                   proper_subset = TRUE;
5091                   break;
5092                 }
5093               else if ((gap_start == range->start) && (range->end == gap_end))
5094                 {
5095                   break;
5096                 }
5097               else if (gap_start <= range->end && range->start <= gap_end)
5098                 /* intersect */
5099                 {
5100                   overlaps_or_adjoins = TRUE;
5101                   break;
5102                 }
5103             }
5104
5105           if (!proper_subset)
5106             {
5107               /* We need to make adjustments.  Remove from, or add the gap
5108                  to, CHILD->REMAINING_RANGES as appropriate. */
5109
5110               if (overlaps_or_adjoins)
5111                 SVN_ERR(svn_rangelist_merge2(child->remaining_ranges,
5112                                              merge_b->implicit_src_gap,
5113                                              result_pool, iterpool));
5114               else /* equals == TRUE */
5115                 SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges),
5116                                              merge_b->implicit_src_gap,
5117                                              child->remaining_ranges, FALSE,
5118                                              result_pool));
5119             }
5120
5121           if (source->loc1->rev > source->loc2->rev) /* Reverse merge */
5122             SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
5123         }
5124     }
5125
5126   svn_pool_destroy(iterpool);
5127   return SVN_NO_ERROR;
5128 }
5129
5130
5131 /*-----------------------------------------------------------------------*/
5132 \f
5133 /*** Other Helper Functions ***/
5134
5135 /* Calculate the new mergeinfo for the target tree rooted at TARGET_ABSPATH
5136    based on MERGES (a mapping of absolute WC paths to rangelists representing
5137    a merge from the source SOURCE_FSPATH).
5138
5139    If RESULT_CATALOG is NULL, then record the new mergeinfo in the WC (at,
5140    and possibly below, TARGET_ABSPATH).
5141
5142    If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the
5143    WC, but instead record it in RESULT_CATALOG, where the keys are absolute
5144    working copy paths and the values are the new mergeinfos for each.
5145    Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
5146    created in. */
5147 static svn_error_t *
5148 update_wc_mergeinfo(svn_mergeinfo_catalog_t result_catalog,
5149                     const char *target_abspath,
5150                     const char *source_fspath,
5151                     apr_hash_t *merges,
5152                     svn_boolean_t is_rollback,
5153                     svn_client_ctx_t *ctx,
5154                     apr_pool_t *scratch_pool)
5155 {
5156   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
5157   apr_hash_index_t *hi;
5158
5159   /* Combine the mergeinfo for the revision range just merged into
5160      the WC with its on-disk mergeinfo. */
5161   for (hi = apr_hash_first(scratch_pool, merges); hi; hi = apr_hash_next(hi))
5162     {
5163       const char *local_abspath = svn__apr_hash_index_key(hi);
5164       svn_rangelist_t *ranges = svn__apr_hash_index_val(hi);
5165       svn_rangelist_t *rangelist;
5166       svn_error_t *err;
5167       const char *local_abspath_rel_to_target;
5168       const char *fspath;
5169       svn_mergeinfo_t mergeinfo;
5170
5171       svn_pool_clear(iterpool);
5172
5173       /* As some of the merges may've changed the WC's mergeinfo, get
5174          a fresh copy before using it to update the WC's mergeinfo. */
5175       err = svn_client__parse_mergeinfo(&mergeinfo, ctx->wc_ctx,
5176                                         local_abspath, iterpool, iterpool);
5177
5178       /* If a directory PATH was skipped because it is missing or was
5179          obstructed by an unversioned item then there's nothing we can
5180          do with that, so skip it. */
5181       if (err)
5182         {
5183           if (err->apr_err == SVN_ERR_WC_NOT_LOCKED
5184               || err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
5185             {
5186               svn_error_clear(err);
5187               continue;
5188             }
5189           else
5190             {
5191               return svn_error_trace(err);
5192             }
5193         }
5194
5195       /* If we are attempting to set empty revision range override mergeinfo
5196          on a path with no explicit mergeinfo, we first need the
5197          mergeinfo that path inherits. */
5198       if (mergeinfo == NULL && ranges->nelts == 0)
5199         {
5200           SVN_ERR(svn_client__get_wc_mergeinfo(&mergeinfo, NULL,
5201                                                svn_mergeinfo_nearest_ancestor,
5202                                                local_abspath, NULL, NULL,
5203                                                FALSE, ctx, iterpool, iterpool));
5204         }
5205
5206       if (mergeinfo == NULL)
5207         mergeinfo = apr_hash_make(iterpool);
5208
5209       local_abspath_rel_to_target = svn_dirent_skip_ancestor(target_abspath,
5210                                                              local_abspath);
5211       SVN_ERR_ASSERT(local_abspath_rel_to_target != NULL);
5212       fspath = svn_fspath__join(source_fspath,
5213                                 local_abspath_rel_to_target,
5214                                 iterpool);
5215       rangelist = svn_hash_gets(mergeinfo, fspath);
5216       if (rangelist == NULL)
5217         rangelist = apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *));
5218
5219       if (is_rollback)
5220         {
5221           ranges = svn_rangelist_dup(ranges, iterpool);
5222           SVN_ERR(svn_rangelist_reverse(ranges, iterpool));
5223           SVN_ERR(svn_rangelist_remove(&rangelist, ranges, rangelist,
5224                                        FALSE,
5225                                        iterpool));
5226         }
5227       else
5228         {
5229           SVN_ERR(svn_rangelist_merge2(rangelist, ranges, iterpool, iterpool));
5230         }
5231       /* Update the mergeinfo by adjusting the path's rangelist. */
5232       svn_hash_sets(mergeinfo, fspath, rangelist);
5233
5234       if (is_rollback && apr_hash_count(mergeinfo) == 0)
5235         mergeinfo = NULL;
5236
5237       svn_mergeinfo__remove_empty_rangelists(mergeinfo, scratch_pool);
5238
5239       if (result_catalog)
5240         {
5241           svn_mergeinfo_t existing_mergeinfo =
5242             svn_hash_gets(result_catalog, local_abspath);
5243           apr_pool_t *result_catalog_pool = apr_hash_pool_get(result_catalog);
5244
5245           if (existing_mergeinfo)
5246             SVN_ERR(svn_mergeinfo_merge2(mergeinfo, existing_mergeinfo,
5247                                          result_catalog_pool, scratch_pool));
5248           svn_hash_sets(result_catalog,
5249                         apr_pstrdup(result_catalog_pool, local_abspath),
5250                         svn_mergeinfo_dup(mergeinfo, result_catalog_pool));
5251         }
5252       else
5253         {
5254           err = svn_client__record_wc_mergeinfo(local_abspath, mergeinfo,
5255                                                 TRUE, ctx, iterpool);
5256
5257           if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
5258             {
5259               /* PATH isn't just missing, it's not even versioned as far
5260                  as this working copy knows.  But it was included in
5261                  MERGES, which means that the server knows about it.
5262                  Likely we don't have access to the source due to authz
5263                  restrictions.  For now just clear the error and
5264                  continue...
5265
5266                  ### TODO:  Set non-inheritable mergeinfo on PATH's immediate
5267                  ### parent and normal mergeinfo on PATH's siblings which we
5268                  ### do have access to. */
5269               svn_error_clear(err);
5270             }
5271           else
5272             SVN_ERR(err);
5273         }
5274     }
5275
5276   svn_pool_destroy(iterpool);
5277   return SVN_NO_ERROR;
5278 }
5279
5280 /* Helper for record_mergeinfo_for_dir_merge().
5281
5282    Record override mergeinfo on any paths skipped during a merge.
5283
5284    Set empty mergeinfo on each path in MERGE_B->SKIPPED_ABSPATHS so the path
5285    does not incorrectly inherit mergeinfo that will later be describing
5286    the merge.
5287
5288    MERGEINFO_PATH and MERGE_B are cascaded from
5289    arguments of the same name in the caller.
5290
5291    IS_ROLLBACK is true if the caller is recording a reverse merge and false
5292    otherwise.  RANGELIST is the set of revisions being merged from
5293    MERGEINFO_PATH to MERGE_B->target. */
5294 static svn_error_t *
5295 record_skips_in_mergeinfo(const char *mergeinfo_path,
5296                           const svn_rangelist_t *rangelist,
5297                           svn_boolean_t is_rollback,
5298                           merge_cmd_baton_t *merge_b,
5299                           apr_pool_t *scratch_pool)
5300 {
5301   apr_hash_index_t *hi;
5302   apr_hash_t *merges;
5303   apr_size_t nbr_skips = apr_hash_count(merge_b->skipped_abspaths);
5304   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
5305
5306   if (nbr_skips == 0)
5307     return SVN_NO_ERROR;
5308
5309   merges = apr_hash_make(scratch_pool);
5310
5311   /* Override the mergeinfo for child paths which weren't actually merged. */
5312   for (hi = apr_hash_first(scratch_pool, merge_b->skipped_abspaths); hi;
5313        hi = apr_hash_next(hi))
5314     {
5315       const char *skipped_abspath = svn__apr_hash_index_key(hi);
5316       svn_wc_notify_state_t obstruction_state;
5317
5318       svn_pool_clear(iterpool);
5319
5320       /* Before we override, make sure this is a versioned path, it might
5321          be an external or missing from disk due to authz restrictions. */
5322       SVN_ERR(perform_obstruction_check(&obstruction_state, NULL, NULL,
5323                                         NULL, NULL,
5324                                         merge_b, skipped_abspath,
5325                                         iterpool));
5326       if (obstruction_state == svn_wc_notify_state_obstructed
5327           || obstruction_state == svn_wc_notify_state_missing)
5328         continue;
5329
5330       /* Add an empty range list for this path.
5331
5332          ### TODO: This works fine for a file path skipped because it is
5333          ### missing as long as the file's parent directory is present.
5334          ### But missing directory paths skipped are not handled yet,
5335          ### see issue #2915.
5336
5337          ### TODO: An empty range is fine if the skipped path doesn't
5338          ### inherit any mergeinfo from a parent, but if it does
5339          ### we need to account for that.  See issue #3440
5340          ### http://subversion.tigris.org/issues/show_bug.cgi?id=3440. */
5341       svn_hash_sets(merges, skipped_abspath,
5342                     apr_array_make(scratch_pool, 0,
5343                                    sizeof(svn_merge_range_t *)));
5344
5345       /* if (nbr_skips < notify_b->nbr_notifications)
5346            ### Use RANGELIST as the mergeinfo for all children of
5347            ### this path which were not also explicitly
5348            ### skipped? */
5349     }
5350   SVN_ERR(update_wc_mergeinfo(NULL, merge_b->target->abspath,
5351                               mergeinfo_path, merges,
5352                               is_rollback, merge_b->ctx, iterpool));
5353   svn_pool_destroy(iterpool);
5354   return SVN_NO_ERROR;
5355 }
5356
5357 /* Data for reporting when a merge aborted because of raising conflicts.
5358  */
5359 typedef struct single_range_conflict_report_t
5360 {
5361   /* What sub-range of the requested source raised conflicts?
5362    * The 'inheritable' flag is ignored. */
5363   merge_source_t *conflicted_range;
5364   /* What sub-range of the requested source remains to be merged?
5365    * NULL if no more.  The 'inheritable' flag is ignored. */
5366   merge_source_t *remaining_source;
5367
5368 } single_range_conflict_report_t;
5369
5370 /* Create a single_range_conflict_report_t, containing deep copies of
5371  * CONFLICTED_RANGE and REMAINING_SOURCE, allocated in RESULT_POOL. */
5372 static single_range_conflict_report_t *
5373 single_range_conflict_report_create(const merge_source_t *conflicted_range,
5374                                     const merge_source_t *remaining_source,
5375                                     apr_pool_t *result_pool)
5376 {
5377   single_range_conflict_report_t *report
5378     = apr_palloc(result_pool, sizeof(*report));
5379
5380   assert(conflicted_range != NULL);
5381
5382   report->conflicted_range = merge_source_dup(conflicted_range, result_pool);
5383   report->remaining_source
5384     = remaining_source ? merge_source_dup(remaining_source, result_pool)
5385                        : NULL;
5386   return report;
5387 }
5388
5389 /* Data for reporting when a merge aborted because of raising conflicts.
5390  *
5391  * ### TODO: More info, including the ranges (or other parameters) the user
5392  *     needs to complete the merge.
5393  */
5394 typedef struct conflict_report_t
5395 {
5396   const char *target_abspath;
5397   /* The revision range during which conflicts were raised */
5398   const merge_source_t *conflicted_range;
5399   /* Was the conflicted range the last range in the whole requested merge? */
5400   svn_boolean_t was_last_range;
5401 } conflict_report_t;
5402
5403 /* Return a new conflict_report_t containing deep copies of the parameters,
5404  * allocated in RESULT_POOL. */
5405 static conflict_report_t *
5406 conflict_report_create(const char *target_abspath,
5407                        const merge_source_t *conflicted_range,
5408                        svn_boolean_t was_last_range,
5409                        apr_pool_t *result_pool)
5410 {
5411   conflict_report_t *report = apr_palloc(result_pool, sizeof(*report));
5412
5413   report->target_abspath = apr_pstrdup(result_pool, target_abspath);
5414   report->conflicted_range = merge_source_dup(conflicted_range, result_pool);
5415   report->was_last_range = was_last_range;
5416   return report;
5417 }
5418
5419 /* Return a deep copy of REPORT, allocated in RESULT_POOL. */
5420 static conflict_report_t *
5421 conflict_report_dup(const conflict_report_t *report,
5422                     apr_pool_t *result_pool)
5423 {
5424   conflict_report_t *new = apr_pmemdup(result_pool, report, sizeof(*new));
5425
5426   new->target_abspath = apr_pstrdup(result_pool, report->target_abspath);
5427   new->conflicted_range = merge_source_dup(report->conflicted_range,
5428                                            result_pool);
5429   return new;
5430 }
5431
5432 /* Create and return an error structure appropriate for the unmerged
5433    revisions range(s). */
5434 static APR_INLINE svn_error_t *
5435 make_merge_conflict_error(conflict_report_t *report,
5436                           apr_pool_t *scratch_pool)
5437 {
5438   assert(!report || svn_dirent_is_absolute(report->target_abspath));
5439
5440   if (report && ! report->was_last_range)
5441     {
5442       svn_error_t *err = svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL,
5443        _("One or more conflicts were produced while merging r%ld:%ld into\n"
5444          "'%s' --\n"
5445          "resolve all conflicts and rerun the merge to apply the remaining\n"
5446          "unmerged revisions"),
5447        report->conflicted_range->loc1->rev, report->conflicted_range->loc2->rev,
5448        svn_dirent_local_style(report->target_abspath, scratch_pool));
5449       assert(report->conflicted_range->loc1->rev != report->conflicted_range->loc2->rev); /* ### is a valid case in a 2-URL merge */
5450       return err;
5451     }
5452   return SVN_NO_ERROR;
5453 }
5454
5455 /* Helper for do_directory_merge().
5456
5457    TARGET_WCPATH is a directory and CHILDREN_WITH_MERGEINFO is filled
5458    with paths (svn_client__merge_path_t *) arranged in depth first order,
5459    which have mergeinfo set on them or meet one of the other criteria
5460    defined in get_mergeinfo_paths().  Remove any paths absent from disk
5461    or scheduled for deletion from CHILDREN_WITH_MERGEINFO which are equal to
5462    or are descendants of TARGET_WCPATH by setting those children to NULL. */
5463 static void
5464 remove_absent_children(const char *target_wcpath,
5465                        apr_array_header_t *children_with_mergeinfo)
5466 {
5467   /* Before we try to override mergeinfo for skipped paths, make sure
5468      the path isn't absent due to authz restrictions, because there's
5469      nothing we can do about those. */
5470   int i;
5471   for (i = 0; i < children_with_mergeinfo->nelts; i++)
5472     {
5473       svn_client__merge_path_t *child =
5474         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
5475       if ((child->absent || child->scheduled_for_deletion)
5476           && svn_dirent_is_ancestor(target_wcpath, child->abspath))
5477         {
5478           svn_sort__array_delete(children_with_mergeinfo, i--, 1);
5479         }
5480     }
5481 }
5482
5483 /* Helper for do_directory_merge() to handle the case where a merge editor
5484    drive removes explicit mergeinfo from a subtree of the merge target.
5485
5486    MERGE_B is cascaded from the argument of the same name in
5487    do_directory_merge().  For each path (if any) in
5488    MERGE_B->PATHS_WITH_DELETED_MERGEINFO remove that path from
5489    CHILDREN_WITH_MERGEINFO.
5490
5491    The one exception is for the merge target itself,
5492    MERGE_B->target->abspath, this must always be present in
5493    CHILDREN_WITH_MERGEINFO so this is never removed by this
5494    function. */
5495 static void
5496 remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b,
5497                                        apr_array_header_t *children_with_mergeinfo)
5498 {
5499   int i;
5500
5501   if (!merge_b->paths_with_deleted_mergeinfo)
5502     return;
5503
5504   /* CHILDREN_WITH_MERGEINFO[0] is the always the merge target
5505      so start at the first child. */
5506   for (i = 1; i < children_with_mergeinfo->nelts; i++)
5507     {
5508       svn_client__merge_path_t *child =
5509         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
5510
5511       if (svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, child->abspath))
5512         {
5513           svn_sort__array_delete(children_with_mergeinfo, i--, 1);
5514         }
5515     }
5516 }
5517
5518 /* Helper for do_directory_merge().
5519
5520    Set up the diff editor report to merge the SOURCE diff
5521    into TARGET_ABSPATH and drive it.
5522
5523    If mergeinfo is not being honored (based on MERGE_B -- see the doc
5524    string for HONOR_MERGEINFO() for how this is determined), then ignore
5525    CHILDREN_WITH_MERGEINFO and merge the SOURCE diff to TARGET_ABSPATH.
5526
5527    If mergeinfo is being honored then perform a history-aware merge,
5528    describing TARGET_ABSPATH and its subtrees to the reporter in such as way
5529    as to avoid repeating merges already performed per the mergeinfo and
5530    natural history of TARGET_ABSPATH and its subtrees.
5531
5532    The ranges that still need to be merged to the TARGET_ABSPATH and its
5533    subtrees are described in CHILDREN_WITH_MERGEINFO, an array of
5534    svn_client__merge_path_t * -- see 'THE CHILDREN_WITH_MERGEINFO ARRAY'
5535    comment at the top of this file for more info.  Note that it is possible
5536    TARGET_ABSPATH and/or some of its subtrees need only a subset, or no part,
5537    of SOURCE to be merged.  Though there is little point to
5538    calling this function if TARGET_ABSPATH and all its subtrees have already
5539    had SOURCE merged, this will work but is a no-op.
5540
5541    SOURCE->rev1 and SOURCE->rev2 must be bound by the set of remaining_ranges
5542    fields in CHILDREN_WITH_MERGEINFO's elements, specifically:
5543
5544    For forward merges (SOURCE->rev1 < SOURCE->rev2):
5545
5546      1) The first svn_merge_range_t * element of each child's remaining_ranges
5547         array must meet one of the following conditions:
5548
5549         a) The range's start field is greater than or equal to SOURCE->rev2.
5550
5551         b) The range's end field is SOURCE->rev2.
5552
5553      2) Among all the ranges that meet condition 'b' the oldest start
5554         revision must equal SOURCE->rev1.
5555
5556    For reverse merges (SOURCE->rev1 > SOURCE->rev2):
5557
5558      1) The first svn_merge_range_t * element of each child's remaining_ranges
5559         array must meet one of the following conditions:
5560
5561         a) The range's start field is less than or equal to SOURCE->rev2.
5562
5563         b) The range's end field is SOURCE->rev2.
5564
5565      2) Among all the ranges that meet condition 'b' the youngest start
5566         revision must equal SOURCE->rev1.
5567
5568    Note: If the first svn_merge_range_t * element of some subtree child's
5569    remaining_ranges array is the same as the first range of that child's
5570    nearest path-wise ancestor, then the subtree child *will not* be described
5571    to the reporter.
5572
5573    DEPTH, NOTIFY_B, and MERGE_B are cascaded from do_directory_merge(), see
5574    that function for more info.
5575
5576    MERGE_B->ra_session1 and MERGE_B->ra_session2 are RA sessions open to any
5577    URL in the repository of SOURCE; they may be temporarily reparented within
5578    this function.
5579
5580    If SOURCE->ancestral is set, then SOURCE->loc1 must be a
5581    historical ancestor of SOURCE->loc2, or vice-versa (see
5582    `MERGEINFO MERGE SOURCE NORMALIZATION' for more requirements around
5583    SOURCE in this case).
5584 */
5585 static svn_error_t *
5586 drive_merge_report_editor(const char *target_abspath,
5587                           const merge_source_t *source,
5588                           const apr_array_header_t *children_with_mergeinfo,
5589                           const svn_diff_tree_processor_t *processor,
5590                           svn_depth_t depth,
5591                           merge_cmd_baton_t *merge_b,
5592                           apr_pool_t *scratch_pool)
5593 {
5594   const svn_ra_reporter3_t *reporter;
5595   const svn_delta_editor_t *diff_editor;
5596   void *diff_edit_baton;
5597   void *report_baton;
5598   svn_revnum_t target_start;
5599   svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b);
5600   const char *old_sess1_url, *old_sess2_url;
5601   svn_boolean_t is_rollback = source->loc1->rev > source->loc2->rev;
5602
5603   /* Start with a safe default starting revision for the editor and the
5604      merge target. */
5605   target_start = source->loc1->rev;
5606
5607   /* If we are honoring mergeinfo the starting revision for the merge target
5608      might not be SOURCE->rev1, in fact the merge target might not need *any*
5609      part of SOURCE merged -- Instead some subtree of the target
5610      needs SOURCE -- So get the right starting revision for the
5611      target. */
5612   if (honor_mergeinfo)
5613     {
5614       svn_client__merge_path_t *child;
5615
5616       /* CHILDREN_WITH_MERGEINFO must always exist if we are honoring
5617          mergeinfo and must have at least one element (describing the
5618          merge target). */
5619       SVN_ERR_ASSERT(children_with_mergeinfo);
5620       SVN_ERR_ASSERT(children_with_mergeinfo->nelts);
5621
5622       /* Get the merge target's svn_client__merge_path_t, which is always
5623          the first in the array due to depth first sorting requirement,
5624          see 'THE CHILDREN_WITH_MERGEINFO ARRAY'. */
5625       child = APR_ARRAY_IDX(children_with_mergeinfo, 0,
5626                             svn_client__merge_path_t *);
5627       SVN_ERR_ASSERT(child);
5628       if (child->remaining_ranges->nelts == 0)
5629         {
5630           /* The merge target doesn't need anything merged. */
5631           target_start = source->loc2->rev;
5632         }
5633       else
5634         {
5635           /* The merge target has remaining revisions to merge.  These
5636              ranges may fully or partially overlap the range described
5637              by SOURCE->rev1:rev2 or may not intersect that range at
5638              all. */
5639           svn_merge_range_t *range =
5640             APR_ARRAY_IDX(child->remaining_ranges, 0,
5641                           svn_merge_range_t *);
5642           if ((!is_rollback && range->start > source->loc2->rev)
5643               || (is_rollback && range->start < source->loc2->rev))
5644             {
5645               /* Merge target's first remaining range doesn't intersect. */
5646               target_start = source->loc2->rev;
5647             }
5648           else
5649             {
5650               /* Merge target's first remaining range partially or
5651                  fully overlaps. */
5652               target_start = range->start;
5653             }
5654         }
5655     }
5656
5657   SVN_ERR(svn_client__ensure_ra_session_url(&old_sess1_url,
5658                                             merge_b->ra_session1,
5659                                             source->loc1->url, scratch_pool));
5660   /* Temporarily point our second RA session to SOURCE->loc1->url, too.  We use
5661      this to request individual file contents. */
5662   SVN_ERR(svn_client__ensure_ra_session_url(&old_sess2_url,
5663                                             merge_b->ra_session2,
5664                                             source->loc1->url, scratch_pool));
5665
5666   /* Get the diff editor and a reporter with which to, ultimately,
5667      drive it. */
5668   SVN_ERR(svn_client__get_diff_editor2(&diff_editor, &diff_edit_baton,
5669                                        merge_b->ra_session2,
5670                                        depth,
5671                                        source->loc1->rev,
5672                                        TRUE /* text_deltas */,
5673                                        processor,
5674                                        merge_b->ctx->cancel_func,
5675                                        merge_b->ctx->cancel_baton,
5676                                        scratch_pool));
5677   SVN_ERR(svn_ra_do_diff3(merge_b->ra_session1,
5678                           &reporter, &report_baton, source->loc2->rev,
5679                           "", depth, merge_b->diff_ignore_ancestry,
5680                           TRUE,  /* text_deltas */
5681                           source->loc2->url, diff_editor, diff_edit_baton,
5682                           scratch_pool));
5683
5684   /* Drive the reporter. */
5685   SVN_ERR(reporter->set_path(report_baton, "", target_start, depth,
5686                              FALSE, NULL, scratch_pool));
5687   if (honor_mergeinfo && children_with_mergeinfo)
5688     {
5689       /* Describe children with mergeinfo overlapping this merge
5690          operation such that no repeated diff is retrieved for them from
5691          the repository. */
5692       int i;
5693       apr_pool_t *iterpool = svn_pool_create(scratch_pool);
5694
5695       /* Start with CHILDREN_WITH_MERGEINFO[1], CHILDREN_WITH_MERGEINFO[0]
5696          is always the merge target (TARGET_ABSPATH). */
5697       for (i = 1; i < children_with_mergeinfo->nelts; i++)
5698         {
5699           svn_merge_range_t *range;
5700           const char *child_repos_path;
5701           const svn_client__merge_path_t *parent;
5702           const svn_client__merge_path_t *child =
5703             APR_ARRAY_IDX(children_with_mergeinfo, i,
5704                           svn_client__merge_path_t *);
5705
5706           SVN_ERR_ASSERT(child);
5707           if (child->absent)
5708             continue;
5709
5710           svn_pool_clear(iterpool);
5711
5712           /* Find this child's nearest wc ancestor with mergeinfo. */
5713           parent = find_nearest_ancestor(children_with_mergeinfo,
5714                                          FALSE, child->abspath);
5715
5716           /* If a subtree needs the same range applied as its nearest parent
5717              with mergeinfo or neither the subtree nor this parent need
5718              SOURCE->rev1:rev2 merged, then we don't need to describe the
5719              subtree separately.  In the latter case this could break the
5720              editor if child->abspath didn't exist at SOURCE->rev2 and we
5721              attempt to describe it via a reporter set_path call. */
5722           if (child->remaining_ranges->nelts)
5723             {
5724               range = APR_ARRAY_IDX(child->remaining_ranges, 0,
5725                                     svn_merge_range_t *);
5726               if ((!is_rollback && range->start > source->loc2->rev)
5727                   || (is_rollback && range->start < source->loc2->rev))
5728                 {
5729                   /* This child's first remaining range comes after the range
5730                      we are currently merging, so skip it. We expect to get
5731                      to it in a subsequent call to this function. */
5732                   continue;
5733                 }
5734               else if (parent->remaining_ranges->nelts)
5735                 {
5736                    svn_merge_range_t *parent_range =
5737                     APR_ARRAY_IDX(parent->remaining_ranges, 0,
5738                                   svn_merge_range_t *);
5739                    svn_merge_range_t *child_range =
5740                     APR_ARRAY_IDX(child->remaining_ranges, 0,
5741                                   svn_merge_range_t *);
5742                   if (parent_range->start == child_range->start)
5743                     continue; /* Subtree needs same range as parent. */
5744                 }
5745             }
5746           else /* child->remaining_ranges->nelts == 0*/
5747             {
5748               /* If both the subtree and its parent need no ranges applied
5749                  consider that as the "same ranges" and don't describe
5750                  the subtree. */
5751               if (parent->remaining_ranges->nelts == 0)
5752                 continue;
5753             }
5754
5755           /* Ok, we really need to describe this subtree as it needs different
5756              ranges applied than its nearest working copy parent. */
5757           child_repos_path = svn_dirent_is_child(target_abspath,
5758                                                  child->abspath,
5759                                                  iterpool);
5760           /* This loop is only processing subtrees, so CHILD->ABSPATH
5761              better be a proper child of the merge target. */
5762           SVN_ERR_ASSERT(child_repos_path);
5763
5764           if ((child->remaining_ranges->nelts == 0)
5765               || (is_rollback && (range->start < source->loc2->rev))
5766               || (!is_rollback && (range->start > source->loc2->rev)))
5767             {
5768               /* Nothing to merge to this child.  We'll claim we have
5769                  it up to date so the server doesn't send us
5770                  anything. */
5771               SVN_ERR(reporter->set_path(report_baton, child_repos_path,
5772                                          source->loc2->rev, depth, FALSE,
5773                                          NULL, iterpool));
5774             }
5775           else
5776             {
5777               SVN_ERR(reporter->set_path(report_baton, child_repos_path,
5778                                          range->start, depth, FALSE,
5779                                          NULL, iterpool));
5780             }
5781         }
5782       svn_pool_destroy(iterpool);
5783     }
5784   SVN_ERR(reporter->finish_report(report_baton, scratch_pool));
5785
5786   /* Point the merge baton's RA sessions back where they were. */
5787   SVN_ERR(svn_ra_reparent(merge_b->ra_session1, old_sess1_url, scratch_pool));
5788   SVN_ERR(svn_ra_reparent(merge_b->ra_session2, old_sess2_url, scratch_pool));
5789
5790   return SVN_NO_ERROR;
5791 }
5792
5793 /* Iterate over each svn_client__merge_path_t * element in
5794    CHILDREN_WITH_MERGEINFO and, if START_REV is true, find the most inclusive
5795    start revision among those element's first remaining_ranges element.  If
5796    START_REV is false, then look for the most inclusive end revision.
5797
5798    If IS_ROLLBACK is true the youngest start or end (as per START_REV)
5799    revision is considered the "most inclusive" otherwise the oldest revision
5800    is.
5801
5802    If none of CHILDREN_WITH_MERGEINFO's elements have any remaining ranges
5803    return SVN_INVALID_REVNUM. */
5804 static svn_revnum_t
5805 get_most_inclusive_rev(const apr_array_header_t *children_with_mergeinfo,
5806                        svn_boolean_t is_rollback,
5807                        svn_boolean_t start_rev)
5808 {
5809   int i;
5810   svn_revnum_t most_inclusive_rev = SVN_INVALID_REVNUM;
5811
5812   for (i = 0; i < children_with_mergeinfo->nelts; i++)
5813     {
5814       svn_client__merge_path_t *child =
5815         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
5816
5817       if ((! child) || child->absent)
5818         continue;
5819       if (child->remaining_ranges->nelts > 0)
5820         {
5821           svn_merge_range_t *range =
5822             APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *);
5823
5824           /* Are we looking for the most inclusive start or end rev? */
5825           svn_revnum_t rev = start_rev ? range->start : range->end;
5826
5827           if ((most_inclusive_rev == SVN_INVALID_REVNUM)
5828               || (is_rollback && (rev > most_inclusive_rev))
5829               || ((! is_rollback) && (rev < most_inclusive_rev)))
5830             most_inclusive_rev = rev;
5831         }
5832     }
5833   return most_inclusive_rev;
5834 }
5835
5836
5837 /* If first item in each child of CHILDREN_WITH_MERGEINFO's
5838    remaining_ranges is inclusive of END_REV, Slice the first range in
5839    to two at END_REV. All the allocations are persistent and allocated
5840    from POOL. */
5841 static void
5842 slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
5843                        svn_boolean_t is_rollback, svn_revnum_t end_rev,
5844                        apr_pool_t *pool)
5845 {
5846   int i;
5847   for (i = 0; i < children_with_mergeinfo->nelts; i++)
5848     {
5849       svn_client__merge_path_t *child =
5850                                      APR_ARRAY_IDX(children_with_mergeinfo, i,
5851                                                    svn_client__merge_path_t *);
5852       if (!child || child->absent)
5853         continue;
5854       if (child->remaining_ranges->nelts > 0)
5855         {
5856           svn_merge_range_t *range = APR_ARRAY_IDX(child->remaining_ranges, 0,
5857                                                    svn_merge_range_t *);
5858           if ((is_rollback && (range->start > end_rev)
5859                && (range->end < end_rev))
5860               || (!is_rollback && (range->start < end_rev)
5861                   && (range->end > end_rev)))
5862             {
5863               svn_merge_range_t *split_range1, *split_range2;
5864
5865               split_range1 = svn_merge_range_dup(range, pool);
5866               split_range2 = svn_merge_range_dup(range, pool);
5867               split_range1->end = end_rev;
5868               split_range2->start = end_rev;
5869               APR_ARRAY_IDX(child->remaining_ranges, 0,
5870                             svn_merge_range_t *) = split_range1;
5871               svn_sort__array_insert(&split_range2, child->remaining_ranges, 1);
5872             }
5873         }
5874     }
5875 }
5876
5877 /* Helper for do_directory_merge().
5878
5879    For each child in CHILDREN_WITH_MERGEINFO remove the first remaining_ranges
5880    svn_merge_range_t *element of the child if that range has an end revision
5881    equal to REVISION.
5882
5883    If a range is removed from a child's remaining_ranges array, allocate the
5884    new remaining_ranges array in POOL.
5885  */
5886 static void
5887 remove_first_range_from_remaining_ranges(svn_revnum_t revision,
5888                                          apr_array_header_t
5889                                            *children_with_mergeinfo,
5890                                          apr_pool_t *pool)
5891 {
5892   int i;
5893
5894   for (i = 0; i < children_with_mergeinfo->nelts; i++)
5895     {
5896       svn_client__merge_path_t *child =
5897                                 APR_ARRAY_IDX(children_with_mergeinfo, i,
5898                                               svn_client__merge_path_t *);
5899       if (!child || child->absent)
5900         continue;
5901       if (child->remaining_ranges->nelts > 0)
5902         {
5903           svn_merge_range_t *first_range =
5904             APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *);
5905           if (first_range->end == revision)
5906             {
5907               svn_sort__array_delete(child->remaining_ranges, 0, 1);
5908             }
5909         }
5910     }
5911 }
5912
5913 /* Get a file's content and properties from the repository.
5914    Set *FILENAME to the local path to a new temporary file holding its text,
5915    and set *PROPS to a new hash of its properties.
5916
5917    RA_SESSION is a session open to the correct repository, which will be
5918    temporarily reparented to the URL of the file itself.  LOCATION is the
5919    repository location of the file.
5920
5921    The resulting file and the return values live as long as RESULT_POOL, all
5922    other allocations occur in SCRATCH_POOL.
5923 */
5924 static svn_error_t *
5925 single_file_merge_get_file(const char **filename,
5926                            apr_hash_t **props,
5927                            svn_ra_session_t *ra_session,
5928                            const svn_client__pathrev_t *location,
5929                            const char *wc_target,
5930                            apr_pool_t *result_pool,
5931                            apr_pool_t *scratch_pool)
5932 {
5933   svn_stream_t *stream;
5934   const char *old_sess_url;
5935   svn_error_t *err;
5936
5937   SVN_ERR(svn_stream_open_unique(&stream, filename, NULL,
5938                                  svn_io_file_del_on_pool_cleanup,
5939                                  result_pool, scratch_pool));
5940
5941   SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url, ra_session, location->url,
5942                                             scratch_pool));
5943   err = svn_ra_get_file(ra_session, "", location->rev,
5944                         stream, NULL, props, scratch_pool);
5945   SVN_ERR(svn_error_compose_create(
5946             err, svn_ra_reparent(ra_session, old_sess_url, scratch_pool)));
5947
5948   return svn_error_trace(svn_stream_close(stream));
5949 }
5950
5951 /* Compare two svn_client__merge_path_t elements **A and **B, given the
5952    addresses of pointers to them. Return an integer less than, equal to, or
5953    greater than zero if A sorts before, the same as, or after B, respectively.
5954    This is a helper for qsort() and bsearch() on an array of such elements. */
5955 static int
5956 compare_merge_path_t_as_paths(const void *a,
5957                               const void *b)
5958 {
5959   const svn_client__merge_path_t *child1
5960     = *((const svn_client__merge_path_t * const *) a);
5961   const svn_client__merge_path_t *child2
5962     = *((const svn_client__merge_path_t * const *) b);
5963
5964   return svn_path_compare_paths(child1->abspath, child2->abspath);
5965 }
5966
5967 /* Return a pointer to the element of CHILDREN_WITH_MERGEINFO whose path
5968  * is PATH, or return NULL if there is no such element. */
5969 static svn_client__merge_path_t *
5970 get_child_with_mergeinfo(const apr_array_header_t *children_with_mergeinfo,
5971                          const char *abspath)
5972 {
5973   svn_client__merge_path_t merge_path;
5974   svn_client__merge_path_t *key;
5975   svn_client__merge_path_t **pchild;
5976
5977   merge_path.abspath = abspath;
5978   key = &merge_path;
5979   pchild = bsearch(&key, children_with_mergeinfo->elts,
5980                    children_with_mergeinfo->nelts,
5981                    children_with_mergeinfo->elt_size,
5982                    compare_merge_path_t_as_paths);
5983   return pchild ? *pchild : NULL;
5984 }
5985
5986 /* Insert a deep copy of INSERT_ELEMENT into the CHILDREN_WITH_MERGEINFO
5987    array at its correct position.  Allocate the new storage in POOL.
5988    CHILDREN_WITH_MERGEINFO is a depth first sorted array of
5989    (svn_client__merge_path_t *).
5990
5991    ### Most callers don't need this to deep-copy the new element.
5992    ### It may be more efficient for some callers to insert a bunch of items
5993        out of order and then sort afterwards. (One caller is doing a qsort
5994        after calling this anyway.)
5995  */
5996 static void
5997 insert_child_to_merge(apr_array_header_t *children_with_mergeinfo,
5998                       const svn_client__merge_path_t *insert_element,
5999                       apr_pool_t *pool)
6000 {
6001   int insert_index;
6002   const svn_client__merge_path_t *new_element;
6003
6004   /* Find where to insert the new element */
6005   insert_index =
6006     svn_sort__bsearch_lower_bound(&insert_element, children_with_mergeinfo,
6007                                   compare_merge_path_t_as_paths);
6008
6009   new_element = svn_client__merge_path_dup(insert_element, pool);
6010   svn_sort__array_insert(&new_element, children_with_mergeinfo, insert_index);
6011 }
6012
6013 /* Helper for get_mergeinfo_paths().
6014
6015    CHILDREN_WITH_MERGEINFO, DEPTH, and POOL are
6016    all cascaded from the arguments of the same name to get_mergeinfo_paths().
6017
6018    TARGET is the merge target.
6019
6020    *CHILD is the element in in CHILDREN_WITH_MERGEINFO that
6021    get_mergeinfo_paths() is iterating over and *CURR_INDEX is index for
6022    *CHILD.
6023
6024    If CHILD->ABSPATH is equal to MERGE_CMD_BATON->target->abspath do nothing.
6025    Else if CHILD->ABSPATH is switched or absent then make sure its immediate
6026    (as opposed to nearest) parent in CHILDREN_WITH_MERGEINFO is marked as
6027    missing a child.  If the immediate parent does not exist in
6028    CHILDREN_WITH_MERGEINFO then create it (and increment *CURR_INDEX so that
6029    caller doesn't process the inserted element).  Also ensure that
6030    CHILD->ABSPATH's siblings which are not already present in
6031    CHILDREN_WITH_MERGEINFO are also added to the array, limited by DEPTH
6032    (e.g. don't add directory siblings of a switched file).
6033    Use POOL for temporary allocations only, any new CHILDREN_WITH_MERGEINFO
6034    elements are allocated in POOL. */
6035 static svn_error_t *
6036 insert_parent_and_sibs_of_sw_absent_del_subtree(
6037                                    apr_array_header_t *children_with_mergeinfo,
6038                                    const merge_target_t *target,
6039                                    int *curr_index,
6040                                    svn_client__merge_path_t *child,
6041                                    svn_depth_t depth,
6042                                    svn_client_ctx_t *ctx,
6043                                    apr_pool_t *pool)
6044 {
6045   svn_client__merge_path_t *parent;
6046   const char *parent_abspath;
6047   apr_pool_t *iterpool;
6048   const apr_array_header_t *children;
6049   int i;
6050
6051   if (!(child->absent
6052           || (child->switched
6053               && strcmp(target->abspath,
6054                         child->abspath) != 0)))
6055     return SVN_NO_ERROR;
6056
6057   parent_abspath = svn_dirent_dirname(child->abspath, pool);
6058   parent = get_child_with_mergeinfo(children_with_mergeinfo, parent_abspath);
6059   if (parent)
6060     {
6061       parent->missing_child = child->absent;
6062       parent->switched_child = child->switched;
6063     }
6064   else
6065     {
6066       /* Create a new element to insert into CHILDREN_WITH_MERGEINFO. */
6067       parent = svn_client__merge_path_create(parent_abspath, pool);
6068       parent->missing_child = child->absent;
6069       parent->switched_child = child->switched;
6070       /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
6071       insert_child_to_merge(children_with_mergeinfo, parent, pool);
6072       /* Increment for loop index so we don't process the inserted element. */
6073       (*curr_index)++;
6074     } /*(parent == NULL) */
6075
6076   /* Add all of PARENT's non-missing children that are not already present.*/
6077   SVN_ERR(svn_wc__node_get_children(&children, ctx->wc_ctx,
6078                                     parent_abspath, FALSE, pool, pool));
6079   iterpool = svn_pool_create(pool);
6080   for (i = 0; i < children->nelts; i++)
6081     {
6082       const char *child_abspath = APR_ARRAY_IDX(children, i, const char *);
6083       svn_client__merge_path_t *sibling_of_missing;
6084
6085       svn_pool_clear(iterpool);
6086
6087       /* Does this child already exist in CHILDREN_WITH_MERGEINFO? */
6088       sibling_of_missing = get_child_with_mergeinfo(children_with_mergeinfo,
6089                                                     child_abspath);
6090       /* Create the missing child and insert it into CHILDREN_WITH_MERGEINFO.*/
6091       if (!sibling_of_missing)
6092         {
6093           /* Don't add directory children if DEPTH is svn_depth_files. */
6094           if (depth == svn_depth_files)
6095             {
6096               svn_node_kind_t child_kind;
6097
6098               SVN_ERR(svn_wc_read_kind2(&child_kind,
6099                                         ctx->wc_ctx, child_abspath,
6100                                         FALSE, FALSE, iterpool));
6101               if (child_kind != svn_node_file)
6102                 continue;
6103             }
6104
6105           sibling_of_missing = svn_client__merge_path_create(child_abspath,
6106                                                              pool);
6107           insert_child_to_merge(children_with_mergeinfo, sibling_of_missing,
6108                                 pool);
6109         }
6110     }
6111
6112   svn_pool_destroy(iterpool);
6113
6114   return SVN_NO_ERROR;
6115 }
6116
6117 /* pre_merge_status_cb's baton */
6118 struct pre_merge_status_baton_t
6119 {
6120   svn_wc_context_t *wc_ctx;
6121
6122   /* const char *absolute_wc_path to svn_depth_t * mapping for depths
6123      of empty, immediates, and files. */
6124   apr_hash_t *shallow_subtrees;
6125
6126   /* const char *absolute_wc_path to the same, for all paths missing
6127      from the working copy. */
6128   apr_hash_t *missing_subtrees;
6129
6130   /* const char *absolute_wc_path const char * repos relative path, describing
6131      the root of each switched subtree in the working copy and the repository
6132      relative path it is switched to. */
6133   apr_hash_t *switched_subtrees;
6134
6135   /* A pool to allocate additions to the above hashes in. */
6136   apr_pool_t *pool;
6137 };
6138
6139 /* A svn_wc_status_func4_t callback used by get_mergeinfo_paths to gather
6140    all switched, depth filtered and missing subtrees under a merge target.
6141
6142    Note that this doesn't see server and user excluded trees. */
6143 static svn_error_t *
6144 pre_merge_status_cb(void *baton,
6145                     const char *local_abspath,
6146                     const svn_wc_status3_t *status,
6147                     apr_pool_t *scratch_pool)
6148 {
6149   struct pre_merge_status_baton_t *pmsb = baton;
6150
6151   if (status->switched && !status->file_external)
6152     {
6153       store_path(pmsb->switched_subtrees, local_abspath);
6154     }
6155
6156   if (status->depth == svn_depth_empty
6157       || status->depth == svn_depth_files)
6158     {
6159       const char *dup_abspath;
6160       svn_depth_t *depth = apr_pmemdup(pmsb->pool, &status->depth,
6161                                        sizeof *depth);
6162
6163       dup_abspath = apr_pstrdup(pmsb->pool, local_abspath);
6164
6165       svn_hash_sets(pmsb->shallow_subtrees, dup_abspath, depth);
6166     }
6167
6168   if (status->node_status == svn_wc_status_missing)
6169     {
6170       svn_boolean_t new_missing_root = TRUE;
6171       apr_hash_index_t *hi;
6172
6173       for (hi = apr_hash_first(scratch_pool, pmsb->missing_subtrees);
6174            hi;
6175            hi = apr_hash_next(hi))
6176         {
6177           const char *missing_root_path = svn__apr_hash_index_key(hi);
6178
6179           if (svn_dirent_is_ancestor(missing_root_path,
6180                                      local_abspath))
6181             {
6182               new_missing_root = FALSE;
6183               break;
6184             }
6185         }
6186
6187       if (new_missing_root)
6188         store_path(pmsb->missing_subtrees, local_abspath);
6189     }
6190
6191   return SVN_NO_ERROR;
6192 }
6193
6194 /* Find all the subtrees in the working copy tree rooted at TARGET_ABSPATH
6195  * that have explicit mergeinfo.
6196  * Set *SUBTREES_WITH_MERGEINFO to a hash mapping (const char *) absolute
6197  * WC path to (svn_mergeinfo_t *) mergeinfo.
6198  *
6199  * ### Is this function equivalent to:
6200  *
6201  *   svn_client__get_wc_mergeinfo_catalog(
6202  *     subtrees_with_mergeinfo, inherited=NULL, include_descendants=TRUE,
6203  *     svn_mergeinfo_explicit, target_abspath, limit_path=NULL,
6204  *     walked_path=NULL, ignore_invalid_mergeinfo=FALSE, ...)
6205  *
6206  *   except for the catalog keys being abspaths instead of repo-relpaths?
6207  */
6208 static svn_error_t *
6209 get_wc_explicit_mergeinfo_catalog(apr_hash_t **subtrees_with_mergeinfo,
6210                                   const char *target_abspath,
6211                                   svn_depth_t depth,
6212                                   svn_client_ctx_t *ctx,
6213                                   apr_pool_t *result_pool,
6214                                   apr_pool_t *scratch_pool)
6215 {
6216   svn_opt_revision_t working_revision = { svn_opt_revision_working, { 0 } };
6217   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
6218   apr_hash_index_t *hi;
6219   apr_hash_t *externals;
6220
6221   SVN_ERR(svn_client_propget5(subtrees_with_mergeinfo, NULL,
6222                               SVN_PROP_MERGEINFO, target_abspath,
6223                               &working_revision, &working_revision, NULL,
6224                               depth, NULL, ctx, result_pool, scratch_pool));
6225
6226   SVN_ERR(svn_wc__externals_defined_below(&externals, ctx->wc_ctx,
6227                                           target_abspath, scratch_pool,
6228                                           scratch_pool));
6229
6230   /* Convert property values to svn_mergeinfo_t. */
6231   for (hi = apr_hash_first(scratch_pool, *subtrees_with_mergeinfo);
6232        hi;
6233        hi = apr_hash_next(hi))
6234     {
6235       const char *wc_path = svn__apr_hash_index_key(hi);
6236       svn_string_t *mergeinfo_string = svn__apr_hash_index_val(hi);
6237       svn_mergeinfo_t mergeinfo;
6238       svn_error_t *err;
6239
6240       /* svn_client_propget5 picks up file externals with
6241          mergeinfo, but we don't want those. */
6242       if (svn_hash_gets(externals, wc_path))
6243         {
6244           svn_hash_sets(*subtrees_with_mergeinfo, wc_path, NULL);
6245           continue;
6246         }
6247
6248       svn_pool_clear(iterpool);
6249
6250       err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_string->data,
6251                                 result_pool);
6252       if (err)
6253         {
6254           if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
6255             {
6256               err = svn_error_createf(
6257                 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err,
6258                 _("Invalid mergeinfo detected on '%s', "
6259                   "merge tracking not possible"),
6260                 svn_dirent_local_style(wc_path, scratch_pool));
6261             }
6262           return svn_error_trace(err);
6263         }
6264       svn_hash_sets(*subtrees_with_mergeinfo, wc_path, mergeinfo);
6265     }
6266   svn_pool_destroy(iterpool);
6267
6268   return SVN_NO_ERROR;
6269 }
6270
6271 /* Helper for do_directory_merge() when performing merge-tracking aware
6272    merges.
6273
6274    Walk of the working copy tree rooted at TARGET->abspath to
6275    depth DEPTH.  Create an svn_client__merge_path_t * for any path which meets
6276    one or more of the following criteria:
6277
6278      1) Path has working svn:mergeinfo.
6279      2) Path is switched.
6280      3) Path is a subtree of the merge target (i.e. is not equal to
6281         TARGET->abspath) and has no mergeinfo of its own but
6282         its immediate parent has mergeinfo with non-inheritable ranges.  If
6283         this isn't a dry-run and the merge is between differences in the same
6284         repository, then this function will set working mergeinfo on the path
6285         equal to the mergeinfo inheritable from its parent.
6286      4) Path has an immediate child (or children) missing from the WC because
6287         the child is switched or absent from the WC, or due to a sparse
6288         checkout.
6289      5) Path has a sibling (or siblings) missing from the WC because the
6290         sibling is switched, absent, scheduled for deletion, or missing due to
6291         a sparse checkout.
6292      6) Path is absent from disk due to an authz restriction.
6293      7) Path is equal to TARGET->abspath.
6294      8) Path is an immediate *directory* child of
6295         TARGET->abspath and DEPTH is svn_depth_immediates.
6296      9) Path is an immediate *file* child of TARGET->abspath
6297         and DEPTH is svn_depth_files.
6298      10) Path is at a depth of 'empty' or 'files'.
6299      11) Path is missing from disk (e.g. due to an OS-level deletion).
6300
6301    If subtrees within the requested DEPTH are unexpectedly missing disk,
6302    then raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE.
6303
6304    Store the svn_client__merge_path_t *'s in *CHILDREN_WITH_MERGEINFO in
6305    depth-first order based on the svn_client__merge_path_t *s path member as
6306    sorted by svn_path_compare_paths().  Set the remaining_ranges field of each
6307    element to NULL.
6308
6309    Note: Since the walk is rooted at TARGET->abspath, the
6310    latter is guaranteed to be in *CHILDREN_WITH_MERGEINFO and due to the
6311    depth-first ordering it is guaranteed to be the first element in
6312    *CHILDREN_WITH_MERGEINFO.
6313
6314    MERGE_CMD_BATON is cascaded from the argument of the same name in
6315    do_directory_merge().
6316 */
6317 static svn_error_t *
6318 get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo,
6319                     const merge_target_t *target,
6320                     svn_depth_t depth,
6321                     svn_boolean_t dry_run,
6322                     svn_boolean_t same_repos,
6323                     svn_client_ctx_t *ctx,
6324                     apr_pool_t *result_pool,
6325                     apr_pool_t *scratch_pool)
6326 {
6327   int i;
6328   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
6329   apr_hash_t *subtrees_with_mergeinfo;
6330   apr_hash_t *excluded_subtrees;
6331   apr_hash_t *switched_subtrees;
6332   apr_hash_t *shallow_subtrees;
6333   apr_hash_t *missing_subtrees;
6334   struct pre_merge_status_baton_t pre_merge_status_baton;
6335
6336   /* Case 1: Subtrees with explicit mergeinfo. */
6337   SVN_ERR(get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo,
6338                                             target->abspath,
6339                                             depth, ctx,
6340                                             result_pool, scratch_pool));
6341   if (subtrees_with_mergeinfo)
6342     {
6343       apr_hash_index_t *hi;
6344
6345       for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo);
6346            hi;
6347            hi = apr_hash_next(hi))
6348         {
6349           const char *wc_path = svn__apr_hash_index_key(hi);
6350           svn_mergeinfo_t mergeinfo = svn__apr_hash_index_val(hi);
6351           svn_client__merge_path_t *mergeinfo_child =
6352             svn_client__merge_path_create(wc_path, result_pool);
6353
6354           svn_pool_clear(iterpool);
6355
6356           /* Stash this child's pre-existing mergeinfo. */
6357           mergeinfo_child->pre_merge_mergeinfo = mergeinfo;
6358
6359           /* Note if this child has non-inheritable mergeinfo */
6360           mergeinfo_child->has_noninheritable
6361             = svn_mergeinfo__is_noninheritable(
6362                 mergeinfo_child->pre_merge_mergeinfo, iterpool);
6363
6364           /* Append it.  We'll sort below. */
6365           APR_ARRAY_PUSH(children_with_mergeinfo, svn_client__merge_path_t *)
6366             = svn_client__merge_path_dup(mergeinfo_child, result_pool);
6367         }
6368
6369       /* Sort CHILDREN_WITH_MERGEINFO by each child's path (i.e. as per
6370          compare_merge_path_t_as_paths).  Any subsequent insertions of new
6371          children with insert_child_to_merge() require this ordering. */
6372       qsort(children_with_mergeinfo->elts,
6373             children_with_mergeinfo->nelts,
6374             children_with_mergeinfo->elt_size,
6375             compare_merge_path_t_as_paths);
6376     }
6377
6378   /* Case 2: Switched subtrees
6379      Case 10: Paths at depths of 'empty' or 'files'
6380      Case 11: Paths missing from disk */
6381   pre_merge_status_baton.wc_ctx = ctx->wc_ctx;
6382   switched_subtrees = apr_hash_make(scratch_pool);
6383   pre_merge_status_baton.switched_subtrees = switched_subtrees;
6384   shallow_subtrees = apr_hash_make(scratch_pool);
6385   pre_merge_status_baton.shallow_subtrees = shallow_subtrees;
6386   missing_subtrees = apr_hash_make(scratch_pool);
6387   pre_merge_status_baton.missing_subtrees = missing_subtrees;
6388   pre_merge_status_baton.pool = scratch_pool;
6389   SVN_ERR(svn_wc_walk_status(ctx->wc_ctx,
6390                              target->abspath,
6391                              depth,
6392                              TRUE /* get_all */,
6393                              FALSE /* no_ignore */,
6394                              TRUE /* ignore_text_mods */,
6395                              NULL /* ingore_patterns */,
6396                              pre_merge_status_cb, &pre_merge_status_baton,
6397                              ctx->cancel_func, ctx->cancel_baton,
6398                              scratch_pool));
6399
6400   /* Issue #2915: Raise an error describing the roots of any missing
6401      subtrees, i.e. those that the WC thinks are on disk but have been
6402      removed outside of Subversion. */
6403   if (apr_hash_count(missing_subtrees))
6404     {
6405       apr_hash_index_t *hi;
6406       svn_stringbuf_t *missing_subtree_err_buf =
6407         svn_stringbuf_create(_("Merge tracking not allowed with missing "
6408                                "subtrees; try restoring these items "
6409                                "first:\n"), scratch_pool);
6410
6411       for (hi = apr_hash_first(scratch_pool, missing_subtrees);
6412            hi;
6413            hi = apr_hash_next(hi))
6414         {
6415           svn_pool_clear(iterpool);
6416           svn_stringbuf_appendcstr(missing_subtree_err_buf,
6417                                    svn_dirent_local_style(
6418                                      svn__apr_hash_index_key(hi), iterpool));
6419           svn_stringbuf_appendcstr(missing_subtree_err_buf, "\n");
6420         }
6421
6422       return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
6423                               NULL, missing_subtree_err_buf->data);
6424     }
6425
6426   if (apr_hash_count(switched_subtrees))
6427     {
6428       apr_hash_index_t *hi;
6429
6430       for (hi = apr_hash_first(scratch_pool, switched_subtrees);
6431            hi;
6432            hi = apr_hash_next(hi))
6433         {
6434            const char *wc_path = svn__apr_hash_index_key(hi);
6435            svn_client__merge_path_t *child = get_child_with_mergeinfo(
6436              children_with_mergeinfo, wc_path);
6437
6438            if (child)
6439              {
6440                child->switched = TRUE;
6441              }
6442            else
6443              {
6444                svn_client__merge_path_t *switched_child =
6445                  svn_client__merge_path_create(wc_path, result_pool);
6446                switched_child->switched = TRUE;
6447                insert_child_to_merge(children_with_mergeinfo, switched_child,
6448                                      result_pool);
6449              }
6450         }
6451     }
6452
6453   if (apr_hash_count(shallow_subtrees))
6454     {
6455       apr_hash_index_t *hi;
6456
6457       for (hi = apr_hash_first(scratch_pool, shallow_subtrees);
6458            hi;
6459            hi = apr_hash_next(hi))
6460         {
6461            svn_boolean_t new_shallow_child = FALSE;
6462            const char *wc_path = svn__apr_hash_index_key(hi);
6463            svn_depth_t *child_depth = svn__apr_hash_index_val(hi);
6464            svn_client__merge_path_t *shallow_child = get_child_with_mergeinfo(
6465              children_with_mergeinfo, wc_path);
6466
6467            if (shallow_child)
6468              {
6469                if (*child_depth == svn_depth_empty
6470                    || *child_depth == svn_depth_files)
6471                  shallow_child->missing_child = TRUE;
6472              }
6473            else
6474              {
6475                shallow_child = svn_client__merge_path_create(wc_path,
6476                                                              result_pool);
6477                new_shallow_child = TRUE;
6478
6479                if (*child_depth == svn_depth_empty
6480                    || *child_depth == svn_depth_files)
6481                  shallow_child->missing_child = TRUE;
6482              }
6483
6484           /* A little trickery: If PATH doesn't have any mergeinfo or has
6485              only inheritable mergeinfo, we still describe it as having
6486              non-inheritable mergeinfo if it is missing a child due to
6487              a shallow depth.  Why? Because the mergeinfo we'll add to PATH
6488              to describe the merge must be non-inheritable, so PATH's missing
6489              children don't inherit it.  Marking these PATHs as non-
6490              inheritable allows the logic for case 3 to properly account
6491              for PATH's children. */
6492           if (!shallow_child->has_noninheritable
6493               && (*child_depth == svn_depth_empty
6494                   || *child_depth == svn_depth_files))
6495             {
6496               shallow_child->has_noninheritable = TRUE;
6497             }
6498
6499           if (new_shallow_child)
6500             insert_child_to_merge(children_with_mergeinfo, shallow_child,
6501                                   result_pool);
6502        }
6503     }
6504
6505   /* Case 6: Paths absent from disk due to server or user exclusion. */
6506   SVN_ERR(svn_wc__get_excluded_subtrees(&excluded_subtrees,
6507                                         ctx->wc_ctx, target->abspath,
6508                                         result_pool, scratch_pool));
6509   if (excluded_subtrees)
6510     {
6511       apr_hash_index_t *hi;
6512
6513       for (hi = apr_hash_first(scratch_pool, excluded_subtrees);
6514            hi;
6515            hi = apr_hash_next(hi))
6516         {
6517            const char *wc_path = svn__apr_hash_index_key(hi);
6518            svn_client__merge_path_t *child = get_child_with_mergeinfo(
6519              children_with_mergeinfo, wc_path);
6520
6521            if (child)
6522              {
6523                child->absent = TRUE;
6524              }
6525            else
6526              {
6527                svn_client__merge_path_t *absent_child =
6528                  svn_client__merge_path_create(wc_path, result_pool);
6529                absent_child->absent = TRUE;
6530                insert_child_to_merge(children_with_mergeinfo, absent_child,
6531                                      result_pool);
6532              }
6533         }
6534     }
6535
6536   /* Case 7: The merge target MERGE_CMD_BATON->target->abspath is always
6537      present. */
6538   if (!get_child_with_mergeinfo(children_with_mergeinfo,
6539                                 target->abspath))
6540     {
6541       svn_client__merge_path_t *target_child =
6542         svn_client__merge_path_create(target->abspath,
6543                                       result_pool);
6544       insert_child_to_merge(children_with_mergeinfo, target_child,
6545                             result_pool);
6546     }
6547
6548   /* Case 8: Path is an immediate *directory* child of
6549      MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_immediates.
6550
6551      Case 9: Path is an immediate *file* child of
6552      MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_files. */
6553   if (depth == svn_depth_immediates || depth == svn_depth_files)
6554     {
6555       int j;
6556       const apr_array_header_t *immediate_children;
6557
6558       SVN_ERR(svn_wc__node_get_children_of_working_node(
6559         &immediate_children, ctx->wc_ctx,
6560         target->abspath, FALSE, scratch_pool, scratch_pool));
6561
6562       for (j = 0; j < immediate_children->nelts; j++)
6563         {
6564           const char *immediate_child_abspath =
6565             APR_ARRAY_IDX(immediate_children, j, const char *);
6566           svn_node_kind_t immediate_child_kind;
6567
6568           svn_pool_clear(iterpool);
6569           SVN_ERR(svn_wc_read_kind2(&immediate_child_kind,
6570                                     ctx->wc_ctx, immediate_child_abspath,
6571                                     FALSE, FALSE, iterpool));
6572           if ((immediate_child_kind == svn_node_dir
6573                && depth == svn_depth_immediates)
6574               || (immediate_child_kind == svn_node_file
6575                   && depth == svn_depth_files))
6576             {
6577               if (!get_child_with_mergeinfo(children_with_mergeinfo,
6578                                             immediate_child_abspath))
6579                 {
6580                   svn_client__merge_path_t *immediate_child =
6581                     svn_client__merge_path_create(immediate_child_abspath,
6582                                                   result_pool);
6583
6584                   if (immediate_child_kind == svn_node_dir
6585                       && depth == svn_depth_immediates)
6586                     immediate_child->immediate_child_dir = TRUE;
6587
6588                   insert_child_to_merge(children_with_mergeinfo,
6589                                         immediate_child, result_pool);
6590                 }
6591             }
6592         }
6593     }
6594
6595   /* If DEPTH isn't empty then cover cases 3), 4), and 5), possibly adding
6596      elements to CHILDREN_WITH_MERGEINFO. */
6597   if (depth <= svn_depth_empty)
6598     return SVN_NO_ERROR;
6599
6600   for (i = 0; i < children_with_mergeinfo->nelts; i++)
6601     {
6602       svn_client__merge_path_t *child =
6603         APR_ARRAY_IDX(children_with_mergeinfo, i,
6604                       svn_client__merge_path_t *);
6605       svn_pool_clear(iterpool);
6606
6607       /* Case 3) Where merging to a path with a switched child the path
6608          gets non-inheritable mergeinfo for the merge range performed and
6609          the child gets its own set of mergeinfo.  If the switched child
6610          later "returns", e.g. a switched path is unswitched, the child
6611          may not have any explicit mergeinfo.  If the initial merge is
6612          repeated we don't want to repeat the merge for the path, but we
6613          do want to repeat it for the previously switched child.  To
6614          ensure this we check if all of CHILD's non-missing children have
6615          explicit mergeinfo (they should already be present in
6616          CHILDREN_WITH_MERGEINFO if they do).  If not,
6617          add the children without mergeinfo to CHILDREN_WITH_MERGEINFO so
6618          do_directory_merge() will merge them independently.
6619
6620          But that's not enough!  Since do_directory_merge() performs
6621          the merges on the paths in CHILDREN_WITH_MERGEINFO in a depth
6622          first manner it will merge the previously switched path's parent
6623          first.  As part of this merge it will update the parent's
6624          previously non-inheritable mergeinfo and make it inheritable
6625          (since it notices the path has no missing children), then when
6626          do_directory_merge() finally merges the previously missing
6627          child it needs to get mergeinfo from the child's nearest
6628          ancestor, but since do_directory_merge() already tweaked that
6629          mergeinfo, removing the non-inheritable flag, it appears that the
6630          child already has been merged to.  To prevent this we set
6631          override mergeinfo on the child now, before any merging is done,
6632          so it has explicit mergeinfo that reflects only CHILD's
6633          inheritable mergeinfo. */
6634
6635       /* If depth is immediates or files then don't add new children if
6636          CHILD is a subtree of the merge target; those children are below
6637          the operational depth of the merge. */
6638       if (child->has_noninheritable
6639           && (i == 0 || depth == svn_depth_infinity))
6640         {
6641           const apr_array_header_t *children;
6642           int j;
6643
6644           SVN_ERR(svn_wc__node_get_children(&children,
6645                                             ctx->wc_ctx,
6646                                             child->abspath, FALSE,
6647                                             iterpool, iterpool));
6648           for (j = 0; j < children->nelts; j++)
6649             {
6650               svn_client__merge_path_t *child_of_noninheritable;
6651               const char *child_abspath = APR_ARRAY_IDX(children, j,
6652                                                         const char*);
6653
6654               /* Does this child already exist in CHILDREN_WITH_MERGEINFO?
6655                  If not, create it and insert it into
6656                  CHILDREN_WITH_MERGEINFO and set override mergeinfo on
6657                  it. */
6658               child_of_noninheritable =
6659                 get_child_with_mergeinfo(children_with_mergeinfo,
6660                                          child_abspath);
6661               if (!child_of_noninheritable)
6662                 {
6663                   /* Don't add directory children if DEPTH
6664                      is svn_depth_files. */
6665                   if (depth == svn_depth_files)
6666                     {
6667                       svn_node_kind_t child_kind;
6668                       SVN_ERR(svn_wc_read_kind2(&child_kind,
6669                                                 ctx->wc_ctx, child_abspath,
6670                                                 FALSE, FALSE, iterpool));
6671                       if (child_kind != svn_node_file)
6672                         continue;
6673                     }
6674                   /* else DEPTH is infinity or immediates so we want both
6675                      directory and file children. */
6676
6677                   child_of_noninheritable =
6678                     svn_client__merge_path_create(child_abspath, result_pool);
6679                   child_of_noninheritable->child_of_noninheritable = TRUE;
6680                   insert_child_to_merge(children_with_mergeinfo,
6681                                         child_of_noninheritable,
6682                                         result_pool);
6683                   if (!dry_run && same_repos)
6684                     {
6685                       svn_mergeinfo_t mergeinfo;
6686
6687                       SVN_ERR(svn_client__get_wc_mergeinfo(
6688                         &mergeinfo, NULL,
6689                         svn_mergeinfo_nearest_ancestor,
6690                         child_of_noninheritable->abspath,
6691                         target->abspath, NULL, FALSE,
6692                         ctx, iterpool, iterpool));
6693
6694                       SVN_ERR(svn_client__record_wc_mergeinfo(
6695                         child_of_noninheritable->abspath, mergeinfo,
6696                         FALSE, ctx, iterpool));
6697                     }
6698                 }
6699             }
6700         }
6701       /* Case 4 and 5 are handled by the following function. */
6702       SVN_ERR(insert_parent_and_sibs_of_sw_absent_del_subtree(
6703         children_with_mergeinfo, target, &i, child,
6704         depth, ctx, result_pool));
6705     } /* i < children_with_mergeinfo->nelts */
6706   svn_pool_destroy(iterpool);
6707
6708   return SVN_NO_ERROR;
6709 }
6710
6711
6712 /* Implements the svn_log_entry_receiver_t interface.
6713  *
6714  * BATON is an 'apr_array_header_t *' array of 'svn_revnum_t'.
6715  * Push a copy of LOG_ENTRY->revision onto BATON.  Thus, a
6716  * series of invocations of this callback accumulates the
6717  * corresponding set of revisions into BATON.
6718  */
6719 static svn_error_t *
6720 log_changed_revs(void *baton,
6721                  svn_log_entry_t *log_entry,
6722                  apr_pool_t *pool)
6723 {
6724   apr_array_header_t *revs = baton;
6725
6726   APR_ARRAY_PUSH(revs, svn_revnum_t) = log_entry->revision;
6727   return SVN_NO_ERROR;
6728 }
6729
6730
6731 /* Set *MIN_REV_P to the oldest and *MAX_REV_P to the youngest start or end
6732  * revision occurring in RANGELIST, or to SVN_INVALID_REVNUM if RANGELIST
6733  * is empty. */
6734 static void
6735 merge_range_find_extremes(svn_revnum_t *min_rev_p,
6736                           svn_revnum_t *max_rev_p,
6737                           const svn_rangelist_t *rangelist)
6738 {
6739   int i;
6740
6741   *min_rev_p = SVN_INVALID_REVNUM;
6742   *max_rev_p = SVN_INVALID_REVNUM;
6743   for (i = 0; i < rangelist->nelts; i++)
6744     {
6745       svn_merge_range_t *range
6746         = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
6747       svn_revnum_t range_min = MIN(range->start, range->end);
6748       svn_revnum_t range_max = MAX(range->start, range->end);
6749
6750       if ((! SVN_IS_VALID_REVNUM(*min_rev_p)) || (range_min < *min_rev_p))
6751         *min_rev_p = range_min;
6752       if ((! SVN_IS_VALID_REVNUM(*max_rev_p)) || (range_max > *max_rev_p))
6753         *max_rev_p = range_max;
6754     }
6755 }
6756
6757 /* Wrapper around svn_ra_get_log2(). Invoke RECEIVER with RECEIVER_BATON
6758  * on each commit from YOUNGEST_REV to OLDEST_REV in which TARGET_RELPATH
6759  * changed.  TARGET_RELPATH is relative to RA_SESSION's URL.
6760  * Important: Revision properties are not retrieved by this function for
6761  * performance reasons.
6762  */
6763 static svn_error_t *
6764 get_log(svn_ra_session_t *ra_session,
6765         const char *target_relpath,
6766         svn_revnum_t youngest_rev,
6767         svn_revnum_t oldest_rev,
6768         svn_boolean_t discover_changed_paths,
6769         svn_log_entry_receiver_t receiver,
6770         void *receiver_baton,
6771         apr_pool_t *pool)
6772 {
6773   apr_array_header_t *log_targets;
6774   apr_array_header_t *revprops;
6775
6776   log_targets = apr_array_make(pool, 1, sizeof(const char *));
6777   APR_ARRAY_PUSH(log_targets, const char *) = target_relpath;
6778
6779   revprops = apr_array_make(pool, 0, sizeof(const char *));
6780
6781   SVN_ERR(svn_ra_get_log2(ra_session, log_targets, youngest_rev,
6782                           oldest_rev, 0 /* limit */, discover_changed_paths,
6783                           FALSE /* strict_node_history */,
6784                           FALSE /* include_merged_revisions */,
6785                           revprops, receiver, receiver_baton, pool));
6786
6787   return SVN_NO_ERROR;
6788 }
6789
6790 /* Set *OPERATIVE_RANGES_P to an array of svn_merge_range_t * merge
6791    range objects copied wholesale from RANGES which have the property
6792    that in some revision within that range the object identified by
6793    RA_SESSION was modified (if by "modified" we mean "'svn log' would
6794    return that revision).  *OPERATIVE_RANGES_P is allocated from the
6795    same pool as RANGES, and the ranges within it are shared with
6796    RANGES, too.
6797
6798    *OPERATIVE_RANGES_P may be the same as RANGES (that is, the output
6799    parameter is set only after the input is no longer used).
6800
6801    Use POOL for temporary allocations.  */
6802 static svn_error_t *
6803 remove_noop_merge_ranges(svn_rangelist_t **operative_ranges_p,
6804                          svn_ra_session_t *ra_session,
6805                          const svn_rangelist_t *ranges,
6806                          apr_pool_t *pool)
6807 {
6808   int i;
6809   svn_revnum_t oldest_rev, youngest_rev;
6810   apr_array_header_t *changed_revs =
6811     apr_array_make(pool, ranges->nelts, sizeof(svn_revnum_t));
6812   svn_rangelist_t *operative_ranges =
6813     apr_array_make(ranges->pool, ranges->nelts, ranges->elt_size);
6814
6815   /* Find the revision extremes of the RANGES we have. */
6816   merge_range_find_extremes(&oldest_rev, &youngest_rev, ranges);
6817   if (SVN_IS_VALID_REVNUM(oldest_rev))
6818     oldest_rev++;  /* make it inclusive */
6819
6820   /* Get logs across those ranges, recording which revisions hold
6821      changes to our object's history. */
6822   SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev, FALSE,
6823                   log_changed_revs, changed_revs, pool));
6824
6825   /* Are there *any* changes? */
6826   if (changed_revs->nelts)
6827     {
6828       /* Our list of changed revisions should be in youngest-to-oldest
6829          order. */
6830       svn_revnum_t youngest_changed_rev
6831         = APR_ARRAY_IDX(changed_revs, 0, svn_revnum_t);
6832       svn_revnum_t oldest_changed_rev
6833         = APR_ARRAY_IDX(changed_revs, changed_revs->nelts - 1, svn_revnum_t);
6834
6835       /* Now, copy from RANGES to *OPERATIVE_RANGES, filtering out ranges
6836          that aren't operative (by virtue of not having any revisions
6837          represented in the CHANGED_REVS array). */
6838       for (i = 0; i < ranges->nelts; i++)
6839         {
6840           svn_merge_range_t *range = APR_ARRAY_IDX(ranges, i,
6841                                                    svn_merge_range_t *);
6842           svn_revnum_t range_min = MIN(range->start, range->end) + 1;
6843           svn_revnum_t range_max = MAX(range->start, range->end);
6844           int j;
6845
6846           /* If the merge range is entirely outside the range of changed
6847              revisions, we've no use for it. */
6848           if ((range_min > youngest_changed_rev)
6849               || (range_max < oldest_changed_rev))
6850             continue;
6851
6852           /* Walk through the changed_revs to see if any of them fall
6853              inside our current range. */
6854           for (j = 0; j < changed_revs->nelts; j++)
6855             {
6856               svn_revnum_t changed_rev
6857                 = APR_ARRAY_IDX(changed_revs, j, svn_revnum_t);
6858               if ((changed_rev >= range_min) && (changed_rev <= range_max))
6859                 {
6860                   APR_ARRAY_PUSH(operative_ranges, svn_merge_range_t *) =
6861                     range;
6862                   break;
6863                 }
6864             }
6865         }
6866     }
6867
6868   *operative_ranges_p = operative_ranges;
6869   return SVN_NO_ERROR;
6870 }
6871
6872
6873 /*-----------------------------------------------------------------------*/
6874 \f
6875 /*** Merge Source Normalization ***/
6876
6877 /* qsort-compatible sort routine, rating merge_source_t * objects to
6878    be in descending (youngest-to-oldest) order based on their ->loc1->rev
6879    component. */
6880 static int
6881 compare_merge_source_ts(const void *a,
6882                         const void *b)
6883 {
6884   svn_revnum_t a_rev = (*(const merge_source_t *const *)a)->loc1->rev;
6885   svn_revnum_t b_rev = (*(const merge_source_t *const *)b)->loc1->rev;
6886   if (a_rev == b_rev)
6887     return 0;
6888   return a_rev < b_rev ? 1 : -1;
6889 }
6890
6891 /* Set *MERGE_SOURCE_TS_P to a list of merge sources generated by
6892    slicing history location SEGMENTS with a given requested merge
6893    RANGE.  Use SOURCE_LOC for full source URL calculation.
6894
6895    Order the merge sources in *MERGE_SOURCE_TS_P from oldest to
6896    youngest. */
6897 static svn_error_t *
6898 combine_range_with_segments(apr_array_header_t **merge_source_ts_p,
6899                             const svn_merge_range_t *range,
6900                             const apr_array_header_t *segments,
6901                             const svn_client__pathrev_t *source_loc,
6902                             apr_pool_t *pool)
6903 {
6904   apr_array_header_t *merge_source_ts =
6905     apr_array_make(pool, 1, sizeof(merge_source_t *));
6906   svn_revnum_t minrev = MIN(range->start, range->end) + 1;
6907   svn_revnum_t maxrev = MAX(range->start, range->end);
6908   svn_boolean_t subtractive = (range->start > range->end);
6909   int i;
6910
6911   for (i = 0; i < segments->nelts; i++)
6912     {
6913       svn_location_segment_t *segment =
6914         APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
6915       svn_client__pathrev_t *loc1, *loc2;
6916       merge_source_t *merge_source;
6917       const char *path1 = NULL;
6918       svn_revnum_t rev1;
6919
6920       /* If this segment doesn't overlap our range at all, or
6921          represents a gap, ignore it. */
6922       if ((segment->range_end < minrev)
6923           || (segment->range_start > maxrev)
6924           || (! segment->path))
6925         continue;
6926
6927       /* If our range spans a segment boundary, we have to point our
6928          merge_source_t's path1 to the path of the immediately older
6929          segment, else it points to the same location as its path2.  */
6930       rev1 = MAX(segment->range_start, minrev) - 1;
6931       if (minrev <= segment->range_start)
6932         {
6933           if (i > 0)
6934             {
6935               path1 = (APR_ARRAY_IDX(segments, i - 1,
6936                                      svn_location_segment_t *))->path;
6937             }
6938           /* If we've backed PATH1 up into a segment gap, let's back
6939              it up further still to the segment before the gap.  We'll
6940              have to adjust rev1, too. */
6941           if ((! path1) && (i > 1))
6942             {
6943               path1 = (APR_ARRAY_IDX(segments, i - 2,
6944                                      svn_location_segment_t *))->path;
6945               rev1 = (APR_ARRAY_IDX(segments, i - 2,
6946                                     svn_location_segment_t *))->range_end;
6947             }
6948         }
6949       else
6950         {
6951           path1 = apr_pstrdup(pool, segment->path);
6952         }
6953
6954       /* If we don't have two valid paths, we won't know what to do
6955          when merging.  This could happen if someone requested a merge
6956          where the source didn't exist in a particular revision or
6957          something.  The merge code would probably bomb out anyway, so
6958          we'll just *not* create a merge source in this case. */
6959       if (! (path1 && segment->path))
6960         continue;
6961
6962       /* Build our merge source structure. */
6963       loc1 = svn_client__pathrev_create_with_relpath(
6964                source_loc->repos_root_url, source_loc->repos_uuid,
6965                rev1, path1, pool);
6966       loc2 = svn_client__pathrev_create_with_relpath(
6967                source_loc->repos_root_url, source_loc->repos_uuid,
6968                MIN(segment->range_end, maxrev), segment->path, pool);
6969       /* If this is subtractive, reverse the whole calculation. */
6970       if (subtractive)
6971         merge_source = merge_source_create(loc2, loc1, TRUE /* ancestral */,
6972                                            pool);
6973       else
6974         merge_source = merge_source_create(loc1, loc2, TRUE /* ancestral */,
6975                                            pool);
6976
6977       APR_ARRAY_PUSH(merge_source_ts, merge_source_t *) = merge_source;
6978     }
6979
6980   /* If this was a subtractive merge, and we created more than one
6981      merge source, we need to reverse the sort ordering of our sources. */
6982   if (subtractive && (merge_source_ts->nelts > 1))
6983     qsort(merge_source_ts->elts, merge_source_ts->nelts,
6984           merge_source_ts->elt_size, compare_merge_source_ts);
6985
6986   *merge_source_ts_p = merge_source_ts;
6987   return SVN_NO_ERROR;
6988 }
6989
6990 /* Similar to normalize_merge_sources() except the input MERGE_RANGE_TS is a
6991  * rangelist.
6992  */
6993 static svn_error_t *
6994 normalize_merge_sources_internal(apr_array_header_t **merge_sources_p,
6995                                  const svn_client__pathrev_t *source_loc,
6996                                  const svn_rangelist_t *merge_range_ts,
6997                                  svn_ra_session_t *ra_session,
6998                                  svn_client_ctx_t *ctx,
6999                                  apr_pool_t *result_pool,
7000                                  apr_pool_t *scratch_pool)
7001 {
7002   svn_revnum_t source_peg_revnum = source_loc->rev;
7003   svn_revnum_t oldest_requested, youngest_requested;
7004   svn_revnum_t trim_revision = SVN_INVALID_REVNUM;
7005   apr_array_header_t *segments;
7006   int i;
7007
7008   /* Initialize our return variable. */
7009   *merge_sources_p = apr_array_make(result_pool, 1, sizeof(merge_source_t *));
7010
7011   /* No ranges to merge?  No problem. */
7012   if (merge_range_ts->nelts == 0)
7013     return SVN_NO_ERROR;
7014
7015   /* Find the extremes of the revisions across our set of ranges. */
7016   merge_range_find_extremes(&oldest_requested, &youngest_requested,
7017                             merge_range_ts);
7018
7019   /* ### FIXME:  Our underlying APIs can't yet handle the case where
7020      the peg revision isn't the youngest of the three revisions.  So
7021      we'll just verify that the source in the peg revision is related
7022      to the source in the youngest requested revision (which is
7023      all the underlying APIs would do in this case right now anyway). */
7024   if (source_peg_revnum < youngest_requested)
7025     {
7026       svn_client__pathrev_t *start_loc;
7027
7028       SVN_ERR(svn_client__repos_location(&start_loc,
7029                                          ra_session, source_loc,
7030                                          youngest_requested,
7031                                          ctx, scratch_pool, scratch_pool));
7032       source_peg_revnum = youngest_requested;
7033     }
7034
7035   /* Fetch the locations for our merge range span. */
7036   SVN_ERR(svn_client__repos_location_segments(&segments,
7037                                               ra_session, source_loc->url,
7038                                               source_peg_revnum,
7039                                               youngest_requested,
7040                                               oldest_requested,
7041                                               ctx, result_pool));
7042
7043   /* See if we fetched enough history to do the job.  "Surely we did,"
7044      you say.  "After all, we covered the entire requested merge
7045      range."  Yes, that's true, but if our first segment doesn't
7046      extend back to the oldest request revision, we've got a special
7047      case to deal with.  Or if the first segment represents a gap,
7048      that's another special case.  */
7049   trim_revision = SVN_INVALID_REVNUM;
7050   if (segments->nelts)
7051     {
7052       svn_location_segment_t *first_segment =
7053         APR_ARRAY_IDX(segments, 0, svn_location_segment_t *);
7054
7055       /* If the first segment doesn't start with the OLDEST_REQUESTED
7056          revision, we'll need to pass a trim revision to our range
7057          cruncher. */
7058       if (first_segment->range_start != oldest_requested)
7059         {
7060           trim_revision = first_segment->range_start;
7061         }
7062
7063       /* Else, if the first segment has no path (and therefore is a
7064          gap), then we'll fetch the copy source revision from the
7065          second segment (provided there is one, of course) and use it
7066          to prepend an extra pathful segment to our list.
7067
7068          ### We could avoid this bit entirely if we'd passed
7069          ### SVN_INVALID_REVNUM instead of OLDEST_REQUESTED to
7070          ### svn_client__repos_location_segments(), but that would
7071          ### really penalize clients hitting pre-1.5 repositories with
7072          ### the typical small merge range request (because of the
7073          ### lack of a node-origins cache in the repository).  */
7074       else if (! first_segment->path)
7075         {
7076           if (segments->nelts > 1)
7077             {
7078               svn_location_segment_t *second_segment =
7079                 APR_ARRAY_IDX(segments, 1, svn_location_segment_t *);
7080               const char *segment_url;
7081               const char *original_repos_relpath;
7082               svn_revnum_t original_revision;
7083               svn_opt_revision_t range_start_rev;
7084               range_start_rev.kind = svn_opt_revision_number;
7085               range_start_rev.value.number = second_segment->range_start;
7086
7087               segment_url = svn_path_url_add_component2(
7088                               source_loc->repos_root_url, second_segment->path,
7089                               scratch_pool);
7090               SVN_ERR(svn_client__get_copy_source(&original_repos_relpath,
7091                                                   &original_revision,
7092                                                   segment_url,
7093                                                   &range_start_rev, ctx,
7094                                                   result_pool, scratch_pool));
7095               /* Got copyfrom data?  Fix up the first segment to cover
7096                  back to COPYFROM_REV + 1, and then prepend a new
7097                  segment covering just COPYFROM_REV. */
7098               if (original_repos_relpath)
7099                 {
7100                   svn_location_segment_t *new_segment =
7101                     apr_pcalloc(result_pool, sizeof(*new_segment));
7102
7103                   new_segment->path = original_repos_relpath;
7104                   new_segment->range_start = original_revision;
7105                   new_segment->range_end = original_revision;
7106                   svn_sort__array_insert(&new_segment, segments, 0);
7107                 }
7108             }
7109         }
7110     }
7111
7112   /* For each range in our requested range set, try to determine the
7113      path(s) associated with that range.  */
7114   for (i = 0; i < merge_range_ts->nelts; i++)
7115     {
7116       svn_merge_range_t *range =
7117         APR_ARRAY_IDX(merge_range_ts, i, svn_merge_range_t *);
7118       apr_array_header_t *merge_sources;
7119
7120       if (SVN_IS_VALID_REVNUM(trim_revision))
7121         {
7122           /* If the range predates the trim revision, discard it. */
7123           if (MAX(range->start, range->end) < trim_revision)
7124             continue;
7125
7126           /* If the range overlaps the trim revision, trim it. */
7127           if (range->start < trim_revision)
7128             range->start = trim_revision;
7129           if (range->end < trim_revision)
7130             range->end = trim_revision;
7131         }
7132
7133       /* Copy the resulting merge sources into master list thereof. */
7134       SVN_ERR(combine_range_with_segments(&merge_sources, range,
7135                                           segments, source_loc,
7136                                           result_pool));
7137       apr_array_cat(*merge_sources_p, merge_sources);
7138     }
7139
7140   return SVN_NO_ERROR;
7141 }
7142
7143 /* Determine the normalized ranges to merge from a given line of history.
7144
7145    Calculate the result by intersecting the list of location segments at
7146    which SOURCE_LOC existed along its line of history with the requested
7147    revision ranges in RANGES_TO_MERGE.  RANGES_TO_MERGE is an array of
7148    (svn_opt_revision_range_t *) revision ranges.  Use SOURCE_PATH_OR_URL to
7149    resolve any WC-relative revision specifiers (such as 'base') in
7150    RANGES_TO_MERGE.
7151
7152    Set *MERGE_SOURCES_P to an array of merge_source_t * objects, each
7153    describing a normalized range of revisions to be merged from the line
7154    history of SOURCE_LOC.  Order the objects from oldest to youngest.
7155
7156    RA_SESSION is an RA session open to the repository of SOURCE_LOC; it may
7157    be temporarily reparented within this function.  Use RA_SESSION to find
7158    the location segments along the line of history of SOURCE_LOC.
7159
7160    Allocate MERGE_SOURCES_P and its contents in RESULT_POOL.
7161
7162    See `MERGEINFO MERGE SOURCE NORMALIZATION' for more on the
7163    background of this function.
7164 */
7165 static svn_error_t *
7166 normalize_merge_sources(apr_array_header_t **merge_sources_p,
7167                         const char *source_path_or_url,
7168                         const svn_client__pathrev_t *source_loc,
7169                         const apr_array_header_t *ranges_to_merge,
7170                         svn_ra_session_t *ra_session,
7171                         svn_client_ctx_t *ctx,
7172                         apr_pool_t *result_pool,
7173                         apr_pool_t *scratch_pool)
7174 {
7175   const char *source_abspath_or_url;
7176   svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
7177   svn_rangelist_t *merge_range_ts;
7178   int i;
7179   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
7180
7181   if(!svn_path_is_url(source_path_or_url))
7182     SVN_ERR(svn_dirent_get_absolute(&source_abspath_or_url, source_path_or_url,
7183                                     scratch_pool));
7184   else
7185     source_abspath_or_url = source_path_or_url;
7186
7187   /* Create a list to hold svn_merge_range_t's. */
7188   merge_range_ts = apr_array_make(scratch_pool, ranges_to_merge->nelts,
7189                                   sizeof(svn_merge_range_t *));
7190
7191   for (i = 0; i < ranges_to_merge->nelts; i++)
7192     {
7193       svn_opt_revision_range_t *range
7194         = APR_ARRAY_IDX(ranges_to_merge, i, svn_opt_revision_range_t *);
7195       svn_merge_range_t mrange;
7196
7197       svn_pool_clear(iterpool);
7198
7199       /* Resolve revisions to real numbers, validating as we go. */
7200       if ((range->start.kind == svn_opt_revision_unspecified)
7201           || (range->end.kind == svn_opt_revision_unspecified))
7202         return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
7203                                 _("Not all required revisions are specified"));
7204
7205       SVN_ERR(svn_client__get_revision_number(&mrange.start, &youngest_rev,
7206                                               ctx->wc_ctx,
7207                                               source_abspath_or_url,
7208                                               ra_session, &range->start,
7209                                               iterpool));
7210       SVN_ERR(svn_client__get_revision_number(&mrange.end, &youngest_rev,
7211                                               ctx->wc_ctx,
7212                                               source_abspath_or_url,
7213                                               ra_session, &range->end,
7214                                               iterpool));
7215
7216       /* If this isn't a no-op range... */
7217       if (mrange.start != mrange.end)
7218         {
7219           /* ...then add it to the list. */
7220           mrange.inheritable = TRUE;
7221           APR_ARRAY_PUSH(merge_range_ts, svn_merge_range_t *)
7222             = svn_merge_range_dup(&mrange, scratch_pool);
7223         }
7224     }
7225
7226   SVN_ERR(normalize_merge_sources_internal(
7227             merge_sources_p, source_loc,
7228             merge_range_ts, ra_session, ctx, result_pool, scratch_pool));
7229
7230   svn_pool_destroy(iterpool);
7231   return SVN_NO_ERROR;
7232 }
7233
7234
7235 /*-----------------------------------------------------------------------*/
7236 \f
7237 /*** Merge Workhorse Functions ***/
7238
7239 /* Helper for do_directory_merge() and do_file_merge() which filters out a
7240    path's own natural history from the mergeinfo describing a merge.
7241
7242    Given the natural history IMPLICIT_MERGEINFO of some wc merge target path,
7243    the repository-relative merge source path SOURCE_REL_PATH, and the
7244    requested merge range REQUESTED_RANGE from SOURCE_REL_PATH, remove any
7245    portion of REQUESTED_RANGE which is already described in
7246    IMPLICIT_MERGEINFO.  Store the result in *FILTERED_RANGELIST.
7247
7248    This function only filters natural history for mergeinfo that will be
7249    *added* during a forward merge.  Removing natural history from explicit
7250    mergeinfo is harmless.  If REQUESTED_RANGE describes a reverse merge,
7251    then *FILTERED_RANGELIST is simply populated with one range described
7252    by REQUESTED_RANGE.  *FILTERED_RANGELIST is never NULL.
7253
7254    Allocate *FILTERED_RANGELIST in POOL. */
7255 static svn_error_t *
7256 filter_natural_history_from_mergeinfo(svn_rangelist_t **filtered_rangelist,
7257                                       const char *source_rel_path,
7258                                       svn_mergeinfo_t implicit_mergeinfo,
7259                                       svn_merge_range_t *requested_range,
7260                                       apr_pool_t *pool)
7261 {
7262   /* Make the REQUESTED_RANGE into a rangelist. */
7263   svn_rangelist_t *requested_rangelist =
7264     svn_rangelist__initialize(requested_range->start, requested_range->end,
7265                               requested_range->inheritable, pool);
7266
7267   *filtered_rangelist = NULL;
7268
7269   /* For forward merges: If the IMPLICIT_MERGEINFO already describes ranges
7270      associated with SOURCE_REL_PATH then filter those ranges out. */
7271   if (implicit_mergeinfo
7272       && (requested_range->start < requested_range->end))
7273     {
7274       svn_rangelist_t *implied_rangelist =
7275                         svn_hash_gets(implicit_mergeinfo, source_rel_path);
7276
7277       if (implied_rangelist)
7278         SVN_ERR(svn_rangelist_remove(filtered_rangelist,
7279                                      implied_rangelist,
7280                                      requested_rangelist,
7281                                      FALSE, pool));
7282     }
7283
7284   /* If no filtering was performed the filtered rangelist is
7285      simply the requested rangelist.*/
7286   if (! (*filtered_rangelist))
7287     *filtered_rangelist = requested_rangelist;
7288
7289   return SVN_NO_ERROR;
7290 }
7291
7292 /* Return a merge source representing the sub-range from START_REV to
7293    END_REV of SOURCE.  SOURCE obeys the rules described in the
7294    'MERGEINFO MERGE SOURCE NORMALIZATION' comment at the top of this file.
7295    The younger of START_REV and END_REV is inclusive while the older is
7296    exclusive.
7297
7298    Allocate the result structure in POOL but leave the URLs in it as shallow
7299    copies of the URLs in SOURCE.
7300 */
7301 static merge_source_t *
7302 subrange_source(const merge_source_t *source,
7303                 svn_revnum_t start_rev,
7304                 svn_revnum_t end_rev,
7305                 apr_pool_t *pool)
7306 {
7307   svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
7308   svn_boolean_t same_urls = (strcmp(source->loc1->url, source->loc2->url) == 0);
7309   svn_client__pathrev_t loc1 = *source->loc1;
7310   svn_client__pathrev_t loc2 = *source->loc2;
7311
7312   /* For this function we require that the input source is 'ancestral'. */
7313   SVN_ERR_ASSERT_NO_RETURN(source->ancestral);
7314   SVN_ERR_ASSERT_NO_RETURN(start_rev != end_rev);
7315
7316   loc1.rev = start_rev;
7317   loc2.rev = end_rev;
7318   if (! same_urls)
7319     {
7320       if (is_rollback && (end_rev != source->loc2->rev))
7321         {
7322           loc2.url = source->loc1->url;
7323         }
7324       if ((! is_rollback) && (start_rev != source->loc1->rev))
7325         {
7326           loc1.url = source->loc2->url;
7327         }
7328     }
7329   return merge_source_create(&loc1, &loc2, source->ancestral, pool);
7330 }
7331
7332 /* The single-file, simplified version of do_directory_merge(), which see for
7333    parameter descriptions.
7334
7335    Additional parameters:
7336
7337    If SOURCES_RELATED is set, the "left" and "right" sides of SOURCE are
7338    historically related (ancestors, uncles, second
7339    cousins thrice removed, etc...).  (This is used to simulate the
7340    history checks that the repository logic does in the directory case.)
7341
7342    If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
7343    is not NULL, then don't record the new mergeinfo on the TARGET_ABSPATH,
7344    but instead record it in RESULT_CATALOG, where the key is TARGET_ABSPATH
7345    and the value is the new mergeinfo for that path.  Allocate additions
7346    to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
7347
7348    CONFLICTED_RANGE is as documented for do_directory_merge().
7349
7350    Note: MERGE_B->RA_SESSION1 must be associated with SOURCE->loc1->url and
7351    MERGE_B->RA_SESSION2 with SOURCE->loc2->url.
7352 */
7353 static svn_error_t *
7354 do_file_merge(svn_mergeinfo_catalog_t result_catalog,
7355               single_range_conflict_report_t **conflict_report,
7356               const merge_source_t *source,
7357               const char *target_abspath,
7358               const svn_diff_tree_processor_t *processor,
7359               svn_boolean_t sources_related,
7360               svn_boolean_t squelch_mergeinfo_notifications,
7361               merge_cmd_baton_t *merge_b,
7362               apr_pool_t *result_pool,
7363               apr_pool_t *scratch_pool)
7364 {
7365   svn_rangelist_t *remaining_ranges;
7366   svn_client_ctx_t *ctx = merge_b->ctx;
7367   svn_merge_range_t range;
7368   svn_mergeinfo_t target_mergeinfo;
7369   svn_boolean_t inherited = FALSE;
7370   svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
7371   const svn_client__pathrev_t *primary_src
7372     = is_rollback ? source->loc1 : source->loc2;
7373   svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b);
7374   svn_client__merge_path_t *merge_target = NULL;
7375   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
7376
7377   SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
7378
7379   *conflict_report = NULL;
7380
7381   /* Note that this is a single-file merge. */
7382   range.start = source->loc1->rev;
7383   range.end = source->loc2->rev;
7384   range.inheritable = TRUE;
7385
7386   merge_target = svn_client__merge_path_create(target_abspath, scratch_pool);
7387
7388   if (honor_mergeinfo)
7389     {
7390       svn_error_t *err;
7391
7392       /* Fetch mergeinfo. */
7393       err = get_full_mergeinfo(&target_mergeinfo,
7394                                &(merge_target->implicit_mergeinfo),
7395                                &inherited, svn_mergeinfo_inherited,
7396                                merge_b->ra_session1, target_abspath,
7397                                MAX(source->loc1->rev, source->loc2->rev),
7398                                MIN(source->loc1->rev, source->loc2->rev),
7399                                ctx, scratch_pool, iterpool);
7400
7401       if (err)
7402         {
7403           if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
7404             {
7405               err = svn_error_createf(
7406                 SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING, err,
7407                 _("Invalid mergeinfo detected on merge target '%s', "
7408                   "merge tracking not possible"),
7409                 svn_dirent_local_style(target_abspath, scratch_pool));
7410             }
7411           return svn_error_trace(err);
7412         }
7413
7414       /* Calculate remaining merges unless this is a record only merge.
7415          In that case the remaining range is the whole range described
7416          by SOURCE->rev1:rev2. */
7417       if (!merge_b->record_only)
7418         {
7419           /* ### Bug?  calculate_remaining_ranges() needs 'source' to adhere
7420            *   to the requirements of 'MERGEINFO MERGE SOURCE NORMALIZATION'
7421            *   here, but it doesn't appear to be guaranteed so. */
7422           SVN_ERR(calculate_remaining_ranges(NULL, merge_target,
7423                                              source,
7424                                              target_mergeinfo,
7425                                              merge_b->implicit_src_gap, FALSE,
7426                                              merge_b->ra_session1,
7427                                              ctx, scratch_pool,
7428                                              iterpool));
7429           remaining_ranges = merge_target->remaining_ranges;
7430
7431           /* We are honoring mergeinfo and this is not a simple record only
7432              merge which blindly records mergeinfo describing the merge of
7433              SOURCE->LOC1->URL@SOURCE->LOC1->REV through
7434              SOURCE->LOC2->URL@SOURCE->LOC2->REV.  This means that the oldest
7435              and youngest revisions merged (as determined above by
7436              calculate_remaining_ranges) might differ from those described
7437              in SOURCE.  To keep the '--- Merging *' notifications consistent
7438              with the '--- Recording mergeinfo *' notifications, we adjust
7439              RANGE to account for such changes. */
7440           if (remaining_ranges->nelts)
7441             {
7442               svn_merge_range_t *adj_start_range =
7443                 APR_ARRAY_IDX(remaining_ranges, 0, svn_merge_range_t *);
7444               svn_merge_range_t *adj_end_range =
7445                 APR_ARRAY_IDX(remaining_ranges, remaining_ranges->nelts - 1,
7446                               svn_merge_range_t *);
7447               range.start = adj_start_range->start;
7448               range.end = adj_end_range->end;
7449             }
7450         }
7451     }
7452
7453   /* The simple cases where our remaining range is SOURCE->rev1:rev2. */
7454   if (!honor_mergeinfo || merge_b->record_only)
7455     {
7456       remaining_ranges = apr_array_make(scratch_pool, 1, sizeof(&range));
7457       APR_ARRAY_PUSH(remaining_ranges, svn_merge_range_t *) = &range;
7458     }
7459
7460   if (!merge_b->record_only)
7461     {
7462       svn_rangelist_t *ranges_to_merge = apr_array_copy(scratch_pool,
7463                                                         remaining_ranges);
7464       const char *target_relpath = "";  /* relative to root of merge */
7465
7466       if (source->ancestral)
7467         {
7468           apr_array_header_t *child_with_mergeinfo;
7469           svn_client__merge_path_t *target_info;
7470
7471           /* If we have ancestrally related sources and more than one
7472              range to merge, eliminate no-op ranges before going through
7473              the effort of downloading the many copies of the file
7474              required to do these merges (two copies per range). */
7475           if (remaining_ranges->nelts > 1)
7476             {
7477               const char *old_sess_url;
7478               svn_error_t *err;
7479
7480               SVN_ERR(svn_client__ensure_ra_session_url(&old_sess_url,
7481                                                         merge_b->ra_session1,
7482                                                         primary_src->url,
7483                                                         iterpool));
7484               err = remove_noop_merge_ranges(&ranges_to_merge,
7485                                              merge_b->ra_session1,
7486                                              remaining_ranges, scratch_pool);
7487               SVN_ERR(svn_error_compose_create(
7488                         err, svn_ra_reparent(merge_b->ra_session1,
7489                                              old_sess_url, iterpool)));
7490             }
7491
7492           /* To support notify_merge_begin() initialize our
7493              CHILD_WITH_MERGEINFO. See the comment
7494              'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */
7495
7496           child_with_mergeinfo = apr_array_make(scratch_pool, 1,
7497                                         sizeof(svn_client__merge_path_t *));
7498
7499           /* ### Create a fake copy of merge_target as we don't keep
7500                  remaining_ranges in sync (yet). */
7501           target_info = apr_pcalloc(scratch_pool, sizeof(*target_info));
7502
7503           target_info->abspath = merge_target->abspath;
7504           target_info->remaining_ranges = ranges_to_merge;
7505
7506           APR_ARRAY_PUSH(child_with_mergeinfo, svn_client__merge_path_t *)
7507                                     = target_info;
7508
7509           /* And store in baton to allow using it from notify_merge_begin() */
7510           merge_b->notify_begin.nodes_with_mergeinfo = child_with_mergeinfo;
7511         }
7512
7513       while (ranges_to_merge->nelts > 0)
7514         {
7515           svn_merge_range_t *r = APR_ARRAY_IDX(ranges_to_merge, 0,
7516                                                svn_merge_range_t *);
7517           const merge_source_t *real_source;
7518           const char *left_file, *right_file;
7519           apr_hash_t *left_props, *right_props;
7520           const svn_diff_source_t *left_source;
7521           const svn_diff_source_t *right_source;
7522
7523           svn_pool_clear(iterpool);
7524
7525           /* Ensure any subsequent drives gets their own notification. */
7526           merge_b->notify_begin.last_abspath = NULL;
7527
7528           /* While we currently don't allow it, in theory we could be
7529              fetching two fulltexts from two different repositories here. */
7530           if (source->ancestral)
7531             real_source = subrange_source(source, r->start, r->end, iterpool);
7532           else
7533             real_source = source;
7534           SVN_ERR(single_file_merge_get_file(&left_file, &left_props,
7535                                              merge_b->ra_session1,
7536                                              real_source->loc1,
7537                                              target_abspath,
7538                                              iterpool, iterpool));
7539           SVN_ERR(single_file_merge_get_file(&right_file, &right_props,
7540                                              merge_b->ra_session2,
7541                                              real_source->loc2,
7542                                              target_abspath,
7543                                              iterpool, iterpool));
7544           /* Calculate sources for the diff processor */
7545           left_source = svn_diff__source_create(r->start, iterpool);
7546           right_source = svn_diff__source_create(r->end, iterpool);
7547
7548
7549           /* If the sources are related or we're ignoring ancestry in diffs,
7550              do a text-n-props merge; otherwise, do a delete-n-add merge. */
7551           if (! (merge_b->diff_ignore_ancestry || sources_related))
7552             {
7553               struct merge_dir_baton_t dir_baton;
7554               void *file_baton;
7555               svn_boolean_t skip;
7556
7557               /* Initialize minimal dir baton to allow calculating 'R'eplace
7558                  from 'D'elete + 'A'dd. */
7559
7560               memset(&dir_baton, 0, sizeof(dir_baton));
7561               dir_baton.pool = iterpool;
7562               dir_baton.tree_conflict_reason = CONFLICT_REASON_NONE;
7563               dir_baton.tree_conflict_action = svn_wc_conflict_action_edit;
7564               dir_baton.skip_reason = svn_wc_notify_state_unknown;
7565
7566               /* Delete... */
7567               file_baton = NULL;
7568               skip = FALSE;
7569               SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath,
7570                                              left_source,
7571                                              NULL /* right_source */,
7572                                              NULL /* copyfrom_source */,
7573                                              &dir_baton,
7574                                              processor,
7575                                              iterpool, iterpool));
7576               if (! skip)
7577                 SVN_ERR(processor->file_deleted(target_relpath,
7578                                                 left_source,
7579                                                 left_file,
7580                                                 left_props,
7581                                                 file_baton,
7582                                                 processor,
7583                                                 iterpool));
7584
7585               /* ...plus add... */
7586               file_baton = NULL;
7587               skip = FALSE;
7588               SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath,
7589                                              NULL /* left_source */,
7590                                              right_source,
7591                                              NULL /* copyfrom_source */,
7592                                              &dir_baton,
7593                                              processor,
7594                                              iterpool, iterpool));
7595               if (! skip)
7596                 SVN_ERR(processor->file_added(target_relpath,
7597                                               NULL /* copyfrom_source */,
7598                                               right_source,
7599                                               NULL /* copyfrom_file */,
7600                                               right_file,
7601                                               NULL /* copyfrom_props */,
7602                                               right_props,
7603                                               file_baton,
7604                                               processor,
7605                                               iterpool));
7606               /* ... equals replace. */
7607             }
7608           else
7609             {
7610               void *file_baton = NULL;
7611               svn_boolean_t skip = FALSE;
7612               apr_array_header_t *propchanges;
7613
7614
7615               /* Deduce property diffs. */
7616               SVN_ERR(svn_prop_diffs(&propchanges, right_props, left_props,
7617                                      iterpool));
7618
7619               SVN_ERR(processor->file_opened(&file_baton, &skip, target_relpath,
7620                                              left_source,
7621                                              right_source,
7622                                              NULL /* copyfrom_source */,
7623                                              NULL /* dir_baton */,
7624                                              processor,
7625                                              iterpool, iterpool));
7626               if (! skip)
7627                 SVN_ERR(processor->file_changed(target_relpath,
7628                                               left_source,
7629                                               right_source,
7630                                               left_file,
7631                                               right_file,
7632                                               left_props,
7633                                               right_props,
7634                                               TRUE /* file changed */,
7635                                               propchanges,
7636                                               file_baton,
7637                                               processor,
7638                                               iterpool));
7639             }
7640
7641           if (is_path_conflicted_by_merge(merge_b))
7642             {
7643               merge_source_t *remaining_range = NULL;
7644
7645               if (real_source->loc2->rev != source->loc2->rev)
7646                 remaining_range = subrange_source(source,
7647                                                   real_source->loc2->rev,
7648                                                   source->loc2->rev,
7649                                                   scratch_pool);
7650               *conflict_report = single_range_conflict_report_create(
7651                                    real_source, remaining_range, result_pool);
7652
7653               /* Only record partial mergeinfo if only a partial merge was
7654                  performed before a conflict was encountered. */
7655               range.end = r->end;
7656               break;
7657             }
7658
7659           /* Now delete the just merged range from the hash
7660              (This list is used from notify_merge_begin)
7661
7662             Directory merges use remove_first_range_from_remaining_ranges() */
7663           svn_sort__array_delete(ranges_to_merge, 0, 1);
7664         }
7665       merge_b->notify_begin.last_abspath = NULL;
7666     } /* !merge_b->record_only */
7667
7668   /* Record updated WC mergeinfo to account for our new merges, minus
7669      any unresolved conflicts and skips.  We use the original
7670      REMAINING_RANGES here because we want to record all the requested
7671      merge ranges, include the noop ones.  */
7672   if (RECORD_MERGEINFO(merge_b) && remaining_ranges->nelts)
7673     {
7674       const char *mergeinfo_path = svn_client__pathrev_fspath(primary_src,
7675                                                               scratch_pool);
7676       svn_rangelist_t *filtered_rangelist;
7677
7678       /* Filter any ranges from TARGET_WCPATH's own history, there is no
7679          need to record this explicitly in mergeinfo, it is already part
7680          of TARGET_WCPATH's natural history (implicit mergeinfo). */
7681       SVN_ERR(filter_natural_history_from_mergeinfo(
7682         &filtered_rangelist,
7683         mergeinfo_path,
7684         merge_target->implicit_mergeinfo,
7685         &range,
7686         iterpool));
7687
7688       /* Only record mergeinfo if there is something other than
7689          self-referential mergeinfo, but don't record mergeinfo if
7690          TARGET_WCPATH was skipped. */
7691       if (filtered_rangelist->nelts
7692           && (apr_hash_count(merge_b->skipped_abspaths) == 0))
7693         {
7694           apr_hash_t *merges = apr_hash_make(iterpool);
7695
7696           /* If merge target has inherited mergeinfo set it before
7697              recording the first merge range. */
7698           if (inherited)
7699             SVN_ERR(svn_client__record_wc_mergeinfo(target_abspath,
7700                                                     target_mergeinfo,
7701                                                     FALSE, ctx,
7702                                                     iterpool));
7703
7704           svn_hash_sets(merges, target_abspath, filtered_rangelist);
7705
7706           if (!squelch_mergeinfo_notifications)
7707             {
7708               /* Notify that we are recording mergeinfo describing a merge. */
7709               svn_merge_range_t n_range;
7710
7711               SVN_ERR(svn_mergeinfo__get_range_endpoints(
7712                         &n_range.end, &n_range.start, merges, iterpool));
7713               n_range.inheritable = TRUE;
7714               notify_mergeinfo_recording(target_abspath, &n_range,
7715                                          merge_b->ctx, iterpool);
7716             }
7717
7718           SVN_ERR(update_wc_mergeinfo(result_catalog, target_abspath,
7719                                       mergeinfo_path, merges, is_rollback,
7720                                       ctx, iterpool));
7721         }
7722     }
7723
7724   merge_b->notify_begin.nodes_with_mergeinfo = NULL;
7725
7726   svn_pool_destroy(iterpool);
7727
7728   return SVN_NO_ERROR;
7729 }
7730
7731 /* Helper for do_directory_merge() to handle the case where a merge editor
7732    drive adds explicit mergeinfo to a path which didn't have any explicit
7733    mergeinfo previously.
7734
7735    MERGE_B is cascaded from the argument of the same
7736    name in do_directory_merge().  Should be called only after
7737    do_directory_merge() has called populate_remaining_ranges() and populated
7738    the remaining_ranges field of each child in
7739    CHILDREN_WITH_MERGEINFO (i.e. the remaining_ranges fields can be
7740    empty but never NULL).
7741
7742    If MERGE_B->DRY_RUN is true do nothing, if it is false then
7743    for each path (if any) in MERGE_B->PATHS_WITH_NEW_MERGEINFO merge that
7744    path's inherited mergeinfo (if any) with its working explicit mergeinfo
7745    and set that as the path's new explicit mergeinfo.  Then add an
7746    svn_client__merge_path_t * element representing the path to
7747    CHILDREN_WITH_MERGEINFO if it isn't already present.  All fields
7748    in any elements added to CHILDREN_WITH_MERGEINFO are initialized
7749    to FALSE/NULL with the exception of 'path' and 'remaining_ranges'.  The
7750    latter is set to a rangelist equal to the remaining_ranges of the path's
7751    nearest path-wise ancestor in CHILDREN_WITH_MERGEINFO.
7752
7753    Any elements added to CHILDREN_WITH_MERGEINFO are allocated
7754    in POOL. */
7755 static svn_error_t *
7756 process_children_with_new_mergeinfo(merge_cmd_baton_t *merge_b,
7757                                     apr_array_header_t *children_with_mergeinfo,
7758                                     apr_pool_t *pool)
7759 {
7760   apr_pool_t *iterpool;
7761   apr_hash_index_t *hi;
7762
7763   if (!merge_b->paths_with_new_mergeinfo || merge_b->dry_run)
7764     return SVN_NO_ERROR;
7765
7766   /* Iterate over each path with explicit mergeinfo added by the merge. */
7767   iterpool = svn_pool_create(pool);
7768   for (hi = apr_hash_first(pool, merge_b->paths_with_new_mergeinfo);
7769        hi;
7770        hi = apr_hash_next(hi))
7771     {
7772       const char *abspath_with_new_mergeinfo = svn__apr_hash_index_key(hi);
7773       svn_mergeinfo_t path_inherited_mergeinfo;
7774       svn_mergeinfo_t path_explicit_mergeinfo;
7775       svn_client__merge_path_t *new_child;
7776
7777       svn_pool_clear(iterpool);
7778
7779       /* Note: We could skip recording inherited mergeinfo here if this path
7780          was added (with preexisting mergeinfo) by the merge.  That's actually
7781          more correct, since the inherited mergeinfo likely describes
7782          non-existent or unrelated merge history, but it's not quite so simple
7783          as that, see http://subversion.tigris.org/issues/show_bug.cgi?id=4309
7784          */
7785
7786       /* Get the path's new explicit mergeinfo... */
7787       SVN_ERR(svn_client__get_wc_mergeinfo(&path_explicit_mergeinfo, NULL,
7788                                            svn_mergeinfo_explicit,
7789                                            abspath_with_new_mergeinfo,
7790                                            NULL, NULL, FALSE,
7791                                            merge_b->ctx,
7792                                            iterpool, iterpool));
7793       /* ...there *should* always be explicit mergeinfo at this point
7794          but you can't be too careful. */
7795       if (path_explicit_mergeinfo)
7796         {
7797           /* Get the mergeinfo the path would have inherited before
7798              the merge. */
7799           SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(
7800             &path_inherited_mergeinfo,
7801             NULL, NULL,
7802             FALSE,
7803             svn_mergeinfo_nearest_ancestor, /* We only want inherited MI */
7804             merge_b->ra_session2,
7805             abspath_with_new_mergeinfo,
7806             merge_b->ctx,
7807             iterpool));
7808
7809           /* If the path inherited any mergeinfo then merge that with the
7810              explicit mergeinfo and record the result as the path's new
7811              explicit mergeinfo. */
7812           if (path_inherited_mergeinfo)
7813             {
7814               SVN_ERR(svn_mergeinfo_merge2(path_explicit_mergeinfo,
7815                                            path_inherited_mergeinfo,
7816                                            iterpool, iterpool));
7817               SVN_ERR(svn_client__record_wc_mergeinfo(
7818                                           abspath_with_new_mergeinfo,
7819                                           path_explicit_mergeinfo,
7820                                           FALSE, merge_b->ctx, iterpool));
7821             }
7822
7823           /* If the path is not in CHILDREN_WITH_MERGEINFO then add it. */
7824           new_child =
7825             get_child_with_mergeinfo(children_with_mergeinfo,
7826                                      abspath_with_new_mergeinfo);
7827           if (!new_child)
7828             {
7829               const svn_client__merge_path_t *parent
7830                 = find_nearest_ancestor(children_with_mergeinfo,
7831                                         FALSE, abspath_with_new_mergeinfo);
7832               new_child
7833                 = svn_client__merge_path_create(abspath_with_new_mergeinfo,
7834                                                 pool);
7835
7836               /* If path_with_new_mergeinfo is the merge target itself
7837                  then it should already be in
7838                  CHILDREN_WITH_MERGEINFO per the criteria of
7839                  get_mergeinfo_paths() and we shouldn't be in this block.
7840                  If path_with_new_mergeinfo is a subtree then it must have
7841                  a parent in CHILDREN_WITH_MERGEINFO if only
7842                  the merge target itself...so if we don't find a parent
7843                  the caller has done something quite wrong. */
7844               SVN_ERR_ASSERT(parent);
7845               SVN_ERR_ASSERT(parent->remaining_ranges);
7846
7847               /* Set the path's remaining_ranges equal to its parent's. */
7848               new_child->remaining_ranges = svn_rangelist_dup(
7849                  parent->remaining_ranges, pool);
7850               insert_child_to_merge(children_with_mergeinfo, new_child, pool);
7851             }
7852         }
7853     }
7854   svn_pool_destroy(iterpool);
7855
7856   return SVN_NO_ERROR;
7857 }
7858
7859 /* Return true if any path in SUBTREES is equal to, or is a subtree of,
7860    LOCAL_ABSPATH.  Return false otherwise.  The keys of SUBTREES are
7861    (const char *) absolute paths and its values are irrelevant.
7862    If SUBTREES is NULL return false. */
7863 static svn_boolean_t
7864 path_is_subtree(const char *local_abspath,
7865                 apr_hash_t *subtrees,
7866                 apr_pool_t *pool)
7867 {
7868   if (subtrees)
7869     {
7870       apr_hash_index_t *hi;
7871
7872       for (hi = apr_hash_first(pool, subtrees);
7873            hi; hi = apr_hash_next(hi))
7874         {
7875           const char *path_touched_by_merge = svn__apr_hash_index_key(hi);
7876           if (svn_dirent_is_ancestor(local_abspath, path_touched_by_merge))
7877             return TRUE;
7878         }
7879     }
7880   return FALSE;
7881 }
7882
7883 /* Return true if any merged, skipped, added or tree-conflicted path
7884    recorded in MERGE_B is equal to, or is a subtree of LOCAL_ABSPATH.  Return
7885    false otherwise.
7886
7887    ### Why not text- or prop-conflicted paths? Are such paths guaranteed
7888        to be recorded as 'merged' or 'skipped' or 'added', perhaps?
7889 */
7890 static svn_boolean_t
7891 subtree_touched_by_merge(const char *local_abspath,
7892                          merge_cmd_baton_t *merge_b,
7893                          apr_pool_t *pool)
7894 {
7895   return (path_is_subtree(local_abspath, merge_b->merged_abspaths, pool)
7896           || path_is_subtree(local_abspath, merge_b->skipped_abspaths, pool)
7897           || path_is_subtree(local_abspath, merge_b->added_abspaths, pool)
7898           || path_is_subtree(local_abspath, merge_b->tree_conflicted_abspaths,
7899                              pool));
7900 }
7901
7902 /* Helper for do_directory_merge() when performing mergeinfo unaware merges.
7903
7904    Merge the SOURCE diff into TARGET_DIR_WCPATH.
7905
7906    SOURCE, DEPTH, NOTIFY_B, and MERGE_B
7907    are all cascaded from do_directory_merge's arguments of the same names.
7908
7909    CONFLICT_REPORT is as documented for do_directory_merge().
7910
7911    NOTE: This is a very thin wrapper around drive_merge_report_editor() and
7912    exists only to populate CHILDREN_WITH_MERGEINFO with the single element
7913    expected during mergeinfo unaware merges.
7914 */
7915 static svn_error_t *
7916 do_mergeinfo_unaware_dir_merge(single_range_conflict_report_t **conflict_report,
7917                                const merge_source_t *source,
7918                                const char *target_dir_wcpath,
7919                                apr_array_header_t *children_with_mergeinfo,
7920                                const svn_diff_tree_processor_t *processor,
7921                                svn_depth_t depth,
7922                                merge_cmd_baton_t *merge_b,
7923                                apr_pool_t *result_pool,
7924                                apr_pool_t *scratch_pool)
7925 {
7926   /* Initialize CHILDREN_WITH_MERGEINFO and populate it with
7927      one element describing the merge of SOURCE->rev1:rev2 to
7928      TARGET_DIR_WCPATH. */
7929   svn_client__merge_path_t *item
7930     = svn_client__merge_path_create(target_dir_wcpath, scratch_pool);
7931
7932   *conflict_report = NULL;
7933   item->remaining_ranges = svn_rangelist__initialize(source->loc1->rev,
7934                                                      source->loc2->rev,
7935                                                      TRUE, scratch_pool);
7936   APR_ARRAY_PUSH(children_with_mergeinfo,
7937                  svn_client__merge_path_t *) = item;
7938   SVN_ERR(drive_merge_report_editor(target_dir_wcpath,
7939                                     source,
7940                                     NULL, processor, depth,
7941                                     merge_b, scratch_pool));
7942   if (is_path_conflicted_by_merge(merge_b))
7943     {
7944       *conflict_report = single_range_conflict_report_create(
7945                            source, NULL, result_pool);
7946     }
7947   return SVN_NO_ERROR;
7948 }
7949
7950 /* A svn_log_entry_receiver_t baton for log_find_operative_subtree_revs(). */
7951 typedef struct log_find_operative_subtree_baton_t
7952 {
7953   /* Mapping of const char * absolute working copy paths to those
7954      path's const char * repos absolute paths. */
7955   apr_hash_t *operative_children;
7956
7957   /* As per the arguments of the same name to
7958      get_operative_immediate_children(). */
7959   const char *merge_source_fspath;
7960   const char *merge_target_abspath;
7961   svn_depth_t depth;
7962   svn_wc_context_t *wc_ctx;
7963
7964   /* A pool to allocate additions to the hashes in. */
7965   apr_pool_t *result_pool;
7966 } log_find_operative_subtree_baton_t;
7967
7968 /* A svn_log_entry_receiver_t callback for
7969    get_inoperative_immediate_children(). */
7970 static svn_error_t *
7971 log_find_operative_subtree_revs(void *baton,
7972                                 svn_log_entry_t *log_entry,
7973                                 apr_pool_t *pool)
7974 {
7975   log_find_operative_subtree_baton_t *log_baton = baton;
7976   apr_hash_index_t *hi;
7977   apr_pool_t *iterpool;
7978
7979   /* It's possible that authz restrictions on the merge source prevent us
7980      from knowing about any of the changes for LOG_ENTRY->REVISION. */
7981   if (!log_entry->changed_paths2)
7982     return SVN_NO_ERROR;
7983
7984   iterpool = svn_pool_create(pool);
7985
7986   for (hi = apr_hash_first(pool, log_entry->changed_paths2);
7987        hi;
7988        hi = apr_hash_next(hi))
7989     {
7990       const char *path = svn__apr_hash_index_key(hi);
7991       svn_log_changed_path2_t *change = svn__apr_hash_index_val(hi);
7992
7993         {
7994           const char *child;
7995           const char *potential_child;
7996           const char *rel_path =
7997             svn_fspath__skip_ancestor(log_baton->merge_source_fspath, path);
7998
7999           /* Some affected paths might be the root of the merge source or
8000              entirely outside our subtree of interest. In either case they
8001              are not operative *immediate* children. */
8002           if (rel_path == NULL
8003               || rel_path[0] == '\0')
8004             continue;
8005
8006           svn_pool_clear(iterpool);
8007
8008           child = svn_relpath_dirname(rel_path, iterpool);
8009           if (child[0] == '\0')
8010             {
8011               /* The svn_log_changed_path2_t.node_kind members in
8012                  LOG_ENTRY->CHANGED_PATHS2 may be set to
8013                  svn_node_unknown, see svn_log_changed_path2_t and
8014                  svn_fs_paths_changed2.  In that case we check the
8015                  type of the corresponding subtree in the merge
8016                  target. */
8017               svn_node_kind_t node_kind;
8018
8019               if (change->node_kind == svn_node_unknown)
8020                 {
8021                   const char *wc_child_abspath =
8022                     svn_dirent_join(log_baton->merge_target_abspath,
8023                                     rel_path, iterpool);
8024
8025                   SVN_ERR(svn_wc_read_kind2(&node_kind, log_baton->wc_ctx,
8026                                             wc_child_abspath, FALSE, FALSE,
8027                                             iterpool));
8028                 }
8029               else
8030                 {
8031                   node_kind = change->node_kind;
8032                 }
8033
8034               /* We only care about immediate directory children if
8035                  DEPTH is svn_depth_files. */
8036               if (log_baton->depth == svn_depth_files
8037                   && node_kind != svn_node_dir)
8038                 continue;
8039
8040               /* If depth is svn_depth_immediates, then we only care
8041                  about changes to proper subtrees of PATH.  If the change
8042                  is to PATH itself then PATH is within the operational
8043                  depth of the merge. */
8044               if (log_baton->depth == svn_depth_immediates)
8045                 continue;
8046
8047               child = rel_path;
8048             }
8049
8050           potential_child = svn_dirent_join(log_baton->merge_target_abspath,
8051                                             child, iterpool);
8052
8053           if (change->action == 'A'
8054               || !svn_hash_gets(log_baton->operative_children,
8055                                 potential_child))
8056             {
8057               svn_hash_sets(log_baton->operative_children,
8058                             apr_pstrdup(log_baton->result_pool,
8059                                         potential_child),
8060                             apr_pstrdup(log_baton->result_pool, path));
8061             }
8062         }
8063     }
8064   svn_pool_destroy(iterpool);
8065   return SVN_NO_ERROR;
8066 }
8067
8068 /* Find immediate subtrees of MERGE_TARGET_ABSPATH which would have
8069    additional differences applied if record_mergeinfo_for_dir_merge() were
8070    recording mergeinfo describing a merge at svn_depth_infinity, rather
8071    than at DEPTH (which is assumed to be shallow; if
8072    DEPTH == svn_depth_infinity then this function does nothing beyond
8073    setting *OPERATIVE_CHILDREN to an empty hash).
8074
8075    MERGE_SOURCE_FSPATH is the absolute repository path of the merge
8076    source.  OLDEST_REV and YOUNGEST_REV are the revisions merged from
8077    MERGE_SOURCE_FSPATH to MERGE_TARGET_ABSPATH.
8078
8079    RA_SESSION points to MERGE_SOURCE_FSPATH.
8080
8081    Set *OPERATIVE_CHILDREN to a hash (mapping const char * absolute
8082    working copy paths to those path's const char * repos absolute paths)
8083    containing all the immediate subtrees of MERGE_TARGET_ABSPATH which would
8084    have a different diff applied if MERGE_SOURCE_FSPATH
8085    -r(OLDEST_REV - 1):YOUNGEST_REV were merged to MERGE_TARGET_ABSPATH at
8086    svn_depth_infinity rather than DEPTH.
8087
8088    RESULT_POOL is used to allocate the contents of *OPERATIVE_CHILDREN.
8089    SCRATCH_POOL is used for temporary allocations. */
8090 static svn_error_t *
8091 get_operative_immediate_children(apr_hash_t **operative_children,
8092                                  const char *merge_source_fspath,
8093                                  svn_revnum_t oldest_rev,
8094                                  svn_revnum_t youngest_rev,
8095                                  const char *merge_target_abspath,
8096                                  svn_depth_t depth,
8097                                  svn_wc_context_t *wc_ctx,
8098                                  svn_ra_session_t *ra_session,
8099                                  apr_pool_t *result_pool,
8100                                  apr_pool_t *scratch_pool)
8101 {
8102   log_find_operative_subtree_baton_t log_baton;
8103
8104   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev));
8105   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
8106   SVN_ERR_ASSERT(oldest_rev <= youngest_rev);
8107
8108   *operative_children = apr_hash_make(result_pool);
8109
8110   if (depth == svn_depth_infinity)
8111     return SVN_NO_ERROR;
8112
8113   /* Now remove any paths from *OPERATIVE_CHILDREN that are inoperative when
8114      merging MERGE_SOURCE_REPOS_PATH -r(OLDEST_REV - 1):YOUNGEST_REV to
8115      MERGE_TARGET_ABSPATH at --depth infinity. */
8116   log_baton.operative_children = *operative_children;
8117   log_baton.merge_source_fspath = merge_source_fspath;
8118   log_baton.merge_target_abspath = merge_target_abspath;
8119   log_baton.depth = depth;
8120   log_baton.wc_ctx = wc_ctx;
8121   log_baton.result_pool = result_pool;
8122
8123   SVN_ERR(get_log(ra_session, "", youngest_rev, oldest_rev,
8124                   TRUE, /* discover_changed_paths */
8125                   log_find_operative_subtree_revs,
8126                   &log_baton, scratch_pool));
8127
8128   return SVN_NO_ERROR;
8129 }
8130
8131 /* Helper for record_mergeinfo_for_dir_merge(): Identify which elements of
8132    CHILDREN_WITH_MERGEINFO need new mergeinfo set to accurately
8133    describe a merge, what inheritance type such new mergeinfo should have,
8134    and what subtrees can be ignored altogether.
8135
8136    For each svn_client__merge_path_t CHILD in CHILDREN_WITH_MERGEINFO,
8137    set CHILD->RECORD_MERGEINFO and CHILD->RECORD_NONINHERITABLE to true
8138    if the subtree needs mergeinfo to describe the merge and if that
8139    mergeinfo should be non-inheritable respectively.
8140
8141    If OPERATIVE_MERGE is true, then the merge being described is operative
8142    as per subtree_touched_by_merge().  OPERATIVE_MERGE is false otherwise.
8143
8144    MERGED_RANGE, MERGEINFO_FSPATH, DEPTH, NOTIFY_B, and MERGE_B are all
8145    cascaded from record_mergeinfo_for_dir_merge's arguments of the same
8146    names.
8147
8148    SCRATCH_POOL is used for temporary allocations.
8149 */
8150 static svn_error_t *
8151 flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
8152                                 const svn_merge_range_t *merged_range,
8153                                 apr_array_header_t *children_with_mergeinfo,
8154                                 const char *mergeinfo_fspath,
8155                                 svn_depth_t depth,
8156                                 merge_cmd_baton_t *merge_b,
8157                                 apr_pool_t *scratch_pool)
8158 {
8159   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
8160   int i;
8161   apr_hash_t *operative_immediate_children = NULL;
8162
8163   assert(! merge_b->dry_run);
8164
8165   if (!merge_b->record_only
8166       && merged_range->start <= merged_range->end
8167       && (depth < svn_depth_infinity))
8168     SVN_ERR(get_operative_immediate_children(
8169       &operative_immediate_children,
8170       mergeinfo_fspath, merged_range->start + 1, merged_range->end,
8171       merge_b->target->abspath, depth, merge_b->ctx->wc_ctx,
8172       merge_b->ra_session1, scratch_pool, iterpool));
8173
8174   /* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first
8175      order.  This way each child knows if it has operative missing/switched
8176      children which necessitates non-inheritable mergeinfo. */
8177   for (i = children_with_mergeinfo->nelts - 1; i >= 0; i--)
8178     {
8179       svn_client__merge_path_t *child =
8180                      APR_ARRAY_IDX(children_with_mergeinfo, i,
8181                                    svn_client__merge_path_t *);
8182
8183       /* Can't record mergeinfo on something that isn't here. */
8184       if (child->absent)
8185         continue;
8186
8187       /* Verify that remove_children_with_deleted_mergeinfo() did its job */
8188       assert((i == 0)
8189              ||! merge_b->paths_with_deleted_mergeinfo
8190              || !svn_hash_gets(merge_b->paths_with_deleted_mergeinfo,
8191                                child->abspath));
8192
8193       /* Don't record mergeinfo on skipped paths. */
8194       if (svn_hash_gets(merge_b->skipped_abspaths, child->abspath))
8195         continue;
8196
8197       /* ### ptb: Yes, we could combine the following into a single
8198          ### conditional, but clarity would suffer (even more than
8199          ### it does now). */
8200       if (i == 0)
8201         {
8202           /* Always record mergeinfo on the merge target. */
8203           child->record_mergeinfo = TRUE;
8204         }
8205       else if (merge_b->record_only && !merge_b->reintegrate_merge)
8206         {
8207           /* Always record mergeinfo for --record-only merges. */
8208           child->record_mergeinfo = TRUE;
8209         }
8210       else if (child->immediate_child_dir
8211                && !child->pre_merge_mergeinfo
8212                && operative_immediate_children
8213                && svn_hash_gets(operative_immediate_children, child->abspath))
8214         {
8215           /* We must record mergeinfo on those issue #3642 children
8216              that are operative at a greater depth. */
8217           child->record_mergeinfo = TRUE;
8218         }
8219
8220       if (operative_merge
8221           && subtree_touched_by_merge(child->abspath, merge_b, iterpool))
8222         {
8223           svn_pool_clear(iterpool);
8224
8225           /* This subtree was affected by the merge. */
8226           child->record_mergeinfo = TRUE;
8227
8228           /* Were any CHILD's missing children skipped by the merge?
8229              If not, then CHILD's missing children don't need to be
8230              considered when recording mergeinfo describing the merge. */
8231           if (! merge_b->reintegrate_merge
8232               && child->missing_child
8233               && !path_is_subtree(child->abspath,
8234                                   merge_b->skipped_abspaths,
8235                                   iterpool))
8236             {
8237               child->missing_child = FALSE;
8238             }
8239
8240           /* If CHILD has an immediate switched child or children and
8241              none of these were touched by the merge, then we don't need
8242              need to do any special handling of those switched subtrees
8243              (e.g. record non-inheritable mergeinfo) when recording
8244              mergeinfo describing the merge. */
8245           if (child->switched_child)
8246             {
8247               int j;
8248               svn_boolean_t operative_switched_child = FALSE;
8249
8250               for (j = i + 1;
8251                    j < children_with_mergeinfo->nelts;
8252                    j++)
8253                 {
8254                   svn_client__merge_path_t *potential_child =
8255                     APR_ARRAY_IDX(children_with_mergeinfo, j,
8256                                   svn_client__merge_path_t *);
8257                   if (!svn_dirent_is_ancestor(child->abspath,
8258                                               potential_child->abspath))
8259                     break;
8260
8261                   /* POTENTIAL_CHILD is a subtree of CHILD, but is it
8262                      an immediate child? */
8263                   if (strcmp(child->abspath,
8264                              svn_dirent_dirname(potential_child->abspath,
8265                                                 iterpool)))
8266                     continue;
8267
8268                   if (potential_child->switched
8269                       && potential_child->record_mergeinfo)
8270                     {
8271                       operative_switched_child = TRUE;
8272                       break;
8273                     }
8274                 }
8275
8276               /* Can we treat CHILD as if it has no switched children? */
8277               if (! operative_switched_child)
8278                 child->switched_child = FALSE;
8279             }
8280         }
8281
8282       if (child->record_mergeinfo)
8283         {
8284           /* We need to record mergeinfo, but should that mergeinfo be
8285              non-inheritable? */
8286           svn_node_kind_t path_kind;
8287           SVN_ERR(svn_wc_read_kind2(&path_kind, merge_b->ctx->wc_ctx,
8288                                     child->abspath, FALSE, FALSE, iterpool));
8289
8290           /* Only directories can have non-inheritable mergeinfo. */
8291           if (path_kind == svn_node_dir)
8292             {
8293               /* There are two general cases where non-inheritable mergeinfo
8294                  is required:
8295
8296                  1) There merge target has missing subtrees (due to authz
8297                     restrictions, switched subtrees, or a shallow working
8298                     copy).
8299
8300                  2) The operational depth of the merge itself is shallow. */
8301
8302               /* We've already determined the first case. */
8303               child->record_noninheritable =
8304                 child->missing_child || child->switched_child;
8305
8306               /* The second case requires a bit more work. */
8307               if (i == 0)
8308                 {
8309                   /* If CHILD is the root of the merge target and the
8310                      operational depth is empty or files, then the mere
8311                      existence of operative immediate children means we
8312                      must record non-inheritable mergeinfo.
8313
8314                      ### What about svn_depth_immediates?  In that case
8315                      ### the merge target needs only normal inheritable
8316                      ### mergeinfo and the target's immediate children will
8317                      ### get non-inheritable mergeinfo, assuming they
8318                      ### need even that. */
8319                   if (depth < svn_depth_immediates
8320                       && operative_immediate_children
8321                       && apr_hash_count(operative_immediate_children))
8322                     child->record_noninheritable = TRUE;
8323                 }
8324               else if (depth == svn_depth_immediates)
8325                 {
8326                   /* An immediate directory child of the merge target, which
8327                       was affected by a --depth=immediates merge, needs
8328                       non-inheritable mergeinfo. */
8329                   if (svn_hash_gets(operative_immediate_children,
8330                                     child->abspath))
8331                     child->record_noninheritable = TRUE;
8332                 }
8333             }
8334         }
8335       else /* child->record_mergeinfo */
8336         {
8337           /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
8338              because it had no explicit mergeinfo of its own at the
8339              start of the merge but is the child of of some path with
8340              non-inheritable mergeinfo, then the explicit mergeinfo it
8341              has *now* was set by get_mergeinfo_paths() -- see criteria
8342              3 in that function's doc string.  So since CHILD->ABSPATH
8343              was not touched by the merge we can remove the
8344              mergeinfo. */
8345           if (child->child_of_noninheritable)
8346             SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
8347                                                     NULL, FALSE,
8348                                                     merge_b->ctx,
8349                                                     iterpool));
8350         }
8351     }
8352
8353   svn_pool_destroy(iterpool);
8354   return SVN_NO_ERROR;
8355 }
8356
8357 /* Helper for do_directory_merge().
8358
8359    If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
8360    MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
8361    MERGEINFO_FSPATH to the merge target (and possibly its subtrees) described
8362    by NOTIFY_B->CHILDREN_WITH_MERGEINFO -- see the global comment
8363    'THE CHILDREN_WITH_MERGEINFO ARRAY'.  Obviously this should only
8364    be called if recording mergeinfo -- see doc string for RECORD_MERGEINFO().
8365
8366    If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the
8367    WC, but instead record it in RESULT_CATALOG, where the keys are absolute
8368    working copy paths and the values are the new mergeinfos for each.
8369    Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
8370    created in.
8371
8372    DEPTH, NOTIFY_B, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS are all
8373    cascaded from do_directory_merge's arguments of the same names.
8374
8375    SCRATCH_POOL is used for temporary allocations.
8376 */
8377 static svn_error_t *
8378 record_mergeinfo_for_dir_merge(svn_mergeinfo_catalog_t result_catalog,
8379                                const svn_merge_range_t *merged_range,
8380                                const char *mergeinfo_fspath,
8381                                apr_array_header_t *children_with_mergeinfo,
8382                                svn_depth_t depth,
8383                                svn_boolean_t squelch_mergeinfo_notifications,
8384                                merge_cmd_baton_t *merge_b,
8385                                apr_pool_t *scratch_pool)
8386 {
8387   int i;
8388   svn_boolean_t is_rollback = (merged_range->start > merged_range->end);
8389   svn_boolean_t operative_merge;
8390
8391   /* Update the WC mergeinfo here to account for our new
8392      merges, minus any unresolved conflicts and skips. */
8393
8394   /* We need a scratch pool for iterations below. */
8395   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
8396
8397   svn_merge_range_t range = *merged_range;
8398
8399   assert(! merge_b->dry_run);
8400
8401   /* Regardless of what subtrees in MERGE_B->target->abspath might be missing
8402      could this merge have been operative? */
8403   operative_merge = subtree_touched_by_merge(merge_b->target->abspath,
8404                                              merge_b, iterpool);
8405
8406   /* If this couldn't be an operative merge then don't bother with
8407      the added complexity (and user confusion) of non-inheritable ranges.
8408      There is no harm in subtrees inheriting inoperative mergeinfo. */
8409   if (!operative_merge)
8410     range.inheritable = TRUE;
8411
8412   /* Remove absent children at or under MERGE_B->target->abspath from
8413      NOTIFY_B->CHILDREN_WITH_MERGEINFO
8414      before we calculate the merges performed. */
8415   remove_absent_children(merge_b->target->abspath,
8416                          children_with_mergeinfo);
8417
8418   /* Determine which subtrees of interest need mergeinfo recorded... */
8419   SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range,
8420                                           children_with_mergeinfo,
8421                                           mergeinfo_fspath, depth,
8422                                           merge_b, iterpool));
8423
8424   /* ...and then record it. */
8425   for (i = 0; i < children_with_mergeinfo->nelts; i++)
8426     {
8427       const char *child_repos_path;
8428       const char *child_merge_src_fspath;
8429       svn_rangelist_t *child_merge_rangelist;
8430       apr_hash_t *child_merges;
8431       svn_client__merge_path_t *child =
8432                      APR_ARRAY_IDX(children_with_mergeinfo, i,
8433                                    svn_client__merge_path_t *);
8434       SVN_ERR_ASSERT(child);
8435
8436       svn_pool_clear(iterpool);
8437
8438       if (child->record_mergeinfo)
8439         {
8440           child_repos_path = svn_dirent_skip_ancestor(merge_b->target->abspath,
8441                                                       child->abspath);
8442           SVN_ERR_ASSERT(child_repos_path != NULL);
8443           child_merge_src_fspath = svn_fspath__join(mergeinfo_fspath,
8444                                                     child_repos_path,
8445                                                     iterpool);
8446           /* Filter any ranges from each child's natural history before
8447              setting mergeinfo describing the merge. */
8448           SVN_ERR(filter_natural_history_from_mergeinfo(
8449             &child_merge_rangelist, child_merge_src_fspath,
8450             child->implicit_mergeinfo, &range, iterpool));
8451
8452           if (child_merge_rangelist->nelts == 0)
8453             continue;
8454
8455           if (!squelch_mergeinfo_notifications)
8456             {
8457               /* If the merge source has a gap, then don't mention
8458                  those gap revisions in the notification. */
8459               remove_source_gap(&range, merge_b->implicit_src_gap);
8460               notify_mergeinfo_recording(child->abspath, &range,
8461                                          merge_b->ctx, iterpool);
8462             }
8463
8464           /* If we are here we know we will be recording some mergeinfo, but
8465              before we do, set override mergeinfo on skipped paths so they
8466              don't incorrectly inherit the mergeinfo we are about to set. */
8467           if (i == 0)
8468             SVN_ERR(record_skips_in_mergeinfo(mergeinfo_fspath,
8469                                               child_merge_rangelist,
8470                                               is_rollback, merge_b, iterpool));
8471
8472           /* We may need to record non-inheritable mergeinfo that applies
8473              only to CHILD->ABSPATH. */
8474           if (child->record_noninheritable)
8475             svn_rangelist__set_inheritance(child_merge_rangelist, FALSE);
8476
8477           /* If CHILD has inherited mergeinfo set it before
8478              recording the first merge range. */
8479           if (child->inherited_mergeinfo)
8480             SVN_ERR(svn_client__record_wc_mergeinfo(
8481               child->abspath,
8482               child->pre_merge_mergeinfo,
8483               FALSE, merge_b->ctx,
8484               iterpool));
8485           if (merge_b->implicit_src_gap)
8486             {
8487               /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
8488                  so it will work with the svn_rangelist_remove API. */
8489               if (is_rollback)
8490                 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist,
8491                                               iterpool));
8492
8493               SVN_ERR(svn_rangelist_remove(&child_merge_rangelist,
8494                                            merge_b->implicit_src_gap,
8495                                            child_merge_rangelist, FALSE,
8496                                            iterpool));
8497               if (is_rollback)
8498                 SVN_ERR(svn_rangelist_reverse(child_merge_rangelist,
8499                                               iterpool));
8500             }
8501
8502           child_merges = apr_hash_make(iterpool);
8503
8504           /* The short story:
8505
8506              If we are describing a forward merge, then the naive mergeinfo
8507              defined by MERGE_SOURCE_PATH:MERGED_RANGE->START:
8508              MERGE_SOURCE_PATH:MERGED_RANGE->END may contain non-existent
8509              path-revs or may describe other lines of history.  We must
8510              remove these invalid portion(s) before recording mergeinfo
8511              describing the merge.
8512
8513              The long story:
8514
8515              If CHILD is the merge target we know that
8516              MERGE_SOURCE_PATH:MERGED_RANGE->END exists.  Further, if there
8517              were no copies in MERGE_SOURCE_PATH's history going back to
8518              RANGE->START then we know that
8519              MERGE_SOURCE_PATH:MERGED_RANGE->START exists too and the two
8520              describe an unbroken line of history, and thus
8521              MERGE_SOURCE_PATH:MERGED_RANGE->START:
8522              MERGE_SOURCE_PATH:MERGED_RANGE->END is a valid description of
8523              the merge -- see normalize_merge_sources() and the global comment
8524              'MERGEINFO MERGE SOURCE NORMALIZATION'.
8525
8526              However, if there *was* a copy, then
8527              MERGE_SOURCE_PATH:MERGED_RANGE->START doesn't exist or is
8528              unrelated to MERGE_SOURCE_PATH:MERGED_RANGE->END.  Also, we
8529              don't know if (MERGE_SOURCE_PATH:MERGED_RANGE->START)+1 through
8530              (MERGE_SOURCE_PATH:MERGED_RANGE->END)-1 actually exist.
8531
8532              If CHILD is a subtree of the merge target, then nothing is
8533              guaranteed beyond the fact that MERGE_SOURCE_PATH exists at
8534              MERGED_RANGE->END. */
8535           if ((!merge_b->record_only || merge_b->reintegrate_merge)
8536               && (!is_rollback))
8537             {
8538               svn_error_t *err;
8539               svn_mergeinfo_t subtree_history_as_mergeinfo;
8540               svn_rangelist_t *child_merge_src_rangelist;
8541               svn_client__pathrev_t *subtree_mergeinfo_pathrev
8542                 = svn_client__pathrev_create_with_relpath(
8543                     merge_b->target->loc.repos_root_url,
8544                     merge_b->target->loc.repos_uuid,
8545                     merged_range->end, child_merge_src_fspath + 1,
8546                     iterpool);
8547
8548               /* Confirm that the naive mergeinfo we want to set on
8549                  CHILD->ABSPATH both exists and is part of
8550                  (MERGE_SOURCE_PATH+CHILD_REPOS_PATH)@MERGED_RANGE->END's
8551                  history. */
8552               /* We know MERGED_RANGE->END is younger than MERGE_RANGE->START
8553                  because we only do this for forward merges. */
8554               err = svn_client__get_history_as_mergeinfo(
8555                 &subtree_history_as_mergeinfo, NULL,
8556                 subtree_mergeinfo_pathrev,
8557                 merged_range->end, merged_range->start,
8558                 merge_b->ra_session2, merge_b->ctx, iterpool);
8559
8560               /* If CHILD is a subtree it may have been deleted prior to
8561                  MERGED_RANGE->END so the above call to get its history
8562                  will fail. */
8563               if (err)
8564                 {
8565                   if (err->apr_err != SVN_ERR_FS_NOT_FOUND)
8566                       return svn_error_trace(err);
8567                   svn_error_clear(err);
8568                 }
8569               else
8570                 {
8571                   child_merge_src_rangelist = svn_hash_gets(
8572                                                 subtree_history_as_mergeinfo,
8573                                                 child_merge_src_fspath);
8574                   SVN_ERR(svn_rangelist_intersect(&child_merge_rangelist,
8575                                                   child_merge_rangelist,
8576                                                   child_merge_src_rangelist,
8577                                                   FALSE, iterpool));
8578                   if (child->record_noninheritable)
8579                     svn_rangelist__set_inheritance(child_merge_rangelist,
8580                                                    FALSE);
8581                 }
8582             }
8583
8584           svn_hash_sets(child_merges, child->abspath, child_merge_rangelist);
8585           SVN_ERR(update_wc_mergeinfo(result_catalog,
8586                                       child->abspath,
8587                                       child_merge_src_fspath,
8588                                       child_merges, is_rollback,
8589                                       merge_b->ctx, iterpool));
8590
8591           /* Once is enough: We don't need to record mergeinfo describing
8592              the merge a second.  If CHILD->ABSPATH is in
8593              MERGE_B->ADDED_ABSPATHS, we'll do just that, so remove the
8594              former from the latter. */
8595           svn_hash_sets(merge_b->added_abspaths, child->abspath, NULL);
8596         }
8597
8598       /* Elide explicit subtree mergeinfo whether or not we updated it. */
8599       if (i > 0)
8600         {
8601           svn_boolean_t in_switched_subtree = FALSE;
8602
8603           if (child->switched)
8604             in_switched_subtree = TRUE;
8605           else if (i > 1)
8606             {
8607               /* Check if CHILD is part of a switched subtree */
8608               svn_client__merge_path_t *parent;
8609               int j = i - 1;
8610               for (; j > 0; j--)
8611                 {
8612                   parent = APR_ARRAY_IDX(children_with_mergeinfo,
8613                                          j, svn_client__merge_path_t *);
8614                   if (parent
8615                       && parent->switched
8616                       && svn_dirent_is_ancestor(parent->abspath,
8617                                                 child->abspath))
8618                     {
8619                       in_switched_subtree = TRUE;
8620                       break;
8621                     }
8622                 }
8623             }
8624
8625           /* Allow mergeinfo on switched subtrees to elide to the
8626              repository. Otherwise limit elision to the merge target
8627              for now.  do_directory_merge() will eventually try to
8628              elide that when the merge is complete. */
8629           SVN_ERR(svn_client__elide_mergeinfo(
8630             child->abspath,
8631             in_switched_subtree ? NULL : merge_b->target->abspath,
8632             merge_b->ctx, iterpool));
8633         }
8634     } /* (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++) */
8635
8636   svn_pool_destroy(iterpool);
8637   return SVN_NO_ERROR;
8638 }
8639
8640 /* Helper for do_directory_merge().
8641
8642    Record mergeinfo describing a merge of
8643    MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
8644    MERGEINFO_FSPATH to each path in ADDED_ABSPATHS which has explicit
8645    mergeinfo or is the immediate child of a parent with explicit
8646    non-inheritable mergeinfo.
8647
8648    DEPTH, MERGE_B, and SQUELCH_MERGEINFO_NOTIFICATIONS, are
8649    cascaded from do_directory_merge's arguments of the same names.
8650
8651    Note: This is intended to support forward merges only, i.e.
8652    MERGED_RANGE->START must be older than MERGED_RANGE->END.
8653 */
8654 static svn_error_t *
8655 record_mergeinfo_for_added_subtrees(
8656   svn_merge_range_t *merged_range,
8657   const char *mergeinfo_fspath,
8658   svn_depth_t depth,
8659   svn_boolean_t squelch_mergeinfo_notifications,
8660   apr_hash_t *added_abspaths,
8661   merge_cmd_baton_t *merge_b,
8662   apr_pool_t *pool)
8663 {
8664   apr_pool_t *iterpool;
8665   apr_hash_index_t *hi;
8666
8667   /* If no paths were added by the merge then we have nothing to do. */
8668   if (!added_abspaths)
8669     return SVN_NO_ERROR;
8670
8671   SVN_ERR_ASSERT(merged_range->start < merged_range->end);
8672
8673   iterpool = svn_pool_create(pool);
8674   for (hi = apr_hash_first(pool, added_abspaths); hi; hi = apr_hash_next(hi))
8675     {
8676       const char *added_abspath = svn__apr_hash_index_key(hi);
8677       const char *dir_abspath;
8678       svn_mergeinfo_t parent_mergeinfo;
8679       svn_mergeinfo_t added_path_mergeinfo;
8680
8681       svn_pool_clear(iterpool);
8682       dir_abspath = svn_dirent_dirname(added_abspath, iterpool);
8683
8684       /* Grab the added path's explicit mergeinfo. */
8685       SVN_ERR(svn_client__get_wc_mergeinfo(&added_path_mergeinfo, NULL,
8686                                            svn_mergeinfo_explicit,
8687                                            added_abspath, NULL, NULL, FALSE,
8688                                            merge_b->ctx, iterpool, iterpool));
8689
8690       /* If the added path doesn't have explicit mergeinfo, does its immediate
8691          parent have non-inheritable mergeinfo? */
8692       if (!added_path_mergeinfo)
8693         SVN_ERR(svn_client__get_wc_mergeinfo(&parent_mergeinfo, NULL,
8694                                              svn_mergeinfo_explicit,
8695                                              dir_abspath, NULL, NULL, FALSE,
8696                                              merge_b->ctx,
8697                                              iterpool, iterpool));
8698
8699       if (added_path_mergeinfo
8700           || svn_mergeinfo__is_noninheritable(parent_mergeinfo, iterpool))
8701         {
8702           svn_node_kind_t added_path_kind;
8703           svn_mergeinfo_t merge_mergeinfo;
8704           svn_mergeinfo_t adds_history_as_mergeinfo;
8705           svn_rangelist_t *rangelist;
8706           const char *rel_added_path;
8707           const char *added_path_mergeinfo_fspath;
8708           svn_client__pathrev_t *added_path_pathrev;
8709
8710           SVN_ERR(svn_wc_read_kind2(&added_path_kind, merge_b->ctx->wc_ctx,
8711                                     added_abspath, FALSE, FALSE, iterpool));
8712
8713           /* Calculate the naive mergeinfo describing the merge. */
8714           merge_mergeinfo = apr_hash_make(iterpool);
8715           rangelist = svn_rangelist__initialize(
8716                         merged_range->start, merged_range->end,
8717                         ((added_path_kind == svn_node_file)
8718                          || (!(depth == svn_depth_infinity
8719                                || depth == svn_depth_immediates))),
8720                         iterpool);
8721
8722           /* Create the new mergeinfo path for added_path's mergeinfo.
8723              (added_abspath had better be a child of MERGE_B->target->abspath
8724              or something is *really* wrong.) */
8725           rel_added_path = svn_dirent_is_child(merge_b->target->abspath,
8726                                                added_abspath, iterpool);
8727           SVN_ERR_ASSERT(rel_added_path);
8728           added_path_mergeinfo_fspath = svn_fspath__join(mergeinfo_fspath,
8729                                                          rel_added_path,
8730                                                          iterpool);
8731           svn_hash_sets(merge_mergeinfo, added_path_mergeinfo_fspath,
8732                         rangelist);
8733
8734           /* Don't add new mergeinfo to describe the merge if that mergeinfo
8735              contains non-existent merge sources.
8736
8737              We know that MERGEINFO_PATH/rel_added_path's history does not
8738              span MERGED_RANGE->START:MERGED_RANGE->END but rather that it
8739              was added at some revions greater than MERGED_RANGE->START
8740              (assuming this is a forward merge).  It may have been added,
8741              deleted, and re-added many times.  The point is that we cannot
8742              blindly apply the naive mergeinfo calculated above because it
8743              will describe non-existent merge sources. To avoid this we get
8744              take the intersection of the naive mergeinfo with
8745              MERGEINFO_PATH/rel_added_path's history. */
8746           added_path_pathrev = svn_client__pathrev_create_with_relpath(
8747                                  merge_b->target->loc.repos_root_url,
8748                                  merge_b->target->loc.repos_uuid,
8749                                  MAX(merged_range->start, merged_range->end),
8750                                  added_path_mergeinfo_fspath + 1, iterpool);
8751           SVN_ERR(svn_client__get_history_as_mergeinfo(
8752             &adds_history_as_mergeinfo, NULL,
8753             added_path_pathrev,
8754             MAX(merged_range->start, merged_range->end),
8755             MIN(merged_range->start, merged_range->end),
8756             merge_b->ra_session2, merge_b->ctx, iterpool));
8757
8758           SVN_ERR(svn_mergeinfo_intersect2(&merge_mergeinfo,
8759                                            merge_mergeinfo,
8760                                            adds_history_as_mergeinfo,
8761                                            FALSE, iterpool, iterpool));
8762
8763           /* Combine the explicit mergeinfo on the added path (if any)
8764              with the mergeinfo describing this merge. */
8765           if (added_path_mergeinfo)
8766             SVN_ERR(svn_mergeinfo_merge2(merge_mergeinfo,
8767                                          added_path_mergeinfo,
8768                                          iterpool, iterpool));
8769           SVN_ERR(svn_client__record_wc_mergeinfo(
8770             added_abspath, merge_mergeinfo,
8771             !squelch_mergeinfo_notifications, merge_b->ctx, iterpool));
8772         }
8773     }
8774   svn_pool_destroy(iterpool);
8775
8776   return SVN_NO_ERROR;
8777 }
8778 /* Baton structure for log_noop_revs. */
8779 typedef struct log_noop_baton_t
8780 {
8781   /* See the comment 'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start
8782      of this file.*/
8783   apr_array_header_t *children_with_mergeinfo;
8784
8785   /* Absolute repository path of younger of the two merge sources
8786      being diffed. */
8787   const char *source_fspath;
8788
8789   /* The merge target. */
8790   const merge_target_t *target;
8791
8792   /* Initially empty rangelists allocated in POOL. The rangelists are
8793    * populated across multiple invocations of log_noop_revs(). */
8794   svn_rangelist_t *operative_ranges;
8795   svn_rangelist_t *merged_ranges;
8796
8797   /* Pool to store the rangelists. */
8798   apr_pool_t *pool;
8799 } log_noop_baton_t;
8800
8801 /* Helper for log_noop_revs: Merge a svn_merge_range_t representation of
8802    REVISION into RANGELIST. New elements added to rangelist are allocated
8803    in RESULT_POOL.
8804
8805    This is *not* a general purpose rangelist merge but a special replacement
8806    for svn_rangelist_merge when REVISION is guaranteed to be younger than any
8807    element in RANGELIST.  svn_rangelist_merge is O(n) worst-case (i.e. when
8808    all the ranges in output rangelist are older than the incoming changes).
8809    This turns the special case of a single incoming younger range into O(1).
8810    */
8811 static svn_error_t *
8812 rangelist_merge_revision(svn_rangelist_t *rangelist,
8813                          svn_revnum_t revision,
8814                          apr_pool_t *result_pool)
8815 {
8816   svn_merge_range_t *new_range;
8817   if (rangelist->nelts)
8818     {
8819       svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, rangelist->nelts - 1,
8820                                                svn_merge_range_t *);
8821       if (range->end == revision - 1)
8822         {
8823           /* REVISION is adjacent to the youngest range in RANGELIST
8824              so we can simply expand that range to encompass REVISION. */
8825           range->end = revision;
8826           return SVN_NO_ERROR;
8827         }
8828     }
8829   new_range = apr_palloc(result_pool, sizeof(*new_range));
8830   new_range->start = revision - 1;
8831   new_range->end = revision;
8832   new_range->inheritable = TRUE;
8833
8834   APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = new_range;
8835
8836   return SVN_NO_ERROR;
8837 }
8838
8839 /* Implements the svn_log_entry_receiver_t interface.
8840
8841    BATON is an log_noop_baton_t *.
8842
8843    Add LOG_ENTRY->REVISION to BATON->OPERATIVE_RANGES.
8844
8845    If LOG_ENTRY->REVISION has already been fully merged to
8846    BATON->target->abspath per the mergeinfo in BATON->CHILDREN_WITH_MERGEINFO,
8847    then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES.
8848
8849    Use SCRATCH_POOL for temporary allocations.  Allocate additions to
8850    BATON->MERGED_RANGES and BATON->OPERATIVE_RANGES in BATON->POOL.
8851
8852    Note: This callback must be invoked from oldest LOG_ENTRY->REVISION
8853    to youngest LOG_ENTRY->REVISION -- see rangelist_merge_revision().
8854 */
8855 static svn_error_t *
8856 log_noop_revs(void *baton,
8857               svn_log_entry_t *log_entry,
8858               apr_pool_t *scratch_pool)
8859 {
8860   log_noop_baton_t *log_gap_baton = baton;
8861   apr_hash_index_t *hi;
8862   svn_revnum_t revision;
8863   svn_boolean_t log_entry_rev_required = FALSE;
8864
8865   revision = log_entry->revision;
8866
8867   /* It's possible that authz restrictions on the merge source prevent us
8868      from knowing about any of the changes for LOG_ENTRY->REVISION. */
8869   if (!log_entry->changed_paths2)
8870     return SVN_NO_ERROR;
8871
8872   /* Unconditionally add LOG_ENTRY->REVISION to BATON->OPERATIVE_MERGES. */
8873   SVN_ERR(rangelist_merge_revision(log_gap_baton->operative_ranges,
8874                                    revision,
8875                                    log_gap_baton->pool));
8876
8877   /* Examine each path affected by LOG_ENTRY->REVISION.  If the explicit or
8878      inherited mergeinfo for *all* of the corresponding paths under
8879      BATON->target->abspath reflects that LOG_ENTRY->REVISION has been
8880      merged, then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES. */
8881   for (hi = apr_hash_first(scratch_pool, log_entry->changed_paths2);
8882        hi;
8883        hi = apr_hash_next(hi))
8884     {
8885       const char *fspath = svn__apr_hash_index_key(hi);
8886       const char *rel_path;
8887       const char *cwmi_abspath;
8888       svn_rangelist_t *paths_explicit_rangelist = NULL;
8889       svn_boolean_t mergeinfo_inherited = FALSE;
8890
8891       /* Adjust REL_PATH so it is relative to the merge source then use it to
8892          calculate what path in the merge target would be affected by this
8893          revision. */
8894       rel_path = svn_fspath__skip_ancestor(log_gap_baton->source_fspath,
8895                                            fspath);
8896       /* Is PATH even within the merge target?  If it isn't we
8897          can disregard it altogether. */
8898       if (rel_path == NULL)
8899         continue;
8900       cwmi_abspath = svn_dirent_join(log_gap_baton->target->abspath,
8901                                      rel_path, scratch_pool);
8902
8903       /* Find any explicit or inherited mergeinfo for PATH. */
8904       while (!log_entry_rev_required)
8905         {
8906           svn_client__merge_path_t *child = get_child_with_mergeinfo(
8907             log_gap_baton->children_with_mergeinfo, cwmi_abspath);
8908
8909           if (child && child->pre_merge_mergeinfo)
8910             {
8911               /* Found some explicit mergeinfo, grab any ranges
8912                  for PATH. */
8913               paths_explicit_rangelist =
8914                             svn_hash_gets(child->pre_merge_mergeinfo, fspath);
8915               break;
8916             }
8917
8918           if (cwmi_abspath[0] == '\0'
8919               || svn_dirent_is_root(cwmi_abspath, strlen(cwmi_abspath))
8920               || strcmp(log_gap_baton->target->abspath, cwmi_abspath) == 0)
8921             {
8922               /* Can't crawl any higher. */
8923               break;
8924             }
8925
8926           /* Didn't find anything so crawl up to the parent. */
8927           cwmi_abspath = svn_dirent_dirname(cwmi_abspath, scratch_pool);
8928           fspath = svn_fspath__dirname(fspath, scratch_pool);
8929
8930           /* At this point *if* we find mergeinfo it will be inherited. */
8931           mergeinfo_inherited = TRUE;
8932         }
8933
8934       if (paths_explicit_rangelist)
8935         {
8936           svn_rangelist_t *intersecting_range;
8937           svn_rangelist_t *rangelist;
8938
8939           rangelist = svn_rangelist__initialize(revision - 1, revision, TRUE,
8940                                                 scratch_pool);
8941
8942           /* If PATH inherited mergeinfo we must consider inheritance in the
8943              event the inherited mergeinfo is actually non-inheritable. */
8944           SVN_ERR(svn_rangelist_intersect(&intersecting_range,
8945                                           paths_explicit_rangelist,
8946                                           rangelist,
8947                                           mergeinfo_inherited, scratch_pool));
8948
8949           if (intersecting_range->nelts == 0)
8950             log_entry_rev_required = TRUE;
8951         }
8952       else
8953         {
8954           log_entry_rev_required = TRUE;
8955         }
8956     }
8957
8958   if (!log_entry_rev_required)
8959     SVN_ERR(rangelist_merge_revision(log_gap_baton->merged_ranges,
8960                                      revision,
8961                                      log_gap_baton->pool));
8962
8963   return SVN_NO_ERROR;
8964 }
8965
8966 /* Helper for do_directory_merge().
8967
8968    SOURCE is cascaded from the argument of the same name in
8969    do_directory_merge().  TARGET is the merge target.  RA_SESSION is the
8970    session for SOURCE->loc2.
8971
8972    Find all the ranges required by subtrees in
8973    CHILDREN_WITH_MERGEINFO that are *not* required by
8974    TARGET->abspath (i.e. CHILDREN_WITH_MERGEINFO[0]).  If such
8975    ranges exist, then find any subset of ranges which, if merged, would be
8976    inoperative.  Finally, if any inoperative ranges are found then remove
8977    these ranges from all of the subtree's REMAINING_RANGES.
8978
8979    This function should only be called when honoring mergeinfo during
8980    forward merges (i.e. SOURCE->rev1 < SOURCE->rev2).
8981 */
8982 static svn_error_t *
8983 remove_noop_subtree_ranges(const merge_source_t *source,
8984                            const merge_target_t *target,
8985                            svn_ra_session_t *ra_session,
8986                            apr_array_header_t *children_with_mergeinfo,
8987                            apr_pool_t *result_pool,
8988                            apr_pool_t *scratch_pool)
8989 {
8990   /* ### Do we need to check that we are at a uniform working revision? */
8991   int i;
8992   svn_client__merge_path_t *root_child =
8993     APR_ARRAY_IDX(children_with_mergeinfo, 0, svn_client__merge_path_t *);
8994   svn_rangelist_t *requested_ranges;
8995   svn_rangelist_t *subtree_gap_ranges;
8996   svn_rangelist_t *subtree_remaining_ranges;
8997   log_noop_baton_t log_gap_baton;
8998   svn_merge_range_t *oldest_gap_rev;
8999   svn_merge_range_t *youngest_gap_rev;
9000   svn_rangelist_t *inoperative_ranges;
9001   apr_pool_t *iterpool;
9002   const char *longest_common_subtree_ancestor = NULL;
9003   svn_error_t *err;
9004
9005   assert(session_url_is(ra_session, source->loc2->url, scratch_pool));
9006
9007   /* This function is only intended to work with forward merges. */
9008   if (source->loc1->rev > source->loc2->rev)
9009     return SVN_NO_ERROR;
9010
9011   /* Another easy out: There are no subtrees. */
9012   if (children_with_mergeinfo->nelts < 2)
9013     return SVN_NO_ERROR;
9014
9015   subtree_remaining_ranges = apr_array_make(scratch_pool, 1,
9016                                             sizeof(svn_merge_range_t *));
9017
9018   /* Given the requested merge of SOURCE->rev1:rev2 might there be any
9019      part of this range required for subtrees but not for the target? */
9020   requested_ranges = svn_rangelist__initialize(MIN(source->loc1->rev,
9021                                                    source->loc2->rev),
9022                                                MAX(source->loc1->rev,
9023                                                    source->loc2->rev),
9024                                                TRUE, scratch_pool);
9025   SVN_ERR(svn_rangelist_remove(&subtree_gap_ranges,
9026                                root_child->remaining_ranges,
9027                                requested_ranges, FALSE, scratch_pool));
9028
9029   /* Early out, nothing to operate on */
9030   if (!subtree_gap_ranges->nelts)
9031     return SVN_NO_ERROR;
9032
9033   /* Create a rangelist describing every range required across all subtrees. */
9034   iterpool = svn_pool_create(scratch_pool);
9035   for (i = 1; i < children_with_mergeinfo->nelts; i++)
9036     {
9037       svn_client__merge_path_t *child =
9038         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
9039
9040       svn_pool_clear(iterpool);
9041
9042       /* Issue #4269: Keep track of the longest common ancestor of all the
9043          subtrees which require merges.  This may be a child of
9044          TARGET->ABSPATH, which will allow us to narrow the log request
9045          below. */
9046       if (child->remaining_ranges && child->remaining_ranges->nelts)
9047         {
9048           if (longest_common_subtree_ancestor)
9049             longest_common_subtree_ancestor = svn_dirent_get_longest_ancestor(
9050               longest_common_subtree_ancestor, child->abspath, scratch_pool);
9051           else
9052             longest_common_subtree_ancestor = child->abspath;
9053         }
9054
9055       /* CHILD->REMAINING_RANGES will be NULL if child is absent. */
9056       if (child->remaining_ranges && child->remaining_ranges->nelts)
9057         SVN_ERR(svn_rangelist_merge2(subtree_remaining_ranges,
9058                                      child->remaining_ranges,
9059                                      scratch_pool, iterpool));
9060     }
9061   svn_pool_destroy(iterpool);
9062
9063   /* It's possible that none of the subtrees had any remaining ranges. */
9064   if (!subtree_remaining_ranges->nelts)
9065     return SVN_NO_ERROR;
9066
9067   /* Ok, *finally* we can answer what part(s) of SOURCE->rev1:rev2 are
9068      required for the subtrees but not the target. */
9069   SVN_ERR(svn_rangelist_intersect(&subtree_gap_ranges,
9070                                   subtree_gap_ranges,
9071                                   subtree_remaining_ranges, FALSE,
9072                                   scratch_pool));
9073
9074   /* Another early out */
9075   if (!subtree_gap_ranges->nelts)
9076     return SVN_NO_ERROR;
9077
9078   /* One or more subtrees need some revisions that the target doesn't need.
9079      Use log to determine if any of these revisions are inoperative. */
9080   oldest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges, 0, svn_merge_range_t *);
9081   youngest_gap_rev = APR_ARRAY_IDX(subtree_gap_ranges,
9082                          subtree_gap_ranges->nelts - 1, svn_merge_range_t *);
9083
9084   /* Set up the log baton. */
9085   log_gap_baton.children_with_mergeinfo = children_with_mergeinfo;
9086   log_gap_baton.source_fspath
9087     = svn_client__pathrev_fspath(source->loc2, result_pool);
9088   log_gap_baton.target = target;
9089   log_gap_baton.merged_ranges = apr_array_make(scratch_pool, 0,
9090                                                sizeof(svn_revnum_t *));
9091   log_gap_baton.operative_ranges = apr_array_make(scratch_pool, 0,
9092                                                   sizeof(svn_revnum_t *));
9093   log_gap_baton.pool = svn_pool_create(scratch_pool);
9094
9095   /* Find the longest common ancestor of all subtrees relative to
9096      RA_SESSION's URL. */
9097   if (longest_common_subtree_ancestor)
9098     longest_common_subtree_ancestor =
9099       svn_dirent_skip_ancestor(target->abspath,
9100                                longest_common_subtree_ancestor);
9101   else
9102     longest_common_subtree_ancestor = "";
9103
9104   /* Invoke the svn_log_entry_receiver_t receiver log_noop_revs() from
9105      oldest to youngest.  The receiver is optimized to add ranges to
9106      log_gap_baton.merged_ranges and log_gap_baton.operative_ranges, but
9107      requires that the revs arrive oldest to youngest -- see log_noop_revs()
9108      and rangelist_merge_revision(). */
9109   err = get_log(ra_session, longest_common_subtree_ancestor,
9110                 oldest_gap_rev->start + 1, youngest_gap_rev->end, TRUE,
9111                 log_noop_revs, &log_gap_baton, scratch_pool);
9112
9113   /* It's possible that the only subtrees with mergeinfo in TARGET don't have
9114      any corresponding subtree in SOURCE between SOURCE->REV1 < SOURCE->REV2.
9115      So it's also possible that we may ask for the logs of non-existent paths.
9116      If we do, then assume that no subtree requires any ranges that are not
9117      already required by the TARGET. */
9118   if (err)
9119     {
9120       if (err->apr_err != SVN_ERR_FS_NOT_FOUND
9121           && longest_common_subtree_ancestor[0] != '\0')
9122         return svn_error_trace(err);
9123
9124       /* Asked about a non-existent subtree in SOURCE. */
9125       svn_error_clear(err);
9126       log_gap_baton.merged_ranges =
9127         svn_rangelist__initialize(oldest_gap_rev->start,
9128                                   youngest_gap_rev->end,
9129                                   TRUE, scratch_pool);
9130     }
9131   else
9132     {
9133       inoperative_ranges = svn_rangelist__initialize(oldest_gap_rev->start,
9134                                                      youngest_gap_rev->end,
9135                                                      TRUE, scratch_pool);
9136       SVN_ERR(svn_rangelist_remove(&(inoperative_ranges),
9137                                    log_gap_baton.operative_ranges,
9138                                    inoperative_ranges, FALSE, scratch_pool));
9139       SVN_ERR(svn_rangelist_merge2(log_gap_baton.merged_ranges, inoperative_ranges,
9140                                    scratch_pool, scratch_pool));
9141     }
9142
9143   for (i = 1; i < children_with_mergeinfo->nelts; i++)
9144     {
9145       svn_client__merge_path_t *child =
9146         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
9147
9148       /* CHILD->REMAINING_RANGES will be NULL if child is absent. */
9149       if (child->remaining_ranges && child->remaining_ranges->nelts)
9150         {
9151           /* Remove inoperative ranges from all children so we don't perform
9152              inoperative editor drives. */
9153           SVN_ERR(svn_rangelist_remove(&(child->remaining_ranges),
9154                                        log_gap_baton.merged_ranges,
9155                                        child->remaining_ranges,
9156                                        FALSE, result_pool));
9157         }
9158     }
9159
9160   svn_pool_destroy(log_gap_baton.pool);
9161
9162   return SVN_NO_ERROR;
9163 }
9164
9165 /* Perform a merge of changes in SOURCE to the working copy path
9166    TARGET_ABSPATH. Both URLs in SOURCE, and TARGET_ABSPATH all represent
9167    directories -- for the single file case, the caller should use
9168    do_file_merge().
9169
9170    CHILDREN_WITH_MERGEINFO and MERGE_B describe the merge being performed
9171    As this function is for a mergeinfo-aware merge, SOURCE->ancestral
9172    should be TRUE, and SOURCE->loc1 must be a historical ancestor of
9173    SOURCE->loc2, or vice-versa (see `MERGEINFO MERGE SOURCE NORMALIZATION'
9174    for more requirements around SOURCE).
9175
9176    Mergeinfo changes will be recorded unless MERGE_B->dry_run is true.
9177
9178    If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE,
9179    and MERGE_B->CTX->NOTIFY_FUNC2 is not NULL, then call
9180    MERGE_B->CTX->NOTIFY_FUNC2 with MERGE_B->CTX->NOTIFY_BATON2 and a
9181    svn_wc_notify_merge_record_info_begin notification before any mergeinfo
9182    changes are made to describe the merge performed.
9183
9184    If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
9185    is not NULL, then don't record the new mergeinfo on the WC, but instead
9186    record it in RESULT_CATALOG, where the keys are absolute working copy
9187    paths and the values are the new mergeinfos for each.  Allocate additions
9188    to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
9189
9190    Handle DEPTH as documented for svn_client_merge5().
9191
9192    CONFLICT_REPORT is as documented for do_directory_merge().
9193
9194    Perform any temporary allocations in SCRATCH_POOL.
9195
9196    NOTE: This is a wrapper around drive_merge_report_editor() which
9197    handles the complexities inherent to situations where a given
9198    directory's children may have intersecting merges (because they
9199    meet one or more of the criteria described in get_mergeinfo_paths()).
9200 */
9201 static svn_error_t *
9202 do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
9203                              single_range_conflict_report_t **conflict_report,
9204                              const merge_source_t *source,
9205                              const char *target_abspath,
9206                              apr_array_header_t *children_with_mergeinfo,
9207                              const svn_diff_tree_processor_t *processor,
9208                              svn_depth_t depth,
9209                              svn_boolean_t squelch_mergeinfo_notifications,
9210                              merge_cmd_baton_t *merge_b,
9211                              apr_pool_t *result_pool,
9212                              apr_pool_t *scratch_pool)
9213 {
9214   /* The range defining the mergeinfo we will record to describe the merge
9215      (assuming we are recording mergeinfo
9216
9217      Note: This may be a subset of SOURCE->rev1:rev2 if
9218      populate_remaining_ranges() determines that some part of
9219      SOURCE->rev1:rev2 has already been wholly merged to TARGET_ABSPATH.
9220      Also, the actual editor drive(s) may be a subset of RANGE, if
9221      remove_noop_subtree_ranges() and/or fix_deleted_subtree_ranges()
9222      further tweak things. */
9223   svn_merge_range_t range;
9224
9225   svn_ra_session_t *ra_session;
9226   svn_client__merge_path_t *target_merge_path;
9227   svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
9228
9229   SVN_ERR_ASSERT(source->ancestral);
9230
9231   /*** If we get here, we're dealing with related sources from the
9232        same repository as the target -- merge tracking might be
9233        happenin'! ***/
9234
9235   *conflict_report = NULL;
9236
9237   /* Point our RA_SESSION to the URL of our youngest merge source side. */
9238   ra_session = is_rollback ? merge_b->ra_session1 : merge_b->ra_session2;
9239
9240   /* Fill NOTIFY_B->CHILDREN_WITH_MERGEINFO with child paths (const
9241      svn_client__merge_path_t *) which might have intersecting merges
9242      because they meet one or more of the criteria described in
9243      get_mergeinfo_paths(). Here the paths are arranged in a depth
9244      first order. */
9245   SVN_ERR(get_mergeinfo_paths(children_with_mergeinfo,
9246                               merge_b->target, depth,
9247                               merge_b->dry_run, merge_b->same_repos,
9248                               merge_b->ctx, scratch_pool, scratch_pool));
9249
9250   /* The first item from the NOTIFY_B->CHILDREN_WITH_MERGEINFO is always
9251      the target thanks to depth-first ordering. */
9252   target_merge_path = APR_ARRAY_IDX(children_with_mergeinfo, 0,
9253                                     svn_client__merge_path_t *);
9254
9255   /* If we are honoring mergeinfo, then for each item in
9256      NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
9257      merged, and then merge it.  Otherwise, we just merge what we were asked
9258      to merge across the whole tree.  */
9259   SVN_ERR(populate_remaining_ranges(children_with_mergeinfo,
9260                                     source, ra_session,
9261                                     merge_b, scratch_pool, scratch_pool));
9262
9263   /* Always start with a range which describes the most inclusive merge
9264      possible, i.e. SOURCE->rev1:rev2. */
9265   range.start = source->loc1->rev;
9266   range.end = source->loc2->rev;
9267   range.inheritable = TRUE;
9268
9269   if (!merge_b->reintegrate_merge)
9270     {
9271       svn_revnum_t new_range_start, start_rev;
9272       apr_pool_t *iterpool = svn_pool_create(scratch_pool);
9273
9274       /* The merge target TARGET_ABSPATH and/or its subtrees may not need all
9275          of SOURCE->rev1:rev2 applied.  So examine
9276          NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest starting
9277          revision that actually needs to be merged (for reverse merges this is
9278          the youngest starting revision).
9279
9280          We'll do this twice, right now for the start of the mergeinfo we will
9281          ultimately record to describe this merge and then later for the
9282          start of the actual editor drive. */
9283       new_range_start = get_most_inclusive_rev(
9284         children_with_mergeinfo, is_rollback, TRUE);
9285       if (SVN_IS_VALID_REVNUM(new_range_start))
9286         range.start = new_range_start;
9287
9288       /* Remove inoperative ranges from any subtrees' remaining_ranges
9289          to spare the expense of noop editor drives. */
9290       if (!is_rollback)
9291         SVN_ERR(remove_noop_subtree_ranges(source, merge_b->target,
9292                                            ra_session,
9293                                            children_with_mergeinfo,
9294                                            scratch_pool, iterpool));
9295
9296       /* Adjust subtrees' remaining_ranges to deal with issue #3067:
9297        * "subtrees that don't exist at the start or end of a merge range
9298        * shouldn't break the merge". */
9299       SVN_ERR(fix_deleted_subtree_ranges(source, merge_b->target,
9300                                          ra_session,
9301                                          children_with_mergeinfo,
9302                                          merge_b->ctx, scratch_pool, iterpool));
9303
9304       /* remove_noop_subtree_ranges() and/or fix_deleted_subtree_range()
9305          may have further refined the starting revision for our editor
9306          drive. */
9307       start_rev =
9308         get_most_inclusive_rev(children_with_mergeinfo,
9309                                is_rollback, TRUE);
9310
9311       /* Is there anything to merge? */
9312       if (SVN_IS_VALID_REVNUM(start_rev))
9313         {
9314           /* Now examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest
9315              ending revision that actually needs to be merged (for reverse
9316              merges this is the youngest ending revision). */
9317            svn_revnum_t end_rev =
9318              get_most_inclusive_rev(children_with_mergeinfo,
9319                                     is_rollback, FALSE);
9320
9321           /* While END_REV is valid, do the following:
9322
9323              1. Tweak each NOTIFY_B->CHILDREN_WITH_MERGEINFO element so that
9324                 the element's remaining_ranges member has as its first element
9325                 a range that ends with end_rev.
9326
9327              2. Starting with start_rev, call drive_merge_report_editor()
9328                 on MERGE_B->target->abspath for start_rev:end_rev.
9329
9330              3. Remove the first element from each
9331                 NOTIFY_B->CHILDREN_WITH_MERGEINFO element's remaining_ranges
9332                 member.
9333
9334              4. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most
9335                 inclusive starting revision that actually needs to be merged and
9336                 update start_rev.  This prevents us from needlessly contacting the
9337                 repository and doing a diff where we describe the entire target
9338                 tree as *not* needing any of the requested range.  This can happen
9339                 whenever we have mergeinfo with gaps in it for the merge source.
9340
9341              5. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the most
9342                 inclusive ending revision that actually needs to be merged and
9343                 update end_rev.
9344
9345              6. Lather, rinse, repeat.
9346           */
9347
9348           while (end_rev != SVN_INVALID_REVNUM)
9349             {
9350               merge_source_t *real_source;
9351               svn_merge_range_t *first_target_range
9352                 = (target_merge_path->remaining_ranges->nelts == 0 ? NULL
9353                    : APR_ARRAY_IDX(target_merge_path->remaining_ranges, 0,
9354                                    svn_merge_range_t *));
9355
9356               /* Issue #3324: Stop editor abuse!  Don't call
9357                  drive_merge_report_editor() in such a way that we request an
9358                  editor with svn_client__get_diff_editor() for some rev X,
9359                  then call svn_ra_do_diff3() for some revision Y, and then
9360                  call reporter->set_path(PATH=="") to set the root revision
9361                  for the editor drive to revision Z where
9362                  (X != Z && X < Z < Y).  This is bogus because the server will
9363                  send us the diff between X:Y but the client is expecting the
9364                  diff between Y:Z.  See issue #3324 for full details on the
9365                  problems this can cause. */
9366               if (first_target_range
9367                   && start_rev != first_target_range->start)
9368                 {
9369                   if (is_rollback)
9370                     {
9371                       if (end_rev < first_target_range->start)
9372                         end_rev = first_target_range->start;
9373                     }
9374                   else
9375                     {
9376                       if (end_rev > first_target_range->start)
9377                         end_rev = first_target_range->start;
9378                     }
9379                 }
9380
9381               svn_pool_clear(iterpool);
9382
9383               slice_remaining_ranges(children_with_mergeinfo,
9384                                      is_rollback, end_rev, scratch_pool);
9385
9386               /* Reset variables that must be reset for every drive */
9387               merge_b->notify_begin.last_abspath = NULL;
9388
9389               real_source = subrange_source(source, start_rev, end_rev, iterpool);
9390               SVN_ERR(drive_merge_report_editor(
9391                 merge_b->target->abspath,
9392                 real_source,
9393                 children_with_mergeinfo,
9394                 processor,
9395                 depth,
9396                 merge_b,
9397                 iterpool));
9398
9399               /* If any paths picked up explicit mergeinfo as a result of
9400                  the merge we need to make sure any mergeinfo those paths
9401                  inherited is recorded and then add these paths to
9402                  NOTIFY_B->CHILDREN_WITH_MERGEINFO.*/
9403               SVN_ERR(process_children_with_new_mergeinfo(
9404                         merge_b, children_with_mergeinfo,
9405                         scratch_pool));
9406
9407               /* If any subtrees had their explicit mergeinfo deleted as a
9408                  result of the merge then remove these paths from
9409                  NOTIFY_B->CHILDREN_WITH_MERGEINFO since there is no need
9410                  to consider these subtrees for subsequent editor drives
9411                  nor do we want to record mergeinfo on them describing
9412                  the merge itself. */
9413               remove_children_with_deleted_mergeinfo(
9414                 merge_b, children_with_mergeinfo);
9415
9416               /* Prepare for the next iteration (if any). */
9417               remove_first_range_from_remaining_ranges(
9418                 end_rev, children_with_mergeinfo, scratch_pool);
9419
9420               /* If we raised any conflicts, break out and report how much
9421                  we have merged. */
9422               if (is_path_conflicted_by_merge(merge_b))
9423                 {
9424                   merge_source_t *remaining_range = NULL;
9425
9426                   if (real_source->loc2->rev != source->loc2->rev)
9427                     remaining_range = subrange_source(source,
9428                                                       real_source->loc2->rev,
9429                                                       source->loc2->rev,
9430                                                       scratch_pool);
9431                   *conflict_report = single_range_conflict_report_create(
9432                                        real_source, remaining_range,
9433                                        result_pool);
9434
9435                   range.end = end_rev;
9436                   break;
9437                 }
9438
9439               start_rev =
9440                 get_most_inclusive_rev(children_with_mergeinfo,
9441                                        is_rollback, TRUE);
9442               end_rev =
9443                 get_most_inclusive_rev(children_with_mergeinfo,
9444                                        is_rollback, FALSE);
9445             }
9446         }
9447       svn_pool_destroy(iterpool);
9448     }
9449   else
9450     {
9451       if (!merge_b->record_only)
9452         {
9453           /* Reset cur_ancestor_abspath to null so that subsequent cherry
9454              picked revision ranges will be notified upon subsequent
9455              operative merge. */
9456           merge_b->notify_begin.last_abspath = NULL;
9457
9458           SVN_ERR(drive_merge_report_editor(merge_b->target->abspath,
9459                                             source,
9460                                             NULL,
9461                                             processor,
9462                                             depth,
9463                                             merge_b,
9464                                             scratch_pool));
9465         }
9466     }
9467
9468   /* Record mergeinfo where appropriate.*/
9469   if (RECORD_MERGEINFO(merge_b))
9470     {
9471       const svn_client__pathrev_t *primary_src
9472         = is_rollback ? source->loc1 : source->loc2;
9473       const char *mergeinfo_path
9474         = svn_client__pathrev_fspath(primary_src, scratch_pool);
9475
9476       SVN_ERR(record_mergeinfo_for_dir_merge(result_catalog,
9477                                              &range,
9478                                              mergeinfo_path,
9479                                              children_with_mergeinfo,
9480                                              depth,
9481                                              squelch_mergeinfo_notifications,
9482                                              merge_b,
9483                                              scratch_pool));
9484
9485       /* If a path has an immediate parent with non-inheritable mergeinfo at
9486          this point, then it meets criteria 3 or 5 described in
9487          get_mergeinfo_paths' doc string.  For paths which exist prior to a
9488          merge explicit mergeinfo has already been set.  But for paths added
9489          during the merge this is not the case.  The path might have explicit
9490          mergeinfo from the merge source, but no mergeinfo yet exists
9491          describing *this* merge.  So the added path has either incomplete
9492          explicit mergeinfo or inherits incomplete mergeinfo from its
9493          immediate parent (if any, the parent might have only non-inheritable
9494          ranges in which case the path simply inherits empty mergeinfo).
9495
9496          So here we look at the root path of each subtree added during the
9497          merge and set explicit mergeinfo on it if it meets the aforementioned
9498          conditions. */
9499       if (range.start < range.end) /* Nothing to record on added subtrees
9500                                       resulting from reverse merges. */
9501         {
9502           SVN_ERR(record_mergeinfo_for_added_subtrees(
9503                     &range, mergeinfo_path, depth,
9504                     squelch_mergeinfo_notifications,
9505                     merge_b->added_abspaths, merge_b, scratch_pool));
9506         }
9507     }
9508
9509   return SVN_NO_ERROR;
9510 }
9511
9512 /* Helper for do_merge() when the merge target is a directory.
9513  *
9514  * If any conflict is raised during the merge, set *CONFLICTED_RANGE to
9515  * the revision sub-range that raised the conflict.  In this case, the
9516  * merge will have ended at revision CONFLICTED_RANGE and mergeinfo will
9517  * have been recorded for all revision sub-ranges up to and including
9518  * CONFLICTED_RANGE.  Otherwise, set *CONFLICTED_RANGE to NULL.
9519  */
9520 static svn_error_t *
9521 do_directory_merge(svn_mergeinfo_catalog_t result_catalog,
9522                    single_range_conflict_report_t **conflict_report,
9523                    const merge_source_t *source,
9524                    const char *target_abspath,
9525                    const svn_diff_tree_processor_t *processor,
9526                    svn_depth_t depth,
9527                    svn_boolean_t squelch_mergeinfo_notifications,
9528                    merge_cmd_baton_t *merge_b,
9529                    apr_pool_t *result_pool,
9530                    apr_pool_t *scratch_pool)
9531 {
9532   apr_array_header_t *children_with_mergeinfo;
9533
9534   /* Initialize CHILDREN_WITH_MERGEINFO. See the comment
9535      'THE CHILDREN_WITH_MERGEINFO ARRAY' at the start of this file. */
9536   children_with_mergeinfo =
9537     apr_array_make(scratch_pool, 16, sizeof(svn_client__merge_path_t *));
9538
9539   /* And make it read-only accessible from the baton */
9540   merge_b->notify_begin.nodes_with_mergeinfo = children_with_mergeinfo;
9541
9542   /* If we are not honoring mergeinfo we can skip right to the
9543      business of merging changes! */
9544   if (HONOR_MERGEINFO(merge_b))
9545     SVN_ERR(do_mergeinfo_aware_dir_merge(result_catalog, conflict_report,
9546                                          source, target_abspath,
9547                                          children_with_mergeinfo,
9548                                          processor, depth,
9549                                          squelch_mergeinfo_notifications,
9550                                          merge_b, result_pool, scratch_pool));
9551   else
9552     SVN_ERR(do_mergeinfo_unaware_dir_merge(conflict_report,
9553                                            source, target_abspath,
9554                                            children_with_mergeinfo,
9555                                            processor, depth,
9556                                            merge_b, result_pool, scratch_pool));
9557
9558   merge_b->notify_begin.nodes_with_mergeinfo = NULL;
9559
9560   return SVN_NO_ERROR;
9561 }
9562
9563 /** Ensure that *RA_SESSION is opened to URL, either by reusing
9564  * *RA_SESSION if it is non-null and already opened to URL's
9565  * repository, or by allocating a new *RA_SESSION in POOL.
9566  * (RA_SESSION itself cannot be null, of course.)
9567  *
9568  * CTX is used as for svn_client_open_ra_session().
9569  */
9570 static svn_error_t *
9571 ensure_ra_session_url(svn_ra_session_t **ra_session,
9572                       const char *url,
9573                       const char *wri_abspath,
9574                       svn_client_ctx_t *ctx,
9575                       apr_pool_t *pool)
9576 {
9577   svn_error_t *err = SVN_NO_ERROR;
9578
9579   if (*ra_session)
9580     {
9581       err = svn_ra_reparent(*ra_session, url, pool);
9582     }
9583
9584   /* SVN_ERR_RA_ILLEGAL_URL is raised when url doesn't point to the same
9585      repository as ra_session. */
9586   if (! *ra_session || (err && err->apr_err == SVN_ERR_RA_ILLEGAL_URL))
9587     {
9588       svn_error_clear(err);
9589       err = svn_client_open_ra_session2(ra_session, url, wri_abspath,
9590                                         ctx, pool, pool);
9591     }
9592   SVN_ERR(err);
9593
9594   return SVN_NO_ERROR;
9595 }
9596
9597 /* Drive a merge of MERGE_SOURCES into working copy node TARGET
9598    and possibly record mergeinfo describing the merge -- see
9599    RECORD_MERGEINFO().
9600
9601    If MODIFIED_SUBTREES is not NULL and all the MERGE_SOURCES are 'ancestral'
9602    or REINTEGRATE_MERGE is true, then replace *MODIFIED_SUBTREES with a new
9603    hash containing all the paths that *MODIFIED_SUBTREES contained before,
9604    and also every path modified, skipped, added, or tree-conflicted
9605    by the merge.  Keys and values of the hash are both (const char *)
9606    absolute paths.  The contents of the hash are allocated in RESULT_POOL.
9607
9608    If the merge raises any conflicts while merging a revision range, return
9609    early and set *CONFLICT_REPORT to describe the details.  (In this case,
9610    notify that the merge is complete if and only if this was the last
9611    revision range of the merge.)  If there are no conflicts, set
9612    *CONFLICT_REPORT to NULL.  A revision range here can be one specified
9613    in MERGE_SOURCES or an internally generated sub-range of one of those
9614    when merge tracking is in use.
9615
9616    For every (const merge_source_t *) merge source in MERGE_SOURCES, if
9617    SOURCE->ANCESTRAL is set, then the "left" and "right" side are
9618    ancestrally related.  (See 'MERGEINFO MERGE SOURCE NORMALIZATION'
9619    for more on what that means and how it matters.)
9620
9621    If SOURCES_RELATED is set, the "left" and "right" sides of the
9622    merge source are historically related (ancestors, uncles, second
9623    cousins thrice removed, etc...).  (This is passed through to
9624    do_file_merge() to simulate the history checks that the repository
9625    logic does in the directory case.)
9626
9627    SAME_REPOS is TRUE iff the merge sources live in the same
9628    repository as the one from which the target working copy has been
9629    checked out.
9630
9631    If mergeinfo is being recorded, SQUELCH_MERGEINFO_NOTIFICATIONS is FALSE,
9632    and CTX->NOTIFY_FUNC2 is not NULL, then call CTX->NOTIFY_FUNC2 with
9633    CTX->NOTIFY_BATON2 and a svn_wc_notify_merge_record_info_begin
9634    notification before any mergeinfo changes are made to describe the merge
9635    performed.
9636
9637    If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
9638    is not NULL, then don't record the new mergeinfo on the WC, but instead
9639    record it in RESULT_CATALOG, where the keys are absolute working copy
9640    paths and the values are the new mergeinfos for each.  Allocate additions
9641    to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
9642
9643    FORCE_DELETE, DRY_RUN, RECORD_ONLY, DEPTH, MERGE_OPTIONS,
9644    and CTX are as described in the docstring for svn_client_merge_peg3().
9645
9646    If IGNORE_MERGEINFO is true, disable merge tracking, by treating the two
9647    sources as unrelated even if they actually have a common ancestor.  See
9648    the macro HONOR_MERGEINFO().
9649
9650    If DIFF_IGNORE_ANCESTRY is true, diff the 'left' and 'right' versions
9651    of a node (if they are the same kind) as if they were related, even if
9652    they are not related.  Otherwise, diff unrelated items as a deletion
9653    of one thing and the addition of another.
9654
9655    If not NULL, RECORD_ONLY_PATHS is a hash of (const char *) paths mapped
9656    to the same.  If RECORD_ONLY is true and RECORD_ONLY_PATHS is not NULL,
9657    then record mergeinfo describing the merge only on subtrees which contain
9658    items from RECORD_ONLY_PATHS.  If RECORD_ONLY is true and RECORD_ONLY_PATHS
9659    is NULL, then record mergeinfo on every subtree with mergeinfo in
9660    TARGET.
9661
9662    REINTEGRATE_MERGE is TRUE if this is a reintegrate merge.
9663
9664    *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp
9665    integrity, *USE_SLEEP will be unchanged if no sleep is required.
9666
9667    SCRATCH_POOL is used for all temporary allocations.
9668 */
9669 static svn_error_t *
9670 do_merge(apr_hash_t **modified_subtrees,
9671          svn_mergeinfo_catalog_t result_catalog,
9672          conflict_report_t **conflict_report,
9673          svn_boolean_t *use_sleep,
9674          const apr_array_header_t *merge_sources,
9675          const merge_target_t *target,
9676          svn_ra_session_t *src_session,
9677          svn_boolean_t sources_related,
9678          svn_boolean_t same_repos,
9679          svn_boolean_t ignore_mergeinfo,
9680          svn_boolean_t diff_ignore_ancestry,
9681          svn_boolean_t force_delete,
9682          svn_boolean_t dry_run,
9683          svn_boolean_t record_only,
9684          apr_hash_t *record_only_paths,
9685          svn_boolean_t reintegrate_merge,
9686          svn_boolean_t squelch_mergeinfo_notifications,
9687          svn_depth_t depth,
9688          const apr_array_header_t *merge_options,
9689          svn_client_ctx_t *ctx,
9690          apr_pool_t *result_pool,
9691          apr_pool_t *scratch_pool)
9692 {
9693   merge_cmd_baton_t merge_cmd_baton = { 0 };
9694   svn_config_t *cfg;
9695   const char *diff3_cmd;
9696   const char *preserved_exts_str;
9697   int i;
9698   svn_boolean_t checked_mergeinfo_capability = FALSE;
9699   svn_ra_session_t *ra_session1 = NULL, *ra_session2 = NULL;
9700   const char *old_src_session_url = NULL;
9701   apr_pool_t *iterpool;
9702   const svn_diff_tree_processor_t *processor;
9703
9704   SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
9705
9706   *conflict_report = NULL;
9707
9708   /* Check from some special conditions when in record-only mode
9709      (which is a merge-tracking thing). */
9710   if (record_only)
9711     {
9712       svn_boolean_t sources_ancestral = TRUE;
9713       int j;
9714
9715       /* Find out whether all of the sources are 'ancestral'. */
9716       for (j = 0; j < merge_sources->nelts; j++)
9717         if (! APR_ARRAY_IDX(merge_sources, j, merge_source_t *)->ancestral)
9718           {
9719             sources_ancestral = FALSE;
9720             break;
9721           }
9722
9723       /* We can't do a record-only merge if the sources aren't related. */
9724       if (! sources_ancestral)
9725         return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
9726                                 _("Use of two URLs is not compatible with "
9727                                   "mergeinfo modification"));
9728
9729       /* We can't do a record-only merge if the sources aren't from
9730          the same repository as the target. */
9731       if (! same_repos)
9732         return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
9733                                 _("Merge from foreign repository is not "
9734                                   "compatible with mergeinfo modification"));
9735
9736       /* If this is a dry-run record-only merge, there's nothing to do. */
9737       if (dry_run)
9738         return SVN_NO_ERROR;
9739     }
9740
9741   iterpool = svn_pool_create(scratch_pool);
9742
9743   /* Ensure a known depth. */
9744   if (depth == svn_depth_unknown)
9745     depth = svn_depth_infinity;
9746
9747   /* Set up the diff3 command, so various callers don't have to. */
9748   cfg = ctx->config
9749         ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
9750         : NULL;
9751   svn_config_get(cfg, &diff3_cmd, SVN_CONFIG_SECTION_HELPERS,
9752                  SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
9753
9754   if (diff3_cmd != NULL)
9755     SVN_ERR(svn_path_cstring_to_utf8(&diff3_cmd, diff3_cmd, scratch_pool));
9756
9757     /* See which files the user wants to preserve the extension of when
9758      conflict files are made. */
9759   svn_config_get(cfg, &preserved_exts_str, SVN_CONFIG_SECTION_MISCELLANY,
9760                  SVN_CONFIG_OPTION_PRESERVED_CF_EXTS, "");
9761
9762   /* Build the merge context baton (or at least the parts of it that
9763      don't need to be reset for each merge source).  */
9764   merge_cmd_baton.force_delete = force_delete;
9765   merge_cmd_baton.dry_run = dry_run;
9766   merge_cmd_baton.record_only = record_only;
9767   merge_cmd_baton.ignore_mergeinfo = ignore_mergeinfo;
9768   merge_cmd_baton.diff_ignore_ancestry = diff_ignore_ancestry;
9769   merge_cmd_baton.same_repos = same_repos;
9770   merge_cmd_baton.mergeinfo_capable = FALSE;
9771   merge_cmd_baton.ctx = ctx;
9772   merge_cmd_baton.reintegrate_merge = reintegrate_merge;
9773   merge_cmd_baton.target = target;
9774   merge_cmd_baton.pool = iterpool;
9775   merge_cmd_baton.merge_options = merge_options;
9776   merge_cmd_baton.diff3_cmd = diff3_cmd;
9777   merge_cmd_baton.ext_patterns = *preserved_exts_str
9778                           ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ",
9779                                               FALSE, scratch_pool)
9780                           : NULL;
9781
9782   merge_cmd_baton.use_sleep = use_sleep;
9783
9784   /* Do we already know the specific subtrees with mergeinfo we want
9785      to record-only mergeinfo on? */
9786   if (record_only && record_only_paths)
9787     merge_cmd_baton.merged_abspaths = record_only_paths;
9788   else
9789     merge_cmd_baton.merged_abspaths = apr_hash_make(result_pool);
9790
9791   merge_cmd_baton.skipped_abspaths = apr_hash_make(result_pool);
9792   merge_cmd_baton.added_abspaths = apr_hash_make(result_pool);
9793   merge_cmd_baton.tree_conflicted_abspaths = apr_hash_make(result_pool);
9794
9795   {
9796     svn_diff_tree_processor_t *merge_processor;
9797
9798     merge_processor = svn_diff__tree_processor_create(&merge_cmd_baton,
9799                                                       scratch_pool);
9800
9801     merge_processor->dir_opened   = merge_dir_opened;
9802     merge_processor->dir_changed  = merge_dir_changed;
9803     merge_processor->dir_added    = merge_dir_added;
9804     merge_processor->dir_deleted  = merge_dir_deleted;
9805     merge_processor->dir_closed   = merge_dir_closed;
9806
9807     merge_processor->file_opened  = merge_file_opened;
9808     merge_processor->file_changed = merge_file_changed;
9809     merge_processor->file_added   = merge_file_added;
9810     merge_processor->file_deleted = merge_file_deleted;
9811     /* Not interested in file_closed() */
9812
9813     merge_processor->node_absent = merge_node_absent;
9814
9815     processor = merge_processor;
9816   }
9817
9818   if (src_session)
9819     {
9820       SVN_ERR(svn_ra_get_session_url(src_session, &old_src_session_url,
9821                                      scratch_pool));
9822       ra_session1 = src_session;
9823     }
9824
9825   for (i = 0; i < merge_sources->nelts; i++)
9826     {
9827       svn_node_kind_t src1_kind;
9828       merge_source_t *source =
9829         APR_ARRAY_IDX(merge_sources, i, merge_source_t *);
9830       single_range_conflict_report_t *conflicted_range_report;
9831
9832       svn_pool_clear(iterpool);
9833
9834       /* Sanity check:  if our left- and right-side merge sources are
9835          the same, there's nothing to here. */
9836       if ((strcmp(source->loc1->url, source->loc2->url) == 0)
9837           && (source->loc1->rev == source->loc2->rev))
9838         continue;
9839
9840       /* Establish RA sessions to our URLs, reuse where possible. */
9841       SVN_ERR(ensure_ra_session_url(&ra_session1, source->loc1->url,
9842                                     target->abspath, ctx, scratch_pool));
9843       SVN_ERR(ensure_ra_session_url(&ra_session2, source->loc2->url,
9844                                     target->abspath, ctx, scratch_pool));
9845
9846       /* Populate the portions of the merge context baton that need to
9847          be reset for each merge source iteration. */
9848       merge_cmd_baton.merge_source = *source;
9849       merge_cmd_baton.implicit_src_gap = NULL;
9850       merge_cmd_baton.conflicted_paths = NULL;
9851       merge_cmd_baton.paths_with_new_mergeinfo = NULL;
9852       merge_cmd_baton.paths_with_deleted_mergeinfo = NULL;
9853       merge_cmd_baton.ra_session1 = ra_session1;
9854       merge_cmd_baton.ra_session2 = ra_session2;
9855
9856       merge_cmd_baton.notify_begin.last_abspath = NULL;
9857
9858       /* Populate the portions of the merge context baton that require
9859          an RA session to set, but shouldn't be reset for each iteration. */
9860       if (! checked_mergeinfo_capability)
9861         {
9862           SVN_ERR(svn_ra_has_capability(ra_session1,
9863                                         &merge_cmd_baton.mergeinfo_capable,
9864                                         SVN_RA_CAPABILITY_MERGEINFO,
9865                                         iterpool));
9866           checked_mergeinfo_capability = TRUE;
9867         }
9868
9869       SVN_ERR(svn_ra_check_path(ra_session1, "", source->loc1->rev,
9870                                 &src1_kind, iterpool));
9871
9872       /* Run the merge; if there are conflicts, allow the callback to
9873        * resolve them, and if it resolves all of them, then run the
9874        * merge again with the remaining revision range, until it is all
9875        * done. */
9876       do
9877         {
9878           /* Merge as far as possible without resolving any conflicts */
9879           if (src1_kind != svn_node_dir)
9880             {
9881               SVN_ERR(do_file_merge(result_catalog, &conflicted_range_report,
9882                                     source, target->abspath,
9883                                     processor,
9884                                     sources_related,
9885                                     squelch_mergeinfo_notifications,
9886                                     &merge_cmd_baton, iterpool, iterpool));
9887             }
9888           else /* Directory */
9889             {
9890               SVN_ERR(do_directory_merge(result_catalog, &conflicted_range_report,
9891                                          source, target->abspath,
9892                                          processor,
9893                                          depth, squelch_mergeinfo_notifications,
9894                                          &merge_cmd_baton, iterpool, iterpool));
9895             }
9896
9897           /* Give the conflict resolver callback the opportunity to
9898            * resolve any conflicts that were raised.  If it resolves all
9899            * of them, go around again to merge the next sub-range (if any). */
9900           if (conflicted_range_report && ctx->conflict_func2 && ! dry_run)
9901             {
9902               svn_boolean_t conflicts_remain;
9903
9904               SVN_ERR(svn_client__resolve_conflicts(
9905                         &conflicts_remain, merge_cmd_baton.conflicted_paths,
9906                         ctx, iterpool));
9907               if (conflicts_remain)
9908                 break;
9909
9910               merge_cmd_baton.conflicted_paths = NULL;
9911               /* Caution: this source is in iterpool */
9912               source = conflicted_range_report->remaining_source;
9913               conflicted_range_report = NULL;
9914             }
9915           else
9916             break;
9917         }
9918       while (source);
9919
9920       /* The final mergeinfo on TARGET_WCPATH may itself elide. */
9921       if (! dry_run)
9922         SVN_ERR(svn_client__elide_mergeinfo(target->abspath, NULL,
9923                                             ctx, iterpool));
9924
9925       /* If conflicts occurred while merging any but the very last
9926        * range of a multi-pass merge, we raise an error that aborts
9927        * the merge. The user will be asked to resolve conflicts
9928        * before merging subsequent revision ranges. */
9929       if (conflicted_range_report)
9930         {
9931           *conflict_report = conflict_report_create(
9932                                target->abspath, conflicted_range_report->conflicted_range,
9933                                (i == merge_sources->nelts - 1
9934                                 && ! conflicted_range_report->remaining_source),
9935                                result_pool);
9936           break;
9937         }
9938     }
9939
9940   if (! *conflict_report || (*conflict_report)->was_last_range)
9941     {
9942       /* Let everyone know we're finished here. */
9943       notify_merge_completed(target->abspath, ctx, iterpool);
9944     }
9945
9946   /* Does the caller want to know what the merge has done? */
9947   if (modified_subtrees)
9948     {
9949       *modified_subtrees =
9950           apr_hash_overlay(result_pool, *modified_subtrees,
9951                            merge_cmd_baton.merged_abspaths);
9952       *modified_subtrees =
9953           apr_hash_overlay(result_pool, *modified_subtrees,
9954                            merge_cmd_baton.added_abspaths);
9955       *modified_subtrees =
9956           apr_hash_overlay(result_pool, *modified_subtrees,
9957                            merge_cmd_baton.skipped_abspaths);
9958       *modified_subtrees =
9959           apr_hash_overlay(result_pool, *modified_subtrees,
9960                            merge_cmd_baton.tree_conflicted_abspaths);
9961     }
9962
9963   if (src_session)
9964     SVN_ERR(svn_ra_reparent(src_session, old_src_session_url, iterpool));
9965
9966   svn_pool_destroy(iterpool);
9967   return SVN_NO_ERROR;
9968 }
9969
9970 /* Perform a two-URL merge between URLs which are related, but neither
9971    is a direct ancestor of the other.  This first does a real two-URL
9972    merge (unless this is record-only), followed by record-only merges
9973    to represent the changed mergeinfo.
9974
9975    Set *CONFLICT_REPORT to indicate if there were any conflicts, as in
9976    do_merge().
9977
9978    The diff to be merged is between SOURCE->loc1 (in URL1_RA_SESSION1)
9979    and SOURCE->loc2 (in URL2_RA_SESSION2); YCA is their youngest
9980    common ancestor.
9981
9982    SAME_REPOS must be true if and only if the source URLs are in the same
9983    repository as the target working copy.
9984
9985    DIFF_IGNORE_ANCESTRY is as in do_merge().
9986
9987    Other arguments are as in all of the public merge APIs.
9988
9989    *USE_SLEEP will be set TRUE if a sleep is required to ensure timestamp
9990    integrity, *USE_SLEEP will be unchanged if no sleep is required.
9991
9992    SCRATCH_POOL is used for all temporary allocations.
9993  */
9994 static svn_error_t *
9995 merge_cousins_and_supplement_mergeinfo(conflict_report_t **conflict_report,
9996                                        svn_boolean_t *use_sleep,
9997                                        const merge_target_t *target,
9998                                        svn_ra_session_t *URL1_ra_session,
9999                                        svn_ra_session_t *URL2_ra_session,
10000                                        const merge_source_t *source,
10001                                        const svn_client__pathrev_t *yca,
10002                                        svn_boolean_t same_repos,
10003                                        svn_depth_t depth,
10004                                        svn_boolean_t diff_ignore_ancestry,
10005                                        svn_boolean_t force_delete,
10006                                        svn_boolean_t record_only,
10007                                        svn_boolean_t dry_run,
10008                                        const apr_array_header_t *merge_options,
10009                                        svn_client_ctx_t *ctx,
10010                                        apr_pool_t *result_pool,
10011                                        apr_pool_t *scratch_pool)
10012 {
10013   apr_array_header_t *remove_sources, *add_sources;
10014   apr_hash_t *modified_subtrees = NULL;
10015
10016   /* Sure we could use SCRATCH_POOL throughout this function, but since this
10017      is a wrapper around three separate merges we'll create a subpool we can
10018      clear between each of the three.  If the merge target has a lot of
10019      subtree mergeinfo, then this will help keep memory use in check. */
10020   apr_pool_t *subpool = svn_pool_create(scratch_pool);
10021
10022   assert(session_url_is(URL1_ra_session, source->loc1->url, scratch_pool));
10023   assert(session_url_is(URL2_ra_session, source->loc2->url, scratch_pool));
10024
10025   SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
10026   SVN_ERR_ASSERT(! source->ancestral);
10027
10028   SVN_ERR(normalize_merge_sources_internal(
10029             &remove_sources, source->loc1,
10030             svn_rangelist__initialize(source->loc1->rev, yca->rev, TRUE,
10031                                       scratch_pool),
10032             URL1_ra_session, ctx, scratch_pool, subpool));
10033
10034   SVN_ERR(normalize_merge_sources_internal(
10035             &add_sources, source->loc2,
10036             svn_rangelist__initialize(yca->rev, source->loc2->rev, TRUE,
10037                                       scratch_pool),
10038             URL2_ra_session, ctx, scratch_pool, subpool));
10039
10040   *conflict_report = NULL;
10041
10042   /* If this isn't a record-only merge, we'll first do a stupid
10043      point-to-point merge... */
10044   if (! record_only)
10045     {
10046       apr_array_header_t *faux_sources =
10047         apr_array_make(scratch_pool, 1, sizeof(merge_source_t *));
10048
10049       modified_subtrees = apr_hash_make(scratch_pool);
10050       APR_ARRAY_PUSH(faux_sources, const merge_source_t *) = source;
10051       SVN_ERR(do_merge(&modified_subtrees, NULL, conflict_report, use_sleep,
10052                        faux_sources, target,
10053                        URL1_ra_session, TRUE, same_repos,
10054                        FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
10055                        force_delete, dry_run, FALSE, NULL, TRUE,
10056                        FALSE, depth, merge_options, ctx,
10057                        scratch_pool, subpool));
10058       if (*conflict_report)
10059         {
10060           *conflict_report = conflict_report_dup(*conflict_report, result_pool);
10061           if (! (*conflict_report)->was_last_range)
10062             return SVN_NO_ERROR;
10063         }
10064     }
10065   else if (! same_repos)
10066     {
10067       return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
10068                               _("Merge from foreign repository is not "
10069                                 "compatible with mergeinfo modification"));
10070     }
10071
10072   /* ... and now, if we're doing the mergeinfo thang, we execute a
10073      pair of record-only merges using the real sources we've
10074      calculated.
10075
10076      Issue #3648: We don't actually perform these two record-only merges
10077      on the WC at first, but rather see what each would do and store that
10078      in two mergeinfo catalogs.  We then merge the catalogs together and
10079      then record the result in the WC.  This prevents the second record
10080      only merge from removing legitimate mergeinfo history, from the same
10081      source, that was made in prior merges. */
10082   if (same_repos && !dry_run)
10083     {
10084       svn_mergeinfo_catalog_t add_result_catalog =
10085         apr_hash_make(scratch_pool);
10086       svn_mergeinfo_catalog_t remove_result_catalog =
10087         apr_hash_make(scratch_pool);
10088
10089       notify_mergeinfo_recording(target->abspath, NULL, ctx, scratch_pool);
10090       svn_pool_clear(subpool);
10091       SVN_ERR(do_merge(NULL, add_result_catalog, conflict_report, use_sleep,
10092                        add_sources, target,
10093                        URL1_ra_session, TRUE, same_repos,
10094                        FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
10095                        force_delete, dry_run, TRUE,
10096                        modified_subtrees, TRUE,
10097                        TRUE, depth, merge_options, ctx,
10098                        scratch_pool, subpool));
10099       if (*conflict_report)
10100         {
10101           *conflict_report = conflict_report_dup(*conflict_report, result_pool);
10102           if (! (*conflict_report)->was_last_range)
10103             return SVN_NO_ERROR;
10104         }
10105       svn_pool_clear(subpool);
10106       SVN_ERR(do_merge(NULL, remove_result_catalog, conflict_report, use_sleep,
10107                        remove_sources, target,
10108                        URL1_ra_session, TRUE, same_repos,
10109                        FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
10110                        force_delete, dry_run, TRUE,
10111                        modified_subtrees, TRUE,
10112                        TRUE, depth, merge_options, ctx,
10113                        scratch_pool, subpool));
10114       if (*conflict_report)
10115         {
10116           *conflict_report = conflict_report_dup(*conflict_report, result_pool);
10117           if (! (*conflict_report)->was_last_range)
10118             return SVN_NO_ERROR;
10119         }
10120       SVN_ERR(svn_mergeinfo_catalog_merge(add_result_catalog,
10121                                           remove_result_catalog,
10122                                           scratch_pool, scratch_pool));
10123       SVN_ERR(svn_client__record_wc_mergeinfo_catalog(add_result_catalog,
10124                                                       ctx, scratch_pool));
10125     }
10126
10127   svn_pool_destroy(subpool);
10128   return SVN_NO_ERROR;
10129 }
10130
10131 /* Perform checks to determine whether the working copy at TARGET_ABSPATH
10132  * can safely be used as a merge target. Checks are performed according to
10133  * the ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, and ALLOW_SWITCHED_SUBTREES
10134  * parameters. If any checks fail, raise SVN_ERR_CLIENT_NOT_READY_TO_MERGE.
10135  *
10136  * E.g. if all the ALLOW_* parameters are FALSE, TARGET_ABSPATH must
10137  * be a single-revision, pristine, unswitched working copy.
10138  * In other words, it must reflect a subtree of the repository as found
10139  * at single revision -- although sparse checkouts are permitted. */
10140 static svn_error_t *
10141 ensure_wc_is_suitable_merge_target(const char *target_abspath,
10142                                    svn_client_ctx_t *ctx,
10143                                    svn_boolean_t allow_mixed_rev,
10144                                    svn_boolean_t allow_local_mods,
10145                                    svn_boolean_t allow_switched_subtrees,
10146                                    apr_pool_t *scratch_pool)
10147 {
10148   svn_node_kind_t target_kind;
10149
10150   /* Check the target exists. */
10151   SVN_ERR(svn_io_check_path(target_abspath, &target_kind, scratch_pool));
10152   if (target_kind == svn_node_none)
10153     return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
10154                              _("Path '%s' does not exist"),
10155                              svn_dirent_local_style(target_abspath,
10156                                                     scratch_pool));
10157   SVN_ERR(svn_wc_read_kind2(&target_kind, ctx->wc_ctx, target_abspath,
10158                             FALSE, FALSE, scratch_pool));
10159   if (target_kind != svn_node_dir && target_kind != svn_node_file)
10160     return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
10161                              _("Merge target '%s' does not exist in the "
10162                                "working copy"), target_abspath);
10163
10164   /* Perform the mixed-revision check first because it's the cheapest one. */
10165   if (! allow_mixed_rev)
10166     {
10167       svn_revnum_t min_rev;
10168       svn_revnum_t max_rev;
10169
10170       SVN_ERR(svn_client_min_max_revisions(&min_rev, &max_rev, target_abspath,
10171                                            FALSE, ctx, scratch_pool));
10172
10173       if (!(SVN_IS_VALID_REVNUM(min_rev) && SVN_IS_VALID_REVNUM(max_rev)))
10174         {
10175           svn_boolean_t is_added;
10176
10177           /* Allow merge into added nodes. */
10178           SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath,
10179                                         scratch_pool));
10180           if (is_added)
10181             return SVN_NO_ERROR;
10182           else
10183             return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
10184                                     _("Cannot determine revision of working "
10185                                       "copy"));
10186         }
10187
10188       if (min_rev != max_rev)
10189         return svn_error_createf(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL,
10190                                  _("Cannot merge into mixed-revision working "
10191                                    "copy [%ld:%ld]; try updating first"),
10192                                    min_rev, max_rev);
10193     }
10194
10195   /* Next, check for switched subtrees. */
10196   if (! allow_switched_subtrees)
10197     {
10198       svn_boolean_t is_switched;
10199
10200       SVN_ERR(svn_wc__has_switched_subtrees(&is_switched, ctx->wc_ctx,
10201                                             target_abspath, NULL,
10202                                             scratch_pool));
10203       if (is_switched)
10204         return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
10205                                 _("Cannot merge into a working copy "
10206                                   "with a switched subtree"));
10207     }
10208
10209   /* This is the most expensive check, so it is performed last.*/
10210   if (! allow_local_mods)
10211     {
10212       svn_boolean_t is_modified;
10213
10214       SVN_ERR(svn_wc__has_local_mods(&is_modified, ctx->wc_ctx,
10215                                      target_abspath,
10216                                      ctx->cancel_func,
10217                                      ctx->cancel_baton,
10218                                      scratch_pool));
10219       if (is_modified)
10220         return svn_error_create(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
10221                                 _("Cannot merge into a working copy "
10222                                   "that has local modifications"));
10223     }
10224
10225   return SVN_NO_ERROR;
10226 }
10227
10228 /* Throw an error if PATH_OR_URL is a path and REVISION isn't a repository
10229  * revision. */
10230 static svn_error_t *
10231 ensure_wc_path_has_repo_revision(const char *path_or_url,
10232                                  const svn_opt_revision_t *revision,
10233                                  apr_pool_t *scratch_pool)
10234 {
10235   if (revision->kind != svn_opt_revision_number
10236       && revision->kind != svn_opt_revision_date
10237       && revision->kind != svn_opt_revision_head
10238       && ! svn_path_is_url(path_or_url))
10239     return svn_error_createf(
10240       SVN_ERR_CLIENT_BAD_REVISION, NULL,
10241       _("Invalid merge source '%s'; a working copy path can only be "
10242         "used with a repository revision (a number, a date, or head)"),
10243       svn_dirent_local_style(path_or_url, scratch_pool));
10244   return SVN_NO_ERROR;
10245 }
10246
10247 /* "Open" the target WC for a merge.  That means:
10248  *   - find out its exact repository location
10249  *   - check the WC for suitability (throw an error if unsuitable)
10250  *
10251  * Set *TARGET_P to a new, fully initialized, target description structure.
10252  *
10253  * ALLOW_MIXED_REV, ALLOW_LOCAL_MODS, ALLOW_SWITCHED_SUBTREES determine
10254  * whether the WC is deemed suitable; see ensure_wc_is_suitable_merge_target()
10255  * for details.
10256  *
10257  * If the node is locally added, the rev and URL will be null/invalid. Some
10258  * kinds of merge can use such a target; others can't.
10259  */
10260 static svn_error_t *
10261 open_target_wc(merge_target_t **target_p,
10262                const char *wc_abspath,
10263                svn_boolean_t allow_mixed_rev,
10264                svn_boolean_t allow_local_mods,
10265                svn_boolean_t allow_switched_subtrees,
10266                svn_client_ctx_t *ctx,
10267                apr_pool_t *result_pool,
10268                apr_pool_t *scratch_pool)
10269 {
10270   merge_target_t *target = apr_palloc(result_pool, sizeof(*target));
10271   svn_client__pathrev_t *origin;
10272
10273   target->abspath = apr_pstrdup(result_pool, wc_abspath);
10274
10275   SVN_ERR(svn_client__wc_node_get_origin(&origin, wc_abspath, ctx,
10276                                          result_pool, scratch_pool));
10277   if (origin)
10278     {
10279       target->loc = *origin;
10280     }
10281   else
10282     {
10283       svn_error_t *err;
10284       /* The node has no location in the repository. It's unversioned or
10285        * locally added or locally deleted.
10286        *
10287        * If it's locally added or deleted, find the repository root
10288        * URL and UUID anyway, and leave the node URL and revision as NULL
10289        * and INVALID.  If it's unversioned, this will throw an error. */
10290       err = svn_wc__node_get_repos_info(NULL, NULL,
10291                                         &target->loc.repos_root_url,
10292                                         &target->loc.repos_uuid,
10293                                         ctx->wc_ctx, wc_abspath,
10294                                         result_pool, scratch_pool);
10295
10296       if (err)
10297         {
10298           if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND
10299               && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY
10300               && err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED)
10301             return svn_error_trace(err);
10302
10303           return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, err,
10304                                    _("Merge target '%s' does not exist in the "
10305                                      "working copy"),
10306                                    svn_dirent_local_style(wc_abspath,
10307                                                           scratch_pool));
10308         }
10309
10310       target->loc.rev = SVN_INVALID_REVNUM;
10311       target->loc.url = NULL;
10312     }
10313
10314   SVN_ERR(ensure_wc_is_suitable_merge_target(
10315             wc_abspath, ctx,
10316             allow_mixed_rev, allow_local_mods, allow_switched_subtrees,
10317             scratch_pool));
10318
10319   *target_p = target;
10320   return SVN_NO_ERROR;
10321 }
10322
10323 /*-----------------------------------------------------------------------*/
10324 \f
10325 /*** Public APIs ***/
10326
10327 /* The body of svn_client_merge5(), which see for details.
10328  *
10329  * If SOURCE1 @ REVISION1 is related to SOURCE2 @ REVISION2 then use merge
10330  * tracking (subject to other constraints -- see HONOR_MERGEINFO());
10331  * otherwise disable merge tracking.
10332  *
10333  * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge().
10334  */
10335 static svn_error_t *
10336 merge_locked(conflict_report_t **conflict_report,
10337              const char *source1,
10338              const svn_opt_revision_t *revision1,
10339              const char *source2,
10340              const svn_opt_revision_t *revision2,
10341              const char *target_abspath,
10342              svn_depth_t depth,
10343              svn_boolean_t ignore_mergeinfo,
10344              svn_boolean_t diff_ignore_ancestry,
10345              svn_boolean_t force_delete,
10346              svn_boolean_t record_only,
10347              svn_boolean_t dry_run,
10348              svn_boolean_t allow_mixed_rev,
10349              const apr_array_header_t *merge_options,
10350              svn_client_ctx_t *ctx,
10351              apr_pool_t *result_pool,
10352              apr_pool_t *scratch_pool)
10353 {
10354   merge_target_t *target;
10355   svn_client__pathrev_t *source1_loc, *source2_loc;
10356   svn_boolean_t sources_related = FALSE;
10357   svn_ra_session_t *ra_session1, *ra_session2;
10358   apr_array_header_t *merge_sources;
10359   svn_error_t *err;
10360   svn_boolean_t use_sleep = FALSE;
10361   svn_client__pathrev_t *yca = NULL;
10362   apr_pool_t *sesspool;
10363   svn_boolean_t same_repos;
10364
10365   /* ### FIXME: This function really ought to do a history check on
10366      the left and right sides of the merge source, and -- if one is an
10367      ancestor of the other -- just call svn_client_merge_peg3() with
10368      the appropriate args. */
10369
10370   SVN_ERR(open_target_wc(&target, target_abspath,
10371                          allow_mixed_rev, TRUE, TRUE,
10372                          ctx, scratch_pool, scratch_pool));
10373
10374   /* Open RA sessions to both sides of our merge source, and resolve URLs
10375    * and revisions. */
10376   sesspool = svn_pool_create(scratch_pool);
10377   SVN_ERR(svn_client__ra_session_from_path2(
10378             &ra_session1, &source1_loc,
10379             source1, NULL, revision1, revision1, ctx, sesspool));
10380   SVN_ERR(svn_client__ra_session_from_path2(
10381             &ra_session2, &source2_loc,
10382             source2, NULL, revision2, revision2, ctx, sesspool));
10383
10384   /* We can't do a diff between different repositories. */
10385   /* ### We should also insist that the root URLs of the two sources match,
10386    *     as we are only carrying around a single source-repos-root from now
10387    *     on, and URL calculations will go wrong if they differ.
10388    *     Alternatively, teach the code to cope with differing root URLs. */
10389   SVN_ERR(check_same_repos(source1_loc, source1_loc->url,
10390                            source2_loc, source2_loc->url,
10391                            FALSE /* strict_urls */, scratch_pool));
10392
10393   /* Do our working copy and sources come from the same repository? */
10394   same_repos = is_same_repos(&target->loc, source1_loc, TRUE /* strict_urls */);
10395
10396   /* Unless we're ignoring ancestry, see if the two sources are related.  */
10397   if (! ignore_mergeinfo)
10398     SVN_ERR(svn_client__get_youngest_common_ancestor(
10399                     &yca, source1_loc, source2_loc, ra_session1, ctx,
10400                     scratch_pool, scratch_pool));
10401
10402   /* Check for a youngest common ancestor.  If we have one, we'll be
10403      doing merge tracking.
10404
10405      So, given a requested merge of the differences between A and
10406      B, and a common ancestor of C, we will find ourselves in one of
10407      four positions, and four different approaches:
10408
10409         A == B == C   there's nothing to merge
10410
10411         A == C != B   we merge the changes between A (or C) and B
10412
10413         B == C != A   we merge the changes between B (or C) and A
10414
10415         A != B != C   we merge the changes between A and B without
10416                       merge recording, then record-only two merges:
10417                       from A to C, and from C to B
10418   */
10419   if (yca)
10420     {
10421       /* Note that our merge sources are related. */
10422       sources_related = TRUE;
10423
10424       /* If the common ancestor matches the right side of our merge,
10425          then we only need to reverse-merge the left side. */
10426       if ((strcmp(yca->url, source2_loc->url) == 0)
10427           && (yca->rev == source2_loc->rev))
10428         {
10429           SVN_ERR(normalize_merge_sources_internal(
10430                     &merge_sources, source1_loc,
10431                     svn_rangelist__initialize(source1_loc->rev, yca->rev, TRUE,
10432                                               scratch_pool),
10433                     ra_session1, ctx, scratch_pool, scratch_pool));
10434         }
10435       /* If the common ancestor matches the left side of our merge,
10436          then we only need to merge the right side. */
10437       else if ((strcmp(yca->url, source1_loc->url) == 0)
10438                && (yca->rev == source1_loc->rev))
10439         {
10440           SVN_ERR(normalize_merge_sources_internal(
10441                     &merge_sources, source2_loc,
10442                     svn_rangelist__initialize(yca->rev, source2_loc->rev, TRUE,
10443                                               scratch_pool),
10444                     ra_session2, ctx, scratch_pool, scratch_pool));
10445         }
10446       /* And otherwise, we need to do both: reverse merge the left
10447          side, and merge the right. */
10448       else
10449         {
10450           merge_source_t source;
10451
10452           source.loc1 = source1_loc;
10453           source.loc2 = source2_loc;
10454           source.ancestral = FALSE;
10455
10456           err = merge_cousins_and_supplement_mergeinfo(conflict_report,
10457                                                        &use_sleep,
10458                                                        target,
10459                                                        ra_session1,
10460                                                        ra_session2,
10461                                                        &source,
10462                                                        yca,
10463                                                        same_repos,
10464                                                        depth,
10465                                                        diff_ignore_ancestry,
10466                                                        force_delete,
10467                                                        record_only, dry_run,
10468                                                        merge_options,
10469                                                        ctx,
10470                                                        result_pool,
10471                                                        scratch_pool);
10472           /* Close our temporary RA sessions (this could've happened
10473              after the second call to normalize_merge_sources() inside
10474              the merge_cousins_and_supplement_mergeinfo() routine). */
10475           svn_pool_destroy(sesspool);
10476
10477           if (use_sleep)
10478             svn_io_sleep_for_timestamps(target->abspath, scratch_pool);
10479
10480           SVN_ERR(err);
10481           return SVN_NO_ERROR;
10482         }
10483     }
10484   else
10485     {
10486       /* Build a single-item merge_source_t array. */
10487       merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *));
10488       APR_ARRAY_PUSH(merge_sources, merge_source_t *)
10489         = merge_source_create(source1_loc, source2_loc, FALSE, scratch_pool);
10490     }
10491
10492   err = do_merge(NULL, NULL, conflict_report, &use_sleep,
10493                  merge_sources, target,
10494                  ra_session1, sources_related, same_repos,
10495                  ignore_mergeinfo, diff_ignore_ancestry, force_delete, dry_run,
10496                  record_only, NULL, FALSE, FALSE, depth, merge_options,
10497                  ctx, result_pool, scratch_pool);
10498
10499   /* Close our temporary RA sessions. */
10500   svn_pool_destroy(sesspool);
10501
10502   if (use_sleep)
10503     svn_io_sleep_for_timestamps(target->abspath, scratch_pool);
10504
10505   SVN_ERR(err);
10506   return SVN_NO_ERROR;
10507 }
10508
10509 /* Set *TARGET_ABSPATH to the absolute path of, and *LOCK_ABSPATH to
10510  the absolute path to lock for, TARGET_WCPATH. */
10511 static svn_error_t *
10512 get_target_and_lock_abspath(const char **target_abspath,
10513                             const char **lock_abspath,
10514                             const char *target_wcpath,
10515                             svn_client_ctx_t *ctx,
10516                             apr_pool_t *result_pool)
10517 {
10518   svn_node_kind_t kind;
10519   SVN_ERR(svn_dirent_get_absolute(target_abspath, target_wcpath,
10520                                   result_pool));
10521   SVN_ERR(svn_wc_read_kind2(&kind, ctx->wc_ctx, *target_abspath,
10522                             FALSE, FALSE, result_pool));
10523   if (kind == svn_node_dir)
10524     *lock_abspath = *target_abspath;
10525   else
10526     *lock_abspath = svn_dirent_dirname(*target_abspath, result_pool);
10527
10528   return SVN_NO_ERROR;
10529 }
10530
10531 svn_error_t *
10532 svn_client_merge5(const char *source1,
10533                   const svn_opt_revision_t *revision1,
10534                   const char *source2,
10535                   const svn_opt_revision_t *revision2,
10536                   const char *target_wcpath,
10537                   svn_depth_t depth,
10538                   svn_boolean_t ignore_mergeinfo,
10539                   svn_boolean_t diff_ignore_ancestry,
10540                   svn_boolean_t force_delete,
10541                   svn_boolean_t record_only,
10542                   svn_boolean_t dry_run,
10543                   svn_boolean_t allow_mixed_rev,
10544                   const apr_array_header_t *merge_options,
10545                   svn_client_ctx_t *ctx,
10546                   apr_pool_t *pool)
10547 {
10548   const char *target_abspath, *lock_abspath;
10549   conflict_report_t *conflict_report;
10550
10551   /* Sanity check our input -- we require specified revisions,
10552    * and either 2 paths or 2 URLs. */
10553   if ((revision1->kind == svn_opt_revision_unspecified)
10554       || (revision2->kind == svn_opt_revision_unspecified))
10555     return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL,
10556                             _("Not all required revisions are specified"));
10557   if (svn_path_is_url(source1) != svn_path_is_url(source2))
10558     return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
10559                             _("Merge sources must both be "
10560                               "either paths or URLs"));
10561   /* A WC path must be used with a repository revision, as we can't
10562    * (currently) use the WC itself as a source, we can only read the URL
10563    * from it and use that. */
10564   SVN_ERR(ensure_wc_path_has_repo_revision(source1, revision1, pool));
10565   SVN_ERR(ensure_wc_path_has_repo_revision(source2, revision2, pool));
10566
10567   SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath,
10568                                       target_wcpath, ctx, pool));
10569
10570   if (!dry_run)
10571     SVN_WC__CALL_WITH_WRITE_LOCK(
10572       merge_locked(&conflict_report,
10573                    source1, revision1, source2, revision2,
10574                    target_abspath, depth, ignore_mergeinfo,
10575                    diff_ignore_ancestry,
10576                    force_delete, record_only, dry_run,
10577                    allow_mixed_rev, merge_options, ctx, pool, pool),
10578       ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
10579   else
10580     SVN_ERR(merge_locked(&conflict_report,
10581                    source1, revision1, source2, revision2,
10582                    target_abspath, depth, ignore_mergeinfo,
10583                    diff_ignore_ancestry,
10584                    force_delete, record_only, dry_run,
10585                    allow_mixed_rev, merge_options, ctx, pool, pool));
10586
10587   SVN_ERR(make_merge_conflict_error(conflict_report, pool));
10588   return SVN_NO_ERROR;
10589 }
10590
10591
10592 /* Check if mergeinfo for a given path is described explicitly or via
10593    inheritance in a mergeinfo catalog.
10594
10595    If REPOS_REL_PATH exists in CATALOG and has mergeinfo containing
10596    MERGEINFO, then set *IN_CATALOG to TRUE.  If REPOS_REL_PATH does
10597    not exist in CATALOG, then find its nearest parent which does exist.
10598    If the mergeinfo REPOS_REL_PATH would inherit from that parent
10599    contains MERGEINFO then set *IN_CATALOG to TRUE.  Set *IN_CATALOG
10600    to FALSE in all other cases.
10601
10602    Set *CAT_KEY_PATH to the key path in CATALOG for REPOS_REL_PATH's
10603    explicit or inherited mergeinfo.  If no explicit or inherited mergeinfo
10604    is found for REPOS_REL_PATH then set *CAT_KEY_PATH to NULL.
10605
10606    User RESULT_POOL to allocate *CAT_KEY_PATH.  Use SCRATCH_POOL for
10607    temporary allocations. */
10608 static svn_error_t *
10609 mergeinfo_in_catalog(svn_boolean_t *in_catalog,
10610                      const char **cat_key_path,
10611                      const char *repos_rel_path,
10612                      svn_mergeinfo_t mergeinfo,
10613                      svn_mergeinfo_catalog_t catalog,
10614                      apr_pool_t *result_pool,
10615                      apr_pool_t *scratch_pool)
10616 {
10617   const char *walk_path = NULL;
10618
10619   *in_catalog = FALSE;
10620   *cat_key_path = NULL;
10621
10622   if (mergeinfo && catalog && apr_hash_count(catalog))
10623     {
10624       const char *path = repos_rel_path;
10625
10626       /* Start with the assumption there is no explicit or inherited
10627          mergeinfo for REPOS_REL_PATH in CATALOG. */
10628       svn_mergeinfo_t mergeinfo_in_cat = NULL;
10629
10630       while (1)
10631         {
10632           mergeinfo_in_cat = svn_hash_gets(catalog, path);
10633
10634           if (mergeinfo_in_cat) /* Found it! */
10635             {
10636               *cat_key_path = apr_pstrdup(result_pool, path);
10637               break;
10638             }
10639           else /* Look for inherited mergeinfo. */
10640             {
10641               walk_path = svn_relpath_join(svn_relpath_basename(path,
10642                                                                 scratch_pool),
10643                                            walk_path ? walk_path : "",
10644                                            scratch_pool);
10645               path = svn_relpath_dirname(path, scratch_pool);
10646
10647               if (path[0] == '\0') /* No mergeinfo to inherit. */
10648                 break;
10649             }
10650         }
10651
10652       if (mergeinfo_in_cat)
10653         {
10654           if (walk_path)
10655             SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(&mergeinfo_in_cat,
10656                                                            mergeinfo_in_cat,
10657                                                            walk_path,
10658                                                            scratch_pool,
10659                                                            scratch_pool));
10660           SVN_ERR(svn_mergeinfo_intersect2(&mergeinfo_in_cat,
10661                                            mergeinfo_in_cat, mergeinfo,
10662                                            TRUE,
10663                                            scratch_pool, scratch_pool));
10664           SVN_ERR(svn_mergeinfo__equals(in_catalog, mergeinfo_in_cat,
10665                                         mergeinfo, TRUE, scratch_pool));
10666         }
10667     }
10668
10669   return SVN_NO_ERROR;
10670 }
10671
10672 /* A svn_log_entry_receiver_t baton for log_find_operative_revs(). */
10673 typedef struct log_find_operative_baton_t
10674 {
10675   /* The catalog of explicit mergeinfo on a reintegrate source. */
10676   svn_mergeinfo_catalog_t merged_catalog;
10677
10678   /* The catalog of unmerged history from the reintegrate target to
10679      the source which we will create.  Allocated in RESULT_POOL. */
10680   svn_mergeinfo_catalog_t unmerged_catalog;
10681
10682   /* The repository absolute path of the reintegrate target. */
10683   const char *target_fspath;
10684
10685   /* The path of the reintegrate source relative to the repository root. */
10686   const char *source_repos_rel_path;
10687
10688   apr_pool_t *result_pool;
10689 } log_find_operative_baton_t;
10690
10691 /* A svn_log_entry_receiver_t callback for find_unsynced_ranges(). */
10692 static svn_error_t *
10693 log_find_operative_revs(void *baton,
10694                         svn_log_entry_t *log_entry,
10695                         apr_pool_t *pool)
10696 {
10697   log_find_operative_baton_t *log_baton = baton;
10698   apr_hash_index_t *hi;
10699   svn_revnum_t revision;
10700
10701   /* It's possible that authz restrictions on the merge source prevent us
10702      from knowing about any of the changes for LOG_ENTRY->REVISION. */
10703   if (!log_entry->changed_paths2)
10704     return SVN_NO_ERROR;
10705
10706   revision = log_entry->revision;
10707
10708   for (hi = apr_hash_first(pool, log_entry->changed_paths2);
10709        hi;
10710        hi = apr_hash_next(hi))
10711     {
10712       const char *subtree_missing_this_rev;
10713       const char *path = svn__apr_hash_index_key(hi);
10714       const char *rel_path;
10715       const char *source_rel_path;
10716       svn_boolean_t in_catalog;
10717       svn_mergeinfo_t log_entry_as_mergeinfo;
10718
10719       rel_path = svn_fspath__skip_ancestor(log_baton->target_fspath, path);
10720       /* Easy out: The path is not within the tree of interest. */
10721       if (rel_path == NULL)
10722         continue;
10723
10724       source_rel_path = svn_relpath_join(log_baton->source_repos_rel_path,
10725                                          rel_path, pool);
10726
10727       SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo,
10728                                   apr_psprintf(pool, "%s:%ld",
10729                                                path, revision),
10730                                   pool));
10731
10732       SVN_ERR(mergeinfo_in_catalog(&in_catalog, &subtree_missing_this_rev,
10733                                    source_rel_path, log_entry_as_mergeinfo,
10734                                    log_baton->merged_catalog,
10735                                    pool, pool));
10736
10737       if (!in_catalog)
10738         {
10739           svn_mergeinfo_t unmerged_for_key;
10740           const char *suffix, *missing_path;
10741
10742           /* If there is no mergeinfo on the source tree we'll say
10743              the "subtree" missing this revision is the root of the
10744              source. */
10745           if (!subtree_missing_this_rev)
10746             subtree_missing_this_rev = log_baton->source_repos_rel_path;
10747
10748           suffix = svn_relpath_skip_ancestor(subtree_missing_this_rev,
10749                                              source_rel_path);
10750           if (suffix && suffix[0] != '\0')
10751             {
10752               missing_path = apr_pstrmemdup(pool, path,
10753                                             strlen(path) - strlen(suffix) - 1);
10754             }
10755           else
10756             {
10757               missing_path = path;
10758             }
10759
10760           SVN_ERR(svn_mergeinfo_parse(&log_entry_as_mergeinfo,
10761                                       apr_psprintf(pool, "%s:%ld",
10762                                                    missing_path, revision),
10763                                       log_baton->result_pool));
10764           unmerged_for_key = svn_hash_gets(log_baton->unmerged_catalog,
10765                                            subtree_missing_this_rev);
10766
10767           if (unmerged_for_key)
10768             {
10769               SVN_ERR(svn_mergeinfo_merge2(unmerged_for_key,
10770                                            log_entry_as_mergeinfo,
10771                                            log_baton->result_pool,
10772                                            pool));
10773             }
10774           else
10775             {
10776               svn_hash_sets(log_baton->unmerged_catalog,
10777                             apr_pstrdup(log_baton->result_pool,
10778                                         subtree_missing_this_rev),
10779                             log_entry_as_mergeinfo);
10780             }
10781
10782         }
10783     }
10784   return SVN_NO_ERROR;
10785 }
10786
10787 /* Determine if the mergeinfo on a reintegrate source SOURCE_LOC,
10788    reflects that the source is fully synced with the reintegrate target
10789    TARGET_LOC, even if a naive interpretation of the source's
10790    mergeinfo says otherwise -- See issue #3577.
10791
10792    UNMERGED_CATALOG represents the history (as mergeinfo) from
10793    TARGET_LOC that is not represented in SOURCE_LOC's
10794    explicit/inherited mergeinfo as represented by MERGED_CATALOG.
10795    MERGED_CATALOG may be empty if the source has no explicit or inherited
10796    mergeinfo.
10797
10798    Check that all of the unmerged revisions in UNMERGED_CATALOG's
10799    mergeinfos are "phantoms", that is, one of the following conditions holds:
10800
10801      1) The revision affects no corresponding paths in SOURCE_LOC.
10802
10803      2) The revision affects corresponding paths in SOURCE_LOC,
10804         but based on the mergeinfo in MERGED_CATALOG, the change was
10805         previously merged.
10806
10807    Make a deep copy, allocated in RESULT_POOL, of any portions of
10808    UNMERGED_CATALOG that are not phantoms, to TRUE_UNMERGED_CATALOG.
10809
10810    Note: The keys in all mergeinfo catalogs used here are relative to the
10811    root of the repository.
10812
10813    RA_SESSION is an RA session open to the repository of TARGET_LOC; it may
10814    be temporarily reparented within this function.
10815
10816    Use SCRATCH_POOL for all temporary allocations. */
10817 static svn_error_t *
10818 find_unsynced_ranges(const svn_client__pathrev_t *source_loc,
10819                      const svn_client__pathrev_t *target_loc,
10820                      svn_mergeinfo_catalog_t unmerged_catalog,
10821                      svn_mergeinfo_catalog_t merged_catalog,
10822                      svn_mergeinfo_catalog_t true_unmerged_catalog,
10823                      svn_ra_session_t *ra_session,
10824                      apr_pool_t *result_pool,
10825                      apr_pool_t *scratch_pool)
10826 {
10827   svn_rangelist_t *potentially_unmerged_ranges = NULL;
10828
10829   /* Convert all the unmerged history to a rangelist. */
10830   if (apr_hash_count(unmerged_catalog))
10831     {
10832       apr_hash_index_t *hi_catalog;
10833
10834       potentially_unmerged_ranges =
10835         apr_array_make(scratch_pool, 1, sizeof(svn_merge_range_t *));
10836
10837       for (hi_catalog = apr_hash_first(scratch_pool, unmerged_catalog);
10838            hi_catalog;
10839            hi_catalog = apr_hash_next(hi_catalog))
10840         {
10841           svn_mergeinfo_t mergeinfo = svn__apr_hash_index_val(hi_catalog);
10842
10843           SVN_ERR(svn_rangelist__merge_many(potentially_unmerged_ranges,
10844                                             mergeinfo,
10845                                             scratch_pool, scratch_pool));
10846         }
10847     }
10848
10849   /* Find any unmerged revisions which both affect the source and
10850      are not yet merged to it. */
10851   if (potentially_unmerged_ranges)
10852     {
10853       svn_revnum_t oldest_rev =
10854         (APR_ARRAY_IDX(potentially_unmerged_ranges,
10855                        0,
10856                        svn_merge_range_t *))->start + 1;
10857       svn_revnum_t youngest_rev =
10858         (APR_ARRAY_IDX(potentially_unmerged_ranges,
10859                        potentially_unmerged_ranges->nelts - 1,
10860                        svn_merge_range_t *))->end;
10861       log_find_operative_baton_t log_baton;
10862       const char *old_session_url;
10863       svn_error_t *err;
10864
10865       log_baton.merged_catalog = merged_catalog;
10866       log_baton.unmerged_catalog = true_unmerged_catalog;
10867       log_baton.source_repos_rel_path
10868         = svn_client__pathrev_relpath(source_loc, scratch_pool);
10869       log_baton.target_fspath
10870         = svn_client__pathrev_fspath(target_loc, scratch_pool);
10871       log_baton.result_pool = result_pool;
10872
10873       SVN_ERR(svn_client__ensure_ra_session_url(
10874                 &old_session_url, ra_session, target_loc->url, scratch_pool));
10875       err = get_log(ra_session, "", youngest_rev, oldest_rev,
10876                     TRUE, /* discover_changed_paths */
10877                     log_find_operative_revs, &log_baton,
10878                     scratch_pool);
10879       SVN_ERR(svn_error_compose_create(
10880                 err, svn_ra_reparent(ra_session, old_session_url, scratch_pool)));
10881     }
10882
10883   return SVN_NO_ERROR;
10884 }
10885
10886
10887 /* Find the youngest revision that has been merged from target to source.
10888  *
10889  * If any location in TARGET_HISTORY_AS_MERGEINFO is mentioned in
10890  * SOURCE_MERGEINFO, then we know that at least one merge was done from the
10891  * target to the source.  In that case, set *YOUNGEST_MERGED_REV to the
10892  * youngest revision of that intersection (unless *YOUNGEST_MERGED_REV is
10893  * already younger than that).  Otherwise, leave *YOUNGEST_MERGED_REV alone.
10894  */
10895 static svn_error_t *
10896 find_youngest_merged_rev(svn_revnum_t *youngest_merged_rev,
10897                          svn_mergeinfo_t target_history_as_mergeinfo,
10898                          svn_mergeinfo_t source_mergeinfo,
10899                          apr_pool_t *scratch_pool)
10900 {
10901   svn_mergeinfo_t explicit_source_target_history_intersection;
10902
10903   SVN_ERR(svn_mergeinfo_intersect2(
10904             &explicit_source_target_history_intersection,
10905             source_mergeinfo, target_history_as_mergeinfo, TRUE,
10906             scratch_pool, scratch_pool));
10907   if (apr_hash_count(explicit_source_target_history_intersection))
10908     {
10909       svn_revnum_t old_rev, young_rev;
10910
10911       /* Keep track of the youngest revision merged from target to source. */
10912       SVN_ERR(svn_mergeinfo__get_range_endpoints(
10913                 &young_rev, &old_rev,
10914                 explicit_source_target_history_intersection, scratch_pool));
10915       if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
10916           || (young_rev > *youngest_merged_rev))
10917         *youngest_merged_rev = young_rev;
10918     }
10919
10920   return SVN_NO_ERROR;
10921 }
10922
10923 /* Set *FILTERED_MERGEINFO_P to the parts of TARGET_HISTORY_AS_MERGEINFO
10924  * that are not present in the source branch.
10925  *
10926  * SOURCE_MERGEINFO is the explicit or inherited mergeinfo of the source
10927  * branch SOURCE_PATHREV.  Extend SOURCE_MERGEINFO, modifying it in
10928  * place, to include the natural history (implicit mergeinfo) of
10929  * SOURCE_PATHREV.  ### But make these additions in SCRATCH_POOL.
10930  *
10931  * SOURCE_RA_SESSION is an RA session open to the repository containing
10932  * SOURCE_PATHREV; it may be temporarily reparented within this function.
10933  *
10934  * ### [JAF] This function is named '..._subroutine' simply because I
10935  *     factored it out based on code similarity, without knowing what it's
10936  *     purpose is.  We should clarify its purpose and choose a better name.
10937  */
10938 static svn_error_t *
10939 find_unmerged_mergeinfo_subroutine(svn_mergeinfo_t *filtered_mergeinfo_p,
10940                                    svn_mergeinfo_t target_history_as_mergeinfo,
10941                                    svn_mergeinfo_t source_mergeinfo,
10942                                    const svn_client__pathrev_t *source_pathrev,
10943                                    svn_ra_session_t *source_ra_session,
10944                                    svn_client_ctx_t *ctx,
10945                                    apr_pool_t *result_pool,
10946                                    apr_pool_t *scratch_pool)
10947 {
10948   svn_mergeinfo_t source_history_as_mergeinfo;
10949
10950   /* Get the source path's natural history and merge it into source
10951      path's explicit or inherited mergeinfo. */
10952   SVN_ERR(svn_client__get_history_as_mergeinfo(
10953             &source_history_as_mergeinfo, NULL /* has_rev_zero_history */,
10954             source_pathrev, source_pathrev->rev, SVN_INVALID_REVNUM,
10955             source_ra_session, ctx, scratch_pool));
10956   SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo,
10957                                source_history_as_mergeinfo,
10958                                scratch_pool, scratch_pool));
10959
10960   /* Now source_mergeinfo represents everything we know about
10961      source_path's history.  Now we need to know what part, if any, of the
10962      corresponding target's history is *not* part of source_path's total
10963      history; because it is neither shared history nor was it ever merged
10964      from the target to the source. */
10965   SVN_ERR(svn_mergeinfo_remove2(filtered_mergeinfo_p,
10966                                 source_mergeinfo,
10967                                 target_history_as_mergeinfo, TRUE,
10968                                 result_pool, scratch_pool));
10969   return SVN_NO_ERROR;
10970 }
10971
10972 /* Helper for calculate_left_hand_side() which produces a mergeinfo catalog
10973    describing what parts of of the reintegrate target have not previously been
10974    merged to the reintegrate source.
10975
10976    SOURCE_CATALOG is the collection of explicit mergeinfo on SOURCE_LOC and
10977    all its children, i.e. the mergeinfo catalog for the reintegrate source.
10978
10979    TARGET_HISTORY_HASH is a hash of (const char *) paths mapped to
10980    svn_mergeinfo_t representing the location history.  Each of these
10981    path keys represent a path in the reintegrate target, relative to the
10982    repository root, which has explicit mergeinfo and/or is the reintegrate
10983    target itself.  The svn_mergeinfo_t's contain the natural history of each
10984    path@TARGET_REV.  Effectively this is the mergeinfo catalog on the
10985    reintegrate target.
10986
10987    YC_ANCESTOR_REV is the revision of the youngest common ancestor of the
10988    reintegrate source and the reintegrate target.
10989
10990    SOURCE_LOC is the reintegrate source.
10991
10992    SOURCE_RA_SESSION is a session opened to the URL of SOURCE_LOC
10993    and TARGET_RA_SESSION is open to TARGET->loc.url.
10994
10995    For each entry in TARGET_HISTORY_HASH check that the history it
10996    represents is contained in either the explicit mergeinfo for the
10997    corresponding path in SOURCE_CATALOG, the corresponding path's inherited
10998    mergeinfo (if no explicit mergeinfo for the path is found in
10999    SOURCE_CATALOG), or the corresponding path's natural history.  Populate
11000    *UNMERGED_TO_SOURCE_CATALOG with the corresponding source paths mapped to
11001    the mergeinfo from the target's natural history which is *not* found.  Also
11002    include any mergeinfo from SOURCE_CATALOG which explicitly describes the
11003    target's history but for which *no* entry was found in
11004    TARGET_HISTORY_HASH.
11005
11006    If no part of TARGET_HISTORY_HASH is found in SOURCE_CATALOG set
11007    *YOUNGEST_MERGED_REV to SVN_INVALID_REVNUM; otherwise set it to the youngest
11008    revision previously merged from the target to the source, and filter
11009    *UNMERGED_TO_SOURCE_CATALOG so that it contains no ranges greater than
11010    *YOUNGEST_MERGED_REV.
11011
11012    *UNMERGED_TO_SOURCE_CATALOG is (deeply) allocated in RESULT_POOL.
11013    SCRATCH_POOL is used for all temporary allocations.  */
11014 static svn_error_t *
11015 find_unmerged_mergeinfo(svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
11016                         svn_revnum_t *youngest_merged_rev,
11017                         svn_revnum_t yc_ancestor_rev,
11018                         svn_mergeinfo_catalog_t source_catalog,
11019                         apr_hash_t *target_history_hash,
11020                         const svn_client__pathrev_t *source_loc,
11021                         const merge_target_t *target,
11022                         svn_ra_session_t *source_ra_session,
11023                         svn_ra_session_t *target_ra_session,
11024                         svn_client_ctx_t *ctx,
11025                         apr_pool_t *result_pool,
11026                         apr_pool_t *scratch_pool)
11027 {
11028   const char *source_repos_rel_path
11029     = svn_client__pathrev_relpath(source_loc, scratch_pool);
11030   const char *target_repos_rel_path
11031     = svn_client__pathrev_relpath(&target->loc, scratch_pool);
11032   apr_hash_index_t *hi;
11033   svn_mergeinfo_catalog_t new_catalog = apr_hash_make(result_pool);
11034   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
11035
11036   assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
11037   assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
11038
11039   *youngest_merged_rev = SVN_INVALID_REVNUM;
11040
11041   /* Examine the natural history of each path in the reintegrate target
11042      with explicit mergeinfo. */
11043   for (hi = apr_hash_first(scratch_pool, target_history_hash);
11044        hi;
11045        hi = apr_hash_next(hi))
11046     {
11047       const char *target_path = svn__apr_hash_index_key(hi);
11048       svn_mergeinfo_t target_history_as_mergeinfo = svn__apr_hash_index_val(hi);
11049       const char *path_rel_to_session
11050         = svn_relpath_skip_ancestor(target_repos_rel_path, target_path);
11051       const char *source_path;
11052       svn_client__pathrev_t *source_pathrev;
11053       svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo;
11054
11055       svn_pool_clear(iterpool);
11056
11057       source_path = svn_relpath_join(source_repos_rel_path,
11058                                      path_rel_to_session, iterpool);
11059       source_pathrev = svn_client__pathrev_join_relpath(
11060                          source_loc, path_rel_to_session, iterpool);
11061
11062       /* Remove any target history that is also part of the source's history,
11063          i.e. their common ancestry.  By definition this has already been
11064          "merged" from the target to the source.  If the source has explicit
11065          self referential mergeinfo it would intersect with the target's
11066          history below, making it appear that some merges had been done from
11067          the target to the source, when this might not actually be the case. */
11068       SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
11069         &target_history_as_mergeinfo, target_history_as_mergeinfo,
11070         source_loc->rev, yc_ancestor_rev, TRUE, iterpool, iterpool));
11071
11072       /* Look for any explicit mergeinfo on the source path corresponding to
11073          the target path.  If we find any remove that from SOURCE_CATALOG.
11074          When this iteration over TARGET_HISTORY_HASH is complete all that
11075          should be left in SOURCE_CATALOG are subtrees that have explicit
11076          mergeinfo on the reintegrate source where there is no corresponding
11077          explicit mergeinfo on the reintegrate target. */
11078       source_mergeinfo = svn_hash_gets(source_catalog, source_path);
11079       if (source_mergeinfo)
11080         {
11081           svn_hash_sets(source_catalog, source_path, NULL);
11082
11083           SVN_ERR(find_youngest_merged_rev(youngest_merged_rev,
11084                                            target_history_as_mergeinfo,
11085                                            source_mergeinfo,
11086                                            iterpool));
11087         }
11088       else
11089         {
11090           /* There is no mergeinfo on source_path *or* source_path doesn't
11091              exist at all.  If simply doesn't exist we can ignore it
11092              altogether. */
11093           svn_node_kind_t kind;
11094
11095           SVN_ERR(svn_ra_check_path(source_ra_session,
11096                                     path_rel_to_session,
11097                                     source_loc->rev, &kind, iterpool));
11098           if (kind == svn_node_none)
11099               continue;
11100           /* Else source_path does exist though it has no explicit mergeinfo.
11101              Find its inherited mergeinfo.  If it doesn't have any then simply
11102              set source_mergeinfo to an empty hash. */
11103           SVN_ERR(svn_client__get_repos_mergeinfo(
11104                     &source_mergeinfo, source_ra_session,
11105                     source_pathrev->url, source_pathrev->rev,
11106                     svn_mergeinfo_inherited, FALSE /*squelch_incapable*/,
11107                     iterpool));
11108           if (!source_mergeinfo)
11109             source_mergeinfo = apr_hash_make(iterpool);
11110         }
11111
11112       /* Use scratch_pool rather than iterpool because filtered_mergeinfo
11113          is going into new_catalog below and needs to last to the end of
11114          this function. */
11115       SVN_ERR(find_unmerged_mergeinfo_subroutine(
11116                 &filtered_mergeinfo, target_history_as_mergeinfo,
11117                 source_mergeinfo, source_pathrev,
11118                 source_ra_session, ctx, scratch_pool, iterpool));
11119       svn_hash_sets(new_catalog, apr_pstrdup(scratch_pool, source_path),
11120                     filtered_mergeinfo);
11121     }
11122
11123   /* Are there any subtrees with explicit mergeinfo still left in the merge
11124      source where there was no explicit mergeinfo for the corresponding path
11125      in the merge target?  If so, add the intersection of those path's
11126      mergeinfo and the corresponding target path's mergeinfo to
11127      new_catalog. */
11128   for (hi = apr_hash_first(scratch_pool, source_catalog);
11129        hi;
11130        hi = apr_hash_next(hi))
11131     {
11132       const char *source_path = svn__apr_hash_index_key(hi);
11133       const char *path_rel_to_session =
11134         svn_relpath_skip_ancestor(source_repos_rel_path, source_path);
11135       const char *source_url;
11136       svn_mergeinfo_t source_mergeinfo = svn__apr_hash_index_val(hi);
11137       svn_mergeinfo_t filtered_mergeinfo;
11138       svn_client__pathrev_t *target_pathrev;
11139       svn_mergeinfo_t target_history_as_mergeinfo;
11140       svn_error_t *err;
11141
11142       svn_pool_clear(iterpool);
11143
11144       source_url = svn_path_url_add_component2(source_loc->url,
11145                                                path_rel_to_session, iterpool);
11146       target_pathrev = svn_client__pathrev_join_relpath(
11147                          &target->loc, path_rel_to_session, iterpool);
11148       err = svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo,
11149                                                  NULL /* has_rev_zero_history */,
11150                                                  target_pathrev,
11151                                                  target->loc.rev,
11152                                                  SVN_INVALID_REVNUM,
11153                                                  target_ra_session,
11154                                                  ctx, iterpool);
11155       if (err)
11156         {
11157           if (err->apr_err == SVN_ERR_FS_NOT_FOUND
11158               || err->apr_err == SVN_ERR_RA_DAV_REQUEST_FAILED)
11159             {
11160               /* This path with explicit mergeinfo in the source doesn't
11161                  exist on the target. */
11162               svn_error_clear(err);
11163               err = NULL;
11164             }
11165           else
11166             {
11167               return svn_error_trace(err);
11168             }
11169         }
11170       else
11171         {
11172           svn_client__pathrev_t *pathrev;
11173
11174           SVN_ERR(find_youngest_merged_rev(youngest_merged_rev,
11175                                            target_history_as_mergeinfo,
11176                                            source_mergeinfo,
11177                                            iterpool));
11178
11179           /* Use scratch_pool rather than iterpool because filtered_mergeinfo
11180              is going into new_catalog below and needs to last to the end of
11181              this function. */
11182           /* ### Why looking at SOURCE_url at TARGET_rev? */
11183           SVN_ERR(svn_client__pathrev_create_with_session(
11184                     &pathrev, source_ra_session, target->loc.rev, source_url,
11185                     iterpool));
11186           SVN_ERR(find_unmerged_mergeinfo_subroutine(
11187                     &filtered_mergeinfo, target_history_as_mergeinfo,
11188                     source_mergeinfo, pathrev,
11189                     source_ra_session, ctx, scratch_pool, iterpool));
11190           if (apr_hash_count(filtered_mergeinfo))
11191             svn_hash_sets(new_catalog,
11192                           apr_pstrdup(scratch_pool, source_path),
11193                           filtered_mergeinfo);
11194         }
11195     }
11196
11197   /* Limit new_catalog to the youngest revisions previously merged from
11198      the target to the source. */
11199   if (SVN_IS_VALID_REVNUM(*youngest_merged_rev))
11200     SVN_ERR(svn_mergeinfo__filter_catalog_by_ranges(&new_catalog,
11201                                                     new_catalog,
11202                                                     *youngest_merged_rev,
11203                                                     0, /* No oldest bound. */
11204                                                     TRUE,
11205                                                     scratch_pool,
11206                                                     scratch_pool));
11207
11208   /* Make a shiny new copy before blowing away all the temporary pools. */
11209   *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(new_catalog,
11210                                                           result_pool);
11211   svn_pool_destroy(iterpool);
11212   return SVN_NO_ERROR;
11213 }
11214
11215 /* Helper for svn_client_merge_reintegrate() which calculates the
11216    'left hand side' of the underlying two-URL merge that a --reintegrate
11217    merge actually performs.  If no merge should be performed, set
11218    *LEFT_P to NULL.
11219
11220    TARGET->abspath is the absolute working copy path of the reintegrate
11221    merge.
11222
11223    SOURCE_LOC is the reintegrate source.
11224
11225    SUBTREES_WITH_MERGEINFO is a hash of (const char *) absolute paths mapped
11226    to (svn_mergeinfo_t *) mergeinfo values for each working copy path with
11227    explicit mergeinfo in TARGET->abspath.  Actually we only need to know the
11228    paths, not the mergeinfo.
11229
11230    TARGET->loc.rev is the working revision the entire WC tree rooted at
11231    TARGET is at.
11232
11233    Populate *UNMERGED_TO_SOURCE_CATALOG with the mergeinfo describing what
11234    parts of TARGET->loc have not been merged to SOURCE_LOC, up to the
11235    youngest revision ever merged from the TARGET->abspath to the source if
11236    such exists, see doc string for find_unmerged_mergeinfo().
11237
11238    SOURCE_RA_SESSION is a session opened to the SOURCE_LOC
11239    and TARGET_RA_SESSION is open to TARGET->loc.url.
11240
11241    *LEFT_P, *MERGED_TO_SOURCE_CATALOG , and *UNMERGED_TO_SOURCE_CATALOG are
11242    allocated in RESULT_POOL.  SCRATCH_POOL is used for all temporary
11243    allocations. */
11244 static svn_error_t *
11245 calculate_left_hand_side(svn_client__pathrev_t **left_p,
11246                          svn_mergeinfo_catalog_t *merged_to_source_catalog,
11247                          svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
11248                          const merge_target_t *target,
11249                          apr_hash_t *subtrees_with_mergeinfo,
11250                          const svn_client__pathrev_t *source_loc,
11251                          svn_ra_session_t *source_ra_session,
11252                          svn_ra_session_t *target_ra_session,
11253                          svn_client_ctx_t *ctx,
11254                          apr_pool_t *result_pool,
11255                          apr_pool_t *scratch_pool)
11256 {
11257   svn_mergeinfo_catalog_t mergeinfo_catalog, unmerged_catalog;
11258   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
11259   apr_hash_index_t *hi;
11260   /* hash of paths mapped to arrays of svn_mergeinfo_t. */
11261   apr_hash_t *target_history_hash = apr_hash_make(scratch_pool);
11262   svn_revnum_t youngest_merged_rev;
11263   svn_client__pathrev_t *yc_ancestor;
11264
11265   assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
11266   assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
11267
11268   /* Initialize our return variables. */
11269   *left_p = NULL;
11270
11271   /* TARGET->abspath may not have explicit mergeinfo and thus may not be
11272      contained within SUBTREES_WITH_MERGEINFO.  If this is the case then
11273      add a dummy item for TARGET->abspath so we get its history (i.e. implicit
11274      mergeinfo) below.  */
11275   if (!svn_hash_gets(subtrees_with_mergeinfo, target->abspath))
11276     svn_hash_sets(subtrees_with_mergeinfo, target->abspath,
11277                   apr_hash_make(result_pool));
11278
11279   /* Get the history segments (as mergeinfo) for TARGET->abspath and any of
11280      its subtrees with explicit mergeinfo. */
11281   for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo);
11282        hi;
11283        hi = apr_hash_next(hi))
11284     {
11285       const char *local_abspath = svn__apr_hash_index_key(hi);
11286       svn_client__pathrev_t *target_child;
11287       const char *repos_relpath;
11288       svn_mergeinfo_t target_history_as_mergeinfo;
11289
11290       svn_pool_clear(iterpool);
11291
11292       /* Convert the absolute path with mergeinfo on it to a path relative
11293          to the session root. */
11294       SVN_ERR(svn_wc__node_get_repos_info(NULL, &repos_relpath, NULL, NULL,
11295                                           ctx->wc_ctx, local_abspath,
11296                                           scratch_pool, iterpool));
11297       target_child = svn_client__pathrev_create_with_relpath(
11298                        target->loc.repos_root_url, target->loc.repos_uuid,
11299                        target->loc.rev, repos_relpath, iterpool);
11300       SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo,
11301                                                    NULL /* has_rev_zero_hist */,
11302                                                    target_child,
11303                                                    target->loc.rev,
11304                                                    SVN_INVALID_REVNUM,
11305                                                    target_ra_session,
11306                                                    ctx, scratch_pool));
11307
11308       svn_hash_sets(target_history_hash, repos_relpath,
11309                     target_history_as_mergeinfo);
11310     }
11311
11312   /* Check that SOURCE_LOC and TARGET->loc are
11313      actually related, we can't reintegrate if they are not.  Also
11314      get an initial value for the YCA revision number. */
11315   SVN_ERR(svn_client__get_youngest_common_ancestor(
11316               &yc_ancestor, source_loc, &target->loc, target_ra_session, ctx,
11317               iterpool, iterpool));
11318   if (! yc_ancestor)
11319     return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
11320                              _("'%s@%ld' must be ancestrally related to "
11321                                "'%s@%ld'"), source_loc->url, source_loc->rev,
11322                              target->loc.url, target->loc.rev);
11323
11324   /* If the source revision is the same as the youngest common
11325      revision, then there can't possibly be any unmerged revisions
11326      that we need to apply to target. */
11327   if (source_loc->rev == yc_ancestor->rev)
11328     {
11329       svn_pool_destroy(iterpool);
11330       return SVN_NO_ERROR;
11331     }
11332
11333   /* Get the mergeinfo from the source, including its descendants
11334      with differing explicit mergeinfo. */
11335   SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
11336             &mergeinfo_catalog, source_ra_session,
11337             source_loc->url, source_loc->rev,
11338             svn_mergeinfo_inherited, FALSE /* squelch_incapable */,
11339             TRUE /* include_descendants */, iterpool, iterpool));
11340
11341   if (!mergeinfo_catalog)
11342     mergeinfo_catalog = apr_hash_make(iterpool);
11343
11344   *merged_to_source_catalog = svn_mergeinfo_catalog_dup(mergeinfo_catalog,
11345                                                         result_pool);
11346
11347   /* Filter the source's mergeinfo catalog so that we are left with
11348      mergeinfo that describes what has *not* previously been merged from
11349      TARGET->loc to SOURCE_LOC. */
11350   SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog,
11351                                   &youngest_merged_rev,
11352                                   yc_ancestor->rev,
11353                                   mergeinfo_catalog,
11354                                   target_history_hash,
11355                                   source_loc,
11356                                   target,
11357                                   source_ra_session,
11358                                   target_ra_session,
11359                                   ctx,
11360                                   iterpool, iterpool));
11361
11362   /* Simplify unmerged_catalog through elision then make a copy in POOL. */
11363   SVN_ERR(svn_client__elide_mergeinfo_catalog(unmerged_catalog,
11364                                               iterpool));
11365   *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(unmerged_catalog,
11366                                                           result_pool);
11367
11368   if (youngest_merged_rev == SVN_INVALID_REVNUM)
11369     {
11370       /* We never merged to the source.  Just return the branch point. */
11371       *left_p = svn_client__pathrev_dup(yc_ancestor, result_pool);
11372     }
11373   else
11374     {
11375       /* We've previously merged some or all of the target, up to
11376          youngest_merged_rev, to the source.  Set
11377          *LEFT_P to cover the youngest part of this range. */
11378       SVN_ERR(svn_client__repos_location(left_p, target_ra_session,
11379                                          &target->loc, youngest_merged_rev,
11380                                          ctx, result_pool, iterpool));
11381     }
11382
11383   svn_pool_destroy(iterpool);
11384   return SVN_NO_ERROR;
11385 }
11386
11387 /* Determine the URLs and revisions needed to perform a reintegrate merge
11388  * from SOURCE_LOC into the working copy at TARGET.
11389  *
11390  * SOURCE_RA_SESSION and TARGET_RA_SESSION are RA sessions opened to the
11391  * URLs of SOURCE_LOC and TARGET->loc respectively.
11392  *
11393  * Set *SOURCE_P to
11394  * the source-left and source-right locations of the required merge.  Set
11395  * *YC_ANCESTOR_P to the location of the youngest ancestor.
11396  * Any of these output pointers may be NULL if not wanted.
11397  *
11398  * See svn_client_find_reintegrate_merge() for other details.
11399  */
11400 static svn_error_t *
11401 find_reintegrate_merge(merge_source_t **source_p,
11402                        svn_client__pathrev_t **yc_ancestor_p,
11403                        svn_ra_session_t *source_ra_session,
11404                        const svn_client__pathrev_t *source_loc,
11405                        svn_ra_session_t *target_ra_session,
11406                        const merge_target_t *target,
11407                        svn_client_ctx_t *ctx,
11408                        apr_pool_t *result_pool,
11409                        apr_pool_t *scratch_pool)
11410 {
11411   svn_client__pathrev_t *yc_ancestor;
11412   svn_client__pathrev_t *loc1;
11413   merge_source_t source;
11414   svn_mergeinfo_catalog_t unmerged_to_source_mergeinfo_catalog;
11415   svn_mergeinfo_catalog_t merged_to_source_mergeinfo_catalog;
11416   svn_error_t *err;
11417   apr_hash_t *subtrees_with_mergeinfo;
11418
11419   assert(session_url_is(source_ra_session, source_loc->url, scratch_pool));
11420   assert(session_url_is(target_ra_session, target->loc.url, scratch_pool));
11421
11422   /* As the WC tree is "pure", use its last-updated-to revision as
11423      the default revision for the left side of our merge, since that's
11424      what the repository sub-tree is required to be up to date with
11425      (with regard to the WC). */
11426   /* ### Bogus/obsolete comment? */
11427
11428   /* Can't reintegrate to or from the root of the repository. */
11429   if (strcmp(source_loc->url, source_loc->repos_root_url) == 0
11430       || strcmp(target->loc.url, target->loc.repos_root_url) == 0)
11431     return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
11432                              _("Neither the reintegrate source nor target "
11433                                "can be the root of the repository"));
11434
11435   /* Find all the subtrees in TARGET_WCPATH that have explicit mergeinfo. */
11436   err = get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo,
11437                                           target->abspath, svn_depth_infinity,
11438                                           ctx, scratch_pool, scratch_pool);
11439   /* Issue #3896: If invalid mergeinfo in the reintegrate target
11440      prevents us from proceeding, then raise the best error possible. */
11441   if (err && err->apr_err == SVN_ERR_CLIENT_INVALID_MERGEINFO_NO_MERGETRACKING)
11442     err = svn_error_quick_wrap(err, _("Reintegrate merge not possible"));
11443   SVN_ERR(err);
11444
11445   SVN_ERR(calculate_left_hand_side(&loc1,
11446                                    &merged_to_source_mergeinfo_catalog,
11447                                    &unmerged_to_source_mergeinfo_catalog,
11448                                    target,
11449                                    subtrees_with_mergeinfo,
11450                                    source_loc,
11451                                    source_ra_session,
11452                                    target_ra_session,
11453                                    ctx,
11454                                    scratch_pool, scratch_pool));
11455
11456   /* Did calculate_left_hand_side() decide that there was no merge to
11457      be performed here?  */
11458   if (! loc1)
11459     {
11460       if (source_p)
11461         *source_p = NULL;
11462       if (yc_ancestor_p)
11463         *yc_ancestor_p = NULL;
11464       return SVN_NO_ERROR;
11465     }
11466
11467   source.loc1 = loc1;
11468   source.loc2 = source_loc;
11469
11470   /* If the target was moved after the source was branched from it,
11471      it is possible that the left URL differs from the target's current
11472      URL.  If so, then adjust TARGET_RA_SESSION to point to the old URL. */
11473   if (strcmp(source.loc1->url, target->loc.url))
11474     SVN_ERR(svn_ra_reparent(target_ra_session, source.loc1->url, scratch_pool));
11475
11476   SVN_ERR(svn_client__get_youngest_common_ancestor(
11477             &yc_ancestor, source.loc2, source.loc1, target_ra_session,
11478             ctx, scratch_pool, scratch_pool));
11479
11480   if (! yc_ancestor)
11481     return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
11482                              _("'%s@%ld' must be ancestrally related to "
11483                                "'%s@%ld'"),
11484                              source.loc1->url, source.loc1->rev,
11485                              source.loc2->url, source.loc2->rev);
11486
11487   /* The source side of a reintegrate merge is not 'ancestral', except in
11488    * the degenerate case where source == YCA. */
11489   source.ancestral = (loc1->rev == yc_ancestor->rev);
11490
11491   if (source.loc1->rev > yc_ancestor->rev)
11492     {
11493       /* Have we actually merged anything to the source from the
11494          target?  If so, make sure we've merged a contiguous
11495          prefix. */
11496       svn_mergeinfo_catalog_t final_unmerged_catalog = apr_hash_make(scratch_pool);
11497
11498       SVN_ERR(find_unsynced_ranges(source_loc, &target->loc,
11499                                    unmerged_to_source_mergeinfo_catalog,
11500                                    merged_to_source_mergeinfo_catalog,
11501                                    final_unmerged_catalog,
11502                                    target_ra_session, scratch_pool,
11503                                    scratch_pool));
11504
11505       if (apr_hash_count(final_unmerged_catalog))
11506         {
11507           svn_string_t *source_mergeinfo_cat_string;
11508
11509           SVN_ERR(svn_mergeinfo__catalog_to_formatted_string(
11510             &source_mergeinfo_cat_string,
11511             final_unmerged_catalog,
11512             "  ", "    Missing ranges: ", scratch_pool));
11513           return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
11514                                    NULL,
11515                                    _("Reintegrate can only be used if "
11516                                      "revisions %ld through %ld were "
11517                                      "previously merged from %s to the "
11518                                      "reintegrate source, but this is "
11519                                      "not the case:\n%s"),
11520                                    yc_ancestor->rev + 1, source.loc2->rev,
11521                                    target->loc.url,
11522                                    source_mergeinfo_cat_string->data);
11523         }
11524     }
11525
11526   /* Left side: trunk@youngest-trunk-rev-merged-to-branch-at-specified-peg-rev
11527    * Right side: branch@specified-peg-revision */
11528   if (source_p)
11529     *source_p = merge_source_dup(&source, result_pool);
11530
11531   if (yc_ancestor_p)
11532     *yc_ancestor_p = svn_client__pathrev_dup(yc_ancestor, result_pool);
11533   return SVN_NO_ERROR;
11534 }
11535
11536 /* Resolve the source and target locations and open RA sessions to them, and
11537  * perform some checks appropriate for a reintegrate merge.
11538  *
11539  * Set *SOURCE_RA_SESSION_P and *SOURCE_LOC_P to a new session and the
11540  * repository location of SOURCE_PATH_OR_URL at SOURCE_PEG_REVISION.  Set
11541  * *TARGET_RA_SESSION_P and *TARGET_P to a new session and the repository
11542  * location of the WC at TARGET_ABSPATH.
11543  *
11544  * Throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES error if the target WC node is
11545  * a locally added node or if the source and target are not in the same
11546  * repository.  Throw a SVN_ERR_CLIENT_NOT_READY_TO_MERGE error if the
11547  * target WC is not at a single revision without switched subtrees and
11548  * without local mods.
11549  *
11550  * Allocate all the outputs in RESULT_POOL.
11551  */
11552 static svn_error_t *
11553 open_reintegrate_source_and_target(svn_ra_session_t **source_ra_session_p,
11554                                    svn_client__pathrev_t **source_loc_p,
11555                                    svn_ra_session_t **target_ra_session_p,
11556                                    merge_target_t **target_p,
11557                                    const char *source_path_or_url,
11558                                    const svn_opt_revision_t *source_peg_revision,
11559                                    const char *target_abspath,
11560                                    svn_client_ctx_t *ctx,
11561                                    apr_pool_t *result_pool,
11562                                    apr_pool_t *scratch_pool)
11563 {
11564   svn_client__pathrev_t *source_loc;
11565   merge_target_t *target;
11566
11567   /* Open the target WC.  A reintegrate merge requires the merge target to
11568    * reflect a subtree of the repository as found at a single revision. */
11569   SVN_ERR(open_target_wc(&target, target_abspath,
11570                          FALSE, FALSE, FALSE,
11571                          ctx, scratch_pool, scratch_pool));
11572   SVN_ERR(svn_client_open_ra_session2(target_ra_session_p,
11573                                       target->loc.url, target->abspath,
11574                                       ctx, result_pool, scratch_pool));
11575   if (! target->loc.url)
11576     return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
11577                              _("Can't reintegrate into '%s' because it is "
11578                                "locally added and therefore not related to "
11579                                "the merge source"),
11580                              svn_dirent_local_style(target->abspath,
11581                                                     scratch_pool));
11582
11583   SVN_ERR(svn_client__ra_session_from_path2(
11584             source_ra_session_p, &source_loc,
11585             source_path_or_url, NULL, source_peg_revision, source_peg_revision,
11586             ctx, result_pool));
11587
11588   /* source_loc and target->loc are required to be in the same repository,
11589      as mergeinfo doesn't come into play for cross-repository merging. */
11590   SVN_ERR(check_same_repos(source_loc,
11591                            svn_dirent_local_style(source_path_or_url,
11592                                                   scratch_pool),
11593                            &target->loc,
11594                            svn_dirent_local_style(target->abspath,
11595                                                   scratch_pool),
11596                            TRUE /* strict_urls */, scratch_pool));
11597
11598   *source_loc_p = source_loc;
11599   *target_p = target;
11600   return SVN_NO_ERROR;
11601 }
11602
11603 /* The body of svn_client_merge_reintegrate(), which see for details. */
11604 static svn_error_t *
11605 merge_reintegrate_locked(conflict_report_t **conflict_report,
11606                          const char *source_path_or_url,
11607                          const svn_opt_revision_t *source_peg_revision,
11608                          const char *target_abspath,
11609                          svn_boolean_t diff_ignore_ancestry,
11610                          svn_boolean_t dry_run,
11611                          const apr_array_header_t *merge_options,
11612                          svn_client_ctx_t *ctx,
11613                          apr_pool_t *result_pool,
11614                          apr_pool_t *scratch_pool)
11615 {
11616   svn_ra_session_t *target_ra_session, *source_ra_session;
11617   merge_target_t *target;
11618   svn_client__pathrev_t *source_loc;
11619   merge_source_t *source;
11620   svn_client__pathrev_t *yc_ancestor;
11621   svn_boolean_t use_sleep = FALSE;
11622   svn_error_t *err;
11623
11624   SVN_ERR(open_reintegrate_source_and_target(
11625             &source_ra_session, &source_loc, &target_ra_session, &target,
11626             source_path_or_url, source_peg_revision, target_abspath,
11627             ctx, scratch_pool, scratch_pool));
11628
11629   SVN_ERR(find_reintegrate_merge(&source, &yc_ancestor,
11630                                  source_ra_session, source_loc,
11631                                  target_ra_session, target,
11632                                  ctx, scratch_pool, scratch_pool));
11633
11634   if (! source)
11635     {
11636       return SVN_NO_ERROR;
11637     }
11638
11639   /* Do the real merge! */
11640   /* ### TODO(reint): Make sure that one isn't the same line ancestor
11641      ### of the other (what's erroneously referred to as "ancestrally
11642      ### related" in this source file).  For now, we just say the source
11643      ### isn't "ancestral" even if it is (in the degenerate case where
11644      ### source-left equals YCA). */
11645   source->ancestral = FALSE;
11646   err = merge_cousins_and_supplement_mergeinfo(conflict_report,
11647                                                &use_sleep,
11648                                                target,
11649                                                target_ra_session,
11650                                                source_ra_session,
11651                                                source, yc_ancestor,
11652                                                TRUE /* same_repos */,
11653                                                svn_depth_infinity,
11654                                                diff_ignore_ancestry,
11655                                                FALSE /* force_delete */,
11656                                                FALSE /* record_only */,
11657                                                dry_run,
11658                                                merge_options,
11659                                                ctx,
11660                                                result_pool, scratch_pool);
11661
11662   if (use_sleep)
11663     svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
11664
11665   SVN_ERR(err);
11666   return SVN_NO_ERROR;
11667 }
11668
11669 svn_error_t *
11670 svn_client_merge_reintegrate(const char *source_path_or_url,
11671                              const svn_opt_revision_t *source_peg_revision,
11672                              const char *target_wcpath,
11673                              svn_boolean_t dry_run,
11674                              const apr_array_header_t *merge_options,
11675                              svn_client_ctx_t *ctx,
11676                              apr_pool_t *pool)
11677 {
11678   const char *target_abspath, *lock_abspath;
11679   conflict_report_t *conflict_report;
11680
11681   SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath,
11682                                       target_wcpath, ctx, pool));
11683
11684   if (!dry_run)
11685     SVN_WC__CALL_WITH_WRITE_LOCK(
11686       merge_reintegrate_locked(&conflict_report,
11687                                source_path_or_url, source_peg_revision,
11688                                target_abspath,
11689                                FALSE /*diff_ignore_ancestry*/,
11690                                dry_run, merge_options, ctx, pool, pool),
11691       ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
11692   else
11693     SVN_ERR(merge_reintegrate_locked(&conflict_report,
11694                                      source_path_or_url, source_peg_revision,
11695                                      target_abspath,
11696                                      FALSE /*diff_ignore_ancestry*/,
11697                                      dry_run, merge_options, ctx, pool, pool));
11698
11699   SVN_ERR(make_merge_conflict_error(conflict_report, pool));
11700   return SVN_NO_ERROR;
11701 }
11702
11703
11704 /* The body of svn_client_merge_peg5(), which see for details.
11705  *
11706  * IGNORE_MERGEINFO and DIFF_IGNORE_ANCESTRY are as in do_merge().
11707  */
11708 static svn_error_t *
11709 merge_peg_locked(conflict_report_t **conflict_report,
11710                  const char *source_path_or_url,
11711                  const svn_opt_revision_t *source_peg_revision,
11712                  const svn_rangelist_t *ranges_to_merge,
11713                  const char *target_abspath,
11714                  svn_depth_t depth,
11715                  svn_boolean_t ignore_mergeinfo,
11716                  svn_boolean_t diff_ignore_ancestry,
11717                  svn_boolean_t force_delete,
11718                  svn_boolean_t record_only,
11719                  svn_boolean_t dry_run,
11720                  svn_boolean_t allow_mixed_rev,
11721                  const apr_array_header_t *merge_options,
11722                  svn_client_ctx_t *ctx,
11723                  apr_pool_t *result_pool,
11724                  apr_pool_t *scratch_pool)
11725 {
11726   merge_target_t *target;
11727   svn_client__pathrev_t *source_loc;
11728   apr_array_header_t *merge_sources;
11729   svn_ra_session_t *ra_session;
11730   apr_pool_t *sesspool;
11731   svn_boolean_t use_sleep = FALSE;
11732   svn_error_t *err;
11733   svn_boolean_t same_repos;
11734
11735   SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
11736
11737   SVN_ERR(open_target_wc(&target, target_abspath,
11738                          allow_mixed_rev, TRUE, TRUE,
11739                          ctx, scratch_pool, scratch_pool));
11740
11741   /* Create a short lived session pool */
11742   sesspool = svn_pool_create(scratch_pool);
11743
11744   /* Open an RA session to our source URL, and determine its root URL. */
11745   SVN_ERR(svn_client__ra_session_from_path2(
11746             &ra_session, &source_loc,
11747             source_path_or_url, NULL, source_peg_revision, source_peg_revision,
11748             ctx, sesspool));
11749
11750   /* Normalize our merge sources. */
11751   SVN_ERR(normalize_merge_sources(&merge_sources, source_path_or_url,
11752                                   source_loc,
11753                                   ranges_to_merge, ra_session, ctx,
11754                                   scratch_pool, scratch_pool));
11755
11756   /* Check for same_repos. */
11757   same_repos = is_same_repos(&target->loc, source_loc, TRUE /* strict_urls */);
11758
11759   /* Do the real merge!  (We say with confidence that our merge
11760      sources are both ancestral and related.) */
11761   err = do_merge(NULL, NULL, conflict_report, &use_sleep,
11762                  merge_sources, target, ra_session,
11763                  TRUE /*sources_related*/, same_repos, ignore_mergeinfo,
11764                  diff_ignore_ancestry, force_delete, dry_run,
11765                  record_only, NULL, FALSE, FALSE, depth, merge_options,
11766                  ctx, result_pool, scratch_pool);
11767
11768   /* We're done with our RA session. */
11769   svn_pool_destroy(sesspool);
11770
11771   if (use_sleep)
11772     svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
11773
11774   SVN_ERR(err);
11775   return SVN_NO_ERROR;
11776 }
11777
11778 /* Details of an automatic merge. */
11779 typedef struct automatic_merge_t
11780 {
11781   svn_client__pathrev_t *yca, *base, *right, *target;
11782   svn_boolean_t is_reintegrate_like;
11783   svn_boolean_t allow_mixed_rev, allow_local_mods, allow_switched_subtrees;
11784 } automatic_merge_t;
11785
11786 static svn_error_t *
11787 client_find_automatic_merge(automatic_merge_t **merge_p,
11788                             const char *source_path_or_url,
11789                             const svn_opt_revision_t *source_revision,
11790                             const char *target_abspath,
11791                             svn_boolean_t allow_mixed_rev,
11792                             svn_boolean_t allow_local_mods,
11793                             svn_boolean_t allow_switched_subtrees,
11794                             svn_client_ctx_t *ctx,
11795                             apr_pool_t *result_pool,
11796                             apr_pool_t *scratch_pool);
11797
11798 static svn_error_t *
11799 do_automatic_merge_locked(conflict_report_t **conflict_report,
11800                           const automatic_merge_t *merge,
11801                           const char *target_abspath,
11802                           svn_depth_t depth,
11803                           svn_boolean_t diff_ignore_ancestry,
11804                           svn_boolean_t force_delete,
11805                           svn_boolean_t record_only,
11806                           svn_boolean_t dry_run,
11807                           const apr_array_header_t *merge_options,
11808                           svn_client_ctx_t *ctx,
11809                           apr_pool_t *result_pool,
11810                           apr_pool_t *scratch_pool);
11811
11812 svn_error_t *
11813 svn_client_merge_peg5(const char *source_path_or_url,
11814                       const apr_array_header_t *ranges_to_merge,
11815                       const svn_opt_revision_t *source_peg_revision,
11816                       const char *target_wcpath,
11817                       svn_depth_t depth,
11818                       svn_boolean_t ignore_mergeinfo,
11819                       svn_boolean_t diff_ignore_ancestry,
11820                       svn_boolean_t force_delete,
11821                       svn_boolean_t record_only,
11822                       svn_boolean_t dry_run,
11823                       svn_boolean_t allow_mixed_rev,
11824                       const apr_array_header_t *merge_options,
11825                       svn_client_ctx_t *ctx,
11826                       apr_pool_t *pool)
11827 {
11828   const char *target_abspath, *lock_abspath;
11829   conflict_report_t *conflict_report;
11830
11831   /* No ranges to merge?  No problem. */
11832   if (ranges_to_merge != NULL && ranges_to_merge->nelts == 0)
11833     return SVN_NO_ERROR;
11834
11835   SVN_ERR(get_target_and_lock_abspath(&target_abspath, &lock_abspath,
11836                                       target_wcpath, ctx, pool));
11837
11838   /* Do an automatic merge if no revision ranges are specified. */
11839   if (ranges_to_merge == NULL)
11840     {
11841       automatic_merge_t *merge;
11842
11843       if (ignore_mergeinfo)
11844         return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
11845                                 _("Cannot merge automatically while "
11846                                   "ignoring mergeinfo"));
11847
11848       /* Find the details of the merge needed. */
11849       SVN_ERR(client_find_automatic_merge(
11850                                     &merge,
11851                                     source_path_or_url, source_peg_revision,
11852                                     target_abspath,
11853                                     allow_mixed_rev,
11854                                     TRUE /*allow_local_mods*/,
11855                                     TRUE /*allow_switched_subtrees*/,
11856                                     ctx, pool, pool));
11857
11858       if (!dry_run)
11859         SVN_WC__CALL_WITH_WRITE_LOCK(
11860           do_automatic_merge_locked(&conflict_report,
11861                                     merge,
11862                                     target_abspath, depth,
11863                                     diff_ignore_ancestry,
11864                                     force_delete, record_only, dry_run,
11865                                     merge_options, ctx, pool, pool),
11866           ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
11867       else
11868         SVN_ERR(do_automatic_merge_locked(&conflict_report,
11869                                     merge,
11870                                     target_abspath, depth,
11871                                     diff_ignore_ancestry,
11872                                     force_delete, record_only, dry_run,
11873                                     merge_options, ctx, pool, pool));
11874     }
11875   else if (!dry_run)
11876     SVN_WC__CALL_WITH_WRITE_LOCK(
11877       merge_peg_locked(&conflict_report,
11878                        source_path_or_url, source_peg_revision,
11879                        ranges_to_merge,
11880                        target_abspath, depth, ignore_mergeinfo,
11881                        diff_ignore_ancestry,
11882                        force_delete, record_only, dry_run,
11883                        allow_mixed_rev, merge_options, ctx, pool, pool),
11884       ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
11885   else
11886     SVN_ERR(merge_peg_locked(&conflict_report,
11887                        source_path_or_url, source_peg_revision,
11888                        ranges_to_merge,
11889                        target_abspath, depth, ignore_mergeinfo,
11890                        diff_ignore_ancestry,
11891                        force_delete, record_only, dry_run,
11892                        allow_mixed_rev, merge_options, ctx, pool, pool));
11893
11894   SVN_ERR(make_merge_conflict_error(conflict_report, pool));
11895   return SVN_NO_ERROR;
11896 }
11897
11898
11899 /* The location-history of a branch.
11900  *
11901  * This structure holds the set of path-revisions occupied by a branch,
11902  * from an externally chosen 'tip' location back to its origin.  The
11903  * 'tip' location is the youngest location that we are considering on
11904  * the branch. */
11905 typedef struct branch_history_t
11906 {
11907   /* The tip location of the branch.  That is, the youngest location that's
11908    * in the repository and that we're considering.  If we're considering a
11909    * target branch right up to an uncommitted WC, then this is the WC base
11910    * (pristine) location. */
11911   svn_client__pathrev_t *tip;
11912   /* The location-segment history, as mergeinfo. */
11913   svn_mergeinfo_t history;
11914   /* Whether the location-segment history reached as far as (necessarily
11915      the root path in) revision 0 -- a fact that can't be represented as
11916      mergeinfo. */
11917   svn_boolean_t has_r0_history;
11918 } branch_history_t;
11919
11920 /* Return the location on BRANCH_HISTORY at revision REV, or NULL if none. */
11921 static svn_client__pathrev_t *
11922 location_on_branch_at_rev(const branch_history_t *branch_history,
11923                           svn_revnum_t rev,
11924                           apr_pool_t *result_pool,
11925                           apr_pool_t *scratch_pool)
11926 {
11927   apr_hash_index_t *hi;
11928
11929   for (hi = apr_hash_first(scratch_pool, branch_history->history); hi;
11930        hi = apr_hash_next(hi))
11931     {
11932       const char *fspath = svn__apr_hash_index_key(hi);
11933       svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
11934       int i;
11935
11936       for (i = 0; i < rangelist->nelts; i++)
11937         {
11938           svn_merge_range_t *r = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
11939           if (r->start < rev && rev <= r->end)
11940             {
11941               return svn_client__pathrev_create_with_relpath(
11942                        branch_history->tip->repos_root_url,
11943                        branch_history->tip->repos_uuid,
11944                        rev, fspath + 1, result_pool);
11945             }
11946         }
11947     }
11948   return NULL;
11949 }
11950
11951 /* */
11952 typedef struct source_and_target_t
11953 {
11954   svn_client__pathrev_t *source;
11955   svn_ra_session_t *source_ra_session;
11956   branch_history_t source_branch;
11957
11958   merge_target_t *target;
11959   svn_ra_session_t *target_ra_session;
11960   branch_history_t target_branch;
11961
11962   /* Repos location of the youngest common ancestor of SOURCE and TARGET. */
11963   svn_client__pathrev_t *yca;
11964 } source_and_target_t;
11965
11966 /* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the
11967  * revision range OLDEST_REV to YOUNGEST_REV (inclusive).
11968  *
11969  * If the intersection is empty, the result will be a branch history object
11970  * containing an empty (not null) history.
11971  *
11972  * ### The 'tip' of the result is currently unchanged.
11973  */
11974 static svn_error_t *
11975 branch_history_intersect_range(branch_history_t **intersection_p,
11976                                const branch_history_t *branch_history,
11977                                svn_revnum_t oldest_rev,
11978                                svn_revnum_t youngest_rev,
11979                                apr_pool_t *result_pool,
11980                                apr_pool_t *scratch_pool)
11981 {
11982   branch_history_t *result = apr_palloc(result_pool, sizeof(*result));
11983
11984   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev));
11985   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
11986   SVN_ERR_ASSERT(oldest_rev >= 1);
11987   /* Allow a just-empty range (oldest = youngest + 1) but not an
11988    * arbitrary reverse range (such as oldest = youngest + 2). */
11989   SVN_ERR_ASSERT(oldest_rev <= youngest_rev + 1);
11990
11991   if (oldest_rev <= youngest_rev)
11992     {
11993       SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
11994                 &result->history, branch_history->history,
11995                 youngest_rev, oldest_rev - 1, TRUE /* include_range */,
11996                 result_pool, scratch_pool));
11997       result->history = svn_mergeinfo_dup(result->history, result_pool);
11998     }
11999   else
12000     {
12001       result->history = apr_hash_make(result_pool);
12002     }
12003   result->has_r0_history = FALSE;
12004
12005   /* ### TODO: Set RESULT->tip to the tip of the intersection. */
12006   result->tip = svn_client__pathrev_dup(branch_history->tip, result_pool);
12007
12008   *intersection_p = result;
12009   return SVN_NO_ERROR;
12010 }
12011
12012 /* Set *OLDEST_P and *YOUNGEST_P to the oldest and youngest locations
12013  * (inclusive) along BRANCH.  OLDEST_P and/or YOUNGEST_P may be NULL if not
12014  * wanted.
12015  */
12016 static svn_error_t *
12017 branch_history_get_endpoints(svn_client__pathrev_t **oldest_p,
12018                              svn_client__pathrev_t **youngest_p,
12019                              const branch_history_t *branch,
12020                              apr_pool_t *result_pool,
12021                              apr_pool_t *scratch_pool)
12022 {
12023   svn_revnum_t youngest_rev, oldest_rev;
12024
12025   SVN_ERR(svn_mergeinfo__get_range_endpoints(
12026             &youngest_rev, &oldest_rev,
12027             branch->history, scratch_pool));
12028   if (oldest_p)
12029     *oldest_p = location_on_branch_at_rev(
12030                   branch, oldest_rev + 1, result_pool, scratch_pool);
12031   if (youngest_p)
12032     *youngest_p = location_on_branch_at_rev(
12033                     branch, youngest_rev, result_pool, scratch_pool);
12034   return SVN_NO_ERROR;
12035 }
12036
12037 /* Implements the svn_log_entry_receiver_t interface.
12038
12039   Set *BATON to LOG_ENTRY->revision and return SVN_ERR_CEASE_INVOCATION. */
12040 static svn_error_t *
12041 operative_rev_receiver(void *baton,
12042                        svn_log_entry_t *log_entry,
12043                        apr_pool_t *pool)
12044 {
12045   svn_revnum_t *operative_rev = baton;
12046
12047   *operative_rev = log_entry->revision;
12048
12049   /* We've found the youngest merged or oldest eligible revision, so
12050      we're done...
12051
12052      ...but wait, shouldn't we care if LOG_ENTRY->NON_INHERITABLE is
12053      true?  Because if it is, then LOG_ENTRY->REVISION is only
12054      partially merged/elgibile!  And our only caller,
12055      find_last_merged_location (via short_circuit_mergeinfo_log) is
12056      interested in *fully* merged revisions.  That's all true, but if
12057      find_last_merged_location() finds the youngest merged revision it
12058      will also check for the oldest eligible revision.  So in the case
12059      the youngest merged rev is non-inheritable, the *same* non-inheritable
12060      rev will be found as the oldest eligible rev -- and
12061      find_last_merged_location() handles that situation. */
12062   return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
12063 }
12064
12065 /* Wrapper around svn_client__mergeinfo_log. All arguments are as per
12066    that private API.  The discover_changed_paths, depth, and revprops args to
12067    svn_client__mergeinfo_log are always TRUE, svn_depth_infinity_t,
12068    and empty array respectively.
12069
12070    If RECEIVER raises a SVN_ERR_CEASE_INVOCATION error, but still sets
12071    *REVISION to a valid revnum, then clear the error.  Otherwise return
12072    any error. */
12073 static svn_error_t*
12074 short_circuit_mergeinfo_log(svn_mergeinfo_catalog_t *target_mergeinfo_cat,
12075                             svn_boolean_t finding_merged,
12076                             const char *target_path_or_url,
12077                             const svn_opt_revision_t *target_peg_revision,
12078                             const char *source_path_or_url,
12079                             const svn_opt_revision_t *source_peg_revision,
12080                             const svn_opt_revision_t *source_start_revision,
12081                             const svn_opt_revision_t *source_end_revision,
12082                             svn_log_entry_receiver_t receiver,
12083                             svn_revnum_t *revision,
12084                             svn_client_ctx_t *ctx,
12085                             svn_ra_session_t *ra_session,
12086                             apr_pool_t *result_pool,
12087                             apr_pool_t *scratch_pool)
12088 {
12089   apr_array_header_t *revprops;
12090   svn_error_t *err;
12091   const char *session_url;
12092
12093   SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool));
12094
12095   revprops = apr_array_make(scratch_pool, 0, sizeof(const char *));
12096   err = svn_client__mergeinfo_log(finding_merged,
12097                                   target_path_or_url,
12098                                   target_peg_revision,
12099                                   target_mergeinfo_cat,
12100                                   source_path_or_url,
12101                                   source_peg_revision,
12102                                   source_start_revision,
12103                                   source_end_revision,
12104                                   receiver, revision,
12105                                   TRUE, svn_depth_infinity,
12106                                   revprops, ctx, ra_session,
12107                                   result_pool, scratch_pool);
12108
12109   err = svn_error_compose_create(
12110                   err,
12111                   svn_ra_reparent(ra_session, session_url, scratch_pool));
12112
12113   if (err)
12114     {
12115       /* We expect RECEIVER to short-circuit the (potentially expensive) log
12116          by raising an SVN_ERR_CEASE_INVOCATION -- see operative_rev_receiver.
12117          So we can ignore that error, but only as long as we actually found a
12118          valid revision. */
12119       if (SVN_IS_VALID_REVNUM(*revision)
12120           && err->apr_err == SVN_ERR_CEASE_INVOCATION)
12121         {
12122           svn_error_clear(err);
12123           err = NULL;
12124         }
12125       else
12126         {
12127           return svn_error_trace(err);
12128         }
12129     }
12130   return SVN_NO_ERROR;
12131 }
12132
12133 /* Set *BASE_P to the last location on SOURCE_BRANCH such that all changes
12134  * on SOURCE_BRANCH after YCA up to and including *BASE_P have already
12135  * been fully merged into TARGET.
12136  *
12137  *               *BASE_P       TIP
12138  *          o-------o-----------o--- SOURCE_BRANCH
12139  *         /         \
12140  *   -----o     prev. \
12141  *     YCA \    merges \
12142  *          o-----------o----------- TARGET branch
12143  *
12144  * In terms of mergeinfo:
12145  *
12146  *     Source     a--...                     o=change, -=no-op revision
12147  *       branch  /   \
12148  *     YCA -->  o     a---o---o---o---o---   d=delete, a=add-as-a-copy
12149  *
12150  *     Eligible -.eee.eeeeeeeeeeeeeeeeeeee   .=not a source branch location
12151  *
12152  *     Tgt-mi   -.mmm.mm-mm-------m-------   m=merged to root of TARGET or
12153  *                                           subtree of TARGET with no
12154  *                                           operative changes outside of that
12155  *                                           subtree, -=not merged
12156  *
12157  *     Eligible -.---.--e--eeeeeee-eeeeeee
12158  *
12159  *     Next     --------^-----------------   BASE is just before here.
12160  *
12161  *             /         \
12162  *       -----o     prev. \
12163  *         YCA \    merges \
12164  *              o-----------o-------------
12165  *
12166  * If no revisions from SOURCE_BRANCH have been completely merged to TARGET,
12167  * then set *BASE_P to the YCA.
12168  */
12169 static svn_error_t *
12170 find_last_merged_location(svn_client__pathrev_t **base_p,
12171                           svn_client__pathrev_t *yca,
12172                           const branch_history_t *source_branch,
12173                           svn_client__pathrev_t *target,
12174                           svn_client_ctx_t *ctx,
12175                           svn_ra_session_t *ra_session,
12176                           apr_pool_t *result_pool,
12177                           apr_pool_t *scratch_pool)
12178 {
12179   svn_opt_revision_t source_peg_rev, source_start_rev, source_end_rev,
12180     target_opt_rev;
12181   svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM;
12182   svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL;
12183
12184   source_peg_rev.kind = svn_opt_revision_number;
12185   source_peg_rev.value.number = source_branch->tip->rev;
12186   source_start_rev.kind = svn_opt_revision_number;
12187   source_start_rev.value.number = yca->rev;
12188   source_end_rev.kind = svn_opt_revision_number;
12189   source_end_rev.value.number = source_branch->tip->rev;
12190   target_opt_rev.kind = svn_opt_revision_number;
12191   target_opt_rev.value.number = target->rev;
12192
12193   /* Find the youngest revision fully merged from SOURCE_BRANCH to TARGET,
12194      if such a revision exists. */
12195   SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
12196                                       TRUE, /* Find merged */
12197                                       target->url, &target_opt_rev,
12198                                       source_branch->tip->url,
12199                                       &source_peg_rev,
12200                                       &source_end_rev, &source_start_rev,
12201                                       operative_rev_receiver,
12202                                       &youngest_merged_rev,
12203                                       ctx, ra_session,
12204                                       result_pool, scratch_pool));
12205
12206   if (!SVN_IS_VALID_REVNUM(youngest_merged_rev))
12207     {
12208       /* No revisions have been completely merged from SOURCE_BRANCH to
12209          TARGET so the base for the next merge is the YCA. */
12210       *base_p = yca;
12211     }
12212   else
12213     {
12214       /* One or more revisions have already been completely merged from
12215          SOURCE_BRANCH to TARGET, now find the oldest revision, older
12216          than the youngest merged revision, which is still eligible to
12217          be merged, if such exists. */
12218       branch_history_t *contiguous_source;
12219       svn_revnum_t base_rev;
12220       svn_revnum_t oldest_eligible_rev = SVN_INVALID_REVNUM;
12221
12222       /* If the only revisions eligible are younger than the youngest merged
12223          revision we can simply assume that the youngest eligible revision
12224          is the youngest merged revision.  Obviously this may not be true!
12225          The revisions between the youngest merged revision and the tip of
12226          the branch may have several inoperative revisions -- they may *all*
12227          be inoperative revisions!  But for the purpose of this function
12228          (i.e. finding the youngest revision after the YCA where all revs have
12229          been merged) that doesn't matter. */
12230       source_end_rev.value.number = youngest_merged_rev;
12231       SVN_ERR(short_circuit_mergeinfo_log(&target_mergeinfo_cat,
12232                                           FALSE, /* Find eligible */
12233                                           target->url, &target_opt_rev,
12234                                           source_branch->tip->url,
12235                                           &source_peg_rev,
12236                                           &source_start_rev, &source_end_rev,
12237                                           operative_rev_receiver,
12238                                           &oldest_eligible_rev,
12239                                           ctx, ra_session,
12240                                           scratch_pool, scratch_pool));
12241
12242       /* If there are revisions eligible for merging, use the oldest one
12243          to calculate the base.  Otherwise there are no operative revisions
12244          to merge and we can simple set the base to the youngest revision
12245          already merged. */
12246       if (SVN_IS_VALID_REVNUM(oldest_eligible_rev))
12247         base_rev = oldest_eligible_rev - 1;
12248       else
12249         base_rev = youngest_merged_rev;
12250
12251       /* Find the branch location just before the oldest eligible rev.
12252          (We can't just use the base revs calculated above because the branch
12253          might have a gap there.) */
12254       SVN_ERR(branch_history_intersect_range(&contiguous_source,
12255                                              source_branch, yca->rev,
12256                                              base_rev,
12257                                              scratch_pool, scratch_pool));
12258       SVN_ERR(branch_history_get_endpoints(NULL, base_p, contiguous_source,
12259                                            result_pool, scratch_pool));
12260     }
12261
12262   return SVN_NO_ERROR;
12263 }
12264
12265 /* Find a merge base location on the target branch, like in a sync
12266  * merge.
12267  *
12268  *                BASE          S_T->source
12269  *          o-------o-----------o---
12270  *         /         \           \
12271  *   -----o     prev. \           \  this
12272  *     YCA \    merge  \           \ merge
12273  *          o-----------o-----------o
12274  *                                  S_T->target
12275  *
12276  * Set *BASE_P to BASE, the youngest location in the history of S_T->source
12277  * (at or after the YCA) at which all revisions up to BASE are effectively
12278  * merged into S_T->target.
12279  *
12280  * If no locations on the history of S_T->source are effectively merged to
12281  * S_T->target, set *BASE_P to the YCA.
12282  */
12283 static svn_error_t *
12284 find_base_on_source(svn_client__pathrev_t **base_p,
12285                     source_and_target_t *s_t,
12286                     svn_client_ctx_t *ctx,
12287                     apr_pool_t *result_pool,
12288                     apr_pool_t *scratch_pool)
12289 {
12290   SVN_ERR(find_last_merged_location(base_p,
12291                                     s_t->yca,
12292                                     &s_t->source_branch,
12293                                     s_t->target_branch.tip,
12294                                     ctx,
12295                                     s_t->source_ra_session,
12296                                     result_pool, scratch_pool));
12297   return SVN_NO_ERROR;
12298 }
12299
12300 /* Find a merge base location on the target branch, like in a reintegrate
12301  * merge.
12302  *
12303  *                              S_T->source
12304  *          o-----------o-------o---
12305  *         /    prev.  /         \
12306  *   -----o     merge /           \  this
12307  *     YCA \         /             \ merge
12308  *          o-------o---------------o
12309  *                BASE              S_T->target
12310  *
12311  * Set *BASE_P to BASE, the youngest location in the history of S_T->target
12312  * (at or after the YCA) at which all revisions up to BASE are effectively
12313  * merged into S_T->source.
12314  *
12315  * If no locations on the history of S_T->target are effectively merged to
12316  * S_T->source, set *BASE_P to the YCA.
12317  */
12318 static svn_error_t *
12319 find_base_on_target(svn_client__pathrev_t **base_p,
12320                     source_and_target_t *s_t,
12321                     svn_client_ctx_t *ctx,
12322                     apr_pool_t *result_pool,
12323                     apr_pool_t *scratch_pool)
12324 {
12325   SVN_ERR(find_last_merged_location(base_p,
12326                                     s_t->yca,
12327                                     &s_t->target_branch,
12328                                     s_t->source,
12329                                     ctx,
12330                                     s_t->target_ra_session,
12331                                     result_pool, scratch_pool));
12332
12333   return SVN_NO_ERROR;
12334 }
12335
12336 /* The body of client_find_automatic_merge(), which see.
12337  */
12338 static svn_error_t *
12339 find_automatic_merge(svn_client__pathrev_t **base_p,
12340                      svn_boolean_t *is_reintegrate_like,
12341                      source_and_target_t *s_t,
12342                      svn_client_ctx_t *ctx,
12343                      apr_pool_t *result_pool,
12344                      apr_pool_t *scratch_pool)
12345 {
12346   svn_client__pathrev_t *base_on_source, *base_on_target;
12347
12348   /* Get the location-history of each branch. */
12349   s_t->source_branch.tip = s_t->source;
12350   SVN_ERR(svn_client__get_history_as_mergeinfo(
12351             &s_t->source_branch.history, &s_t->source_branch.has_r0_history,
12352             s_t->source, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
12353             s_t->source_ra_session, ctx, scratch_pool));
12354   s_t->target_branch.tip = &s_t->target->loc;
12355   SVN_ERR(svn_client__get_history_as_mergeinfo(
12356             &s_t->target_branch.history, &s_t->target_branch.has_r0_history,
12357             &s_t->target->loc, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
12358             s_t->target_ra_session, ctx, scratch_pool));
12359
12360   SVN_ERR(svn_client__calc_youngest_common_ancestor(
12361             &s_t->yca, s_t->source, s_t->source_branch.history,
12362             s_t->source_branch.has_r0_history,
12363             &s_t->target->loc, s_t->target_branch.history,
12364             s_t->target_branch.has_r0_history,
12365             result_pool, scratch_pool));
12366
12367   if (! s_t->yca)
12368     return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
12369                              _("'%s@%ld' must be ancestrally related to "
12370                                "'%s@%ld'"),
12371                              s_t->source->url, s_t->source->rev,
12372                              s_t->target->loc.url, s_t->target->loc.rev);
12373
12374   /* Find the latest revision of A synced to B and the latest
12375    * revision of B synced to A.
12376    *
12377    *   base_on_source = youngest_complete_synced_point(source, target)
12378    *   base_on_target = youngest_complete_synced_point(target, source)
12379    */
12380   SVN_ERR(find_base_on_source(&base_on_source, s_t,
12381                               ctx, scratch_pool, scratch_pool));
12382   SVN_ERR(find_base_on_target(&base_on_target, s_t,
12383                               ctx, scratch_pool, scratch_pool));
12384
12385   /* Choose a base. */
12386   if (base_on_source->rev >= base_on_target->rev)
12387     {
12388       *base_p = base_on_source;
12389       *is_reintegrate_like = FALSE;
12390     }
12391   else
12392     {
12393       *base_p = base_on_target;
12394       *is_reintegrate_like = TRUE;
12395     }
12396
12397   return SVN_NO_ERROR;
12398 }
12399
12400 /** Find out what kind of automatic merge would be needed, when the target
12401  * is only known as a repository location rather than a WC.
12402  *
12403  * Like find_automatic_merge() except that the target is
12404  * specified by @a target_path_or_url at @a target_revision, which must
12405  * refer to a repository location, instead of by a WC path argument.
12406  */
12407 static svn_error_t *
12408 find_automatic_merge_no_wc(automatic_merge_t **merge_p,
12409                            const char *source_path_or_url,
12410                            const svn_opt_revision_t *source_revision,
12411                            const char *target_path_or_url,
12412                            const svn_opt_revision_t *target_revision,
12413                            svn_client_ctx_t *ctx,
12414                            apr_pool_t *result_pool,
12415                            apr_pool_t *scratch_pool)
12416 {
12417   source_and_target_t *s_t = apr_palloc(scratch_pool, sizeof(*s_t));
12418   svn_client__pathrev_t *target_loc;
12419   automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
12420
12421   /* Source */
12422   SVN_ERR(svn_client__ra_session_from_path2(
12423             &s_t->source_ra_session, &s_t->source,
12424             source_path_or_url, NULL, source_revision, source_revision,
12425             ctx, result_pool));
12426
12427   /* Target */
12428   SVN_ERR(svn_client__ra_session_from_path2(
12429             &s_t->target_ra_session, &target_loc,
12430             target_path_or_url, NULL, target_revision, target_revision,
12431             ctx, result_pool));
12432   s_t->target = apr_palloc(scratch_pool, sizeof(*s_t->target));
12433   s_t->target->abspath = NULL;  /* indicate the target is not a WC */
12434   s_t->target->loc = *target_loc;
12435
12436   SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t,
12437                                ctx, result_pool, scratch_pool));
12438
12439   merge->right = s_t->source;
12440   merge->target = &s_t->target->loc;
12441   merge->yca = s_t->yca;
12442   *merge_p = merge;
12443
12444   return SVN_NO_ERROR;
12445 }
12446
12447 /* Find the information needed to merge all unmerged changes from a source
12448  * branch into a target branch.
12449  *
12450  * Set @a *merge_p to the information needed to merge all unmerged changes
12451  * (up to @a source_revision) from the source branch @a source_path_or_url
12452  * at @a source_revision into the target WC at @a target_abspath.
12453  *
12454  * The flags @a allow_mixed_rev, @a allow_local_mods and
12455  * @a allow_switched_subtrees enable merging into a WC that is in any or all
12456  * of the states described by their names, but only if this function decides
12457  * that the merge will be in the same direction as the last automatic merge.
12458  * If, on the other hand, the last automatic merge was in the opposite
12459  * direction, then such states of the WC are not allowed regardless
12460  * of these flags.  This function merely records these flags in the
12461  * @a *merge_p structure; do_automatic_merge_locked() checks the WC
12462  * state for compliance.
12463  *
12464  * Allocate the @a *merge_p structure in @a result_pool.
12465  */
12466 static svn_error_t *
12467 client_find_automatic_merge(automatic_merge_t **merge_p,
12468                             const char *source_path_or_url,
12469                             const svn_opt_revision_t *source_revision,
12470                             const char *target_abspath,
12471                             svn_boolean_t allow_mixed_rev,
12472                             svn_boolean_t allow_local_mods,
12473                             svn_boolean_t allow_switched_subtrees,
12474                             svn_client_ctx_t *ctx,
12475                             apr_pool_t *result_pool,
12476                             apr_pool_t *scratch_pool)
12477 {
12478   source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
12479   automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
12480
12481   /* "Open" the target WC.  Check the target WC for mixed-rev, local mods and
12482    * switched subtrees yet to faster exit and notify user before contacting
12483    * with server.  After we find out what kind of merge is required, then if a
12484    * reintegrate-like merge is required we'll do the stricter checks, in
12485    * do_automatic_merge_locked(). */
12486   SVN_ERR(open_target_wc(&s_t->target, target_abspath,
12487                          allow_mixed_rev,
12488                          allow_local_mods,
12489                          allow_switched_subtrees,
12490                          ctx, result_pool, scratch_pool));
12491
12492   /* Open RA sessions to the source and target trees. */
12493   SVN_ERR(svn_client_open_ra_session2(&s_t->target_ra_session,
12494                                       s_t->target->loc.url,
12495                                       s_t->target->abspath,
12496                                       ctx, result_pool, scratch_pool));
12497   /* ### check for null URL (i.e. added path) here, like in reintegrate? */
12498   SVN_ERR(svn_client__ra_session_from_path2(
12499             &s_t->source_ra_session, &s_t->source,
12500             source_path_or_url, NULL, source_revision, source_revision,
12501             ctx, result_pool));
12502
12503   /* Check source is in same repos as target. */
12504   SVN_ERR(check_same_repos(s_t->source, source_path_or_url,
12505                            &s_t->target->loc, target_abspath,
12506                            TRUE /* strict_urls */, scratch_pool));
12507
12508   SVN_ERR(find_automatic_merge(&merge->base, &merge->is_reintegrate_like, s_t,
12509                                ctx, result_pool, scratch_pool));
12510   merge->yca = s_t->yca;
12511   merge->right = s_t->source;
12512   merge->allow_mixed_rev = allow_mixed_rev;
12513   merge->allow_local_mods = allow_local_mods;
12514   merge->allow_switched_subtrees = allow_switched_subtrees;
12515
12516   *merge_p = merge;
12517
12518   /* TODO: Close the source and target sessions here? */
12519
12520   return SVN_NO_ERROR;
12521 }
12522
12523 /* Perform an automatic merge, given the information in MERGE which
12524  * must have come from calling client_find_automatic_merge().
12525  *
12526  * Four locations are inputs: YCA, BASE, RIGHT, TARGET, as shown
12527  * depending on whether the base is on the source branch or the target
12528  * branch of this merge.
12529  *
12530  *                            RIGHT     (is_reintegrate_like)
12531  *          o-----------o-------o---
12532  *         /    prev.  /         \
12533  *   -----o     merge /           \  this
12534  *     YCA \         /             \ merge
12535  *          o-------o---------------o
12536  *                BASE            TARGET
12537  *
12538  * or
12539  *
12540  *                BASE        RIGHT      (! is_reintegrate_like)
12541  *          o-------o-----------o---
12542  *         /         \           \
12543  *   -----o     prev. \           \  this
12544  *     YCA \    merge  \           \ merge
12545  *          o-----------o-----------o
12546  *                                TARGET
12547  *
12548  * ### TODO: The reintegrate-like code path does not yet
12549  * eliminate already-cherry-picked revisions from the source.
12550  */
12551 static svn_error_t *
12552 do_automatic_merge_locked(conflict_report_t **conflict_report,
12553                           const automatic_merge_t *merge,
12554                           const char *target_abspath,
12555                           svn_depth_t depth,
12556                           svn_boolean_t diff_ignore_ancestry,
12557                           svn_boolean_t force_delete,
12558                           svn_boolean_t record_only,
12559                           svn_boolean_t dry_run,
12560                           const apr_array_header_t *merge_options,
12561                           svn_client_ctx_t *ctx,
12562                           apr_pool_t *result_pool,
12563                           apr_pool_t *scratch_pool)
12564 {
12565   merge_target_t *target;
12566   svn_boolean_t reintegrate_like = merge->is_reintegrate_like;
12567   svn_boolean_t use_sleep = FALSE;
12568   svn_error_t *err;
12569
12570   SVN_ERR(open_target_wc(&target, target_abspath,
12571                          merge->allow_mixed_rev && ! reintegrate_like,
12572                          merge->allow_local_mods && ! reintegrate_like,
12573                          merge->allow_switched_subtrees && ! reintegrate_like,
12574                          ctx, scratch_pool, scratch_pool));
12575
12576   if (reintegrate_like)
12577     {
12578       merge_source_t source;
12579       svn_ra_session_t *base_ra_session = NULL;
12580       svn_ra_session_t *right_ra_session = NULL;
12581       svn_ra_session_t *target_ra_session = NULL;
12582
12583       if (record_only)
12584         return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
12585                                 _("The required merge is reintegrate-like, "
12586                                   "and the record-only option "
12587                                   "cannot be used with this kind of merge"));
12588
12589       if (depth != svn_depth_unknown)
12590         return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
12591                                 _("The required merge is reintegrate-like, "
12592                                   "and the depth option "
12593                                   "cannot be used with this kind of merge"));
12594
12595       if (force_delete)
12596         return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
12597                                 _("The required merge is reintegrate-like, "
12598                                   "and the force_delete option "
12599                                   "cannot be used with this kind of merge"));
12600
12601       SVN_ERR(ensure_ra_session_url(&base_ra_session, merge->base->url,
12602                                     target->abspath, ctx, scratch_pool));
12603       SVN_ERR(ensure_ra_session_url(&right_ra_session, merge->right->url,
12604                                     target->abspath, ctx, scratch_pool));
12605       SVN_ERR(ensure_ra_session_url(&target_ra_session, target->loc.url,
12606                                     target->abspath, ctx, scratch_pool));
12607
12608       /* Check for and reject any abnormalities -- such as revisions that
12609        * have not yet been merged in the opposite direction -- that a
12610        * 'reintegrate' merge would have rejected. */
12611       {
12612         merge_source_t *source2;
12613
12614         SVN_ERR(find_reintegrate_merge(&source2, NULL,
12615                                        right_ra_session, merge->right,
12616                                        target_ra_session, target,
12617                                        ctx, scratch_pool, scratch_pool));
12618       }
12619
12620       source.loc1 = merge->base;
12621       source.loc2 = merge->right;
12622       source.ancestral = ! merge->is_reintegrate_like;
12623
12624       err = merge_cousins_and_supplement_mergeinfo(conflict_report,
12625                                                    &use_sleep,
12626                                                    target,
12627                                                    base_ra_session,
12628                                                    right_ra_session,
12629                                                    &source, merge->yca,
12630                                                    TRUE /* same_repos */,
12631                                                    depth,
12632                                                    FALSE /*diff_ignore_ancestry*/,
12633                                                    force_delete, record_only,
12634                                                    dry_run,
12635                                                    merge_options,
12636                                                    ctx,
12637                                                    result_pool, scratch_pool);
12638     }
12639   else /* ! merge->is_reintegrate_like */
12640     {
12641       /* Ignoring the base that we found, we pass the YCA instead and let
12642          do_merge() work out which subtrees need which revision ranges to
12643          be merged.  This enables do_merge() to fill in revision-range
12644          gaps that are older than the base that we calculated (which is
12645          for the root path of the merge).
12646
12647          An improvement would be to change find_automatic_merge() to
12648          find the base for each sutree, and then here use the oldest base
12649          among all subtrees. */
12650       apr_array_header_t *merge_sources;
12651       svn_ra_session_t *ra_session = NULL;
12652
12653       /* Normalize our merge sources, do_merge() requires this.  See the
12654          'MERGEINFO MERGE SOURCE NORMALIZATION' global comment. */
12655       SVN_ERR(ensure_ra_session_url(&ra_session, merge->right->url,
12656                                     target->abspath, ctx, scratch_pool));
12657       SVN_ERR(normalize_merge_sources_internal(
12658         &merge_sources, merge->right,
12659         svn_rangelist__initialize(merge->yca->rev, merge->right->rev, TRUE,
12660                                   scratch_pool),
12661         ra_session, ctx, scratch_pool, scratch_pool));
12662
12663       err = do_merge(NULL, NULL, conflict_report, &use_sleep,
12664                      merge_sources, target, ra_session,
12665                      TRUE /*related*/, TRUE /*same_repos*/,
12666                      FALSE /*ignore_mergeinfo*/, diff_ignore_ancestry,
12667                      force_delete, dry_run,
12668                      record_only, NULL, FALSE, FALSE, depth, merge_options,
12669                      ctx, result_pool, scratch_pool);
12670     }
12671
12672   if (use_sleep)
12673     svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
12674
12675   SVN_ERR(err);
12676
12677   return SVN_NO_ERROR;
12678 }
12679
12680 svn_error_t *
12681 svn_client_get_merging_summary(svn_boolean_t *needs_reintegration,
12682                                const char **yca_url, svn_revnum_t *yca_rev,
12683                                const char **base_url, svn_revnum_t *base_rev,
12684                                const char **right_url, svn_revnum_t *right_rev,
12685                                const char **target_url, svn_revnum_t *target_rev,
12686                                const char **repos_root_url,
12687                                const char *source_path_or_url,
12688                                const svn_opt_revision_t *source_revision,
12689                                const char *target_path_or_url,
12690                                const svn_opt_revision_t *target_revision,
12691                                svn_client_ctx_t *ctx,
12692                                apr_pool_t *result_pool,
12693                                apr_pool_t *scratch_pool)
12694 {
12695   svn_boolean_t target_is_wc;
12696   automatic_merge_t *merge;
12697
12698   target_is_wc = (! svn_path_is_url(target_path_or_url))
12699                  && (target_revision->kind == svn_opt_revision_unspecified
12700                      || target_revision->kind == svn_opt_revision_working);
12701   if (target_is_wc)
12702     SVN_ERR(client_find_automatic_merge(
12703               &merge,
12704               source_path_or_url, source_revision,
12705               target_path_or_url,
12706               TRUE, TRUE, TRUE,  /* allow_* */
12707               ctx, scratch_pool, scratch_pool));
12708   else
12709     SVN_ERR(find_automatic_merge_no_wc(
12710               &merge,
12711               source_path_or_url, source_revision,
12712               target_path_or_url, target_revision,
12713               ctx, scratch_pool, scratch_pool));
12714
12715   if (needs_reintegration)
12716     *needs_reintegration = merge->is_reintegrate_like;
12717   if (yca_url)
12718     *yca_url = apr_pstrdup(result_pool, merge->yca->url);
12719   if (yca_rev)
12720     *yca_rev = merge->yca->rev;
12721   if (base_url)
12722     *base_url = apr_pstrdup(result_pool, merge->base->url);
12723   if (base_rev)
12724     *base_rev = merge->base->rev;
12725   if (right_url)
12726     *right_url = apr_pstrdup(result_pool, merge->right->url);
12727   if (right_rev)
12728     *right_rev = merge->right->rev;
12729   if (target_url)
12730     *target_url = apr_pstrdup(result_pool, merge->target->url);
12731   if (target_rev)
12732     *target_rev = merge->target->rev;
12733   if (repos_root_url)
12734     *repos_root_url = apr_pstrdup(result_pool, merge->yca->repos_root_url);
12735
12736   return SVN_NO_ERROR;
12737 }