You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2010/03/16 19:03:41 UTC
svn commit: r923910 [4/9] - in /subversion/branches/1.6.x-issue3432: ./
build/ build/ac-macros/ build/generator/ contrib/cgi/
contrib/client-side/emacs/ contrib/client-side/svn_load_dirs/
contrib/hook-scripts/ contrib/server-side/ doc/user/ notes/ pack...
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/mergeinfo.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/mergeinfo.c Tue Mar 16 18:03:37 2010
@@ -45,7 +45,8 @@
http://c2.com/cgi-bin/wiki/fullSearch?TestIfDateRangesOverlap
*/
static svn_boolean_t
-combine_ranges(svn_merge_range_t **output, svn_merge_range_t *in1,
+combine_ranges(svn_merge_range_t *output,
+ svn_merge_range_t *in1,
svn_merge_range_t *in2,
svn_boolean_t consider_inheritance)
{
@@ -55,9 +56,9 @@ combine_ranges(svn_merge_range_t **outpu
|| (consider_inheritance
&& (in1->inheritable == in2->inheritable)))
{
- (*output)->start = MIN(in1->start, in2->start);
- (*output)->end = MAX(in1->end, in2->end);
- (*output)->inheritable = (in1->inheritable || in2->inheritable);
+ output->start = MIN(in1->start, in2->start);
+ output->end = MAX(in1->end, in2->end);
+ output->inheritable = (in1->inheritable || in2->inheritable);
return TRUE;
}
}
@@ -66,8 +67,10 @@ combine_ranges(svn_merge_range_t **outpu
/* pathname -> PATHNAME */
static svn_error_t *
-parse_pathname(const char **input, const char *end,
- svn_stringbuf_t **pathname, apr_pool_t *pool)
+parse_pathname(const char **input,
+ const char *end,
+ svn_stringbuf_t **pathname,
+ apr_pool_t *pool)
{
const char *curr = *input;
const char *last_colon = NULL;
@@ -89,257 +92,341 @@ parse_pathname(const char **input, const
return svn_error_create(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
_("No pathname preceding ':'"));
- *pathname = svn_stringbuf_ncreate(*input, last_colon - *input, pool);
+ /* Tolerate relative repository paths, but convert them to absolute. */
+ if (**input == '/')
+ {
+ *pathname = svn_stringbuf_ncreate(*input, last_colon - *input, pool);
+ }
+ else
+ {
+ const char *repos_rel_path = apr_pstrndup(pool, *input,
+ last_colon - *input);
+ *pathname = svn_stringbuf_createf(pool, "/%s", repos_rel_path);
+ }
+
*input = last_colon;
return SVN_NO_ERROR;
}
+/* Ways in which two svn_merge_range_t can intersect, if at all. */
+typedef enum
+{
+ /* Ranges don't intersect. */
+ svn__no_intersection,
+
+ /* Ranges are equal. */
+ svn__equal_intersection,
+
+ /* Ranges adjoin but don't overlap. */
+ svn__adjoining_intersection,
+
+ /* Ranges overalp but neither is a subset of the other. */
+ svn__overlapping_intersection,
+
+ /* One range is a proper subset of the other. */
+ svn__proper_subset_intersection
+} intersection_type_t;
+
+/* Given ranges R1 and R2, both of which must be forward merge ranges,
+ set *INTERSECTION_TYPE to describe how the ranges intersect, if they
+ do at all. The inheritance type of the ranges is not considered. */
+static svn_error_t *
+get_type_of_intersection(svn_merge_range_t *r1,
+ svn_merge_range_t *r2,
+ intersection_type_t *intersection_type)
+{
+ SVN_ERR_ASSERT(r1);
+ SVN_ERR_ASSERT(r2);
+
+ /* Why not use SVN_IS_VALID_REVNUM here? Because revision 0
+ is described START = -1, END = 0. See svn_merge_range_t. */
+ SVN_ERR_ASSERT(r1->start >= -1);
+ SVN_ERR_ASSERT(r2->start >= -1);
+
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(r1->end));
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(r2->end));
+ SVN_ERR_ASSERT(r1->start < r1->end);
+ SVN_ERR_ASSERT(r2->start < r2->end);
+
+ if (!(r1->start <= r2->end && r2->start <= r1->end))
+ *intersection_type = svn__no_intersection;
+ else if (r1->start == r2->start && r1->end == r2->end)
+ *intersection_type = svn__equal_intersection;
+ else if (r1->end == r2->start || r2->end == r1->start)
+ *intersection_type = svn__adjoining_intersection;
+ else if (r1->start <= r2->start && r1->end >= r2->end)
+ *intersection_type = svn__proper_subset_intersection;
+ else if (r2->start <= r1->start && r2->end >= r1->end)
+ *intersection_type = svn__proper_subset_intersection;
+ else
+ *intersection_type = svn__overlapping_intersection;
+
+ return SVN_NO_ERROR;
+}
+
/* Helper for svn_rangelist_merge() and rangelist_intersect_or_remove().
If *LASTRANGE is not NULL it should point to the last element in REVLIST.
REVLIST must be sorted from lowest to highest revision and contain no
- overlapping revision ranges. Any changes made to REVLIST will maintain
- this guarantee.
-
- If *LASTRANGE is NULL then push MRANGE to REVLIST.
-
- If *LASTRANGE and MRANGE don't intersect then push MRANGE to REVLIST.
- If they do intersect and have the same inheritability then combine the
- ranges, updating *LASTRANGE to reflect the new combined range. If the
- ranges intersect but differ in inheritability, then merge the ranges - see
- the doc string for svn_mergeinfo_merge. This may result in a change to
- *LASTRANGE's end field and the pushing of up to two new ranges on REVLIST.
-
- e.g. *LASTRANGE: '4-10*' merged with MRANGE: '6'________
- | | |
- Update end field Push Account for trimmed
- | | range from *LASTRANGE.
- | | Push it last to
- | | maintain sort order.
- | | |
- V V V
- *LASTRANGE: '4-5*' MRANGE: '6' NEWRANGE: '6-10*'
+ overlapping revision ranges. All ranges in REVLIST must describe forward
+ merges. Any changes made to REVLIST will maintain these guarantees.
- Upon return, if any new ranges were pushed onto REVLIST, then set
- *LASTRANGE to the last range pushed.
+ Make a copy of NEW_RANGE allocated in RESULT_POOL. In some cases
+ *LASTRANGE may be popped from REVLIST, a copy made (allocated in
+ RESULT_POOL), the copy modified and then pushed back onto REVLIST.
+
+ If *LASTRANGE is NULL then push the copy of NEW_RANGE onto REVLIST.
+
+ If *LASTRANGE and NEW_RANGE don't intersect then push the copy of
+ NEW_RANGE onto REVLIST.
+
+ If the ranges do intersect and have the same inheritability then combine
+ the ranges.
+
+ If the ranges intersect but differ in inheritability, then merge the
+ ranges as dictated below by CONSIDER_INHERITANCE.
CONSIDER_INHERITANCE determines how to account for the inheritability of
- MRANGE and *LASTRANGE when determining if they intersect. If
- CONSIDER_INHERITANCE is TRUE, then only ranges with the same
- inheritability can intersect and therefore be combined.
+ NEW_RANGE and *LASTRANGE when determining if they intersect.
+
+ If CONSIDER_INHERITANCE is false then any intersection between *LASTRANGE
+ and NEW_RANGE is determined strictly on the ranges start and end revisions.
+ If the ranges intersect then they are joined. The inheritability of the
+ resulting range is non-inheritable *only* if both ranges were
+ non-inheritable, otherwise the combined range is inheritable, e.g.:
+
+ *LASTRANGE NEW_RANGE RESULTING RANGES
+ ---------- --------- ----------------
+ 4-10* 6-13 4-13
+ 4-10 6-13* 4-13
+ 4-10* 6-13* 4-13*
+
+ If CONSIDER_INHERITANCE is true, then only the intersection between two
+ ranges with differing inheritance can be combined. If one range has
+ non-inheritable ranges unique to it and the other range is inheritable,
+ then the unique non-inheritable ranges are pushed onto REVLIST as separate
+ ranges. Adjoining ranges of the same inheritance are joined to make a
+ single range, e.g.:
+
+ *LASTRANGE NEW_RANGE RESULTING RANGES
+ ---------- --------- ----------------
+ 4-10* 6 4-5*, 6, 7-10*
+ 4-10 6* 4-10
+ 4-10* 6-12 4-5*, 6-12
- If DUP_MRANGE is TRUE then allocate a copy of MRANGE before pushing it
- onto REVLIST.
+ SCRATCH_POOL is used for any temporary allocations. RESULT_POOL is used
+ to allocate any svn_merge_range_t added to REVLIST.
*/
-static APR_INLINE void
+static svn_error_t *
combine_with_lastrange(svn_merge_range_t** lastrange,
- svn_merge_range_t *mrange, svn_boolean_t dup_mrange,
+ svn_merge_range_t *new_range,
apr_array_header_t *revlist,
svn_boolean_t consider_inheritance,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_merge_range_t *pushed_mrange_1 = NULL;
- svn_merge_range_t *pushed_mrange_2 = NULL;
- svn_boolean_t ranges_intersect = FALSE;
- svn_boolean_t ranges_have_same_inheritance = FALSE;
+ svn_merge_range_t combined_range;
+
+ /* We don't accept a NULL REVLIST. */
+ SVN_ERR_ASSERT(revlist);
+ /* Our contract requires that *LASTRANGE is the "last" range
+ if it isn't NULL. */
if (*lastrange)
- {
- if ((*lastrange)->start <= mrange->end
- && mrange->start <= (*lastrange)->end)
- ranges_intersect = TRUE;
- if ((*lastrange)->inheritable == mrange->inheritable)
- ranges_have_same_inheritance = TRUE;
- }
-
- if (!(*lastrange)
- || (!ranges_intersect || (!ranges_have_same_inheritance
- && consider_inheritance)))
-
- {
- /* No *LASTRANGE
- or
- LASTRANGE and MRANGE don't intersect
- or
- LASTRANGE and MRANGE "intersect" but have different
- inheritability and we are considering inheritance so
- can't combined them...
-
- ...In all these cases just push MRANGE onto *LASTRANGE. */
- if (dup_mrange)
- pushed_mrange_1 = svn_merge_range_dup(mrange, pool);
+ SVN_ERR_ASSERT(*lastrange == APR_ARRAY_IDX(revlist,
+ revlist->nelts - 1,
+ svn_merge_range_t *));
+
+ if (!*lastrange)
+ {
+ /* No *LASTRANGE so push NEW_RANGE onto REVLIST and we are done. */
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) =
+ svn_merge_range_dup(new_range, result_pool);
+ }
+ else if (!consider_inheritance)
+ {
+ /* We are not considering inheritance so we can merge intersecting
+ ranges of different inheritability. Of course if the ranges
+ don't intersect at all we simply push NEW_RANGE only REVLIST. */
+ if (combine_ranges(&combined_range, *lastrange, new_range, FALSE))
+ {
+ (*lastrange)->start = combined_range.start;
+ (*lastrange)->end = combined_range.end;
+ (*lastrange)->inheritable = combined_range.inheritable;
+ }
else
- pushed_mrange_1 = mrange;
+ {
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) =
+ svn_merge_range_dup(new_range, result_pool);
+ }
}
- else /* MRANGE and *LASTRANGE intersect */
+ else /* Considering inheritance */
{
- if (ranges_have_same_inheritance)
+ if (combine_ranges(&combined_range, *lastrange, new_range, TRUE))
{
- /* Intersecting ranges have the same inheritability
- so just combine them. */
- (*lastrange)->start = MIN((*lastrange)->start, mrange->start);
- (*lastrange)->end = MAX((*lastrange)->end, mrange->end);
- (*lastrange)->inheritable =
- ((*lastrange)->inheritable || mrange->inheritable);
+ /* Even when considering inheritance two intersection ranges
+ of the same inheritability can simply be combined. */
+ (*lastrange)->start = combined_range.start;
+ (*lastrange)->end = combined_range.end;
+ (*lastrange)->inheritable = combined_range.inheritable;
}
- else /* Ranges intersect but have different
- inheritability so merge the ranges. */
+ else
{
- svn_revnum_t tmp_revnum;
-
- /* Ranges have same starting revision. */
- if ((*lastrange)->start == mrange->start)
- {
- if ((*lastrange)->end == mrange->end)
- {
- (*lastrange)->inheritable = TRUE;
- }
- else if ((*lastrange)->end > mrange->end)
- {
- if (!(*lastrange)->inheritable)
- {
- tmp_revnum = (*lastrange)->end;
- (*lastrange)->end = mrange->end;
- (*lastrange)->inheritable = TRUE;
- if (dup_mrange)
- pushed_mrange_1 = svn_merge_range_dup(mrange, pool);
- else
- pushed_mrange_1 = mrange;
- pushed_mrange_1->start = pushed_mrange_1->start;
- pushed_mrange_1->end = tmp_revnum;
- *lastrange = pushed_mrange_1;
- }
- }
- else /* (*lastrange)->end < mrange->end) */
- {
- if (mrange->inheritable)
- {
- (*lastrange)->inheritable = TRUE;
- (*lastrange)->end = mrange->end;
- }
- else
- {
- if (dup_mrange)
- pushed_mrange_1 = svn_merge_range_dup(mrange, pool);
- else
- pushed_mrange_1 = mrange;
- pushed_mrange_1->start = (*lastrange)->end;
- }
- }
- }
- /* Ranges have same ending revision. (Same starting
- and ending revisions already handled above.) */
- else if ((*lastrange)->end == mrange->end)
- {
- if ((*lastrange)->start < mrange->start)
+ /* If we are here then the ranges either don't intersect or do
+ intersect but have differing inheritability. Check for the
+ first case as that is easy to handle. */
+ intersection_type_t intersection_type;
+
+ SVN_ERR(get_type_of_intersection(new_range, *lastrange,
+ &intersection_type));
+
+ switch (intersection_type)
{
- if (!(*lastrange)->inheritable)
+ case svn__no_intersection:
+ /* NEW_RANGE and *LASTRANGE *really* don't intersect so
+ just push NEW_RANGE only REVLIST. */
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) =
+ svn_merge_range_dup(new_range, result_pool);
+ break;
+
+ case svn__equal_intersection:
+ /* They range are equal so all we do is force the
+ inheritability of lastrange to true. */
+ (*lastrange)->inheritable = TRUE;
+ break;
+
+ case svn__adjoining_intersection:
+ /* They adjoin but don't overlap so just push NEW_RANGE
+ onto REVLIST. */
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) =
+ svn_merge_range_dup(new_range, result_pool);
+ break;
+
+ case svn__overlapping_intersection:
+ /* They ranges overlap but neither is a proper subset of
+ the other. We'll end up pusing two new ranges onto
+ REVLIST, the intersecting part and the part unique to
+ NEW_RANGE.*/
{
- (*lastrange)->end = mrange->start;
- if (dup_mrange)
- pushed_mrange_1 = svn_merge_range_dup(mrange, pool);
+ svn_merge_range_t *r1 = svn_merge_range_dup(*lastrange,
+ result_pool);
+ svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
+ result_pool);
+
+ /* Pop off *LASTRANGE to make our manipulations
+ easier. */
+ apr_array_pop(revlist);
+
+ /* Ensure R1 is the older range. */
+ if (r2->start < r1->start)
+ {
+ /* Swap R1 and R2. */
+ r2->start = r1->start;
+ r2->end = r1->end;
+ r2->inheritable = r1->inheritable;
+ r1->start = new_range->start;
+ r1->end = new_range->end;
+ r1->inheritable = new_range->inheritable;
+ }
+
+ /* Absorb the intersecting ranges into the
+ inheritable range. */
+ if (r1->inheritable)
+ r2->start = r1->end;
else
- pushed_mrange_1 = mrange;
- *lastrange = pushed_mrange_1;
+ r1->end = r2->start;
+
+ /* Push everything back onto REVLIST. */
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) = r1;
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) = r2;
+
+ break;
}
- }
- else /* (*lastrange)->start > mrange->start */
- {
- (*lastrange)->start = mrange->start;
- (*lastrange)->end = mrange->end;
- (*lastrange)->inheritable = mrange->inheritable;
- if (dup_mrange)
- pushed_mrange_1 = svn_merge_range_dup(mrange, pool);
- else
- pushed_mrange_1 = mrange;
- pushed_mrange_1->start = (*lastrange)->end;
- pushed_mrange_1->inheritable = TRUE;
- }
- }
- else /* Ranges have different starting and ending revisions. */
- {
- if ((*lastrange)->start < mrange->start)
- {
- /* If MRANGE is a proper subset of *LASTRANGE and
- *LASTRANGE is inheritable there is nothing more
- to do. */
- if (!((*lastrange)->end > mrange->end
- && (*lastrange)->inheritable))
+ default: /* svn__proper_subset_intersection */
{
- tmp_revnum = (*lastrange)->end;
- if (!(*lastrange)->inheritable)
- (*lastrange)->end = mrange->start;
- else
- mrange->start = (*lastrange)->end;
- if (dup_mrange)
- pushed_mrange_1 = svn_merge_range_dup(mrange, pool);
- else
- pushed_mrange_1 = mrange;
+ /* One range is a proper subset of the other. */
+ svn_merge_range_t *r1 = svn_merge_range_dup(*lastrange,
+ result_pool);
+ svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
+ result_pool);
+ svn_merge_range_t *r3 = NULL;
+ svn_revnum_t tmp_revnum;
+
+ /* Pop off *LASTRANGE to make our manipulations
+ easier. */
+ apr_array_pop(revlist);
- if (tmp_revnum > mrange->end)
+ /* Ensure R1 is the superset. */
+ if (r2->start < r1->start || r2->end > r1->end)
{
- pushed_mrange_2 =
- apr_palloc(pool, sizeof(*pushed_mrange_2));
- pushed_mrange_2->start = mrange->end;
- pushed_mrange_2->end = tmp_revnum;
- pushed_mrange_2->inheritable =
- (*lastrange)->inheritable;
+ /* Swap R1 and R2. */
+ r2->start = r1->start;
+ r2->end = r1->end;
+ r2->inheritable = r1->inheritable;
+ r1->start = new_range->start;
+ r1->end = new_range->end;
+ r1->inheritable = new_range->inheritable;
}
- mrange->inheritable = TRUE;
- }
- }
- else /* ((*lastrange)->start > mrange->start) */
- {
- pushed_mrange_2 =
- apr_palloc(pool, sizeof(*pushed_mrange_2));
- if ((*lastrange)->end < mrange->end)
- {
- pushed_mrange_2->start = (*lastrange)->end;
- pushed_mrange_2->end = mrange->end;
- pushed_mrange_2->inheritable = mrange->inheritable;
-
- tmp_revnum = (*lastrange)->start;
- (*lastrange)->start = mrange->start;
- (*lastrange)->end = tmp_revnum;
- (*lastrange)->inheritable = mrange->inheritable;
-
- mrange->start = tmp_revnum;
- mrange->end = pushed_mrange_2->start;
- mrange->inheritable = TRUE;
- }
- else /* (*lastrange)->end > mrange->end */
- {
- pushed_mrange_2->start = mrange->end;
- pushed_mrange_2->end = (*lastrange)->end;
- pushed_mrange_2->inheritable =
- (*lastrange)->inheritable;
-
- tmp_revnum = (*lastrange)->start;
- (*lastrange)->start = mrange->start;
- (*lastrange)->end = tmp_revnum;
- (*lastrange)->inheritable = mrange->inheritable;
-
- mrange->start = tmp_revnum;
- mrange->end = pushed_mrange_2->start;
- mrange->inheritable = TRUE;
+ if (r1->inheritable)
+ {
+ /* The simple case: The superset is inheritable, so
+ just combine r1 and r2. */
+ r1->start = MIN(r1->start, r2->start);
+ r1->end = MAX(r1->end, r2->end);
+ r2 = NULL;
+ }
+ else if (r1->start == r2->start)
+ {
+ /* *LASTRANGE and NEW_RANGE share an end point. */
+ tmp_revnum = r1->end;
+ r1->end = r2->end;
+ r2->inheritable = r1->inheritable;
+ r1->inheritable = TRUE;
+ r2->start = r1->end;
+ r2->end = tmp_revnum;
+ }
+ else if (r1->end == r2->end)
+ {
+ /* *LASTRANGE and NEW_RANGE share an end point. */
+ r1->end = r2->start;
+ r2->inheritable = TRUE;
+ }
+ else
+ {
+ /* NEW_RANGE and *LASTRANGE share neither start
+ nor end points. */
+ r3 = apr_pcalloc(result_pool, sizeof(*r3));
+ r3->start = r2->end;
+ r3->end = r1->end;
+ r3->inheritable = r1->inheritable;
+ r2->inheritable = TRUE;
+ r1->end = r2->start;
+ }
+
+ /* Push everything back onto REVLIST. */
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) = r1;
+ if (r2)
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) = r2;
+ if (r3)
+ APR_ARRAY_PUSH(revlist, svn_merge_range_t *) = r3;
+
+ break;
}
}
- }
+
+ /* Some of the above cases might have put *REVLIST out of
+ order, so re-sort.*/
+ qsort(revlist->elts, revlist->nelts, revlist->elt_size,
+ svn_sort_compare_ranges);
}
}
- if (pushed_mrange_1)
- {
- APR_ARRAY_PUSH(revlist, svn_merge_range_t *) = pushed_mrange_1;
- *lastrange = pushed_mrange_1;
- }
- if (pushed_mrange_2)
- {
- APR_ARRAY_PUSH(revlist, svn_merge_range_t *) = pushed_mrange_2;
- *lastrange = pushed_mrange_2;
- }
+
+ /* Make sure *LASTRANGE points at the "last" range. */
+ *lastrange = APR_ARRAY_IDX(revlist, revlist->nelts - 1, svn_merge_range_t *);
+ return SVN_NO_ERROR;
}
/* Convert a single svn_merge_range_t * back into an svn_string_t *. */
@@ -487,6 +574,7 @@ parse_revision_line(const char **input,
apr_pool_t *pool)
{
svn_stringbuf_t *pathname;
+ apr_array_header_t *existing_rangelist;
apr_array_header_t *revlist = apr_array_make(pool, 1,
sizeof(svn_merge_range_t *));
@@ -559,6 +647,17 @@ parse_revision_line(const char **input,
lastrange = APR_ARRAY_IDX(revlist, i, svn_merge_range_t *);
}
}
+
+ /* Handle any funky mergeinfo with relative merge source paths that
+ might exist due to issue #3547. It's possible that this issue allowed
+ the creation of mergeinfo with path keys that differ only by a
+ leading slash, e.g. "trunk:4033\n/trunk:4039-4995". In the event
+ we encounter this we merge the rangelists together under a single
+ absolute path key. */
+ if (existing_rangelist = apr_hash_get(hash, pathname->data,
+ APR_HASH_KEY_STRING))
+ svn_rangelist_merge(&revlist, existing_rangelist, pool);
+
apr_hash_set(hash, pathname->data, APR_HASH_KEY_STRING, revlist);
return SVN_NO_ERROR;
@@ -621,21 +720,21 @@ svn_rangelist_merge(apr_array_header_t *
result. */
if (elt1->inheritable || elt2->inheritable)
elt1->inheritable = TRUE;
- combine_with_lastrange(&lastrange, elt1, TRUE, output,
- FALSE, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, elt1, output,
+ TRUE, pool, pool));
i++;
j++;
}
else if (res < 0)
{
- combine_with_lastrange(&lastrange, elt1, TRUE, output,
- FALSE, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, elt1, output,
+ TRUE, pool, pool));
i++;
}
else
{
- combine_with_lastrange(&lastrange, elt2, TRUE, output,
- FALSE, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, elt2, output,
+ TRUE, pool, pool));
j++;
}
}
@@ -648,16 +747,16 @@ svn_rangelist_merge(apr_array_header_t *
{
svn_merge_range_t *elt = APR_ARRAY_IDX(*rangelist, i,
svn_merge_range_t *);
- combine_with_lastrange(&lastrange, elt, TRUE, output,
- FALSE, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, elt, output,
+ TRUE, pool, pool));
}
for (; j < changes->nelts; j++)
{
svn_merge_range_t *elt = APR_ARRAY_IDX(changes, j, svn_merge_range_t *);
- combine_with_lastrange(&lastrange, elt, TRUE, output,
- FALSE, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, elt, output,
+ TRUE, pool, pool));
}
*rangelist = output;
@@ -787,8 +886,9 @@ rangelist_intersect_or_remove(apr_array_
if (range_contains(elt2, elt1, consider_inheritance))
{
if (!do_remove)
- combine_with_lastrange(&lastrange, elt1, TRUE, *output,
- consider_inheritance, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, elt1, *output,
+ consider_inheritance, pool,
+ pool));
i++;
@@ -816,8 +916,9 @@ rangelist_intersect_or_remove(apr_array_
tmp_range.end = MIN(elt1->end, elt2->end);
}
- combine_with_lastrange(&lastrange, &tmp_range, TRUE,
- *output, consider_inheritance, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, &tmp_range,
+ *output, consider_inheritance,
+ pool, pool));
}
/* Set up the rest of the whiteboard range for further
@@ -832,8 +933,10 @@ rangelist_intersect_or_remove(apr_array_
tmp_range.start = MAX(elt1->start, elt2->start);
tmp_range.end = elt2->end;
tmp_range.inheritable = elt1->inheritable;
- combine_with_lastrange(&lastrange, &tmp_range, TRUE,
- *output, consider_inheritance, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, &tmp_range,
+ *output,
+ consider_inheritance,
+ pool, pool));
}
wboardelt.start = elt2->end;
@@ -855,7 +958,7 @@ rangelist_intersect_or_remove(apr_array_
else
{
if (do_remove && !(lastrange &&
- combine_ranges(&lastrange, lastrange, elt1,
+ combine_ranges(lastrange, lastrange, elt1,
consider_inheritance)))
{
lastrange = svn_merge_range_dup(elt1, pool);
@@ -876,8 +979,8 @@ rangelist_intersect_or_remove(apr_array_
the whiteboard element. */
if (i == lasti && i < whiteboard->nelts)
{
- combine_with_lastrange(&lastrange, &wboardelt, TRUE, *output,
- consider_inheritance, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, &wboardelt, *output,
+ consider_inheritance, pool, pool));
i++;
}
@@ -887,8 +990,8 @@ rangelist_intersect_or_remove(apr_array_
svn_merge_range_t *elt = APR_ARRAY_IDX(whiteboard, i,
svn_merge_range_t *);
- combine_with_lastrange(&lastrange, elt, TRUE, *output,
- consider_inheritance, pool);
+ SVN_ERR(combine_with_lastrange(&lastrange, elt, *output,
+ consider_inheritance, pool, pool));
}
}
@@ -1253,7 +1356,9 @@ svn_rangelist_to_string(svn_string_t **o
/* Converts a mergeinfo INPUT to an unparsed mergeinfo in OUTPUT. If PREFIX
is not NULL then prepend PREFIX to each line in OUTPUT. If INPUT contains
- no elements, return the empty string.
+ no elements, return the empty string. If INPUT contains any merge source
+ path keys that are relative then convert these to absolute paths in
+ *OUTPUT.
*/
static svn_error_t *
mergeinfo_to_stringbuf(svn_stringbuf_t **output,
@@ -1275,11 +1380,13 @@ mergeinfo_to_stringbuf(svn_stringbuf_t *
svn_string_t *revlist;
SVN_ERR(svn_rangelist_to_string(&revlist, elt.value, pool));
- svn_stringbuf_appendcstr(*output,
- apr_psprintf(pool, "%s%s:%s",
- prefix ? prefix : "",
- (const char *) elt.key,
- revlist->data));
+ svn_stringbuf_appendcstr(
+ *output,
+ apr_psprintf(pool, "%s%s%s:%s",
+ prefix ? prefix : "",
+ *((const char *) elt.key) == '/' ? "" : "/",
+ (const char *) elt.key,
+ revlist->data));
if (i < sorted->nelts - 1)
svn_stringbuf_appendcstr(*output, "\n");
}
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/opt.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/opt.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/opt.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/opt.c Tue Mar 16 18:03:37 2010
@@ -872,13 +872,22 @@ svn_opt__split_arg_at_peg_revision(const
if (peg_start)
{
+ /* Error out if target is the empty string. */
+ if (j == 0)
+ return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
+ _("'%s' is just a peg revision. "
+ "Maybe try '%s@' instead?"),
+ utf8_target, utf8_target);
+
*true_target = apr_pstrmemdup(pool, utf8_target, j);
- *peg_revision = apr_pstrdup(pool, peg_start);
+ if (peg_revision)
+ *peg_revision = apr_pstrdup(pool, peg_start);
}
else
{
*true_target = utf8_target;
- *peg_revision = "";
+ if (peg_revision)
+ *peg_revision = "";
}
return SVN_NO_ERROR;
@@ -1017,3 +1026,29 @@ svn_opt_print_help3(apr_getopt_t *os,
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_opt__eat_peg_revisions(apr_array_header_t **true_targets_p,
+ apr_array_header_t *targets,
+ apr_pool_t *pool)
+{
+ unsigned int i;
+ apr_array_header_t *true_targets;
+
+ true_targets = apr_array_make(pool, DEFAULT_ARRAY_SIZE, sizeof(const char *));
+
+ for (i = 0; i < targets->nelts; i++)
+ {
+ const char *target = APR_ARRAY_IDX(targets, i, const char *);
+ const char *true_target;
+
+ SVN_ERR(svn_opt__split_arg_at_peg_revision(&true_target, NULL,
+ target, pool));
+ APR_ARRAY_PUSH(true_targets, const char *) = true_target;
+ }
+
+ SVN_ERR_ASSERT(true_targets_p);
+ *true_targets_p = true_targets;
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/prompt.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/prompt.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/prompt.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/prompt.c Tue Mar 16 18:03:37 2010
@@ -438,8 +438,8 @@ svn_cmdline_auth_plaintext_prompt(svn_bo
{
const char *prompt_string = _("Store password unencrypted (yes/no)? ");
const char *prompt_text =
- _("-----------------------------------------------------------------------\n"
- "ATTENTION! Your password for authentication realm:\n"
+ _("\n-----------------------------------------------------------------------"
+ "\nATTENTION! Your password for authentication realm:\n"
"\n"
" %s\n"
"\n"
@@ -467,7 +467,7 @@ svn_cmdline_auth_plaintext_passphrase_pr
{
const char *prompt_string = _("Store passphrase unencrypted (yes/no)? ");
const char *prompt_text =
- _("-----------------------------------------------------------------------\n"
+ _("\n-----------------------------------------------------------------------\n"
"ATTENTION! Your passphrase for client certificate:\n"
"\n"
" %s\n"
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/sqlite.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/sqlite.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/sqlite.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_subr/sqlite.c Tue Mar 16 18:03:37 2010
@@ -492,6 +492,7 @@ init_sqlite(apr_pool_t *pool)
SQLITE_VERSION, sqlite3_libversion());
}
+#if APR_HAS_THREADS
#if SQLITE_VERSION_AT_LEAST(3,5,0)
/* SQLite 3.5 allows verification of its thread-safety at runtime.
Older versions are simply expected to have been configured with
@@ -513,6 +514,7 @@ init_sqlite(apr_pool_t *pool)
}
SQLITE_ERR_MSG(sqlite3_initialize(), "Could not initialize SQLite");
#endif
+#endif /* APR_HAS_THRADS */
return SVN_NO_ERROR;
}
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/adm_ops.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/adm_ops.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/adm_ops.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/adm_ops.c Tue Mar 16 18:03:37 2010
@@ -36,6 +36,7 @@
#include "svn_pools.h"
#include "svn_string.h"
#include "svn_error.h"
+#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_hash.h"
#include "svn_wc.h"
@@ -2631,7 +2632,8 @@ svn_wc_remove_from_revision_control(svn_
function is called by svn_wc_crop_tree(). */
dir_entry = apr_hash_get(parent_entries, base_name,
APR_HASH_KEY_STRING);
- if (dir_entry->depth != svn_depth_exclude)
+ if (dir_entry
+ && dir_entry->depth != svn_depth_exclude)
{
svn_wc__entry_remove(parent_entries, base_name);
SVN_ERR(svn_wc__entries_write(parent_entries, parent_access, pool));
@@ -2739,23 +2741,31 @@ resolve_conflict_on_entry(const char *pa
if (resolve_text)
{
- const char *auto_resolve_src;
+ const char *auto_resolve_src = NULL;
/* Handle automatic conflict resolution before the temporary files are
* deleted, if necessary. */
switch (conflict_choice)
{
case svn_wc_conflict_choose_base:
- auto_resolve_src = entry->conflict_old;
+ if (entry->conflict_old)
+ auto_resolve_src = svn_path_join(
+ svn_wc_adm_access_path(conflict_dir),
+ entry->conflict_old, pool);
break;
case svn_wc_conflict_choose_mine_full:
- auto_resolve_src = entry->conflict_wrk;
+ if (entry->conflict_wrk)
+ auto_resolve_src = svn_path_join(
+ svn_wc_adm_access_path(conflict_dir),
+ entry->conflict_wrk, pool);
break;
case svn_wc_conflict_choose_theirs_full:
- auto_resolve_src = entry->conflict_new;
+ if (entry->conflict_new)
+ auto_resolve_src = svn_path_join(
+ svn_wc_adm_access_path(conflict_dir),
+ entry->conflict_new, pool);
break;
case svn_wc_conflict_choose_merged:
- auto_resolve_src = NULL;
break;
case svn_wc_conflict_choose_theirs_conflict:
case svn_wc_conflict_choose_mine_conflict:
@@ -2766,6 +2776,9 @@ resolve_conflict_on_entry(const char *pa
apr_file_t *tmp_f;
svn_stream_t *tmp_stream;
svn_diff_t *diff;
+ const char *conflict_old;
+ const char *conflict_wrk;
+ const char *conflict_new;
svn_diff_conflict_display_style_t style =
conflict_choice == svn_wc_conflict_choose_theirs_conflict
? svn_diff_conflict_display_latest
@@ -2777,24 +2790,46 @@ resolve_conflict_on_entry(const char *pa
svn_io_file_del_none,
pool));
tmp_stream = svn_stream_from_aprfile2(tmp_f, FALSE, pool);
+
+ /* ### If any of these paths isn't absolute, treat it
+ * ### as relative to CONFLICT_DIR_ABSPATH.
+ * ### Else we end up erroring out here, e.g. if the file
+ * ### is just a basename, and does not live in the current
+ * ### working directory.
+ * ### The API docs are unclear about whether these paths
+ * ### must be absolute or not. */
+ conflict_old = entry->conflict_old;
+ conflict_wrk = entry->conflict_wrk;
+ conflict_new = entry->conflict_new;
+ if (! svn_dirent_is_absolute(conflict_old))
+ conflict_old = svn_dirent_join(
+ svn_wc_adm_access_path(conflict_dir),
+ entry->conflict_old, pool);
+ if (! svn_dirent_is_absolute(conflict_wrk))
+ conflict_wrk = svn_dirent_join(
+ svn_wc_adm_access_path(conflict_dir),
+ entry->conflict_wrk, pool);
+ if (! svn_dirent_is_absolute(conflict_new))
+ conflict_new = svn_dirent_join(
+ svn_wc_adm_access_path(conflict_dir),
+ entry->conflict_new, pool);
+
SVN_ERR(svn_diff_file_diff3_2(&diff,
- entry->conflict_old,
- entry->conflict_wrk,
- entry->conflict_new,
+ conflict_old,
+ conflict_wrk,
+ conflict_new,
svn_diff_file_options_create(pool),
pool));
SVN_ERR(svn_diff_file_output_merge2(tmp_stream, diff,
- entry->conflict_old,
- entry->conflict_wrk,
- entry->conflict_new,
+ conflict_old,
+ conflict_wrk,
+ conflict_new,
/* markers ignored */
NULL, NULL, NULL, NULL,
style,
pool));
SVN_ERR(svn_stream_close(tmp_stream));
}
- else
- auto_resolve_src = NULL;
break;
}
default:
@@ -2803,10 +2838,7 @@ resolve_conflict_on_entry(const char *pa
}
if (auto_resolve_src)
- SVN_ERR(svn_io_copy_file(
- svn_path_join(svn_wc_adm_access_path(conflict_dir), auto_resolve_src,
- pool),
- path, TRUE, pool));
+ SVN_ERR(svn_io_copy_file(auto_resolve_src, path, TRUE, pool));
}
/* Yes indeed, being able to map a function over a list would be nice. */
@@ -2954,6 +2986,20 @@ resolve_found_entry_callback(const char
pool));
if (conflict)
{
+ /* For now, we only clear tree conflict information and resolve
+ * to the working state. There is no way to pick theirs-full
+ * or mine-full, etc. Throw an error if the user expects us
+ * to be smarter than we really are. */
+ if (baton->conflict_choice != svn_wc_conflict_choose_merged)
+ {
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+ NULL,
+ _("Tree conflicts can only be resolved "
+ "to 'working' state; "
+ "'%s' not resolved"),
+ svn_dirent_local_style(path, pool));
+ }
+
SVN_ERR(svn_wc__del_tree_conflict(path, parent_adm_access, pool));
/* Sanity check: see if libsvn_wc *still* thinks this item is in a
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/props.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/props.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/props.c Tue Mar 16 18:03:37 2010
@@ -926,7 +926,7 @@ diff_mergeinfo_props(svn_mergeinfo_t *de
SVN_ERR(svn_mergeinfo_parse(&from, from_prop_val->data, pool));
SVN_ERR(svn_mergeinfo_parse(&to, to_prop_val->data, pool));
SVN_ERR(svn_mergeinfo_diff(deleted, added, from, to,
- FALSE, pool));
+ TRUE, pool));
}
return SVN_NO_ERROR;
}
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/questions.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/questions.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/questions.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/questions.c Tue Mar 16 18:03:37 2010
@@ -41,8 +41,52 @@
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
+#include "private/svn_sqlite.h"
+#define SVN_WC_NG_CHECK_ENV_VAR "SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_CHECK_FOR_WC_NG"
+static svn_error_t *
+is_inside_wc_ng(const char *abspath,
+ const char *target_path,
+ int *wc_format,
+ apr_pool_t *pool)
+{
+ svn_node_kind_t kind;
+ const char *wc_db_path;
+ char *wc_ng_check_env_var;
+
+ wc_ng_check_env_var = getenv(SVN_WC_NG_CHECK_ENV_VAR);
+ if (wc_ng_check_env_var &&
+ apr_strnatcasecmp(wc_ng_check_env_var, "yes") == 0)
+ return SVN_NO_ERROR; /* Allow skipping for testing */
+
+ wc_db_path = svn_path_join_many(pool, abspath, SVN_WC_ADM_DIR_NAME,
+ "wc.db", NULL);
+ SVN_ERR(svn_io_check_path(wc_db_path, &kind, pool));
+
+ if (kind == svn_node_file)
+ {
+ /* This value is completely bogus, but it is much higher than 1.6 will
+ have any prayer of reading. */
+ *wc_format = 9999;
+
+ return svn_error_createf(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
+ _("The path '%s' appears to be part of a Subversion 1.7 or greater\n"
+ "working copy rooted at '%s'.\n"
+ "Please upgrade your Subversion client to use this working copy."
+ ),
+ svn_path_local_style(target_path, pool),
+ svn_path_local_style(abspath, pool));
+ }
+
+ if (svn_dirent_is_root(abspath, strlen(abspath)))
+ return SVN_NO_ERROR;
+ else
+ return is_inside_wc_ng(svn_path_dirname(abspath, pool), target_path,
+ wc_format, pool);
+}
+
+
/* ### todo: make this compare repository too? Or do so in parallel
code. */
svn_error_t *
@@ -95,7 +139,17 @@ svn_wc_check_wc(const char *path,
}
else if (err)
return err;
- else
+
+ /* Let's check for the future. */
+ if (*wc_format == 0)
+ {
+ const char *abspath;
+
+ SVN_ERR(svn_path_get_absolute(&abspath, path, pool));
+ SVN_ERR(is_inside_wc_ng(abspath, path, wc_format, pool));
+ }
+
+ if (*wc_format > 0)
{
/* If we managed to read the format file we assume that we
are dealing with a real wc so we can return a nice
@@ -125,12 +179,9 @@ svn_wc__check_format(int wc_format, cons
least post-1.5 crossgrades will be somewhat less painful. */
return svn_error_createf
(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
- _("This client is too old to work with working copy '%s'. You need\n"
- "to get a newer Subversion client, or to downgrade this working "
- "copy.\n"
- "See "
- "http://subversion.tigris.org/faq.html#working-copy-format-change\n"
- "for details."
+ _("The path '%s' appears to be part of a Subversion 1.7 or greater\n"
+ "working copy. Please upgrade your Subversion client to use this\n"
+ "working copy."
),
svn_path_local_style(path, pool));
}
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/tree_conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/tree_conflicts.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/tree_conflicts.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/tree_conflicts.c Tue Mar 16 18:03:37 2010
@@ -512,8 +512,10 @@ svn_wc__add_tree_conflict(const svn_wc_c
SVN_ERR(svn_wc__get_tree_conflict(&existing_conflict, conflict->path,
adm_access, pool));
if (existing_conflict != NULL)
- return svn_error_create(SVN_ERR_WC_CORRUPT, NULL,
- _("Attempt to add tree conflict that already exists"));
+ return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+ _("Attempt to add tree conflict that already "
+ "exists at '%s'"),
+ svn_path_local_style(conflict->path, pool));
SVN_ERR(svn_wc__loggy_add_tree_conflict(&log_accum, conflict, adm_access,
pool));
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/update_editor.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/update_editor.c Tue Mar 16 18:03:37 2010
@@ -1851,8 +1851,9 @@ set_copied_handle_error(const char *path
return err;
}
-/* Schedule the WC item PATH, whose entry is ENTRY, for re-addition as a copy
- * with history of (ENTRY->url)@(ENTRY->rev). PATH's parent is PARENT_PATH.
+/* Schedule the WC item PATH, whose entry is ENTRY, for re-addition.
+ * If MODIFY_COPYFROM is TRUE, re-add the item as a copy with history
+ * of (ENTRY->url)@(ENTRY->rev). PATH's parent is PARENT_PATH.
* PATH and PARENT_PATH are relative to the current working directory.
* Assume that the item exists locally and is scheduled as still existing with
* some local modifications relative to its (old) base, but does not exist in
@@ -1876,6 +1877,7 @@ schedule_existing_item_for_re_add(const
const char *parent_path,
const char *path,
const char *their_url,
+ svn_boolean_t modify_copyfrom,
apr_pool_t *pool)
{
const char *base_name = svn_path_basename(path, pool);
@@ -1894,12 +1896,15 @@ schedule_existing_item_for_re_add(const
flags |= SVN_WC__ENTRY_MODIFY_SCHEDULE;
flags |= SVN_WC__ENTRY_MODIFY_FORCE;
- tmp_entry.copyfrom_url = entry->url;
- flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_URL;
- tmp_entry.copyfrom_rev = entry->revision;
- flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_REV;
- tmp_entry.copied = TRUE;
- flags |= SVN_WC__ENTRY_MODIFY_COPIED;
+ if (modify_copyfrom)
+ {
+ tmp_entry.copyfrom_url = entry->url;
+ flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_URL;
+ tmp_entry.copyfrom_rev = entry->revision;
+ flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_REV;
+ tmp_entry.copied = TRUE;
+ flags |= SVN_WC__ENTRY_MODIFY_COPIED;
+ }
/* ### Need to change the "base" into a "revert-base" ? */
@@ -2062,17 +2067,42 @@ do_entry_deletion(struct edit_baton *eb,
SVN_ERR(schedule_existing_item_for_re_add(entry, eb, parent_path,
full_path, their_url,
- pool));
+ TRUE, pool));
return SVN_NO_ERROR;
}
else if (tree_conflict->reason == svn_wc_conflict_reason_deleted)
{
- /* The item does not exist locally (except perhaps as a skeleton
- * directory tree) because it was already scheduled for delete.
- * We must complete the deletion, leaving the tree conflict info
- * as the only difference from a normal deletion. */
+ if (entry->schedule == svn_wc_schedule_replace)
+ {
+ /* The item was locally replaced with something else. We should
+ * keep the existing item schedule-replace, but we also need to
+ * update the BASE rev of the item to the revision we are
+ * updating to. Otherwise, the replace cannot be committed
+ * because the item is considered out-of-date, and it cannot
+ * be updated either because we're here to do just that. */
+
+ /* Run the log in the parent dir, to record the tree conflict.
+ * Do this before schedule_existing_item_for_re_add(), in case
+ * that needs to modify the same entries. */
+ SVN_ERR(svn_wc__write_log(parent_adm_access, *log_number,
+ log_item, pool));
+ SVN_ERR(svn_wc__run_log(parent_adm_access, NULL, pool));
+ *log_number = 0;
+
+ SVN_ERR(schedule_existing_item_for_re_add(entry, eb, parent_path,
+ full_path, their_url,
+ FALSE, pool));
+ return SVN_NO_ERROR;
+ }
+ else
+ {
+ /* The item does not exist locally (except perhaps as a skeleton
+ * directory tree) because it was already scheduled for delete.
+ * We must complete the deletion, leaving the tree conflict info
+ * as the only difference from a normal deletion. */
- /* Fall through to the normal "delete" code path. */
+ /* Fall through to the normal "delete" code path. */
+ }
}
else
SVN_ERR_MALFUNCTION(); /* other reasons are not expected here */
@@ -3518,7 +3548,7 @@ add_file(const char *path,
"from a different repository"),
svn_path_local_style(full_path, pool));
- if (!eb->switch_url
+ if (!eb->switch_url && fb->new_URL && entry->url
&& strcmp(fb->new_URL, entry->url) != 0)
return svn_error_createf(
SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
@@ -4130,9 +4160,17 @@ merge_file(svn_wc_notify_state_t *conten
different from fb->old_text_base_path if we have a replaced-with-history
file. However, in the case we had an obstruction, we check against the
new text base. (And if we're doing an add-with-history and we've already
- saved a copy of a locally-modified file, then there certainly are mods.) */
+ saved a copy of a locally-modified file, then there certainly are mods.)
+
+ Special case: The working file is referring to a file external? If so
+ then we must mark it as unmodified in order to avoid bogus
+ conflicts, since this file was added as a place holder to
+ merge externals item from the repository. */
if (fb->copied_working_text)
is_locally_modified = TRUE;
+ else if (entry && entry->file_external_path
+ && entry->schedule == svn_wc_schedule_add)
+ is_locally_modified = FALSE;
else if (! fb->existed)
SVN_ERR(svn_wc__text_modified_internal_p(&is_locally_modified, fb->path,
FALSE, adm_access, FALSE, pool));
Modified: subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/wc_db.h?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/1.6.x-issue3432/subversion/libsvn_wc/wc_db.h Tue Mar 16 18:03:37 2010
@@ -238,7 +238,7 @@ svn_wc__db_close(svn_wc__db_t *db,
* Different kind of trees
*
* The design doc mentions three different kinds of trees, BASE, WORKING and
- * ACTUAL: http://svn.collab.net/repos/svn/trunk/notes/wc-ng-design
+ * ACTUAL: http://svn.apache.org/repos/asf/subversion/trunk/notes/wc-ng-design
* We have different APIs to handle each tree, enumerated below, along with
* a blurb to explain what that tree represents.
*/
Modified: subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/liveprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/liveprops.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/liveprops.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/liveprops.c Tue Mar 16 18:03:37 2010
@@ -466,7 +466,7 @@ insert_prop(const dav_resource *resource
&& resource->info->r->content_type)
mime_type = resource->info->r->content_type;
else
- mime_type = ap_default_type(resource->info->r);
+ mime_type = "text/plain";
if ((serr = svn_mime_type_validate(mime_type, p)))
{
Modified: subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/repos.c?rev=923910&r1=923909&r2=923910&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/1.6.x-issue3432/subversion/mod_dav_svn/repos.c Tue Mar 16 18:03:37 2010
@@ -2721,21 +2721,32 @@ set_headers(request_rec *r, const dav_re
else if ((! resource->info->repos->is_svn_client)
&& r->content_type)
mimetype = r->content_type;
- else
- mimetype = ap_default_type(r);
- serr = svn_mime_type_validate(mimetype, resource->pool);
- if (serr)
+ /* If we found a MIME type, we'll make sure it's Subversion-friendly. */
+ if (mimetype)
{
- /* Probably serr->apr == SVN_ERR_BAD_MIME_TYPE, but
- there's no point even checking. No matter what the
- error is, we can't derive the mime type from the
- svn:mime-type property. So we resort to the infamous
- "mime type of last resort." */
- svn_error_clear(serr);
- mimetype = "application/octet-stream";
+ if ((serr = svn_mime_type_validate(mimetype, resource->pool)))
+ {
+ /* Probably serr->apr == SVN_ERR_BAD_MIME_TYPE, but there's
+ no point even checking. No matter what the error is, we
+ can't use this MIME type. */
+ svn_error_clear(serr);
+ mimetype = NULL;
+ }
}
+ /* We've found/calculated/validated no usable MIME type. We
+ could fall back to "application/octet-stream" (aka "bag o'
+ bytes"), but many browsers have grown to expect "text/plain"
+ to mean "*shrug*", and kick off their own MIME type detection
+ routines when they see it. So we'll use "text/plain".
+
+ ### Why not just avoid sending a Content-type at all? Is
+ ### that just bad form for HTTP? */
+ if (! mimetype)
+ mimetype = "text/plain";
+
+
/* if we aren't sending a diff, then we know the length of the file,
so set up the Content-Length header */
serr = svn_fs_file_length(&length,
@@ -2978,9 +2989,23 @@ deliver(const dav_resource *resource, ap
&& (resource->info->restype != DAV_SVN_RESTYPE_PARENTPATH_COLLECTION))
{
if (gen_html)
- ap_fprintf(output, bb, " <li><a href=\"../\">..</a></li>\n");
+ {
+ if (resource->info->pegged)
+ {
+ ap_fprintf(output, bb,
+ " <li><a href=\"../?p=%ld\">..</a></li>\n",
+ resource->info->root.rev);
+ }
+ else
+ {
+ ap_fprintf(output, bb,
+ " <li><a href=\"../\">..</a></li>\n");
+ }
+ }
else
- ap_fprintf(output, bb, " <updir />\n");
+ {
+ ap_fprintf(output, bb, " <updir />\n");
+ }
}
/* get a sorted list of the entries */
@@ -3069,11 +3094,27 @@ deliver(const dav_resource *resource, ap
svn_pool_destroy(entry_pool);
if (gen_html)
- ap_fputs(output, bb,
- " </ul>\n <hr noshade><em>Powered by "
- "<a href=\"http://subversion.tigris.org/\">Subversion</a> "
- "version " SVN_VERSION "."
- "</em>\n</body></html>");
+ {
+ if (strcmp(ap_psignature("FOO", resource->info->r), "") != 0)
+ {
+ /* Apache's signature generation code didn't eat our prefix.
+ ServerSignature must be enabled. Print our version info.
+
+ WARNING: This is a kludge!! ap_psignature() doesn't promise
+ to return the empty string when ServerSignature is off. We
+ know it does by code inspection, but this behavior is subject
+ to change. (Perhaps we should try to get the Apache folks to
+ make this promise, though. Seems harmless/useful enough...)
+ */
+ ap_fputs(output, bb,
+ " </ul>\n <hr noshade><em>Powered by "
+ "<a href=\"http://subversion.tigris.org/\">Subversion"
+ "</a> version " SVN_VERSION "."
+ "</em>\n</body></html>");
+ }
+ else
+ ap_fputs(output, bb, " </ul>\n</body></html>");
+ }
else
ap_fputs(output, bb, " </index>\n</svn>\n");