1333347Speter/* 2333347Speter * branch_nested.c : Nested Branches 3333347Speter * 4333347Speter * ==================================================================== 5333347Speter * Licensed to the Apache Software Foundation (ASF) under one 6333347Speter * or more contributor license agreements. See the NOTICE file 7333347Speter * distributed with this work for additional information 8333347Speter * regarding copyright ownership. The ASF licenses this file 9333347Speter * to you under the Apache License, Version 2.0 (the 10333347Speter * "License"); you may not use this file except in compliance 11333347Speter * with the License. You may obtain a copy of the License at 12333347Speter * 13333347Speter * http://www.apache.org/licenses/LICENSE-2.0 14333347Speter * 15333347Speter * Unless required by applicable law or agreed to in writing, 16333347Speter * software distributed under the License is distributed on an 17333347Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18333347Speter * KIND, either express or implied. See the License for the 19333347Speter * specific language governing permissions and limitations 20333347Speter * under the License. 21333347Speter * ==================================================================== 22333347Speter */ 23333347Speter 24333347Speter#include <assert.h> 25333347Speter 26333347Speter#include "svn_types.h" 27333347Speter#include "svn_error.h" 28333347Speter#include "svn_dirent_uri.h" 29333347Speter#include "svn_hash.h" 30333347Speter#include "svn_iter.h" 31333347Speter#include "svn_pools.h" 32333347Speter 33333347Speter#include "private/svn_branch_nested.h" 34333347Speter#include "private/svn_branch_impl.h" 35333347Speter#include "private/svn_branch_repos.h" 36333347Speter 37333347Speter#include "svn_private_config.h" 38333347Speter 39333347Speter 40333347Spetervoid 41333347Spetersvn_branch__get_outer_branch_and_eid(svn_branch__state_t **outer_branch_p, 42333347Speter int *outer_eid_p, 43333347Speter const svn_branch__state_t *branch, 44333347Speter apr_pool_t *scratch_pool) 45333347Speter{ 46333347Speter const char *outer_bid; 47333347Speter 48333347Speter svn_branch__id_unnest(&outer_bid, outer_eid_p, branch->bid, scratch_pool); 49333347Speter *outer_branch_p = NULL; 50333347Speter if (outer_bid) 51333347Speter { 52333347Speter *outer_branch_p 53333347Speter = svn_branch__txn_get_branch_by_id(branch->txn, outer_bid, 54333347Speter scratch_pool); 55333347Speter } 56333347Speter} 57333347Speter 58333347Speterconst char * 59333347Spetersvn_branch__get_root_rrpath(const svn_branch__state_t *branch, 60333347Speter apr_pool_t *result_pool) 61333347Speter{ 62333347Speter svn_branch__state_t *outer_branch; 63333347Speter int outer_eid; 64333347Speter const char *root_rrpath; 65333347Speter 66333347Speter svn_branch__get_outer_branch_and_eid(&outer_branch, &outer_eid, branch, 67333347Speter result_pool); 68333347Speter if (outer_branch) 69333347Speter { 70333347Speter root_rrpath 71333347Speter = svn_branch__get_rrpath_by_eid(outer_branch, outer_eid, result_pool); 72333347Speter } 73333347Speter else 74333347Speter { 75333347Speter root_rrpath = ""; 76333347Speter } 77333347Speter 78333347Speter SVN_ERR_ASSERT_NO_RETURN(root_rrpath); 79333347Speter return root_rrpath; 80333347Speter} 81333347Speter 82333347Speterconst char * 83333347Spetersvn_branch__get_rrpath_by_eid(const svn_branch__state_t *branch, 84333347Speter int eid, 85333347Speter apr_pool_t *result_pool) 86333347Speter{ 87333347Speter const char *path = svn_branch__get_path_by_eid(branch, eid, result_pool); 88333347Speter const char *rrpath = NULL; 89333347Speter 90333347Speter if (path) 91333347Speter { 92333347Speter rrpath = svn_relpath_join(svn_branch__get_root_rrpath(branch, result_pool), 93333347Speter path, result_pool); 94333347Speter } 95333347Speter return rrpath; 96333347Speter} 97333347Speter 98333347Spetersvn_error_t * 99333347Spetersvn_branch__get_subbranch_at_eid(svn_branch__state_t *branch, 100333347Speter svn_branch__state_t **subbranch_p, 101333347Speter int eid, 102333347Speter apr_pool_t *scratch_pool) 103333347Speter{ 104333347Speter svn_element__content_t *element; 105333347Speter 106333347Speter SVN_ERR(svn_branch__state_get_element(branch, &element, eid, scratch_pool)); 107333347Speter if (element && element->payload->is_subbranch_root) 108333347Speter { 109333347Speter const char *branch_id = svn_branch__get_id(branch, scratch_pool); 110333347Speter const char *subbranch_id = svn_branch__id_nest(branch_id, eid, 111333347Speter scratch_pool); 112333347Speter 113333347Speter *subbranch_p = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id, 114333347Speter scratch_pool); 115333347Speter } 116333347Speter else 117333347Speter { 118333347Speter *subbranch_p = NULL; 119333347Speter } 120333347Speter return SVN_NO_ERROR; 121333347Speter} 122333347Speter 123333347Speter/* Set *SUBBRANCH_EIDS_P an array of EIDs of the subbranch-root elements in 124333347Speter * BRANCH. 125333347Speter */ 126333347Speterstatic svn_error_t * 127333347Spetersvn_branch__get_immediate_subbranch_eids(svn_branch__state_t *branch, 128333347Speter apr_array_header_t **subbranch_eids_p, 129333347Speter apr_pool_t *result_pool, 130333347Speter apr_pool_t *scratch_pool) 131333347Speter{ 132333347Speter apr_array_header_t *subbranch_eids 133333347Speter = apr_array_make(result_pool, 0, sizeof(int)); 134333347Speter svn_element__tree_t *elements; 135333347Speter apr_hash_index_t *hi; 136333347Speter 137333347Speter SVN_ERR(svn_branch__state_get_elements(branch, &elements, scratch_pool)); 138333347Speter for (hi = apr_hash_first(scratch_pool, elements->e_map); 139333347Speter hi; hi = apr_hash_next(hi)) 140333347Speter { 141333347Speter int eid = svn_eid__hash_this_key(hi); 142333347Speter svn_element__content_t *element = apr_hash_this_val(hi); 143333347Speter 144333347Speter if (element->payload->is_subbranch_root) 145333347Speter { 146333347Speter APR_ARRAY_PUSH(subbranch_eids, int) = eid; 147333347Speter } 148333347Speter } 149333347Speter *subbranch_eids_p = subbranch_eids; 150333347Speter return SVN_NO_ERROR; 151333347Speter} 152333347Speter 153333347Spetersvn_error_t * 154333347Spetersvn_branch__get_immediate_subbranches(svn_branch__state_t *branch, 155333347Speter apr_array_header_t **subbranches_p, 156333347Speter apr_pool_t *result_pool, 157333347Speter apr_pool_t *scratch_pool) 158333347Speter{ 159333347Speter apr_array_header_t *subbranch_eids; 160333347Speter apr_array_header_t *subbranches 161333347Speter = apr_array_make(result_pool, 0, sizeof(void *)); 162333347Speter const char *branch_id = svn_branch__get_id(branch, scratch_pool); 163333347Speter int i; 164333347Speter 165333347Speter SVN_ERR(svn_branch__get_immediate_subbranch_eids(branch, &subbranch_eids, 166333347Speter scratch_pool, scratch_pool)); 167333347Speter for (i = 0; i < subbranch_eids->nelts; i++) 168333347Speter { 169333347Speter int eid = APR_ARRAY_IDX(subbranch_eids, i, int); 170333347Speter const char *subbranch_id 171333347Speter = svn_branch__id_nest(branch_id, eid, scratch_pool); 172333347Speter svn_branch__state_t *subbranch 173333347Speter = svn_branch__txn_get_branch_by_id(branch->txn, subbranch_id, 174333347Speter scratch_pool); 175333347Speter 176333347Speter SVN_ERR_ASSERT_NO_RETURN(subbranch); 177333347Speter APR_ARRAY_PUSH(subbranches, void *) = subbranch; 178333347Speter } 179333347Speter *subbranches_p = subbranches; 180333347Speter return SVN_NO_ERROR; 181333347Speter} 182333347Speter 183333347Spetersvn_branch__subtree_t * 184333347Spetersvn_branch__subtree_create(apr_hash_t *e_map, 185333347Speter int root_eid, 186333347Speter apr_pool_t *result_pool) 187333347Speter{ 188333347Speter svn_branch__subtree_t *subtree = apr_pcalloc(result_pool, sizeof(*subtree)); 189333347Speter 190333347Speter subtree->tree = svn_element__tree_create(e_map, root_eid, result_pool); 191333347Speter subtree->subbranches = apr_hash_make(result_pool); 192333347Speter return subtree; 193333347Speter} 194333347Speter 195333347Spetersvn_error_t * 196333347Spetersvn_branch__get_subtree(svn_branch__state_t *branch, 197333347Speter svn_branch__subtree_t **subtree_p, 198333347Speter int eid, 199333347Speter apr_pool_t *result_pool) 200333347Speter{ 201333347Speter svn_element__tree_t *element_tree; 202333347Speter svn_branch__subtree_t *new_subtree; 203333347Speter apr_array_header_t *subbranch_eids; 204333347Speter int i; 205333347Speter apr_pool_t *iterpool = result_pool; /* ### not a proper iterpool */ 206333347Speter 207333347Speter SVN_ERR(svn_branch__state_get_elements(branch, &element_tree, result_pool)); 208333347Speter element_tree = svn_element__tree_get_subtree_at_eid(element_tree, eid, 209333347Speter result_pool); 210333347Speter new_subtree 211333347Speter = svn_branch__subtree_create(element_tree->e_map, eid, result_pool); 212333347Speter 213333347Speter /* Add subbranches */ 214333347Speter SVN_ERR(svn_branch__get_immediate_subbranch_eids(branch, &subbranch_eids, 215333347Speter result_pool, result_pool)); 216333347Speter for (i = 0; i < subbranch_eids->nelts; i++) 217333347Speter { 218333347Speter int outer_eid = APR_ARRAY_IDX(subbranch_eids, i, int); 219333347Speter const char *subbranch_relpath_in_subtree; 220333347Speter 221333347Speter subbranch_relpath_in_subtree 222333347Speter = svn_element__tree_get_path_by_eid(new_subtree->tree, outer_eid, 223333347Speter iterpool); 224333347Speter 225333347Speter /* Is it pathwise at or below EID? If so, add it into the subtree. */ 226333347Speter if (subbranch_relpath_in_subtree) 227333347Speter { 228333347Speter svn_branch__state_t *subbranch; 229333347Speter svn_branch__subtree_t *this_subtree; 230333347Speter 231333347Speter SVN_ERR(svn_branch__get_subbranch_at_eid(branch, &subbranch, 232333347Speter outer_eid, iterpool)); 233333347Speter if (subbranch) 234333347Speter { 235333347Speter SVN_ERR(svn_branch__get_subtree(subbranch, &this_subtree, 236333347Speter svn_branch__root_eid(subbranch), 237333347Speter result_pool)); 238333347Speter svn_eid__hash_set(new_subtree->subbranches, outer_eid, 239333347Speter this_subtree); 240333347Speter } 241333347Speter } 242333347Speter } 243333347Speter *subtree_p = new_subtree; 244333347Speter return SVN_NO_ERROR; 245333347Speter} 246333347Speter 247333347Spetersvn_branch__subtree_t * 248333347Spetersvn_branch__subtree_get_subbranch_at_eid(svn_branch__subtree_t *subtree, 249333347Speter int eid, 250333347Speter apr_pool_t *result_pool) 251333347Speter{ 252333347Speter subtree = svn_eid__hash_get(subtree->subbranches, eid); 253333347Speter 254333347Speter return subtree; 255333347Speter} 256333347Speter 257333347Speter/* Instantiate ELEMENTS in TO_BRANCH. 258333347Speter */ 259333347Speterstatic svn_error_t * 260333347Speterbranch_instantiate_elements(svn_branch__state_t *to_branch, 261333347Speter const svn_element__tree_t *elements, 262333347Speter apr_pool_t *scratch_pool) 263333347Speter{ 264333347Speter apr_hash_index_t *hi; 265333347Speter 266333347Speter for (hi = apr_hash_first(scratch_pool, elements->e_map); 267333347Speter hi; hi = apr_hash_next(hi)) 268333347Speter { 269333347Speter int this_eid = svn_eid__hash_this_key(hi); 270333347Speter svn_element__content_t *this_element = apr_hash_this_val(hi); 271333347Speter 272333347Speter SVN_ERR(svn_branch__state_set_element(to_branch, this_eid, 273333347Speter this_element, scratch_pool)); 274333347Speter } 275333347Speter 276333347Speter return SVN_NO_ERROR; 277333347Speter} 278333347Speter 279333347Spetersvn_error_t * 280333347Spetersvn_branch__instantiate_elements_r(svn_branch__state_t *to_branch, 281333347Speter svn_branch__subtree_t elements, 282333347Speter apr_pool_t *scratch_pool) 283333347Speter{ 284333347Speter SVN_ERR(branch_instantiate_elements(to_branch, elements.tree, 285333347Speter scratch_pool)); 286333347Speter 287333347Speter /* branch any subbranches */ 288333347Speter { 289333347Speter apr_hash_index_t *hi; 290333347Speter 291333347Speter for (hi = apr_hash_first(scratch_pool, elements.subbranches); 292333347Speter hi; hi = apr_hash_next(hi)) 293333347Speter { 294333347Speter int this_outer_eid = svn_eid__hash_this_key(hi); 295333347Speter svn_branch__subtree_t *this_subtree = apr_hash_this_val(hi); 296333347Speter const char *new_branch_id; 297333347Speter svn_branch__state_t *new_branch; 298333347Speter /*### svn_branch__history_t *history;*/ 299333347Speter 300333347Speter /* branch this subbranch into NEW_BRANCH (recursing) */ 301333347Speter new_branch_id = svn_branch__id_nest(to_branch->bid, this_outer_eid, 302333347Speter scratch_pool); 303333347Speter SVN_ERR(svn_branch__txn_open_branch(to_branch->txn, &new_branch, 304333347Speter new_branch_id, 305333347Speter this_subtree->tree->root_eid, 306333347Speter NULL /*tree_ref*/, 307333347Speter scratch_pool, scratch_pool)); 308333347Speter /*### SVN_ERR(svn_branch__state_set_history(new_branch, history, 309333347Speter scratch_pool));*/ 310333347Speter 311333347Speter SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *this_subtree, 312333347Speter scratch_pool)); 313333347Speter } 314333347Speter } 315333347Speter 316333347Speter return SVN_NO_ERROR; 317333347Speter} 318333347Speter 319333347Speter/* 320333347Speter * ======================================================================== 321333347Speter */ 322333347Speter 323333347Spetersvn_error_t * 324333347Spetersvn_branch__find_nested_branch_element_by_relpath( 325333347Speter svn_branch__state_t **branch_p, 326333347Speter int *eid_p, 327333347Speter svn_branch__state_t *root_branch, 328333347Speter const char *relpath, 329333347Speter apr_pool_t *scratch_pool) 330333347Speter{ 331333347Speter /* The path we're looking for is (path-wise) in this branch. See if it 332333347Speter is also in a sub-branch. */ 333333347Speter /* Loop invariants: RELPATH is the path we're looking for, relative to 334333347Speter ROOT_BRANCH which is the current level of nesting that we've descended 335333347Speter into. */ 336333347Speter while (TRUE) 337333347Speter { 338333347Speter apr_array_header_t *subbranch_eids; 339333347Speter int i; 340333347Speter svn_boolean_t found = FALSE; 341333347Speter 342333347Speter SVN_ERR(svn_branch__get_immediate_subbranch_eids( 343333347Speter root_branch, &subbranch_eids, scratch_pool, scratch_pool)); 344333347Speter for (i = 0; i < subbranch_eids->nelts; i++) 345333347Speter { 346333347Speter int outer_eid = APR_ARRAY_IDX(subbranch_eids, i, int); 347333347Speter const char *relpath_to_subbranch; 348333347Speter const char *relpath_in_subbranch; 349333347Speter 350333347Speter /* Check whether the RELPATH we're looking for is within this 351333347Speter subbranch at OUTER_EID. If it is, recurse in the subbranch. */ 352333347Speter relpath_to_subbranch 353333347Speter = svn_branch__get_path_by_eid(root_branch, outer_eid, scratch_pool); 354333347Speter relpath_in_subbranch 355333347Speter = svn_relpath_skip_ancestor(relpath_to_subbranch, relpath); 356333347Speter if (relpath_in_subbranch) 357333347Speter { 358333347Speter svn_branch__state_t *subbranch; 359333347Speter 360333347Speter SVN_ERR(svn_branch__get_subbranch_at_eid( 361333347Speter root_branch, &subbranch, outer_eid, scratch_pool)); 362333347Speter /* If the branch hierarchy is not 'flat' then we might find 363333347Speter there is no actual branch where the subbranch-root element 364333347Speter says there should be one. In that case, ignore it. */ 365333347Speter if (subbranch) 366333347Speter { 367333347Speter root_branch = subbranch; 368333347Speter relpath = relpath_in_subbranch; 369333347Speter found = TRUE; 370333347Speter break; 371333347Speter } 372333347Speter } 373333347Speter } 374333347Speter if (! found) 375333347Speter { 376333347Speter break; 377333347Speter } 378333347Speter } 379333347Speter 380333347Speter *branch_p = root_branch; 381333347Speter if (eid_p) 382333347Speter *eid_p = svn_branch__get_eid_by_path(root_branch, relpath, scratch_pool); 383333347Speter return SVN_NO_ERROR; 384333347Speter} 385333347Speter 386333347Spetersvn_error_t * 387333347Spetersvn_branch__repos_find_el_rev_by_path_rev(svn_branch__el_rev_id_t **el_rev_p, 388333347Speter const svn_branch__repos_t *repos, 389333347Speter svn_revnum_t revnum, 390333347Speter const char *branch_id, 391333347Speter const char *relpath, 392333347Speter apr_pool_t *result_pool, 393333347Speter apr_pool_t *scratch_pool) 394333347Speter{ 395333347Speter svn_branch__el_rev_id_t *el_rev = apr_palloc(result_pool, sizeof(*el_rev)); 396333347Speter svn_branch__state_t *branch; 397333347Speter 398333347Speter SVN_ERR(svn_branch__repos_get_branch_by_id(&branch, 399333347Speter repos, revnum, branch_id, 400333347Speter scratch_pool)); 401333347Speter el_rev->rev = revnum; 402333347Speter SVN_ERR(svn_branch__find_nested_branch_element_by_relpath(&el_rev->branch, 403333347Speter &el_rev->eid, 404333347Speter branch, relpath, 405333347Speter scratch_pool)); 406333347Speter 407333347Speter /* Any relpath must at least be within the originally given branch */ 408333347Speter SVN_ERR_ASSERT_NO_RETURN(el_rev->branch); 409333347Speter *el_rev_p = el_rev; 410333347Speter return SVN_NO_ERROR; 411333347Speter} 412333347Speter 413333347Speter/* Set *BRANCH_P to the branch found in the repository of TXN, at the 414333347Speter * location (in a revision or in this txn) SRC_EL_REV. 415333347Speter * 416333347Speter * Return an error if REVNUM or BRANCH_ID is not found. 417333347Speter */ 418333347Speterstatic svn_error_t * 419333347Speterbranch_in_rev_or_txn(svn_branch__state_t **branch_p, 420333347Speter const svn_branch__rev_bid_eid_t *src_el_rev, 421333347Speter svn_branch__txn_t *txn, 422333347Speter apr_pool_t *result_pool) 423333347Speter{ 424333347Speter if (SVN_IS_VALID_REVNUM(src_el_rev->rev)) 425333347Speter { 426333347Speter SVN_ERR(svn_branch__repos_get_branch_by_id(branch_p, 427333347Speter txn->repos, 428333347Speter src_el_rev->rev, 429333347Speter src_el_rev->bid, 430333347Speter result_pool)); 431333347Speter } 432333347Speter else 433333347Speter { 434333347Speter *branch_p 435333347Speter = svn_branch__txn_get_branch_by_id( 436333347Speter txn, src_el_rev->bid, result_pool); 437333347Speter if (! *branch_p) 438333347Speter return svn_error_createf(SVN_BRANCH__ERR, NULL, 439333347Speter _("Branch %s not found"), 440333347Speter src_el_rev->bid); 441333347Speter } 442333347Speter 443333347Speter return SVN_NO_ERROR; 444333347Speter} 445333347Speter 446333347Speterstruct svn_branch__txn_priv_t 447333347Speter{ 448333347Speter /* The underlying branch-txn that supports only non-nested branching. */ 449333347Speter svn_branch__txn_t *wrapped_txn; 450333347Speter 451333347Speter}; 452333347Speter 453333347Speter/* Implements nested branching. 454333347Speter * An #svn_branch__txn_t method. */ 455333347Speterstatic apr_array_header_t * 456333347Speternested_branch_txn_get_branches(const svn_branch__txn_t *txn, 457333347Speter apr_pool_t *result_pool) 458333347Speter{ 459333347Speter /* Just forwarding: nothing more is needed. */ 460333347Speter apr_array_header_t *branches 461333347Speter = svn_branch__txn_get_branches(txn->priv->wrapped_txn, 462333347Speter result_pool); 463333347Speter 464333347Speter return branches; 465333347Speter} 466333347Speter 467333347Speter/* An #svn_branch__txn_t method. */ 468333347Speterstatic svn_error_t * 469333347Speternested_branch_txn_delete_branch(svn_branch__txn_t *txn, 470333347Speter const char *bid, 471333347Speter apr_pool_t *scratch_pool) 472333347Speter{ 473333347Speter /* Just forwarding: nothing more is needed. */ 474333347Speter SVN_ERR(svn_branch__txn_delete_branch(txn->priv->wrapped_txn, 475333347Speter bid, 476333347Speter scratch_pool)); 477333347Speter return SVN_NO_ERROR; 478333347Speter} 479333347Speter 480333347Speter/* Implements nested branching. 481333347Speter * An #svn_branch__txn_t method. */ 482333347Speterstatic svn_error_t * 483333347Speternested_branch_txn_get_num_new_eids(const svn_branch__txn_t *txn, 484333347Speter int *num_new_eids_p, 485333347Speter apr_pool_t *scratch_pool) 486333347Speter{ 487333347Speter /* Just forwarding: nothing more is needed. */ 488333347Speter SVN_ERR(svn_branch__txn_get_num_new_eids(txn->priv->wrapped_txn, 489333347Speter num_new_eids_p, 490333347Speter scratch_pool)); 491333347Speter return SVN_NO_ERROR; 492333347Speter} 493333347Speter 494333347Speter/* Implements nested branching. 495333347Speter * An #svn_branch__txn_t method. */ 496333347Speterstatic svn_error_t * 497333347Speternested_branch_txn_new_eid(svn_branch__txn_t *txn, 498333347Speter svn_branch__eid_t *eid_p, 499333347Speter apr_pool_t *scratch_pool) 500333347Speter{ 501333347Speter /* Just forwarding: nothing more is needed. */ 502333347Speter SVN_ERR(svn_branch__txn_new_eid(txn->priv->wrapped_txn, 503333347Speter eid_p, 504333347Speter scratch_pool)); 505333347Speter return SVN_NO_ERROR; 506333347Speter} 507333347Speter 508333347Speter/* Implements nested branching. 509333347Speter * An #svn_branch__txn_t method. */ 510333347Speterstatic svn_error_t * 511333347Speternested_branch_txn_open_branch(svn_branch__txn_t *txn, 512333347Speter svn_branch__state_t **new_branch_p, 513333347Speter const char *new_branch_id, 514333347Speter int root_eid, 515333347Speter svn_branch__rev_bid_eid_t *tree_ref, 516333347Speter apr_pool_t *result_pool, 517333347Speter apr_pool_t *scratch_pool) 518333347Speter{ 519333347Speter svn_branch__state_t *new_branch; 520333347Speter 521333347Speter SVN_ERR(svn_branch__txn_open_branch(txn->priv->wrapped_txn, 522333347Speter &new_branch, 523333347Speter new_branch_id, root_eid, tree_ref, 524333347Speter result_pool, 525333347Speter scratch_pool)); 526333347Speter 527333347Speter /* Recursively branch any nested branches */ 528333347Speter if (tree_ref) 529333347Speter { 530333347Speter svn_branch__state_t *from_branch; 531333347Speter svn_branch__subtree_t *from_subtree; 532333347Speter 533333347Speter /* (The way we're doing it here also redundantly re-instantiates all the 534333347Speter elements in NEW_BRANCH.) */ 535333347Speter SVN_ERR(branch_in_rev_or_txn(&from_branch, tree_ref, 536333347Speter txn->priv->wrapped_txn, scratch_pool)); 537333347Speter SVN_ERR(svn_branch__get_subtree(from_branch, &from_subtree, 538333347Speter tree_ref->eid, scratch_pool)); 539333347Speter SVN_ERR(svn_branch__instantiate_elements_r(new_branch, *from_subtree, 540333347Speter scratch_pool)); 541333347Speter } 542333347Speter 543333347Speter if (new_branch_p) 544333347Speter *new_branch_p = new_branch; 545333347Speter return SVN_NO_ERROR; 546333347Speter} 547333347Speter 548333347Speter/* Implements nested branching. 549333347Speter * An #svn_branch__txn_t method. */ 550333347Speterstatic svn_error_t * 551333347Speternested_branch_txn_finalize_eids(svn_branch__txn_t *txn, 552333347Speter apr_pool_t *scratch_pool) 553333347Speter{ 554333347Speter /* Just forwarding: nothing more is needed. */ 555333347Speter SVN_ERR(svn_branch__txn_finalize_eids(txn->priv->wrapped_txn, 556333347Speter scratch_pool)); 557333347Speter return SVN_NO_ERROR; 558333347Speter} 559333347Speter 560333347Speter/* Implements nested branching. 561333347Speter * An #svn_branch__txn_t method. */ 562333347Speterstatic svn_error_t * 563333347Speternested_branch_txn_serialize(svn_branch__txn_t *txn, 564333347Speter svn_stream_t *stream, 565333347Speter apr_pool_t *scratch_pool) 566333347Speter{ 567333347Speter /* Just forwarding: nothing more is needed. */ 568333347Speter SVN_ERR(svn_branch__txn_serialize(txn->priv->wrapped_txn, 569333347Speter stream, 570333347Speter scratch_pool)); 571333347Speter return SVN_NO_ERROR; 572333347Speter} 573333347Speter 574333347Speter/* Implements nested branching. 575333347Speter * An #svn_branch__txn_t method. */ 576333347Speterstatic svn_error_t * 577333347Speternested_branch_txn_sequence_point(svn_branch__txn_t *txn, 578333347Speter apr_pool_t *scratch_pool) 579333347Speter{ 580333347Speter svn_branch__txn_t *wrapped_txn = txn->priv->wrapped_txn; 581333347Speter apr_array_header_t *branches; 582333347Speter int i; 583333347Speter 584333347Speter /* first, purge elements in each branch */ 585333347Speter SVN_ERR(svn_branch__txn_sequence_point(wrapped_txn, scratch_pool)); 586333347Speter 587333347Speter /* second, purge branches that are no longer nested */ 588333347Speter branches = svn_branch__txn_get_branches(wrapped_txn, scratch_pool); 589333347Speter for (i = 0; i < branches->nelts; i++) 590333347Speter { 591333347Speter svn_branch__state_t *b = APR_ARRAY_IDX(branches, i, void *); 592333347Speter svn_branch__state_t *outer_branch; 593333347Speter int outer_eid; 594333347Speter 595333347Speter svn_branch__get_outer_branch_and_eid(&outer_branch, &outer_eid, 596333347Speter b, scratch_pool); 597333347Speter if (outer_branch) 598333347Speter { 599333347Speter svn_element__content_t *element; 600333347Speter 601333347Speter SVN_ERR(svn_branch__state_get_element(outer_branch, &element, 602333347Speter outer_eid, scratch_pool)); 603333347Speter if (! element) 604333347Speter SVN_ERR(svn_branch__txn_delete_branch(wrapped_txn, b->bid, 605333347Speter scratch_pool)); 606333347Speter } 607333347Speter } 608333347Speter return SVN_NO_ERROR; 609333347Speter} 610333347Speter 611333347Speter/* An #svn_branch__txn_t method. */ 612333347Speterstatic svn_error_t * 613333347Speternested_branch_txn_complete(svn_branch__txn_t *txn, 614333347Speter apr_pool_t *scratch_pool) 615333347Speter{ 616333347Speter /* Just forwarding: nothing more is needed. */ 617333347Speter SVN_ERR(svn_branch__txn_complete(txn->priv->wrapped_txn, 618333347Speter scratch_pool)); 619333347Speter return SVN_NO_ERROR; 620333347Speter} 621333347Speter 622333347Speter/* An #svn_branch__txn_t method. */ 623333347Speterstatic svn_error_t * 624333347Speternested_branch_txn_abort(svn_branch__txn_t *txn, 625333347Speter apr_pool_t *scratch_pool) 626333347Speter{ 627333347Speter /* Just forwarding: nothing more is needed. */ 628333347Speter SVN_ERR(svn_branch__txn_abort(txn->priv->wrapped_txn, 629333347Speter scratch_pool)); 630333347Speter return SVN_NO_ERROR; 631333347Speter} 632333347Speter 633333347Spetersvn_branch__txn_t * 634333347Spetersvn_branch__nested_txn_create(svn_branch__txn_t *wrapped_txn, 635333347Speter apr_pool_t *result_pool) 636333347Speter{ 637333347Speter static const svn_branch__txn_vtable_t vtable = { 638333347Speter {0}, 639333347Speter nested_branch_txn_get_branches, 640333347Speter nested_branch_txn_delete_branch, 641333347Speter nested_branch_txn_get_num_new_eids, 642333347Speter nested_branch_txn_new_eid, 643333347Speter nested_branch_txn_open_branch, 644333347Speter nested_branch_txn_finalize_eids, 645333347Speter nested_branch_txn_serialize, 646333347Speter nested_branch_txn_sequence_point, 647333347Speter nested_branch_txn_complete, 648333347Speter nested_branch_txn_abort, 649333347Speter }; 650333347Speter svn_branch__txn_t *txn 651333347Speter = svn_branch__txn_create(&vtable, NULL, NULL, result_pool); 652333347Speter 653333347Speter txn->priv = apr_pcalloc(result_pool, sizeof(*txn->priv)); 654333347Speter txn->priv->wrapped_txn = wrapped_txn; 655333347Speter txn->repos = wrapped_txn->repos; 656333347Speter txn->rev = wrapped_txn->rev; 657333347Speter txn->base_rev = wrapped_txn->base_rev; 658333347Speter return txn; 659333347Speter} 660333347Speter 661