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/libsvn_fs_base/tree.c | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/libsvn_fs_base/tree.c')
-rw-r--r-- | subversion/libsvn_fs_base/tree.c | 177 |
1 files changed, 153 insertions, 24 deletions
diff --git a/subversion/libsvn_fs_base/tree.c b/subversion/libsvn_fs_base/tree.c index 046ab5d..924e7c9 100644 --- a/subversion/libsvn_fs_base/tree.c +++ b/subversion/libsvn_fs_base/tree.c @@ -543,7 +543,7 @@ get_copy_inheritance(copy_id_inherit_t *inherit_p, parent_copy_id = svn_fs_base__id_copy_id(parent_id); /* Easy out: if this child is already mutable, we have nothing to do. */ - if (svn_fs_base__key_compare(svn_fs_base__id_txn_id(child_id), txn_id) == 0) + if (strcmp(svn_fs_base__id_txn_id(child_id), txn_id) == 0) return SVN_NO_ERROR; /* If the child and its parent are on the same branch, then the @@ -560,7 +560,7 @@ get_copy_inheritance(copy_id_inherit_t *inherit_p, target of any copy, and therefore must be on the same branch as its parent. */ if ((strcmp(child_copy_id, "0") == 0) - || (svn_fs_base__key_compare(child_copy_id, parent_copy_id) == 0)) + || (strcmp(child_copy_id, parent_copy_id) == 0)) { *inherit_p = copy_id_inherit_parent; return SVN_NO_ERROR; @@ -569,7 +569,8 @@ get_copy_inheritance(copy_id_inherit_t *inherit_p, { copy_t *copy; SVN_ERR(svn_fs_bdb__get_copy(©, fs, child_copy_id, trail, pool)); - if (svn_fs_base__id_compare(copy->dst_noderev_id, child_id) == -1) + if ( svn_fs_base__id_compare(copy->dst_noderev_id, child_id) + == svn_fs_node_unrelated) { *inherit_p = copy_id_inherit_parent; return SVN_NO_ERROR; @@ -1027,6 +1028,30 @@ base_node_id(const svn_fs_id_t **id_p, return SVN_NO_ERROR; } +static svn_error_t * +base_node_relation(svn_fs_node_relation_t *relation, + svn_fs_root_t *root_a, const char *path_a, + svn_fs_root_t *root_b, const char *path_b, + apr_pool_t *pool) +{ + const svn_fs_id_t *id_a, *id_b; + + /* Paths from different repository are never related. */ + if (root_a->fs != root_b->fs) + { + *relation = svn_fs_node_unrelated; + return SVN_NO_ERROR; + } + + /* Naive implementation. */ + SVN_ERR(base_node_id(&id_a, root_a, path_a, pool)); + SVN_ERR(base_node_id(&id_b, root_b, path_b, pool)); + + *relation = svn_fs_base__id_compare(id_a, id_b); + + return SVN_NO_ERROR; +} + struct node_created_rev_args { svn_revnum_t revision; @@ -1212,7 +1237,7 @@ base_node_prop(svn_string_t **value_p, args.propname = propname; SVN_ERR(svn_fs_base__retry_txn(root->fs, txn_body_node_prop, &args, FALSE, scratch_pool)); - *value_p = value ? svn_string_dup(value, pool) : NULL; + *value_p = svn_string_dup(value, pool); svn_pool_destroy(scratch_pool); return SVN_NO_ERROR; } @@ -1260,6 +1285,21 @@ base_node_proplist(apr_hash_t **table_p, return SVN_NO_ERROR; } +static svn_error_t * +base_node_has_props(svn_boolean_t *has_props, + svn_fs_root_t *root, + const char *path, + apr_pool_t *scratch_pool) +{ + apr_hash_t *props; + + SVN_ERR(base_node_proplist(&props, root, path, scratch_pool)); + + *has_props = (0 < apr_hash_count(props)); + + return SVN_NO_ERROR; +} + struct change_node_prop_args { svn_fs_root_t *root; @@ -1369,6 +1409,7 @@ struct things_changed_args svn_fs_root_t *root2; const char *path1; const char *path2; + svn_boolean_t strict; apr_pool_t *pool; }; @@ -1378,11 +1419,26 @@ txn_body_props_changed(void *baton, trail_t *trail) { struct things_changed_args *args = baton; dag_node_t *node1, *node2; + apr_hash_t *proplist1, *proplist2; SVN_ERR(get_dag(&node1, args->root1, args->path1, trail, trail->pool)); SVN_ERR(get_dag(&node2, args->root2, args->path2, trail, trail->pool)); - return svn_fs_base__things_different(args->changed_p, NULL, - node1, node2, trail, trail->pool); + SVN_ERR(svn_fs_base__things_different(args->changed_p, NULL, + node1, node2, trail, trail->pool)); + + /* Is there a potential false positive and do we want to correct it? */ + if (!args->strict || !*args->changed_p) + return SVN_NO_ERROR; + + /* Different representations. They might still have equal contents. */ + SVN_ERR(svn_fs_base__dag_get_proplist(&proplist1, node1, + trail, trail->pool)); + SVN_ERR(svn_fs_base__dag_get_proplist(&proplist2, node2, + trail, trail->pool)); + + *args->changed_p = !svn_fs__prop_lists_equal(proplist1, proplist2, + trail->pool); + return SVN_NO_ERROR; } @@ -1392,6 +1448,7 @@ base_props_changed(svn_boolean_t *changed_p, const char *path1, svn_fs_root_t *root2, const char *path2, + svn_boolean_t strict, apr_pool_t *pool) { struct things_changed_args args; @@ -1408,6 +1465,7 @@ base_props_changed(svn_boolean_t *changed_p, args.path2 = path2; args.changed_p = changed_p; args.pool = pool; + args.strict = strict; return svn_fs_base__retry_txn(root1->fs, txn_body_props_changed, &args, TRUE, pool); @@ -1561,6 +1619,25 @@ base_dir_entries(apr_hash_t **table_p, return SVN_NO_ERROR; } +static svn_error_t * +base_dir_optimal_order(apr_array_header_t **ordered_p, + svn_fs_root_t *root, + apr_hash_t *entries, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + /* 1:1 copy of entries with no differnce in ordering */ + apr_hash_index_t *hi; + apr_array_header_t *result + = apr_array_make(result_pool, apr_hash_count(entries), + sizeof(svn_fs_dirent_t *)); + for (hi = apr_hash_first(scratch_pool, entries); hi; hi = apr_hash_next(hi)) + APR_ARRAY_PUSH(result, svn_fs_dirent_t *) = apr_hash_this_val(hi); + + *ordered_p = result; + return SVN_NO_ERROR; +} + /* Merges and commits. */ @@ -3104,7 +3181,8 @@ txn_body_copy(void *baton, if ((to_parent_path->node) && (svn_fs_base__id_compare(svn_fs_base__dag_get_id(from_node), svn_fs_base__dag_get_id - (to_parent_path->node)) == 0)) + (to_parent_path->node)) + == svn_fs_node_unchanged)) return SVN_NO_ERROR; if (! from_root->is_txn_root) @@ -3292,8 +3370,8 @@ txn_body_copied_from(void *baton, trail_t *trail) return SVN_NO_ERROR; /* If NODE's copy-ID is the same as that of its predecessor... */ - if (svn_fs_base__key_compare(svn_fs_base__id_copy_id(node_id), - svn_fs_base__id_copy_id(pred_id)) != 0) + if (strcmp(svn_fs_base__id_copy_id(node_id), + svn_fs_base__id_copy_id(pred_id)) != 0) { /* ... then NODE was either the target of a copy operation, a copied subtree item. We examine the actual copy record @@ -3942,11 +4020,53 @@ txn_body_contents_changed(void *baton, trail_t *trail) { struct things_changed_args *args = baton; dag_node_t *node1, *node2; + svn_checksum_t *checksum1, *checksum2; + svn_stream_t *stream1, *stream2; + svn_boolean_t same; SVN_ERR(get_dag(&node1, args->root1, args->path1, trail, trail->pool)); SVN_ERR(get_dag(&node2, args->root2, args->path2, trail, trail->pool)); - return svn_fs_base__things_different(NULL, args->changed_p, - node1, node2, trail, trail->pool); + SVN_ERR(svn_fs_base__things_different(NULL, args->changed_p, + node1, node2, trail, trail->pool)); + + /* Is there a potential false positive and do we want to correct it? */ + if (!args->strict || !*args->changed_p) + return SVN_NO_ERROR; + + /* Different representations. They might still have equal contents. */ + + /* Compare MD5 checksums. These should be readily accessible. */ + SVN_ERR(svn_fs_base__dag_file_checksum(&checksum1, svn_checksum_md5, + node1, trail, trail->pool)); + SVN_ERR(svn_fs_base__dag_file_checksum(&checksum2, svn_checksum_md5, + node2, trail, trail->pool)); + + /* Different MD5 checksums -> different contents */ + if (!svn_checksum_match(checksum1, checksum2)) + return SVN_NO_ERROR; + + /* Paranoia. Compare SHA1 checksums because that's the level of + confidence we require for e.g. the working copy. */ + SVN_ERR(svn_fs_base__dag_file_checksum(&checksum1, svn_checksum_sha1, + node1, trail, trail->pool)); + SVN_ERR(svn_fs_base__dag_file_checksum(&checksum2, svn_checksum_sha1, + node2, trail, trail->pool)); + + /* Different SHA1 checksums -> different contents */ + if (checksum1 && checksum2) + { + *args->changed_p = !svn_checksum_match(checksum1, checksum2); + return SVN_NO_ERROR; + } + + /* SHA1 checksums are not available for very old reps / repositories. */ + SVN_ERR(svn_fs_base__dag_get_contents(&stream1, node1, trail, trail->pool)); + SVN_ERR(svn_fs_base__dag_get_contents(&stream2, node2, trail, trail->pool)); + SVN_ERR(svn_stream_contents_same2(&same, stream1, stream2, trail->pool)); + + /* Now, it's definitive. */ + *args->changed_p = !same; + return SVN_NO_ERROR; } @@ -3958,6 +4078,7 @@ base_contents_changed(svn_boolean_t *changed_p, const char *path1, svn_fs_root_t *root2, const char *path2, + svn_boolean_t strict, apr_pool_t *pool) { struct things_changed_args args; @@ -3989,6 +4110,7 @@ base_contents_changed(svn_boolean_t *changed_p, args.path2 = path2; args.changed_p = changed_p; args.pool = pool; + args.strict = strict; return svn_fs_base__retry_txn(root1->fs, txn_body_contents_changed, &args, TRUE, pool); @@ -4108,7 +4230,8 @@ static svn_error_t * base_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root, const char *path, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_node_kind_t kind; @@ -4117,15 +4240,16 @@ base_node_history(svn_fs_history_t **history_p, return svn_error_create(SVN_ERR_FS_NOT_REVISION_ROOT, NULL, NULL); /* And we require that the path exist in the root. */ - SVN_ERR(base_check_path(&kind, root, path, pool)); + SVN_ERR(base_check_path(&kind, root, path, scratch_pool)); if (kind == svn_node_none) return SVN_FS__NOT_FOUND(root, path); /* Okay, all seems well. Build our history object and return it. */ *history_p = assemble_history(root->fs, - svn_fs__canonicalize_abspath(path, pool), + svn_fs__canonicalize_abspath(path, + result_pool), root->rev, FALSE, NULL, - SVN_INVALID_REVNUM, pool); + SVN_INVALID_REVNUM, result_pool); return SVN_NO_ERROR; } @@ -4298,8 +4422,7 @@ txn_body_history_prev(void *baton, trail_t *trail) (which is either a real predecessor, or is the node itself playing the predecessor role to an imaginary mutable successor), then we need to report a copy. */ - if (svn_fs_base__key_compare(svn_fs_base__id_copy_id(node_id), - end_copy_id) != 0) + if (strcmp(svn_fs_base__id_copy_id(node_id), end_copy_id) != 0) { const char *remainder; dag_node_t *dst_node; @@ -4376,7 +4499,8 @@ static svn_error_t * base_history_prev(svn_fs_history_t **prev_history_p, svn_fs_history_t *history, svn_boolean_t cross_copies, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_fs_history_t *prev_history = NULL; base_history_data_t *bhd = history->fsap_data; @@ -4390,10 +4514,12 @@ base_history_prev(svn_fs_history_t **prev_history_p, { if (! bhd->is_interesting) prev_history = assemble_history(fs, "/", bhd->revision, - 1, NULL, SVN_INVALID_REVNUM, pool); + 1, NULL, SVN_INVALID_REVNUM, + result_pool); else if (bhd->revision > 0) prev_history = assemble_history(fs, "/", bhd->revision - 1, - 1, NULL, SVN_INVALID_REVNUM, pool); + 1, NULL, SVN_INVALID_REVNUM, + result_pool); } else { @@ -4407,9 +4533,9 @@ base_history_prev(svn_fs_history_t **prev_history_p, args.prev_history_p = &prev_history; args.history = prev_history; args.cross_copies = cross_copies; - args.pool = pool; + args.pool = result_pool; SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_history_prev, &args, - FALSE, pool)); + FALSE, result_pool)); if (! prev_history) break; bhd = prev_history->fsap_data; @@ -5370,20 +5496,23 @@ static root_vtable_t root_vtable = { base_check_path, base_node_history, base_node_id, + base_node_relation, base_node_created_rev, base_node_origin_rev, base_node_created_path, base_delete_node, + base_copy, + base_revision_link, base_copied_from, base_closest_copy, base_node_prop, base_node_proplist, + base_node_has_props, base_change_node_prop, base_props_changed, base_dir_entries, + base_dir_optimal_order, base_make_dir, - base_copy, - base_revision_link, base_file_length, base_file_checksum, base_file_contents, |