Index: subversion/libsvn_repos/delta.c =================================================================== --- subversion/libsvn_repos/delta.c (revision 7545) +++ subversion/libsvn_repos/delta.c (working copy) @@ -155,7 +155,99 @@ role, path ? path : "(null)"); } +static svn_error_t * +get_node_id_with_history (svn_fs_root_t *root, + svn_fs_root_t *other_root, + const char *node_fullpath, + const svn_fs_id_t **node_id, + svn_node_kind_t *node_kind_target, + svn_fs_root_t **out_root, + const char **out_fullpath, + apr_pool_t *pool) +{ + svn_fs_history_t * history_p; + svn_error_t * error; + svn_node_kind_t node_kind; + svn_fs_root_t *root_to_use; + const char * fullpath; + + SVN_ERR (svn_fs_check_path (&node_kind, root, node_fullpath, pool)); + if (node_kind == svn_node_none && + svn_fs_is_revision_root(other_root)) + { + const char *path; + svn_revnum_t revision; + svn_revnum_t node_root_revision; + svn_node_kind_t other_root_node_kind; + + /* Search for this revision in the history of this path in the other + * root. But first - check that it exists in the first place. */ + history_p = NULL; + + SVN_ERR (svn_fs_check_path (&other_root_node_kind, other_root, + node_fullpath, pool)); + + if (other_root_node_kind != svn_node_none) + { + SVN_ERR (svn_fs_node_history (&history_p, other_root, + node_fullpath, pool)); + + node_root_revision = svn_fs_revision_root_revision (root); + SVN_ERR (svn_fs_history_location (&path, &revision, history_p, pool)); + while (revision > node_root_revision) + { + SVN_ERR (svn_fs_history_prev (&history_p, history_p, TRUE, + pool)); + if (history_p == NULL) + { + break; + } + SVN_ERR (svn_fs_history_location (&path, &revision, history_p, pool)); + } + fullpath = path; + if (history_p) + { + + SVN_ERR (svn_fs_revision_root (&root_to_use, + svn_fs_root_fs(root), + node_root_revision, + pool)); + + SVN_ERR (svn_fs_check_path (&node_kind, root_to_use, fullpath, pool)); + } + } + + if (! history_p) + { +#if 0 + return svn_error_create (SVN_ERR_FS_PATH_SYNTAX, 0, + "get_node_id_with_history: node could not be found"); +#else + root_to_use = root; + node_kind = svn_node_none; +#endif + } + } + else + { + root_to_use = root; + fullpath = node_fullpath; + } + + if (node_kind != svn_node_none) + { + SVN_ERR (svn_fs_node_id (node_id, root_to_use, fullpath, pool)); + } + + *node_kind_target = node_kind; + *out_root = root_to_use; + *out_fullpath = fullpath; + + return SVN_NO_ERROR; +} + + /* Public interface to computing directory deltas. */ svn_error_t * svn_repos_dir_delta (svn_fs_root_t *src_root, @@ -178,6 +270,9 @@ svn_node_kind_t src_kind, tgt_kind; svn_revnum_t rootrev; int distance; + svn_fs_root_t *active_src_root, *active_tgt_root; + const char *active_src_fullpath; + const char *active_tgt_fullpath; /* SRC_PARENT_DIR must be valid. */ if (! src_parent_dir) @@ -198,10 +293,21 @@ NULL, which is fine). */ src_fullpath = svn_path_join_many (pool, src_parent_dir, src_entry, NULL); +#if 0 /* Get the node kinds for the source and target paths. */ SVN_ERR (svn_fs_check_path (&tgt_kind, tgt_root, tgt_fullpath, pool)); SVN_ERR (svn_fs_check_path (&src_kind, src_root, src_fullpath, pool)); +#endif + /* Get the node IDs for the source and target */ + SVN_ERR (get_node_id_with_history (tgt_root, src_root, tgt_fullpath, + &tgt_id, &tgt_kind, &active_tgt_root, + &active_tgt_fullpath, pool)); + SVN_ERR (get_node_id_with_history (src_root, tgt_root, src_fullpath, + &src_id, &src_kind, &active_src_root, + &active_src_fullpath, pool)); + + /* If neither of our paths exists, we don't really have anything to do. */ if ((tgt_kind == svn_node_none) && (src_kind == svn_node_none)) goto cleanup; @@ -216,15 +322,15 @@ "input paths is not a directory and there was no source entry"); /* Set the global target revision if one can be determined. */ - if (svn_fs_is_revision_root (tgt_root)) + if (svn_fs_is_revision_root (active_tgt_root)) { SVN_ERR (editor->set_target_revision - (edit_baton, svn_fs_revision_root_revision (tgt_root), pool)); + (edit_baton, svn_fs_revision_root_revision (active_tgt_root), pool)); } - else if (svn_fs_is_txn_root (tgt_root)) + else if (svn_fs_is_txn_root (active_tgt_root)) { - svn_fs_t *fs = svn_fs_root_fs (tgt_root); - const char *txn_name = svn_fs_txn_root_name (tgt_root, pool); + svn_fs_t *fs = svn_fs_root_fs (active_tgt_root); + const char *txn_name = svn_fs_txn_root_name (active_tgt_root, pool); svn_fs_txn_t *txn; SVN_ERR (svn_fs_open_txn (&txn, fs, txn_name, pool)); @@ -237,15 +343,15 @@ throughout the deltafication process, so pass them around by reference to all the helper functions. */ c.editor = editor; - c.source_root = src_root; - c.target_root = tgt_root; + c.source_root = active_src_root; + c.target_root = active_tgt_root; c.text_deltas = text_deltas; c.recurse = recurse; c.entry_props = entry_props; c.ignore_ancestry = ignore_ancestry; /* Get our editor root's revision. */ - rootrev = get_path_revision (src_root, src_parent_dir, pool); + rootrev = get_path_revision (active_src_root, src_parent_dir, pool); /* If one or the other of our paths doesn't exist, we have to handle those cases specially. */ @@ -262,14 +368,12 @@ /* The source path no longer exists, but the target does. So transform "nothing" into "something" by adding. */ SVN_ERR (editor->open_root (edit_baton, rootrev, pool, &root_baton)); - SVN_ERR (add_file_or_dir (&c, root_baton, tgt_fullpath, + SVN_ERR (add_file_or_dir (&c, root_baton, active_tgt_fullpath, src_entry, tgt_kind, pool)); goto cleanup; } - /* Get and compare the node IDs for the source and target. */ - SVN_ERR (svn_fs_node_id (&tgt_id, tgt_root, tgt_fullpath, pool)); - SVN_ERR (svn_fs_node_id (&src_id, src_root, src_fullpath, pool)); + /* Compare the node IDs for the source and target. */ distance = svn_fs_compare_ids (src_id, tgt_id); if (distance == 0) @@ -286,16 +390,16 @@ || ((distance == -1) && (! ignore_ancestry))) { SVN_ERR (editor->open_root (edit_baton, rootrev, pool, &root_baton)); - SVN_ERR (delete (&c, root_baton, src_fullpath, pool)); - SVN_ERR (add_file_or_dir (&c, root_baton, tgt_fullpath, + SVN_ERR (delete (&c, root_baton, active_src_fullpath, pool)); + SVN_ERR (add_file_or_dir (&c, root_baton, active_tgt_fullpath, src_entry, tgt_kind, pool)); } /* Otherwise, we just replace the one with the other. */ else { SVN_ERR (editor->open_root (edit_baton, rootrev, pool, &root_baton)); - SVN_ERR (replace_file_or_dir (&c, root_baton, src_fullpath, - tgt_fullpath, src_entry, + SVN_ERR (replace_file_or_dir (&c, root_baton, active_src_fullpath, + active_tgt_fullpath, src_entry, tgt_kind, pool)); } } @@ -303,8 +407,8 @@ { /* There is no entry given, so delta the whole parent directory. */ SVN_ERR (editor->open_root (edit_baton, rootrev, pool, &root_baton)); - SVN_ERR (delta_dirs (&c, root_baton, src_fullpath, - tgt_fullpath, "", pool)); + SVN_ERR (delta_dirs (&c, root_baton, active_src_fullpath, + active_tgt_fullpath, "", pool)); } cleanup: