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