]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_client/iprops.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / subversion / subversion / libsvn_client / iprops.c
1 /*
2  * iprops.c:  wrappers around wc inherited property functionality
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23
24 /* ==================================================================== */
25
26
27 \f
28 /*** Includes. ***/
29
30 #include "svn_error.h"
31 #include "svn_hash.h"
32 #include "svn_pools.h"
33 #include "svn_wc.h"
34 #include "svn_ra.h"
35 #include "svn_props.h"
36 #include "svn_path.h"
37
38 #include "client.h"
39 #include "svn_private_config.h"
40
41 #include "private/svn_wc_private.h"
42
43 \f
44 /*** Code. ***/
45
46 /* Determine if LOCAL_ABSPATH needs an inherited property cache.  If it does,
47    then set *NEEDS_CACHE to TRUE, set it to FALSE otherwise.  All other args
48    are as per svn_client__get_inheritable_props(). */
49 static svn_error_t *
50 need_to_cache_iprops(svn_boolean_t *needs_cache,
51                      const char *local_abspath,
52                      svn_ra_session_t *ra_session,
53                      svn_client_ctx_t *ctx,
54                      apr_pool_t *scratch_pool)
55 {
56   svn_boolean_t is_wc_root;
57   svn_boolean_t is_switched;
58   svn_error_t *err;
59
60   err = svn_wc_check_root(&is_wc_root, &is_switched, NULL,
61                           ctx->wc_ctx, local_abspath,
62                            scratch_pool);
63
64   /* LOCAL_ABSPATH doesn't need a cache if it doesn't exist. */
65   if (err)
66     {
67       if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
68         {
69           svn_error_clear(err);
70           is_wc_root = FALSE;
71           is_switched = FALSE;
72         }
73       else
74         {
75           return svn_error_trace(err);
76         }
77     }
78
79   /* Starting assumption. */
80   *needs_cache = FALSE;
81
82   if (is_wc_root || is_switched)
83     {
84       const char *session_url;
85       const char *session_root_url;
86
87       /* Looks likely that we need an inherited properties cache...Unless
88          LOCAL_ABSPATH is a WC root that points to the repos root.  Then it
89          doesn't need a cache because it has nowhere to inherit from.  Check
90          for that case. */
91       SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool));
92       SVN_ERR(svn_ra_get_repos_root2(ra_session, &session_root_url,
93                                      scratch_pool));
94
95       if (strcmp(session_root_url, session_url) != 0)
96         *needs_cache = TRUE;
97     }
98
99   return SVN_NO_ERROR;
100 }
101
102 svn_error_t *
103 svn_client__iprop_relpaths_to_urls(apr_array_header_t *inherited_props,
104                                    const char *repos_root_url,
105                                    apr_pool_t *result_pool,
106                                    apr_pool_t *scratch_pool)
107 {
108   int i;
109
110   for (i = 0; i < inherited_props->nelts; i++)
111     {
112       svn_prop_inherited_item_t *elt =
113         APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *);
114
115       /* Convert repos root relpaths to full URLs. */
116       if (! (svn_path_is_url(elt->path_or_url)
117              || svn_dirent_is_absolute(elt->path_or_url)))
118         {
119           elt->path_or_url = svn_path_url_add_component2(repos_root_url,
120                                                          elt->path_or_url,
121                                                          result_pool);
122         }
123     }
124   return SVN_NO_ERROR;
125 }
126
127 /* The real implementation of svn_client__get_inheritable_props */
128 static svn_error_t *
129 get_inheritable_props(apr_hash_t **wcroot_iprops,
130                       const char *local_abspath,
131                       svn_revnum_t revision,
132                       svn_depth_t depth,
133                       svn_ra_session_t *ra_session,
134                       svn_client_ctx_t *ctx,
135                       apr_pool_t *result_pool,
136                       apr_pool_t *scratch_pool)
137 {
138   apr_hash_t *iprop_paths;
139   apr_hash_index_t *hi;
140   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
141   apr_pool_t *session_pool = NULL;
142   *wcroot_iprops = apr_hash_make(result_pool);
143
144   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
145
146   /* If we don't have a base revision for LOCAL_ABSPATH then it can't
147      possibly be a working copy root, nor can it contain any WC roots
148      in the form of switched subtrees.  So there is nothing to cache. */
149
150   SVN_ERR(svn_wc__get_cached_iprop_children(&iprop_paths, depth,
151                                             ctx->wc_ctx, local_abspath,
152                                             scratch_pool, iterpool));
153
154   /* If we are in the midst of a checkout or an update that is bringing in
155      an external, then svn_wc__get_cached_iprop_children won't return
156      LOCAL_ABSPATH in IPROPS_PATHS because the former has no cached iprops
157      yet.  So make sure LOCAL_ABSPATH is present if it's a WC root. */
158   if (!svn_hash_gets(iprop_paths, local_abspath))
159     {
160       svn_boolean_t needs_cached_iprops;
161
162       SVN_ERR(need_to_cache_iprops(&needs_cached_iprops, local_abspath,
163                                    ra_session, ctx, iterpool));
164       if (needs_cached_iprops)
165         {
166           const char *target_abspath = apr_pstrdup(scratch_pool,
167                                                    local_abspath);
168
169           /* As value we set TARGET_ABSPATH, but any string besides ""
170              would do */
171           svn_hash_sets(iprop_paths, target_abspath, target_abspath);
172         }
173     }
174
175       for (hi = apr_hash_first(scratch_pool, iprop_paths);
176            hi;
177            hi = apr_hash_next(hi))
178         {
179           const char *child_abspath = svn__apr_hash_index_key(hi);
180           const char *child_repos_relpath = svn__apr_hash_index_val(hi);
181           const char *url;
182           apr_array_header_t *inherited_props;
183           svn_error_t *err;
184
185           svn_pool_clear(iterpool);
186
187           if (*child_repos_relpath == '\0')
188             {
189               /* A repository root doesn't have inherited properties */
190               continue;
191             }
192
193           SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child_abspath,
194                                        iterpool, iterpool));
195           if (ra_session)
196             SVN_ERR(svn_ra_reparent(ra_session, url, scratch_pool));
197           else
198             {
199               if (! session_pool)
200                 session_pool = svn_pool_create(scratch_pool);
201
202               SVN_ERR(svn_client_open_ra_session2(&ra_session, url, NULL,
203                                                   ctx,
204                                                   session_pool, iterpool));
205             }
206
207           err = svn_ra_get_inherited_props(ra_session, &inherited_props,
208                                            "", revision,
209                                            result_pool, iterpool);
210
211           if (err)
212             {
213               if (err->apr_err != SVN_ERR_FS_NOT_FOUND)
214                 return svn_error_trace(err);
215
216               svn_error_clear(err);
217               continue;
218             }
219
220           svn_hash_sets(*wcroot_iprops,
221                         apr_pstrdup(result_pool, child_abspath),
222                         inherited_props);
223         }
224
225
226   svn_pool_destroy(iterpool);
227   if (session_pool)
228     svn_pool_destroy(session_pool);
229
230   return SVN_NO_ERROR;
231
232 }
233
234 svn_error_t *
235 svn_client__get_inheritable_props(apr_hash_t **wcroot_iprops,
236                                   const char *local_abspath,
237                                   svn_revnum_t revision,
238                                   svn_depth_t depth,
239                                   svn_ra_session_t *ra_session,
240                                   svn_client_ctx_t *ctx,
241                                   apr_pool_t *result_pool,
242                                   apr_pool_t *scratch_pool)
243 {
244   const char *old_session_url;
245   svn_error_t *err;
246
247   if (!SVN_IS_VALID_REVNUM(revision))
248     return SVN_NO_ERROR;
249
250   if (ra_session)
251     SVN_ERR(svn_ra_get_session_url(ra_session, &old_session_url, scratch_pool));
252
253   /* We just wrap a simple helper function, as it is to easy to leave the ra
254      session rooted at some wrong path without a wrapper like this.
255
256      During development we had problems where some now deleted switched path
257      made the update try to update to that url instead of the intended url
258    */
259
260   err = get_inheritable_props(wcroot_iprops, local_abspath, revision, depth,
261                               ra_session, ctx, result_pool, scratch_pool);
262
263   if (ra_session)
264     {
265       err = svn_error_compose_create(
266                 err,
267                 svn_ra_reparent(ra_session, old_session_url, scratch_pool));
268     }
269   return svn_error_trace(err);
270 }