iprops.c revision 299742
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 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 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(). */ 49static svn_error_t * 50need_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 102svn_error_t * 103svn_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 */ 128static svn_error_t * 129get_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 = apr_hash_this_key(hi); 180 const char *child_repos_relpath = apr_hash_this_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 234svn_error_t * 235svn_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 *wcroot_iprops = NULL; 248 249 if (!SVN_IS_VALID_REVNUM(revision)) 250 return SVN_NO_ERROR; 251 252 if (ra_session) 253 SVN_ERR(svn_ra_get_session_url(ra_session, &old_session_url, scratch_pool)); 254 255 /* We just wrap a simple helper function, as it is to easy to leave the ra 256 session rooted at some wrong path without a wrapper like this. 257 258 During development we had problems where some now deleted switched path 259 made the update try to update to that url instead of the intended url 260 */ 261 262 err = get_inheritable_props(wcroot_iprops, local_abspath, revision, depth, 263 ra_session, ctx, result_pool, scratch_pool); 264 265 if (ra_session) 266 { 267 err = svn_error_compose_create( 268 err, 269 svn_ra_reparent(ra_session, old_session_url, scratch_pool)); 270 } 271 return svn_error_trace(err); 272} 273