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