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