diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /subversion/svnrdump/load_editor.c | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/svnrdump/load_editor.c')
-rw-r--r-- | subversion/svnrdump/load_editor.c | 309 |
1 files changed, 57 insertions, 252 deletions
diff --git a/subversion/svnrdump/load_editor.c b/subversion/svnrdump/load_editor.c index c35a289..15dac6e 100644 --- a/subversion/svnrdump/load_editor.c +++ b/subversion/svnrdump/load_editor.c @@ -43,14 +43,7 @@ #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r)) -#if 0 -#define LDR_DBG(x) SVN_DBG(x) -#else -#define LDR_DBG(x) while(0) -#endif - - /** * General baton used by the parser functions. */ @@ -68,9 +61,6 @@ struct parse_baton /* To bleep, or not to bleep? (What kind of question is that?) */ svn_boolean_t quiet; - /* UUID found in the dumpstream, if any; NULL otherwise. */ - const char *uuid; - /* Root URL of the target repository. */ const char *root_url; @@ -93,17 +83,20 @@ struct parse_baton /* The oldest revision loaded from the dump stream, or SVN_INVALID_REVNUM if none have been loaded. */ svn_revnum_t oldest_dumpstream_rev; + + /* An hash containing specific revision properties to skip while + loading. */ + apr_hash_t *skip_revprops; }; /** * Use to wrap the dir_context_t in commit.c so we can keep track of - * depth, relpath and parent for open_directory and close_directory. + * relpath and parent for open_directory and close_directory. */ struct directory_baton { void *baton; const char *relpath; - int depth; /* The copy-from source of this directory, no matter whether it is copied explicitly (the root node of a copy) or implicitly (being an @@ -190,160 +183,6 @@ get_revision_mapping(apr_hash_t *rev_map, } -/* Prepend the mergeinfo source paths in MERGEINFO_ORIG with - PARENT_DIR, and return it in *MERGEINFO_VAL. */ -/* ### FIXME: Consider somehow sharing code with - ### libsvn_repos/load-fs-vtable.c:prefix_mergeinfo_paths() */ -static svn_error_t * -prefix_mergeinfo_paths(svn_string_t **mergeinfo_val, - const svn_string_t *mergeinfo_orig, - const char *parent_dir, - apr_pool_t *pool) -{ - apr_hash_t *prefixed_mergeinfo, *mergeinfo; - apr_hash_index_t *hi; - void *rangelist; - - SVN_ERR(svn_mergeinfo_parse(&mergeinfo, mergeinfo_orig->data, pool)); - prefixed_mergeinfo = apr_hash_make(pool); - for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi)) - { - const void *key; - const char *path, *merge_source; - - apr_hash_this(hi, &key, NULL, &rangelist); - merge_source = svn_relpath_canonicalize(key, pool); - - /* The svn:mergeinfo property syntax demands a repos abspath */ - path = svn_fspath__canonicalize(svn_relpath_join(parent_dir, - merge_source, pool), - pool); - svn_hash_sets(prefixed_mergeinfo, path, rangelist); - } - return svn_mergeinfo_to_string(mergeinfo_val, prefixed_mergeinfo, pool); -} - - -/* Examine the mergeinfo in INITIAL_VAL, renumber revisions in rangelists - as appropriate, and return the (possibly new) mergeinfo in *FINAL_VAL - (allocated from POOL). */ -/* ### FIXME: Consider somehow sharing code with - ### libsvn_repos/load-fs-vtable.c:renumber_mergeinfo_revs() */ -static svn_error_t * -renumber_mergeinfo_revs(svn_string_t **final_val, - const svn_string_t *initial_val, - struct revision_baton *rb, - apr_pool_t *pool) -{ - apr_pool_t *subpool = svn_pool_create(pool); - svn_mergeinfo_t mergeinfo, predates_stream_mergeinfo; - svn_mergeinfo_t final_mergeinfo = apr_hash_make(subpool); - apr_hash_index_t *hi; - - SVN_ERR(svn_mergeinfo_parse(&mergeinfo, initial_val->data, subpool)); - - /* Issue #3020 - http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16 - Remove mergeinfo older than the oldest revision in the dump stream - and adjust its revisions by the difference between the head rev of - the target repository and the current dump stream rev. */ - if (rb->pb->oldest_dumpstream_rev > 1) - { - SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( - &predates_stream_mergeinfo, mergeinfo, - rb->pb->oldest_dumpstream_rev - 1, 0, - TRUE, subpool, subpool)); - SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges( - &mergeinfo, mergeinfo, - rb->pb->oldest_dumpstream_rev - 1, 0, - FALSE, subpool, subpool)); - SVN_ERR(svn_mergeinfo__adjust_mergeinfo_rangelists( - &predates_stream_mergeinfo, - predates_stream_mergeinfo, - -rb->rev_offset, subpool, subpool)); - } - else - { - predates_stream_mergeinfo = NULL; - } - - for (hi = apr_hash_first(subpool, mergeinfo); hi; hi = apr_hash_next(hi)) - { - svn_rangelist_t *rangelist; - struct parse_baton *pb = rb->pb; - int i; - const void *path; - apr_ssize_t pathlen; - void *val; - - apr_hash_this(hi, &path, &pathlen, &val); - rangelist = val; - - /* Possibly renumber revisions in merge source's rangelist. */ - for (i = 0; i < rangelist->nelts; i++) - { - svn_revnum_t rev_from_map; - svn_merge_range_t *range = APR_ARRAY_IDX(rangelist, i, - svn_merge_range_t *); - rev_from_map = get_revision_mapping(pb->rev_map, range->start); - if (SVN_IS_VALID_REVNUM(rev_from_map)) - { - range->start = rev_from_map; - } - else if (range->start == pb->oldest_dumpstream_rev - 1) - { - /* Since the start revision of svn_merge_range_t are not - inclusive there is one possible valid start revision that - won't be found in the PB->REV_MAP mapping of load stream - revsions to loaded revisions: The revision immediately - preceeding the oldest revision from the load stream. - This is a valid revision for mergeinfo, but not a valid - copy from revision (which PB->REV_MAP also maps for) so it - will never be in the mapping. - - If that is what we have here, then find the mapping for the - oldest rev from the load stream and subtract 1 to get the - renumbered, non-inclusive, start revision. */ - rev_from_map = get_revision_mapping(pb->rev_map, - pb->oldest_dumpstream_rev); - if (SVN_IS_VALID_REVNUM(rev_from_map)) - range->start = rev_from_map - 1; - } - else - { - /* If we can't remap the start revision then don't even bother - trying to remap the end revision. It's possible we might - actually succeed at the latter, which can result in invalid - mergeinfo with a start rev > end rev. If that gets into the - repository then a world of bustage breaks loose anytime that - bogus mergeinfo is parsed. See - http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc16. - */ - continue; - } - - rev_from_map = get_revision_mapping(pb->rev_map, range->end); - if (SVN_IS_VALID_REVNUM(rev_from_map)) - range->end = rev_from_map; - } - apr_hash_set(final_mergeinfo, path, pathlen, rangelist); - } - - if (predates_stream_mergeinfo) - { - SVN_ERR(svn_mergeinfo_merge2(final_mergeinfo, predates_stream_mergeinfo, - subpool, subpool)); - } - - SVN_ERR(svn_mergeinfo__canonicalize_ranges(final_mergeinfo, subpool)); - - SVN_ERR(svn_mergeinfo_to_string(final_val, final_mergeinfo, pool)); - svn_pool_destroy(subpool); - - return SVN_NO_ERROR; -} - - static svn_error_t * commit_callback(const svn_commit_info_t *commit_info, void *baton, @@ -564,8 +403,8 @@ new_revision_record(void **revision_baton, for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi)) { - const char *hname = svn__apr_hash_index_key(hi); - const char *hval = svn__apr_hash_index_val(hi); + const char *hname = apr_hash_this_key(hi); + const char *hval = apr_hash_this_val(hi); if (strcmp(hname, SVN_REPOS_DUMPFILE_REVISION_NUMBER) == 0) rb->rev = atoi(hval); @@ -606,9 +445,6 @@ uuid_record(const char *uuid, void *parse_baton, apr_pool_t *pool) { - struct parse_baton *pb; - pb = parse_baton; - pb->uuid = apr_pstrdup(pool, uuid); return SVN_NO_ERROR; } @@ -704,8 +540,6 @@ new_node_record(void **node_baton, rb->rev - rb->rev_offset - 1, rb->pool, &child_baton)); - LDR_DBG(("Opened root %p\n", child_baton)); - /* child_baton corresponds to the root directory baton here */ push_directory(rb, child_baton, "", TRUE /*is_added*/, NULL, SVN_INVALID_REVNUM); @@ -713,8 +547,8 @@ new_node_record(void **node_baton, for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi)) { - const char *hname = svn__apr_hash_index_key(hi); - const char *hval = svn__apr_hash_index_val(hi); + const char *hname = apr_hash_this_key(hi); + const char *hval = apr_hash_this_val(hi); /* Parse the different kinds of headers we can encounter and stuff them into the node_baton for writing later */ @@ -741,6 +575,9 @@ new_node_record(void **node_baton, nb->copyfrom_path = apr_pstrdup(rb->pool, hval); } + /* Before handling the new node, ensure depth-first editing order by + traversing the directory hierarchy from the old node's to the new + node's parent directory. */ nb_dirname = svn_relpath_dirname(nb->path, pool); if (svn_path_compare_paths(nb_dirname, rb->db->relpath) != 0) @@ -751,9 +588,6 @@ new_node_record(void **node_baton, int i; apr_size_t n; - /* Before attempting to handle the action, call open_directory - for all the path components and set the directory baton - accordingly */ ancestor_path = svn_relpath_get_longest_ancestor(nb_dirname, rb->db->relpath, pool); @@ -771,7 +605,6 @@ new_node_record(void **node_baton, /* Don't worry about destroying the actual rb->db object, since the pool we're using has the lifetime of one revision anyway */ - LDR_DBG(("Closing dir %p\n", rb->db->baton)); SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool)); rb->db = rb->db->parent; } @@ -786,7 +619,6 @@ new_node_record(void **node_baton, rb->db->baton, rb->rev - rb->rev_offset - 1, rb->pool, &child_baton)); - LDR_DBG(("Opened dir %p\n", child_baton)); push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/, NULL, SVN_INVALID_REVNUM); } @@ -816,6 +648,7 @@ new_node_record(void **node_baton, if (rb->pb->parent_dir) nb->copyfrom_path = svn_relpath_join(rb->pb->parent_dir, nb->copyfrom_path, rb->pool); + /* Convert to a URL, as the commit editor requires. */ nb->copyfrom_url = svn_path_url_add_component2(rb->pb->root_url, nb->copyfrom_path, rb->pool); @@ -826,7 +659,6 @@ new_node_record(void **node_baton, { case svn_node_action_delete: case svn_node_action_replace: - LDR_DBG(("Deleting entry %s in %p\n", nb->path, rb->db->baton)); SVN_ERR(commit_editor->delete_entry(nb->path, rb->rev - rb->rev_offset - 1, rb->db->baton, rb->pool)); @@ -843,16 +675,12 @@ new_node_record(void **node_baton, nb->copyfrom_url, nb->copyfrom_rev, rb->pool, &(nb->file_baton))); - LDR_DBG(("Added file %s to dir %p as %p\n", - nb->path, rb->db->baton, nb->file_baton)); break; case svn_node_dir: SVN_ERR(commit_editor->add_directory(nb->path, rb->db->baton, nb->copyfrom_url, nb->copyfrom_rev, rb->pool, &child_baton)); - LDR_DBG(("Added dir %s to dir %p as %p\n", - nb->path, rb->db->baton, child_baton)); push_directory(rb, child_baton, nb->path, TRUE /*is_added*/, nb->copyfrom_path, nb->copyfrom_rev); break; @@ -896,11 +724,13 @@ set_revision_property(void *baton, if (rb->rev > 0) { - svn_hash_sets(rb->revprop_table, - apr_pstrdup(rb->pool, name), - svn_string_dup(value, rb->pool)); + if (! svn_hash_gets(rb->pb->skip_revprops, name)) + svn_hash_sets(rb->revprop_table, + apr_pstrdup(rb->pool, name), + svn_string_dup(value, rb->pool)); } - else if (rb->rev_offset == -1) + else if (rb->rev_offset == -1 + && ! svn_hash_gets(rb->pb->skip_revprops, name)) { /* Special case: set revision 0 properties directly (which is safe because the commit_editor hasn't been created yet), but @@ -925,51 +755,30 @@ set_node_property(void *baton, const svn_string_t *value) { struct node_baton *nb = baton; + struct revision_baton *rb = nb->rb; + struct parse_baton *pb = rb->pb; apr_pool_t *pool = nb->rb->pool; svn_prop_t *prop; if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0) { - svn_string_t *renumbered_mergeinfo; - svn_string_t prop_val; - - /* Tolerate mergeinfo with "\r\n" line endings because some - dumpstream sources might contain as much. If so normalize - the line endings to '\n' and make a notification to - PARSE_BATON->FEEDBACK_STREAM that we have made this - correction. */ - if (strstr(value->data, "\r")) + svn_string_t *new_value; + svn_error_t *err; + + err = svn_repos__adjust_mergeinfo_property(&new_value, value, + pb->parent_dir, + pb->rev_map, + pb->oldest_dumpstream_rev, + rb->rev_offset, + NULL, NULL, /*notify*/ + pool, pool); + if (err) { - const char *prop_eol_normalized; - - SVN_ERR(svn_subst_translate_cstring2(value->data, - &prop_eol_normalized, - "\n", /* translate to LF */ - FALSE, /* no repair */ - NULL, /* no keywords */ - FALSE, /* no expansion */ - pool)); - prop_val.data = prop_eol_normalized; - prop_val.len = strlen(prop_eol_normalized); - value = &prop_val; - - /* ### TODO: notify? */ + return svn_error_quick_wrap(err, + _("Invalid svn:mergeinfo value")); } - /* Renumber mergeinfo as appropriate. */ - SVN_ERR(renumber_mergeinfo_revs(&renumbered_mergeinfo, value, - nb->rb, pool)); - value = renumbered_mergeinfo; - - if (nb->rb->pb->parent_dir) - { - /* Prefix the merge source paths with PB->parent_dir. */ - /* ASSUMPTION: All source paths are included in the dump stream. */ - svn_string_t *mergeinfo_val; - SVN_ERR(prefix_mergeinfo_paths(&mergeinfo_val, value, - nb->rb->pb->parent_dir, pool)); - value = mergeinfo_val; - } + value = new_value; } SVN_ERR(svn_rdump__normalize_prop(name, &value, pool)); @@ -978,7 +787,7 @@ set_node_property(void *baton, prop = apr_palloc(nb->rb->pool, sizeof (*prop)); prop->name = apr_pstrdup(pool, name); - prop->value = value ? svn_string_dup(value, pool) : NULL; + prop->value = svn_string_dup(value, pool); svn_hash_sets(nb->prop_changes, prop->name, prop); return SVN_NO_ERROR; @@ -1024,7 +833,6 @@ remove_node_props(void *baton) /* Find the path and revision that has the node's original properties */ if (ARE_VALID_COPY_ARGS(nb->copyfrom_path, nb->copyfrom_rev)) { - LDR_DBG(("using nb->copyfrom %s@%ld", nb->copyfrom_path, nb->copyfrom_rev)); orig_path = nb->copyfrom_path; orig_rev = nb->copyfrom_rev; } @@ -1033,8 +841,6 @@ remove_node_props(void *baton) { /* If this is a dir, then it's described by rb->db; if this is a file, then it's a child of the dir in rb->db. */ - LDR_DBG(("using rb->db->copyfrom (k=%d) %s@%ld", - nb->kind, rb->db->copyfrom_path, rb->db->copyfrom_rev)); orig_path = (nb->kind == svn_node_dir) ? rb->db->copyfrom_path : svn_relpath_join(rb->db->copyfrom_path, @@ -1044,13 +850,11 @@ remove_node_props(void *baton) } else { - LDR_DBG(("using self.path@head %s@%ld", nb->path, SVN_INVALID_REVNUM)); /* ### Should we query at a known, fixed, "head" revision number instead of passing SVN_INVALID_REVNUM and getting a moving target? */ orig_path = nb->path; orig_rev = SVN_INVALID_REVNUM; } - LDR_DBG(("Trying %s@%ld", orig_path, orig_rev)); if ((nb->action == svn_node_action_add || nb->action == svn_node_action_replace) @@ -1071,7 +875,7 @@ remove_node_props(void *baton) for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi)) { - const char *name = svn__apr_hash_index_key(hi); + const char *name = apr_hash_this_key(hi); svn_prop_kind_t kind = svn_property_kind2(name); if (kind == svn_prop_regular_kind) @@ -1091,7 +895,6 @@ set_fulltext(svn_stream_t **stream, void *handler_baton; apr_pool_t *pool = nb->rb->pool; - LDR_DBG(("Setting fulltext for %p\n", nb->file_baton)); SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum, pool, &handler, &handler_baton)); *stream = svn_txdelta_target_push(handler, handler_baton, @@ -1108,7 +911,6 @@ apply_textdelta(svn_txdelta_window_handler_t *handler, const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor; apr_pool_t *pool = nb->rb->pool; - LDR_DBG(("Applying textdelta to %p\n", nb->file_baton)); SVN_ERR(commit_editor->apply_textdelta(nb->file_baton, nb->base_checksum, pool, handler, handler_baton)); @@ -1126,8 +928,8 @@ close_node(void *baton) for (hi = apr_hash_first(pool, nb->prop_changes); hi; hi = apr_hash_next(hi)) { - const char *name = svn__apr_hash_index_key(hi); - svn_prop_t *prop = svn__apr_hash_index_val(hi); + const char *name = apr_hash_this_key(hi); + svn_prop_t *prop = apr_hash_this_val(hi); switch (nb->kind) { @@ -1148,7 +950,6 @@ close_node(void *baton) deleted the file (which doesn't require us to open it). */ if ((nb->kind == svn_node_file) && (nb->file_baton)) { - LDR_DBG(("Closing file %p\n", nb->file_baton)); SVN_ERR(commit_editor->close_file(nb->file_baton, NULL, nb->rb->pool)); } @@ -1178,12 +979,10 @@ close_revision(void *baton) session itself */ while (rb->db && rb->db->parent) { - LDR_DBG(("Closing dir %p\n", rb->db->baton)); SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool)); rb->db = rb->db->parent; } /* root dir's baton */ - LDR_DBG(("Closing edit on %p\n", commit_edit_baton)); SVN_ERR(commit_editor->close_directory(rb->db->baton, rb->pool)); SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool)); } @@ -1201,8 +1000,6 @@ close_revision(void *baton) rb->rev - rb->rev_offset - 1, rb->pool, &child_baton)); - LDR_DBG(("Opened root %p\n", child_baton)); - LDR_DBG(("Closing edit on %p\n", commit_edit_baton)); SVN_ERR(commit_editor->close_directory(child_baton, rb->pool)); SVN_ERR(commit_editor->close_edit(commit_edit_baton, rb->pool)); } @@ -1222,16 +1019,22 @@ close_revision(void *baton) if (SVN_IS_VALID_REVNUM(committed_rev)) { - SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_DATE, - rb->datestamp, rb->pool)); - SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev, - SVN_PROP_REVISION_DATE, - NULL, rb->datestamp, rb->pool)); - SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_AUTHOR, - rb->author, rb->pool)); - SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev, - SVN_PROP_REVISION_AUTHOR, - NULL, rb->author, rb->pool)); + if (!svn_hash_gets(rb->pb->skip_revprops, SVN_PROP_REVISION_DATE)) + { + SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_DATE, + rb->datestamp, rb->pool)); + SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev, + SVN_PROP_REVISION_DATE, + NULL, rb->datestamp, rb->pool)); + } + if (!svn_hash_gets(rb->pb->skip_revprops, SVN_PROP_REVISION_AUTHOR)) + { + SVN_ERR(svn_repos__validate_prop(SVN_PROP_REVISION_AUTHOR, + rb->author, rb->pool)); + SVN_ERR(svn_ra_change_rev_prop2(rb->pb->session, committed_rev, + SVN_PROP_REVISION_AUTHOR, + NULL, rb->author, rb->pool)); + } } svn_pool_destroy(rb->pool); @@ -1244,6 +1047,7 @@ svn_rdump__load_dumpstream(svn_stream_t *stream, svn_ra_session_t *session, svn_ra_session_t *aux_session, svn_boolean_t quiet, + apr_hash_t *skip_revprops, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *pool) @@ -1287,6 +1091,7 @@ svn_rdump__load_dumpstream(svn_stream_t *stream, parse_baton->rev_map = apr_hash_make(pool); parse_baton->last_rev_mapped = SVN_INVALID_REVNUM; parse_baton->oldest_dumpstream_rev = SVN_INVALID_REVNUM; + parse_baton->skip_revprops = skip_revprops; err = svn_repos_parse_dumpstream3(stream, parser, parse_baton, FALSE, cancel_func, cancel_baton, pool); |