Modified: subversion/branches/ev2-export/subversion/libsvn_wc/wc_db_update_move.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_wc/wc_db_update_move.c?rev=1436688&r1=1436687&r2=1436688&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_wc/wc_db_update_move.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_wc/wc_db_update_move.c Mon Jan 21 23:37:01 2013 @@ -21,7 +21,13 @@ * ==================================================================== */ -/* This editor is used during resolution of tree conflicts. +/* This file implements an editor and an edit driver which are used + * to resolve an "incoming edit, local move-away" tree conflict resulting + * from an update (or switch). + * + * Our goal is to be able to resolve this conflict such that the end + * result is just the same as if the user had run the update *before* + * the local move. * * When an update (or switch) produces incoming changes for a locally * moved-away subtree, it updates the base nodes of the moved-away tree @@ -40,9 +46,8 @@ * layer. The destination may have additional higher op-depths * representing adds, deletes, moves within the move destination. [2] * - * After the intial move an update, or this editor for trees that have - * been moved more than once, has modified the NODES in the move - * source, and introduced a tree-conflict since the source and + * After the intial move an update has modified the NODES in the move + * source and may have introduced a tree-conflict since the source and * destination trees are no longer equivalent. The source is a * different revision and may have text, property and tree changes * compared to the destination. The driver will compare the two NODES @@ -71,6 +76,8 @@ #define SVN_WC__I_AM_WC_DB +#include <assert.h> + #include "svn_checksum.h" #include "svn_dirent_uri.h" #include "svn_error.h" @@ -78,6 +85,7 @@ #include "svn_wc.h" #include "svn_props.h" #include "svn_pools.h" +#include "svn_sorts.h" #include "private/svn_skel.h" #include "private/svn_sqlite.h" @@ -115,6 +123,7 @@ struct tc_editor_baton { non-Ev2, depth-first, drive for this to make sense. */ const char *conflict_root_relpath; + svn_wc_operation_t operation; svn_wc_conflict_version_t *old_version; svn_wc_conflict_version_t *new_version; svn_wc_notify_func2_t notify_func; @@ -129,12 +138,15 @@ mark_tree_conflict(struct tc_editor_bato svn_node_kind_t new_kind, svn_wc_conflict_reason_t reason, svn_wc_conflict_action_t action, + svn_skel_t *conflict, apr_pool_t *scratch_pool) { const char *repos_relpath; - svn_skel_t *conflict = svn_wc__conflict_skel_create(scratch_pool); svn_wc_conflict_version_t *old_version, *new_version; + if (!conflict) + conflict = svn_wc__conflict_skel_create(scratch_pool); + b->conflict_root_relpath = apr_pstrdup(b->result_pool, local_relpath); SVN_ERR(svn_wc__conflict_skel_add_tree_conflict( @@ -173,10 +185,20 @@ mark_tree_conflict(struct tc_editor_bato new_kind, scratch_pool); - /* What about switch? */ - SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict, - old_version, new_version, - scratch_pool, scratch_pool)); + if (b->operation == svn_wc_operation_update) + { + SVN_ERR(svn_wc__conflict_skel_set_op_update( + conflict, old_version, new_version, + scratch_pool, scratch_pool)); + } + else + { + assert(b->operation == svn_wc_operation_switch); + SVN_ERR(svn_wc__conflict_skel_set_op_switch( + conflict, old_version, new_version, + scratch_pool, scratch_pool)); + } + SVN_ERR(svn_wc__db_mark_conflict_internal(b->wcroot, local_relpath, conflict, scratch_pool)); @@ -194,6 +216,7 @@ check_tree_conflict(svn_boolean_t *is_co struct tc_editor_baton *b, const char *local_relpath, svn_node_kind_t kind, + svn_wc_conflict_action_t action, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; @@ -240,7 +263,8 @@ check_tree_conflict(svn_boolean_t *is_co { conflict_root_relpath = svn_relpath_dirname(conflict_root_relpath, scratch_pool); - old_kind = svn_node_dir; + old_kind = kind = svn_node_dir; + action = svn_wc_conflict_action_edit; } SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, b->wcroot, @@ -248,8 +272,22 @@ check_tree_conflict(svn_boolean_t *is_co scratch_pool, scratch_pool)); if (conflict) - /* ### TODO: check this is the right sort of tree-conflict? */ - return SVN_NO_ERROR; + { + svn_error_t *err + = svn_wc__conflict_read_tree_conflict(NULL, NULL, + b->db, b->wcroot->abspath, + conflict, + scratch_pool, scratch_pool); + if (err && err->apr_err != SVN_ERR_WC_MISSING) + return err; + + if (!err) + /* Already a tree-conflict. */ + return SVN_NO_ERROR; + + /* Not a tree-conflict. */ + svn_error_clear(err); + } SVN_ERR(svn_wc__db_scan_deletion_internal(NULL, &moved_to_relpath, NULL, NULL, @@ -260,7 +298,7 @@ check_tree_conflict(svn_boolean_t *is_co (moved_to_relpath ? svn_wc_conflict_reason_moved_away : svn_wc_conflict_reason_deleted), - svn_wc_conflict_action_edit, + action, conflict, scratch_pool)); return SVN_NO_ERROR; } @@ -287,6 +325,7 @@ tc_editor_add_directory(void *baton, /* Check for NODES tree-conflict. */ SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath, svn_node_dir, + svn_wc_conflict_action_add, scratch_pool)); if (is_conflicted) return SVN_NO_ERROR; @@ -301,7 +340,7 @@ tc_editor_add_directory(void *baton, default: SVN_ERR(mark_tree_conflict(b, relpath, kind, svn_node_dir, svn_wc_conflict_reason_unversioned, - svn_wc_conflict_action_add, + svn_wc_conflict_action_add, NULL, scratch_pool)); break; @@ -342,6 +381,7 @@ tc_editor_add_file(void *baton, /* Check for NODES tree-conflict. */ SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath, svn_node_file, + svn_wc_conflict_action_add, scratch_pool)); if (is_conflicted) return SVN_NO_ERROR; @@ -354,7 +394,7 @@ tc_editor_add_file(void *baton, { SVN_ERR(mark_tree_conflict(b, relpath, kind, svn_node_file, svn_wc_conflict_reason_unversioned, - svn_wc_conflict_action_add, + svn_wc_conflict_action_add, NULL, scratch_pool)); return SVN_NO_ERROR; } @@ -413,6 +453,7 @@ create_conflict_markers(svn_skel_t **wor svn_wc__db_t *db, const char *repos_relpath, svn_skel_t *conflict_skel, + svn_wc_operation_t operation, const working_node_version_t *old_version, const working_node_version_t *new_version, apr_pool_t *result_pool, @@ -425,17 +466,27 @@ create_conflict_markers(svn_skel_t **wor old_version->location_and_kind, scratch_pool); original_version->path_in_repos = repos_relpath; original_version->node_kind = svn_node_file; /* ### ? */ - SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_skel, - original_version, - NULL /* ### derive from new_version & new kind? */, - scratch_pool, - scratch_pool)); + if (operation == svn_wc_operation_update) + { + SVN_ERR(svn_wc__conflict_skel_set_op_update( + conflict_skel, original_version, + NULL /* ### derive from new_version & new kind? */, + scratch_pool, scratch_pool)); + } + else + { + SVN_ERR(svn_wc__conflict_skel_set_op_switch( + conflict_skel, original_version, + NULL /* ### derive from new_version & new kind? */, + scratch_pool, scratch_pool)); + } + /* According to this func's doc string, it is "Currently only used for * property conflicts as text conflict markers are just in-wc files." */ SVN_ERR(svn_wc__conflict_create_markers(&work_item, db, local_abspath, conflict_skel, - scratch_pool, + result_pool, scratch_pool)); *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); @@ -504,6 +555,7 @@ tc_editor_alter_directory(void *baton, SVN_ERR_ASSERT(expected_move_dst_revision == b->old_version->peg_rev); SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath, svn_node_dir, + svn_wc_conflict_action_edit, scratch_pool)); if (is_conflicted) return SVN_NO_ERROR; @@ -546,7 +598,7 @@ tc_editor_alter_directory(void *baton, /* ### need to pass in the node kinds (before & after)? */ SVN_ERR(create_conflict_markers(b->work_items, dst_abspath, b->db, move_dst_repos_relpath, - conflict_skel, + conflict_skel, b->operation, &old_version, &new_version, b->result_pool, scratch_pool)); SVN_ERR(svn_wc__db_mark_conflict_internal(b->wcroot, dst_relpath, @@ -592,6 +644,7 @@ static svn_error_t * update_working_file(svn_skel_t **work_items, const char *local_relpath, const char *repos_relpath, + svn_wc_operation_t operation, const working_node_version_t *old_version, const working_node_version_t *new_version, svn_wc__db_wcroot_t *wcroot, @@ -611,23 +664,15 @@ update_working_file(svn_skel_t **work_it apr_array_header_t *propchanges; enum svn_wc_merge_outcome_t merge_outcome; svn_wc_notify_state_t prop_state, content_state; + svn_skel_t *work_item; + + *work_items = NULL; SVN_ERR(update_working_props(&prop_state, &conflict_skel, &propchanges, &actual_props, db, local_abspath, old_version, new_version, result_pool, scratch_pool)); - /* If there are any conflicts to be stored, convert them into work items - * too. */ - if (conflict_skel) - { - /* ### need to pass in the node kinds (before & after)? */ - SVN_ERR(create_conflict_markers(work_items, local_abspath, db, - repos_relpath, conflict_skel, - old_version, new_version, - result_pool, scratch_pool)); - } - /* * Run a 3-way merge to update the file, using the pre-update * pristine text as the merge base, the post-update pristine @@ -642,7 +687,7 @@ update_working_file(svn_skel_t **work_it db, wcroot->abspath, new_version->checksum, scratch_pool, scratch_pool)); - SVN_ERR(svn_wc__internal_merge(work_items, &conflict_skel, + SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel, &merge_outcome, db, old_pristine_abspath, new_pristine_abspath, @@ -657,6 +702,8 @@ update_working_file(svn_skel_t **work_it NULL, NULL, /* cancel_func + baton */ result_pool, scratch_pool)); + *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); + /* If there are any conflicts to be stored, convert them into work items * too. */ if (conflict_skel) @@ -664,7 +711,7 @@ update_working_file(svn_skel_t **work_it /* ### need to pass in the node kinds (before & after)? */ SVN_ERR(create_conflict_markers(work_items, local_abspath, db, repos_relpath, conflict_skel, - old_version, new_version, + operation, old_version, new_version, result_pool, scratch_pool)); SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath, conflict_skel, @@ -728,6 +775,7 @@ tc_editor_alter_file(void *baton, svn_boolean_t is_conflicted; SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath, svn_node_file, + svn_wc_conflict_action_edit, scratch_pool)); if (is_conflicted) return SVN_NO_ERROR; @@ -751,18 +799,17 @@ tc_editor_alter_file(void *baton, new_version.props = new_props ? new_props : old_version.props; /* Update file and prop contents if the update has changed them. */ - if (!svn_checksum_match(new_checksum, old_version.checksum) - /* ### || props have changed */) + if (!svn_checksum_match(new_checksum, old_version.checksum) || new_props) { - svn_skel_t *work_item; + svn_skel_t *work_items; - SVN_ERR(update_working_file(&work_item, dst_relpath, + SVN_ERR(update_working_file(&work_items, dst_relpath, move_dst_repos_relpath, - &old_version, &new_version, + b->operation, &old_version, &new_version, b->wcroot, b->db, b->notify_func, b->notify_baton, b->result_pool, scratch_pool)); - *b->work_items = svn_wc__wq_merge(*b->work_items, work_item, + *b->work_items = svn_wc__wq_merge(*b->work_items, work_items, b->result_pool); } @@ -789,6 +836,58 @@ tc_editor_delete(void *baton, struct tc_editor_baton *b = baton; svn_sqlite__stmt_t *stmt; int op_depth = relpath_depth(b->move_root_dst_relpath); + svn_boolean_t is_conflicted; + + /* Check before retracting delete to catch delete-delete conflicts. */ + SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath, svn_node_unknown, + svn_wc_conflict_action_delete, + scratch_pool)); + + if (!is_conflicted) + { + svn_boolean_t is_modified, is_all_deletes; + + SVN_ERR(svn_wc__node_has_local_mods(&is_modified, &is_all_deletes, b->db, + svn_dirent_join(b->wcroot->abspath, + relpath, + scratch_pool), + NULL, NULL, scratch_pool)); + if (is_modified) + { + /* No conflict means no NODES rows at the relpath op-depth + so it's easy to convert the modified tree into a copy. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb, + STMT_UPDATE_OP_DEPTH_RECURSIVE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isdd", b->wcroot->wc_id, relpath, + op_depth, relpath_depth(relpath))); + SVN_ERR(svn_sqlite__step_done(stmt)); + + SVN_ERR(mark_tree_conflict(b, relpath, + /* ### kinds? */ + svn_node_dir, svn_node_dir, + svn_wc_conflict_reason_edited, + svn_wc_conflict_action_delete, NULL, + scratch_pool)); + is_conflicted = TRUE; + } + else if (is_all_deletes) + { + SVN_ERR(mark_tree_conflict(b, relpath, + /* ### kinds? */ + svn_node_dir, svn_node_dir, + svn_wc_conflict_reason_deleted, + svn_wc_conflict_action_delete, NULL, + scratch_pool)); + + SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb, + STMT_DELETE_WORKING_OP_DEPTH_ABOVE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath, + op_depth)); + SVN_ERR(svn_sqlite__step_done(stmt)); + + is_conflicted = TRUE; + } + } /* Deleting the ROWS is valid so long as we update the parent before committing the transaction. */ @@ -801,7 +900,11 @@ tc_editor_delete(void *baton, SVN_ERR(svn_wc__db_retract_parent_delete(b->wcroot, relpath, op_depth, scratch_pool)); - /* ### TODO check for, and flag, tree conflict */ + if (is_conflicted) + return SVN_NO_ERROR; + + /* ### TODO delete working files/dirs */ + return SVN_NO_ERROR; } @@ -962,188 +1065,254 @@ get_tc_info(svn_wc_operation_t *operatio return SVN_NO_ERROR; } -/* ### Drive TC_EDITOR so as to ... - */ -static svn_error_t * -update_moved_away_file(svn_editor_t *tc_editor, - svn_boolean_t add, - const char *src_relpath, - const char *dst_relpath, - const char *move_root_dst_relpath, - svn_revnum_t move_root_dst_revision, - svn_wc__db_t *db, - svn_wc__db_wcroot_t *wcroot, - apr_pool_t *scratch_pool) -{ - svn_kind_t kind; - svn_stream_t *new_contents; - const svn_checksum_t *new_checksum; - apr_hash_t *new_props; - - /* Read post-update contents from the updated moved-away file and tell - * the editor to merge them into the moved-here file. */ - SVN_ERR(svn_wc__db_read_pristine_info(NULL, &kind, NULL, NULL, NULL, NULL, - &new_checksum, NULL, NULL, &new_props, - db, svn_dirent_join(wcroot->abspath, - src_relpath, - scratch_pool), - scratch_pool, scratch_pool)); - SVN_ERR(svn_wc__db_pristine_read(&new_contents, NULL, db, - wcroot->abspath, new_checksum, - scratch_pool, scratch_pool)); - - if (add) - /* FIXME: editor API violation: missing svn_editor_alter_directory. */ - SVN_ERR(svn_editor_add_file(tc_editor, dst_relpath, - new_checksum, new_contents, - apr_hash_make(scratch_pool), /* ### TODO props */ - move_root_dst_revision)); +/* Return *PROPS, *CHECKSUM, *CHILDREN and *KIND for LOCAL_RELPATH at + OP_DEPTH provided the row exists. Return *KIND of svn_kind_none if + the row does not exist. *CHILDREN is a sorted array of basenames of + type 'const char *', rather than a hash, to allow the driver to + process children in a defined order. */ +static svn_error_t * +get_info(apr_hash_t **props, + const svn_checksum_t **checksum, + apr_array_header_t **children, + svn_kind_t *kind, + const char *local_relpath, + int op_depth, + svn_wc__db_wcroot_t *wcroot, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_hash_t *hash_children; + apr_array_header_t *sorted_children; + svn_error_t *err; + int i; + + err = svn_wc__db_depth_get_info(NULL, kind, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, checksum, NULL, NULL, props, + wcroot, local_relpath, op_depth, + result_pool, scratch_pool); + if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) + { + svn_error_clear(err); + *kind = svn_kind_none; + } else - SVN_ERR(svn_editor_alter_file(tc_editor, dst_relpath, - move_root_dst_revision, - new_props, new_checksum, - new_contents)); + SVN_ERR(err); - SVN_ERR(svn_stream_close(new_contents)); + + SVN_ERR(svn_wc__db_get_children_op_depth(&hash_children, wcroot, + local_relpath, op_depth, + scratch_pool, scratch_pool)); + sorted_children = svn_sort__hash(hash_children, + svn_sort_compare_items_as_paths, + scratch_pool); + + *children = apr_array_make(result_pool, sorted_children->nelts, + sizeof(const char *)); + for (i = 0; i < sorted_children->nelts; ++i) + APR_ARRAY_PUSH(*children, const char *) + = apr_pstrdup(result_pool, APR_ARRAY_IDX(sorted_children, i, + svn_sort__item_t).key); + return SVN_NO_ERROR; } -/* ### Drive TC_EDITOR so as to ... - */ +/* Return TRUE if SRC_CHILDREN and DST_CHILDREN represent the same + children, FALSE otherwise. SRC_CHILDREN and DST_CHILDREN are + sorted arrays of basenames of type 'const char *'. */ +static svn_boolean_t +children_match(apr_array_header_t *src_children, + apr_array_header_t *dst_children) { int i; + + if (src_children->nelts != dst_children->nelts) + return FALSE; + + for(i = 0; i < src_children->nelts; ++i) + { + const char *src_child = + APR_ARRAY_IDX(src_children, i, const char *); + const char *dst_child = + APR_ARRAY_IDX(dst_children, i, const char *); + + if (strcmp(src_child, dst_child)) + return FALSE; + } + + return TRUE; +} + +/* Return TRUE if SRC_PROPS and DST_PROPS contain the same properties, + FALSE otherwise. SRC_PROPS and DST_PROPS are standard property + hashes. */ static svn_error_t * -update_moved_away_dir(svn_editor_t *tc_editor, - svn_boolean_t add, - apr_hash_t *children_hash, - const char *src_relpath, - const char *dst_relpath, - const char *move_root_dst_relpath, - svn_revnum_t move_root_dst_revision, - svn_wc__db_t *db, - svn_wc__db_wcroot_t *wcroot, - apr_pool_t *scratch_pool) +props_match(svn_boolean_t *match, + apr_hash_t *src_props, + apr_hash_t *dst_props, + apr_pool_t *scratch_pool) { - apr_array_header_t *new_children; - apr_hash_t *new_props; - const char *src_abspath = svn_dirent_join(wcroot->abspath, - src_relpath, - scratch_pool); - - SVN_ERR(svn_hash_keys(&new_children, children_hash, scratch_pool)); - - SVN_ERR(svn_wc__db_read_pristine_props(&new_props, db, src_abspath, - scratch_pool, scratch_pool)); - - /* This is a non-Ev2, depth-first, drive that calls add/alter on all - directories. */ - if (add) - SVN_ERR(svn_editor_add_directory(tc_editor, dst_relpath, - new_children, new_props, - move_root_dst_revision)); + if (!src_props && !dst_props) + *match = TRUE; + else if (!src_props || ! dst_props) + *match = FALSE; else - SVN_ERR(svn_editor_alter_directory(tc_editor, dst_relpath, - move_root_dst_revision, - new_children, new_props)); + { + apr_array_header_t *propdiffs; + SVN_ERR(svn_prop_diffs(&propdiffs, src_props, dst_props, scratch_pool)); + *match = propdiffs->nelts ? FALSE : TRUE; + } return SVN_NO_ERROR; } /* ### Drive TC_EDITOR so as to ... */ static svn_error_t * -update_moved_away_subtree(svn_editor_t *tc_editor, - svn_boolean_t add, - const char *src_relpath, - const char *dst_relpath, - int src_op_depth, - const char *move_root_dst_relpath, - svn_revnum_t move_root_dst_revision, - svn_wc__db_t *db, - svn_wc__db_wcroot_t *wcroot, - apr_pool_t *scratch_pool) +update_moved_away_node(svn_editor_t *tc_editor, + const char *src_relpath, + const char *dst_relpath, + int src_op_depth, + const char *move_root_dst_relpath, + svn_revnum_t move_root_dst_revision, + svn_wc__db_t *db, + svn_wc__db_wcroot_t *wcroot, + apr_pool_t *scratch_pool) { - apr_hash_t *src_children, *dst_children; - apr_pool_t *iterpool; - apr_hash_index_t *hi; + svn_kind_t src_kind, dst_kind; + const svn_checksum_t *src_checksum, *dst_checksum; + apr_hash_t *src_props, *dst_props; + apr_array_header_t *src_children, *dst_children; + int dst_op_depth = relpath_depth(move_root_dst_relpath); + + SVN_ERR(get_info(&src_props, &src_checksum, &src_children, &src_kind, + src_relpath, src_op_depth, + wcroot, scratch_pool, scratch_pool)); + + SVN_ERR(get_info(&dst_props, &dst_checksum, &dst_children, &dst_kind, + dst_relpath, dst_op_depth, + wcroot, scratch_pool, scratch_pool)); - SVN_ERR(svn_wc__db_get_children_op_depth(&src_children, wcroot, - src_relpath, src_op_depth, - scratch_pool, scratch_pool)); + if (src_kind == svn_kind_none + || (dst_kind != svn_kind_none && src_kind != dst_kind)) + { + SVN_ERR(svn_editor_delete(tc_editor, dst_relpath, + move_root_dst_revision)); + } + + if (src_kind != svn_kind_none && src_kind != dst_kind) + { + if (src_kind == svn_kind_file || src_kind == svn_kind_symlink) + { + svn_stream_t *contents; - SVN_ERR(update_moved_away_dir(tc_editor, add, src_children, - src_relpath, dst_relpath, - move_root_dst_relpath, - move_root_dst_revision, - db, wcroot, scratch_pool)); - - SVN_ERR(svn_wc__db_get_children_op_depth(&dst_children, wcroot, - dst_relpath, - relpath_depth(move_root_dst_relpath), + SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db, + wcroot->abspath, src_checksum, scratch_pool, scratch_pool)); - iterpool = svn_pool_create(scratch_pool); - for (hi = apr_hash_first(scratch_pool, src_children); - hi; - hi = apr_hash_next(hi)) - { - const char *src_name = svn__apr_hash_index_key(hi); - svn_kind_t *src_kind = svn__apr_hash_index_val(hi); - svn_kind_t *dst_kind = apr_hash_get(dst_children, src_name, - APR_HASH_KEY_STRING); - svn_boolean_t is_add = FALSE; - const char *child_src_relpath, *child_dst_relpath; - - svn_pool_clear(iterpool); - - child_src_relpath = svn_relpath_join(src_relpath, src_name, iterpool); - child_dst_relpath = svn_relpath_join(dst_relpath, src_name, iterpool); - - if (!dst_kind || (*src_kind != *dst_kind)) - { - is_add = TRUE; - if (dst_kind) - /* FIXME:editor API violation:missing svn_editor_alter_directory. */ - SVN_ERR(svn_editor_delete(tc_editor, child_dst_relpath, + SVN_ERR(svn_editor_add_file(tc_editor, dst_relpath, + src_checksum, contents, src_props, move_root_dst_revision)); } - - if (*src_kind == svn_kind_file || *src_kind == svn_kind_symlink) + else if (src_kind == svn_kind_dir) { - SVN_ERR(update_moved_away_file(tc_editor, is_add, - child_src_relpath, - child_dst_relpath, - move_root_dst_relpath, - move_root_dst_revision, - db, wcroot, iterpool)); + SVN_ERR(svn_editor_add_directory(tc_editor, dst_relpath, + src_children, src_props, + move_root_dst_revision)); } - else if (*src_kind == svn_kind_dir) + } + else if (src_kind != svn_kind_none) + { + svn_boolean_t match; + apr_hash_t *props; + + SVN_ERR(props_match(&match, src_props, dst_props, scratch_pool)); + props = match ? NULL: src_props; + + + if (src_kind == svn_kind_file || src_kind == svn_kind_symlink) { - SVN_ERR(update_moved_away_subtree(tc_editor, is_add, - child_src_relpath, - child_dst_relpath, - src_op_depth, - move_root_dst_relpath, - move_root_dst_revision, - db, wcroot, iterpool)); + svn_stream_t *contents; + + if (svn_checksum_match(src_checksum, dst_checksum)) + src_checksum = NULL; + + if (src_checksum) + SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db, + wcroot->abspath, src_checksum, + scratch_pool, scratch_pool)); + else + contents = NULL; + + if (props || src_checksum) + SVN_ERR(svn_editor_alter_file(tc_editor, dst_relpath, + move_root_dst_revision, + props, src_checksum, contents)); } - else - ; /* ### TODO */ + else if (src_kind == svn_kind_dir) + { + apr_array_header_t *children + = children_match(src_children, dst_children) ? NULL : src_children; - apr_hash_set(dst_children, src_name, APR_HASH_KEY_STRING, NULL); + if (props || children) + SVN_ERR(svn_editor_alter_directory(tc_editor, dst_relpath, + move_root_dst_revision, + children, props)); + } } - for (hi = apr_hash_first(scratch_pool, dst_children); - hi; - hi = apr_hash_next(hi)) + + if (src_kind == svn_kind_dir) { - const char *dst_name = svn__apr_hash_index_key(hi); - const char *child_dst_relpath; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + int i = 0, j = 0; - svn_pool_clear(iterpool); - child_dst_relpath = svn_relpath_join(dst_relpath, dst_name, iterpool); + while (i < src_children->nelts || j < dst_children->nelts) + { + const char *child_name; + const char *src_child_relpath, *dst_child_relpath; + svn_boolean_t src_only = FALSE, dst_only = FALSE; - SVN_ERR(svn_editor_delete(tc_editor, child_dst_relpath, - move_root_dst_revision)); + svn_pool_clear(iterpool); + if (i >= src_children->nelts) + { + dst_only = TRUE; + child_name = APR_ARRAY_IDX(dst_children, j, const char *); + } + else if (j >= dst_children->nelts) + { + src_only = TRUE; + child_name = APR_ARRAY_IDX(src_children, i, const char *); + } + else + { + const char *src_name = APR_ARRAY_IDX(src_children, i, + const char *); + const char *dst_name = APR_ARRAY_IDX(dst_children, j, + const char *); + int cmp = strcmp(src_name, dst_name); + + if (cmp > 0) + dst_only = TRUE; + else if (cmp < 0) + src_only = TRUE; + + child_name = dst_only ? dst_name : src_name; + } + + src_child_relpath = svn_relpath_join(src_relpath, child_name, + iterpool); + dst_child_relpath = svn_relpath_join(dst_relpath, child_name, + iterpool); + + SVN_ERR(update_moved_away_node(tc_editor, src_child_relpath, + dst_child_relpath, src_op_depth, + move_root_dst_relpath, + move_root_dst_revision, + db, wcroot, scratch_pool)); + + if (!dst_only) + ++i; + if (!src_only) + ++j; + } } - svn_pool_destroy(iterpool); return SVN_NO_ERROR; } @@ -1242,16 +1411,10 @@ drive_tree_conflict_editor(svn_editor_t /* We walk the move source (i.e. the post-update tree), comparing each node * with the equivalent node at the move destination and applying the update * to nodes at the move destination. */ - if (old_version->node_kind == svn_node_file) - SVN_ERR(update_moved_away_file(tc_editor, FALSE, src_relpath, dst_relpath, - dst_relpath, old_version->peg_rev, - db, wcroot, scratch_pool)); - else if (old_version->node_kind == svn_node_dir) - SVN_ERR(update_moved_away_subtree(tc_editor, FALSE, - src_relpath, dst_relpath, - src_op_depth, - dst_relpath, old_version->peg_rev, - db, wcroot, scratch_pool)); + SVN_ERR(update_moved_away_node(tc_editor, src_relpath, dst_relpath, + src_op_depth, + dst_relpath, old_version->peg_rev, + db, wcroot, scratch_pool)); SVN_ERR(svn_editor_complete(tc_editor)); @@ -1300,6 +1463,7 @@ update_moved_away_conflict_victim(svn_sk svn_dirent_join(wcroot->abspath, victim_relpath, scratch_pool), scratch_pool)); + tc_editor_baton->operation = operation; tc_editor_baton->old_version= old_version; tc_editor_baton->new_version= new_version; tc_editor_baton->db = db;
Modified: subversion/branches/ev2-export/subversion/libsvn_wc/workqueue.c URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_wc/workqueue.c?rev=1436688&r1=1436687&r2=1436688&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/libsvn_wc/workqueue.c (original) +++ subversion/branches/ev2-export/subversion/libsvn_wc/workqueue.c Mon Jan 21 23:37:01 2013 @@ -155,7 +155,10 @@ run_base_remove(svn_wc__db_t *db, } } - SVN_ERR(svn_wc__db_base_remove(db, local_abspath, FALSE, not_present_rev, + SVN_ERR(svn_wc__db_base_remove(db, local_abspath, + FALSE /* keep_as_working */, + TRUE /* queue_deletes */, + not_present_rev, NULL, NULL, scratch_pool)); return SVN_NO_ERROR; @@ -1476,10 +1479,7 @@ dispatch_work_item(svn_wc__db_t *db, Contrary to issue #1581, we cannot simply remove work items and continue, so bail out with an error. */ return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, NULL, - _("Unrecognized work item in the queue " - "associated with '%s'"), - svn_dirent_local_style(wri_abspath, - scratch_pool)); + _("Unrecognized work item in the queue")); } return SVN_NO_ERROR; @@ -1511,6 +1511,7 @@ svn_wc__wq_run(svn_wc__db_t *db, { apr_uint64_t id; svn_skel_t *work_item; + svn_error_t *err; svn_pool_clear(iterpool); @@ -1530,8 +1531,20 @@ svn_wc__wq_run(svn_wc__db_t *db, we're done. */ if (work_item == NULL) break; - SVN_ERR(dispatch_work_item(db, wri_abspath, work_item, - cancel_func, cancel_baton, iterpool)); + + err = dispatch_work_item(db, wri_abspath, work_item, + cancel_func, cancel_baton, iterpool); + if (err) + { + const char *skel = svn_skel__unparse(work_item, scratch_pool)->data; + + return svn_error_createf(SVN_ERR_WC_BAD_ADM_LOG, err, + _("Failed to run the WC DB work queue " + "associated with '%s', work item %d %s"), + svn_dirent_local_style(wri_abspath, + scratch_pool), + (int)id, skel); + } /* The work item finished without error. Mark it completed in the next loop. */ Modified: subversion/branches/ev2-export/subversion/mod_authz_svn/INSTALL URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/mod_authz_svn/INSTALL?rev=1436688&r1=1436687&r2=1436688&view=diff ============================================================================== --- subversion/branches/ev2-export/subversion/mod_authz_svn/INSTALL (original) +++ subversion/branches/ev2-export/subversion/mod_authz_svn/INSTALL Mon Jan 21 23:37:01 2013 @@ -56,6 +56,12 @@ II. Configuration Satisfy Any Require valid-user </Location> + + NOTE: The access control is designed to never display entries that + the user does not have access to. Combining anonymous access on the + top levels while restricting read access lower in the directory + structure makes it difficult to browse because the server will not + request authentication. C. Example 3: Authenticated access only @@ -123,7 +129,7 @@ II. Configuration restrict access to this authz file and it is in the same repository you should include a rule for it. - F. Example 5: Authz file stored inside the repository being accessed. + F. Example 6: Authz file stored inside the repository being accessed. This configuration allows providing a relative path within the repository being accessed. @@ -144,6 +150,43 @@ II. Configuration NOTE: You should include rules in your authz file to restirct access to the authz file as desired. + G. Example 7: Authenticated access to "Collection of Repositories" + + The "Collection of Repositories" is filtered based on read access to + the root of each repository, i.e. consistent with the directory lists + within repositories. If read access is restricted in repository roots, + it is typically desirable to require authentication for "Collection of + Repositories" in order to ensure that repositories where the user has + access are displayed. + + This is accomplished by specifying "Satisfy All" (which is the default + setting): + + <Location /svn> + DAV svn + SVNParentPath /path/to/reposparent + + AuthType Basic + AuthName "Subversion repository" + AuthUserFile /path/to/htpasswd/file + + AuthzSVNAccessFile /path/to/access/file + # Implicit Satisfy All + Require valid-user + </Location> + + If the same server must be able to serve paths with anonymous access, + it can be defined using an additional location. + + <LocationMatch "^/svn/.+"> + Satisfy Any + Require valid-user + </LocationMatch> + + The "Require" statement in the previous example is not strictly + needed, but has been included for clarity. + + 2. Specifying permissions The file format of the access file looks like this:
