diff options
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 c35a28965933..15dac6e98f18 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);  | 
