summaryrefslogtreecommitdiff
path: root/subversion/svnsync/sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/svnsync/sync.c')
-rw-r--r--subversion/svnsync/sync.c136
1 files changed, 124 insertions, 12 deletions
diff --git a/subversion/svnsync/sync.c b/subversion/svnsync/sync.c
index 525a57c..4d54ee8 100644
--- a/subversion/svnsync/sync.c
+++ b/subversion/svnsync/sync.c
@@ -19,6 +19,7 @@
* ====================================================================
*/
+#include "svn_hash.h"
#include "svn_cmdline.h"
#include "svn_config.h"
#include "svn_pools.h"
@@ -33,8 +34,7 @@
#include "svn_subst.h"
#include "svn_string.h"
-#include "private/svn_opt_private.h"
-#include "private/svn_cmdline_private.h"
+#include "private/svn_string_private.h"
#include "sync.h"
@@ -85,6 +85,92 @@ normalize_string(const svn_string_t **str,
return SVN_NO_ERROR;
}
+/* Remove r0 references from the mergeinfo string *STR.
+ *
+ * r0 was never a valid mergeinfo reference and cannot be committed with
+ * recent servers, but can be committed through a server older than 1.6.18
+ * for HTTP or older than 1.6.17 for the other protocols. See issue #4476
+ * "Mergeinfo containing r0 makes svnsync and dump and load fail".
+ *
+ * Set *WAS_CHANGED to TRUE if *STR was changed, otherwise to FALSE.
+ */
+static svn_error_t *
+remove_r0_mergeinfo(const svn_string_t **str,
+ svn_boolean_t *was_changed,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_stringbuf_t *new_str = svn_stringbuf_create_empty(result_pool);
+ apr_array_header_t *lines;
+ int i;
+
+ SVN_ERR_ASSERT(*str && (*str)->data);
+
+ *was_changed = FALSE;
+
+ /* for each line */
+ lines = svn_cstring_split((*str)->data, "\n", FALSE, scratch_pool);
+
+ for (i = 0; i < lines->nelts; i++)
+ {
+ char *line = APR_ARRAY_IDX(lines, i, char *);
+ char *colon;
+ char *rangelist;
+
+ /* split at the last colon */
+ colon = strrchr(line, ':');
+
+ if (! colon)
+ return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
+ _("Missing colon in svn:mergeinfo "
+ "property"));
+
+ rangelist = colon + 1;
+
+ /* remove r0 */
+ if (colon[1] == '0')
+ {
+ if (strncmp(rangelist, "0*,", 3) == 0)
+ {
+ rangelist += 3;
+ }
+ else if (strcmp(rangelist, "0*") == 0
+ || strncmp(rangelist, "0,", 2) == 0
+ || strncmp(rangelist, "0-1*", 4) == 0
+ || strncmp(rangelist, "0-1,", 4) == 0
+ || strcmp(rangelist, "0-1") == 0)
+ {
+ rangelist += 2;
+ }
+ else if (strcmp(rangelist, "0") == 0)
+ {
+ rangelist += 1;
+ }
+ else if (strncmp(rangelist, "0-", 2) == 0)
+ {
+ rangelist[0] = '1';
+ }
+ }
+
+ /* reassemble */
+ if (rangelist[0])
+ {
+ if (new_str->len)
+ svn_stringbuf_appendbyte(new_str, '\n');
+ svn_stringbuf_appendbytes(new_str, line, colon + 1 - line);
+ svn_stringbuf_appendcstr(new_str, rangelist);
+ }
+ }
+
+ if (strcmp((*str)->data, new_str->data) != 0)
+ {
+ *was_changed = TRUE;
+ }
+
+ *str = svn_stringbuf__morph_into_string(new_str);
+ return SVN_NO_ERROR;
+}
+
/* Normalize the encoding and line ending style of the values of properties
* in REV_PROPS that "need translation" (according to
@@ -119,7 +205,7 @@ svnsync_normalize_revprops(apr_hash_t *rev_props,
source_prop_encoding, pool, pool));
/* Replace the existing prop value. */
- apr_hash_set(rev_props, propname, APR_HASH_KEY_STRING, propval);
+ svn_hash_sets(rev_props, propname, propval);
if (was_normalized)
(*normalized_count)++; /* Count it. */
@@ -155,6 +241,7 @@ typedef struct edit_baton_t {
svn_boolean_t got_textdeltas;
svn_revnum_t base_revision;
svn_boolean_t quiet;
+ svn_boolean_t mergeinfo_tweaked; /* Did we tweak svn:mergeinfo? */
svn_boolean_t strip_mergeinfo; /* Are we stripping svn:mergeinfo? */
svn_boolean_t migrate_svnmerge; /* Are we converting svnmerge.py data? */
svn_boolean_t mergeinfo_stripped; /* Did we strip svn:mergeinfo? */
@@ -228,9 +315,7 @@ add_directory(const char *path,
edit_baton_t *eb = pb->edit_baton;
node_baton_t *b = apr_palloc(pool, sizeof(*b));
- /* if copyfrom_path starts with '/' join rest of copyfrom_path leaving
- * leading '/' with canonicalized url eb->to_url.
- */
+ /* if copyfrom_path is an fspath create a proper uri */
if (copyfrom_path && copyfrom_path[0] == '/')
copyfrom_path = svn_path_url_add_component2(eb->to_url,
copyfrom_path + 1, pool);
@@ -279,9 +364,10 @@ add_file(const char *path,
edit_baton_t *eb = pb->edit_baton;
node_baton_t *fb = apr_palloc(pool, sizeof(*fb));
- if (copyfrom_path)
- copyfrom_path = apr_psprintf(pool, "%s%s", eb->to_url,
- svn_path_uri_encode(copyfrom_path, pool));
+ /* if copyfrom_path is an fspath create a proper uri */
+ if (copyfrom_path && copyfrom_path[0] == '/')
+ copyfrom_path = svn_path_url_add_component2(eb->to_url,
+ copyfrom_path + 1, pool);
SVN_ERR(eb->wrapped_editor->add_file(path, pb->wrapped_node_baton,
copyfrom_path, copyfrom_rev,
@@ -389,7 +475,7 @@ change_file_prop(void *file_baton,
edit_baton_t *eb = fb->edit_baton;
/* only regular properties can pass over libsvn_ra */
- if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+ if (svn_property_kind2(name) != svn_prop_regular_kind)
return SVN_NO_ERROR;
/* Maybe drop svn:mergeinfo. */
@@ -417,8 +503,19 @@ change_file_prop(void *file_baton,
if (svn_prop_needs_translation(name))
{
svn_boolean_t was_normalized;
+ svn_boolean_t mergeinfo_tweaked = FALSE;
+
+ /* Normalize encoding to UTF-8, and EOL style to LF. */
SVN_ERR(normalize_string(&value, &was_normalized,
eb->source_prop_encoding, pool, pool));
+ /* Correct malformed mergeinfo. */
+ if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
+ {
+ SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
+ pool, pool));
+ if (mergeinfo_tweaked)
+ eb->mergeinfo_tweaked = TRUE;
+ }
if (was_normalized)
(*(eb->normalized_node_props_counter))++;
}
@@ -437,7 +534,7 @@ change_dir_prop(void *dir_baton,
edit_baton_t *eb = db->edit_baton;
/* Only regular properties can pass over libsvn_ra */
- if (svn_property_kind(NULL, name) != svn_prop_regular_kind)
+ if (svn_property_kind2(name) != svn_prop_regular_kind)
return SVN_NO_ERROR;
/* Maybe drop svn:mergeinfo. */
@@ -461,7 +558,7 @@ change_dir_prop(void *dir_baton,
are relative URLs, whereas svn:mergeinfo uses relative
paths (not URI-encoded). */
svn_error_t *err;
- svn_stringbuf_t *mergeinfo_buf = svn_stringbuf_create("", pool);
+ svn_stringbuf_t *mergeinfo_buf = svn_stringbuf_create_empty(pool);
svn_mergeinfo_t mergeinfo;
int i;
apr_array_header_t *sources =
@@ -516,8 +613,19 @@ change_dir_prop(void *dir_baton,
if (svn_prop_needs_translation(name))
{
svn_boolean_t was_normalized;
+ svn_boolean_t mergeinfo_tweaked = FALSE;
+
+ /* Normalize encoding to UTF-8, and EOL style to LF. */
SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding,
pool, pool));
+ /* Maybe adjust svn:mergeinfo. */
+ if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
+ {
+ SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
+ pool, pool));
+ if (mergeinfo_tweaked)
+ eb->mergeinfo_tweaked = TRUE;
+ }
if (was_normalized)
(*(eb->normalized_node_props_counter))++;
}
@@ -551,6 +659,10 @@ close_edit(void *edit_baton,
{
if (eb->got_textdeltas)
SVN_ERR(svn_cmdline_printf(pool, "\n"));
+ if (eb->mergeinfo_tweaked)
+ SVN_ERR(svn_cmdline_printf(pool,
+ "NOTE: Adjusted Subversion mergeinfo in "
+ "this revision.\n"));
if (eb->mergeinfo_stripped)
SVN_ERR(svn_cmdline_printf(pool,
"NOTE: Dropped Subversion mergeinfo "