summaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs_base/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs_base/tree.c')
-rw-r--r--subversion/libsvn_fs_base/tree.c177
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(&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,