diff options
Diffstat (limited to 'subversion/libsvn_delta/element.c')
-rw-r--r-- | subversion/libsvn_delta/element.c | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/subversion/libsvn_delta/element.c b/subversion/libsvn_delta/element.c new file mode 100644 index 0000000000000..be7b2171b9b46 --- /dev/null +++ b/subversion/libsvn_delta/element.c @@ -0,0 +1,471 @@ +/* + * element.c : editing trees of versioned resources + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include <assert.h> +#include <apr_pools.h> + +#include "svn_types.h" +#include "svn_error.h" +#include "svn_string.h" +#include "svn_props.h" +#include "svn_dirent_uri.h" +#include "svn_iter.h" +#include "private/svn_sorts_private.h" + +#include "private/svn_element.h" +#include "svn_private_config.h" + + +void * +svn_eid__hash_get(apr_hash_t *ht, + int key) +{ + return apr_hash_get(ht, &key, sizeof(key)); +} + +void +svn_eid__hash_set(apr_hash_t *ht, + int key, + const void *val) +{ + int *id_p = apr_pmemdup(apr_hash_pool_get(ht), &key, sizeof(key)); + + apr_hash_set(ht, id_p, sizeof(key), val); +} + +int +svn_eid__hash_this_key(apr_hash_index_t *hi) +{ + return *(const int *)apr_hash_this_key(hi); +} + +svn_eid__hash_iter_t * +svn_eid__hash_sorted_first(apr_pool_t *pool, + apr_hash_t *ht, + int (*comparison_func)(const svn_sort__item_t *, + const svn_sort__item_t *)) +{ + svn_eid__hash_iter_t *hi = apr_palloc(pool, sizeof(*hi)); + + if (apr_hash_count(ht) == 0) + return NULL; + + hi->array = svn_sort__hash(ht, comparison_func, pool); + hi->i = 0; + hi->eid = *(const int *)(APR_ARRAY_IDX(hi->array, hi->i, + svn_sort__item_t).key); + hi->val = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).value; + return hi; +} + +svn_eid__hash_iter_t * +svn_eid__hash_sorted_next(svn_eid__hash_iter_t *hi) +{ + hi->i++; + if (hi->i >= hi->array->nelts) + { + return NULL; + } + hi->eid = *(const int *)(APR_ARRAY_IDX(hi->array, hi->i, + svn_sort__item_t).key); + hi->val = APR_ARRAY_IDX(hi->array, hi->i, svn_sort__item_t).value; + return hi; +} + +int +svn_eid__hash_sort_compare_items_by_eid(const svn_sort__item_t *a, + const svn_sort__item_t *b) +{ + int eid_a = *(const int *)a->key; + int eid_b = *(const int *)b->key; + + return eid_a - eid_b; +} + + +/* + * =================================================================== + * Element payload + * =================================================================== + */ + +svn_boolean_t +svn_element__payload_invariants(const svn_element__payload_t *payload) +{ + if (payload->is_subbranch_root) + return TRUE; + + /* If kind is unknown, it's a reference; otherwise it has content + specified and may also have a reference. */ + if (payload->kind == svn_node_unknown) + if (SVN_IS_VALID_REVNUM(payload->branch_ref.rev) + && payload->branch_ref.branch_id + && payload->branch_ref.eid != -1) + return TRUE; + if ((payload->kind == svn_node_dir + || payload->kind == svn_node_file + || payload->kind == svn_node_symlink) + && (payload->props + && ((payload->kind == svn_node_file) == !!payload->text) + && ((payload->kind == svn_node_symlink) == !!payload->target))) + return TRUE; + return FALSE; +} + +svn_element__payload_t * +svn_element__payload_dup(const svn_element__payload_t *old, + apr_pool_t *result_pool) +{ + svn_element__payload_t *new_payload; + + assert(! old || svn_element__payload_invariants(old)); + + if (old == NULL) + return NULL; + + new_payload = apr_pmemdup(result_pool, old, sizeof(*new_payload)); + if (old->branch_ref.branch_id) + new_payload->branch_ref.branch_id + = apr_pstrdup(result_pool, old->branch_ref.branch_id); + if (old->props) + new_payload->props = svn_prop_hash_dup(old->props, result_pool); + if (old->kind == svn_node_file && old->text) + new_payload->text = svn_stringbuf_dup(old->text, result_pool); + if (old->kind == svn_node_symlink && old->target) + new_payload->target = apr_pstrdup(result_pool, old->target); + return new_payload; +} + +svn_boolean_t +svn_element__payload_equal(const svn_element__payload_t *left, + const svn_element__payload_t *right, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *prop_diffs; + + assert(svn_element__payload_invariants(left)); + assert(svn_element__payload_invariants(right)); + + /* any two subbranch-root elements compare equal */ + if (left->is_subbranch_root && right->is_subbranch_root) + { + return TRUE; + } + else if (left->is_subbranch_root || right->is_subbranch_root) + { + return FALSE; + } + + /* content defined only by reference is not supported */ + SVN_ERR_ASSERT_NO_RETURN(left->kind != svn_node_unknown + && right->kind != svn_node_unknown); + + if (left->kind != right->kind) + { + return FALSE; + } + + svn_error_clear(svn_prop_diffs(&prop_diffs, + left->props, right->props, + scratch_pool)); + + if (prop_diffs->nelts != 0) + { + return FALSE; + } + switch (left->kind) + { + case svn_node_dir: + break; + case svn_node_file: + if (! svn_stringbuf_compare(left->text, right->text)) + { + return FALSE; + } + break; + case svn_node_symlink: + if (strcmp(left->target, right->target) != 0) + { + return FALSE; + } + break; + default: + break; + } + + return TRUE; +} + +svn_element__payload_t * +svn_element__payload_create_subbranch(apr_pool_t *result_pool) +{ + svn_element__payload_t *new_payload + = apr_pcalloc(result_pool, sizeof(*new_payload)); + + new_payload->pool = result_pool; + new_payload->is_subbranch_root = TRUE; + assert(svn_element__payload_invariants(new_payload)); + return new_payload; +} + +svn_element__payload_t * +svn_element__payload_create_ref(svn_revnum_t rev, + const char *branch_id, + int eid, + apr_pool_t *result_pool) +{ + svn_element__payload_t *new_payload + = apr_pcalloc(result_pool, sizeof(*new_payload)); + + new_payload->pool = result_pool; + new_payload->kind = svn_node_unknown; + new_payload->branch_ref.rev = rev; + new_payload->branch_ref.branch_id = apr_pstrdup(result_pool, branch_id); + new_payload->branch_ref.eid = eid; + assert(svn_element__payload_invariants(new_payload)); + return new_payload; +} + +svn_element__payload_t * +svn_element__payload_create_dir(apr_hash_t *props, + apr_pool_t *result_pool) +{ + svn_element__payload_t *new_payload + = apr_pcalloc(result_pool, sizeof(*new_payload)); + + new_payload->pool = result_pool; + new_payload->kind = svn_node_dir; + new_payload->props = props ? svn_prop_hash_dup(props, result_pool) : NULL; + assert(svn_element__payload_invariants(new_payload)); + return new_payload; +} + +svn_element__payload_t * +svn_element__payload_create_file(apr_hash_t *props, + svn_stringbuf_t *text, + apr_pool_t *result_pool) +{ + svn_element__payload_t *new_payload + = apr_pcalloc(result_pool, sizeof(*new_payload)); + + SVN_ERR_ASSERT_NO_RETURN(text); + + new_payload->pool = result_pool; + new_payload->kind = svn_node_file; + new_payload->props = props ? svn_prop_hash_dup(props, result_pool) : NULL; + new_payload->text = svn_stringbuf_dup(text, result_pool); + assert(svn_element__payload_invariants(new_payload)); + return new_payload; +} + +svn_element__payload_t * +svn_element__payload_create_symlink(apr_hash_t *props, + const char *target, + apr_pool_t *result_pool) +{ + svn_element__payload_t *new_payload + = apr_pcalloc(result_pool, sizeof(*new_payload)); + + SVN_ERR_ASSERT_NO_RETURN(target); + + new_payload->pool = result_pool; + new_payload->kind = svn_node_symlink; + new_payload->props = props ? svn_prop_hash_dup(props, result_pool) : NULL; + new_payload->target = apr_pstrdup(result_pool, target); + assert(svn_element__payload_invariants(new_payload)); + return new_payload; +} + +svn_element__content_t * +svn_element__content_create(int parent_eid, + const char *name, + const svn_element__payload_t *payload, + apr_pool_t *result_pool) +{ + svn_element__content_t *content + = apr_palloc(result_pool, sizeof(*content)); + + content->parent_eid = parent_eid; + content->name = apr_pstrdup(result_pool, name); + content->payload = svn_element__payload_dup(payload, result_pool); + return content; +} + +svn_element__content_t * +svn_element__content_dup(const svn_element__content_t *old, + apr_pool_t *result_pool) +{ + svn_element__content_t *content + = apr_pmemdup(result_pool, old, sizeof(*content)); + + content->name = apr_pstrdup(result_pool, old->name); + content->payload = svn_element__payload_dup(old->payload, result_pool); + return content; +} + +svn_boolean_t +svn_element__content_equal(const svn_element__content_t *content_left, + const svn_element__content_t *content_right, + apr_pool_t *scratch_pool) +{ + if (!content_left && !content_right) + { + return TRUE; + } + else if (!content_left || !content_right) + { + return FALSE; + } + + if (content_left->parent_eid != content_right->parent_eid) + { + return FALSE; + } + if (strcmp(content_left->name, content_right->name) != 0) + { + return FALSE; + } + if (! svn_element__payload_equal(content_left->payload, content_right->payload, + scratch_pool)) + { + return FALSE; + } + + return TRUE; +} + +svn_element__tree_t * +svn_element__tree_create(apr_hash_t *e_map, + int root_eid, + apr_pool_t *result_pool) +{ + svn_element__tree_t *element_tree + = apr_pcalloc(result_pool, sizeof(*element_tree)); + + element_tree->e_map = e_map ? apr_hash_copy(result_pool, e_map) + : apr_hash_make(result_pool); + element_tree->root_eid = root_eid; + return element_tree; +} + +svn_element__content_t * +svn_element__tree_get(const svn_element__tree_t *tree, + int eid) +{ + return svn_eid__hash_get(tree->e_map, eid); +} + +svn_error_t * +svn_element__tree_set(svn_element__tree_t *tree, + int eid, + const svn_element__content_t *element) +{ + svn_eid__hash_set(tree->e_map, eid, element); + + return SVN_NO_ERROR; +} + +void +svn_element__tree_purge_orphans(apr_hash_t *e_map, + int root_eid, + apr_pool_t *scratch_pool) +{ + apr_hash_index_t *hi; + svn_boolean_t changed; + + SVN_ERR_ASSERT_NO_RETURN(svn_eid__hash_get(e_map, root_eid)); + + do + { + changed = FALSE; + + for (hi = apr_hash_first(scratch_pool, e_map); + hi; hi = apr_hash_next(hi)) + { + int this_eid = svn_eid__hash_this_key(hi); + svn_element__content_t *this_element = apr_hash_this_val(hi); + + if (this_eid != root_eid) + { + svn_element__content_t *parent_element + = svn_eid__hash_get(e_map, this_element->parent_eid); + + /* Purge if parent is deleted */ + if (! parent_element) + { + svn_eid__hash_set(e_map, this_eid, NULL); + changed = TRUE; + } + else + SVN_ERR_ASSERT_NO_RETURN( + ! parent_element->payload->is_subbranch_root); + } + } + } + while (changed); +} + +const char * +svn_element__tree_get_path_by_eid(const svn_element__tree_t *tree, + int eid, + apr_pool_t *result_pool) +{ + const char *path = ""; + svn_element__content_t *element; + + for (; eid != tree->root_eid; eid = element->parent_eid) + { + element = svn_element__tree_get(tree, eid); + if (! element) + return NULL; + path = svn_relpath_join(element->name, path, result_pool); + } + SVN_ERR_ASSERT_NO_RETURN(eid == tree->root_eid); + return path; +} + +svn_element__tree_t * +svn_element__tree_get_subtree_at_eid(svn_element__tree_t *element_tree, + int eid, + apr_pool_t *result_pool) +{ + svn_element__tree_t *new_subtree; + svn_element__content_t *subtree_root_element; + + new_subtree = svn_element__tree_create(element_tree->e_map, eid, + result_pool); + + /* Purge orphans */ + svn_element__tree_purge_orphans(new_subtree->e_map, + new_subtree->root_eid, result_pool); + + /* Remove 'parent' and 'name' attributes from subtree root element */ + subtree_root_element + = svn_element__tree_get(new_subtree, new_subtree->root_eid); + svn_element__tree_set(new_subtree, new_subtree->root_eid, + svn_element__content_create( + -1, "", subtree_root_element->payload, result_pool)); + + return new_subtree; +} + |