1251881Speter/* 2251881Speter * iprops.c: wrappers around wc inherited property functionality 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter/* ==================================================================== */ 25251881Speter 26251881Speter 27251881Speter 28251881Speter/*** Includes. ***/ 29251881Speter 30251881Speter#include "svn_error.h" 31251881Speter#include "svn_hash.h" 32251881Speter#include "svn_pools.h" 33251881Speter#include "svn_wc.h" 34251881Speter#include "svn_ra.h" 35251881Speter#include "svn_props.h" 36251881Speter#include "svn_path.h" 37251881Speter 38251881Speter#include "client.h" 39251881Speter#include "svn_private_config.h" 40251881Speter 41251881Speter#include "private/svn_wc_private.h" 42251881Speter 43251881Speter 44251881Speter/*** Code. ***/ 45251881Speter 46251881Speter/* Determine if LOCAL_ABSPATH needs an inherited property cache. If it does, 47251881Speter then set *NEEDS_CACHE to TRUE, set it to FALSE otherwise. All other args 48251881Speter are as per svn_client__get_inheritable_props(). */ 49251881Speterstatic svn_error_t * 50251881Speterneed_to_cache_iprops(svn_boolean_t *needs_cache, 51251881Speter const char *local_abspath, 52251881Speter svn_ra_session_t *ra_session, 53251881Speter svn_client_ctx_t *ctx, 54251881Speter apr_pool_t *scratch_pool) 55251881Speter{ 56251881Speter svn_boolean_t is_wc_root; 57251881Speter svn_boolean_t is_switched; 58251881Speter svn_error_t *err; 59251881Speter 60251881Speter err = svn_wc_check_root(&is_wc_root, &is_switched, NULL, 61251881Speter ctx->wc_ctx, local_abspath, 62251881Speter scratch_pool); 63251881Speter 64251881Speter /* LOCAL_ABSPATH doesn't need a cache if it doesn't exist. */ 65251881Speter if (err) 66251881Speter { 67251881Speter if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 68251881Speter { 69251881Speter svn_error_clear(err); 70251881Speter is_wc_root = FALSE; 71251881Speter is_switched = FALSE; 72251881Speter } 73251881Speter else 74251881Speter { 75251881Speter return svn_error_trace(err); 76251881Speter } 77251881Speter } 78251881Speter 79251881Speter /* Starting assumption. */ 80251881Speter *needs_cache = FALSE; 81251881Speter 82251881Speter if (is_wc_root || is_switched) 83251881Speter { 84251881Speter const char *session_url; 85251881Speter const char *session_root_url; 86251881Speter 87251881Speter /* Looks likely that we need an inherited properties cache...Unless 88251881Speter LOCAL_ABSPATH is a WC root that points to the repos root. Then it 89251881Speter doesn't need a cache because it has nowhere to inherit from. Check 90251881Speter for that case. */ 91251881Speter SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool)); 92251881Speter SVN_ERR(svn_ra_get_repos_root2(ra_session, &session_root_url, 93251881Speter scratch_pool)); 94251881Speter 95251881Speter if (strcmp(session_root_url, session_url) != 0) 96251881Speter *needs_cache = TRUE; 97251881Speter } 98251881Speter 99251881Speter return SVN_NO_ERROR; 100251881Speter} 101251881Speter 102251881Spetersvn_error_t * 103251881Spetersvn_client__iprop_relpaths_to_urls(apr_array_header_t *inherited_props, 104251881Speter const char *repos_root_url, 105251881Speter apr_pool_t *result_pool, 106251881Speter apr_pool_t *scratch_pool) 107251881Speter{ 108251881Speter int i; 109251881Speter 110251881Speter for (i = 0; i < inherited_props->nelts; i++) 111251881Speter { 112251881Speter svn_prop_inherited_item_t *elt = 113251881Speter APR_ARRAY_IDX(inherited_props, i, svn_prop_inherited_item_t *); 114251881Speter 115251881Speter /* Convert repos root relpaths to full URLs. */ 116251881Speter if (! (svn_path_is_url(elt->path_or_url) 117251881Speter || svn_dirent_is_absolute(elt->path_or_url))) 118251881Speter { 119251881Speter elt->path_or_url = svn_path_url_add_component2(repos_root_url, 120251881Speter elt->path_or_url, 121251881Speter result_pool); 122251881Speter } 123251881Speter } 124251881Speter return SVN_NO_ERROR; 125251881Speter} 126251881Speter 127251881Speter/* The real implementation of svn_client__get_inheritable_props */ 128251881Speterstatic svn_error_t * 129251881Speterget_inheritable_props(apr_hash_t **wcroot_iprops, 130251881Speter const char *local_abspath, 131251881Speter svn_revnum_t revision, 132251881Speter svn_depth_t depth, 133251881Speter svn_ra_session_t *ra_session, 134251881Speter svn_client_ctx_t *ctx, 135251881Speter apr_pool_t *result_pool, 136251881Speter apr_pool_t *scratch_pool) 137251881Speter{ 138251881Speter apr_hash_t *iprop_paths; 139251881Speter apr_hash_index_t *hi; 140251881Speter apr_pool_t *iterpool = svn_pool_create(scratch_pool); 141251881Speter apr_pool_t *session_pool = NULL; 142251881Speter *wcroot_iprops = apr_hash_make(result_pool); 143251881Speter 144251881Speter SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision)); 145251881Speter 146251881Speter /* If we don't have a base revision for LOCAL_ABSPATH then it can't 147251881Speter possibly be a working copy root, nor can it contain any WC roots 148251881Speter in the form of switched subtrees. So there is nothing to cache. */ 149251881Speter 150251881Speter SVN_ERR(svn_wc__get_cached_iprop_children(&iprop_paths, depth, 151251881Speter ctx->wc_ctx, local_abspath, 152251881Speter scratch_pool, iterpool)); 153251881Speter 154251881Speter /* If we are in the midst of a checkout or an update that is bringing in 155251881Speter an external, then svn_wc__get_cached_iprop_children won't return 156251881Speter LOCAL_ABSPATH in IPROPS_PATHS because the former has no cached iprops 157251881Speter yet. So make sure LOCAL_ABSPATH is present if it's a WC root. */ 158251881Speter if (!svn_hash_gets(iprop_paths, local_abspath)) 159251881Speter { 160251881Speter svn_boolean_t needs_cached_iprops; 161251881Speter 162251881Speter SVN_ERR(need_to_cache_iprops(&needs_cached_iprops, local_abspath, 163251881Speter ra_session, ctx, iterpool)); 164251881Speter if (needs_cached_iprops) 165251881Speter { 166251881Speter const char *target_abspath = apr_pstrdup(scratch_pool, 167251881Speter local_abspath); 168251881Speter 169251881Speter /* As value we set TARGET_ABSPATH, but any string besides "" 170251881Speter would do */ 171251881Speter svn_hash_sets(iprop_paths, target_abspath, target_abspath); 172251881Speter } 173251881Speter } 174251881Speter 175251881Speter for (hi = apr_hash_first(scratch_pool, iprop_paths); 176251881Speter hi; 177251881Speter hi = apr_hash_next(hi)) 178251881Speter { 179289180Speter const char *child_abspath = apr_hash_this_key(hi); 180289180Speter const char *child_repos_relpath = apr_hash_this_val(hi); 181251881Speter const char *url; 182251881Speter apr_array_header_t *inherited_props; 183251881Speter svn_error_t *err; 184251881Speter 185251881Speter svn_pool_clear(iterpool); 186251881Speter 187251881Speter if (*child_repos_relpath == '\0') 188251881Speter { 189251881Speter /* A repository root doesn't have inherited properties */ 190251881Speter continue; 191251881Speter } 192251881Speter 193251881Speter SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child_abspath, 194251881Speter iterpool, iterpool)); 195251881Speter if (ra_session) 196251881Speter SVN_ERR(svn_ra_reparent(ra_session, url, scratch_pool)); 197251881Speter else 198251881Speter { 199251881Speter if (! session_pool) 200251881Speter session_pool = svn_pool_create(scratch_pool); 201251881Speter 202251881Speter SVN_ERR(svn_client_open_ra_session2(&ra_session, url, NULL, 203251881Speter ctx, 204251881Speter session_pool, iterpool)); 205251881Speter } 206251881Speter 207251881Speter err = svn_ra_get_inherited_props(ra_session, &inherited_props, 208251881Speter "", revision, 209251881Speter result_pool, iterpool); 210251881Speter 211251881Speter if (err) 212251881Speter { 213251881Speter if (err->apr_err != SVN_ERR_FS_NOT_FOUND) 214251881Speter return svn_error_trace(err); 215251881Speter 216251881Speter svn_error_clear(err); 217251881Speter continue; 218251881Speter } 219251881Speter 220251881Speter svn_hash_sets(*wcroot_iprops, 221251881Speter apr_pstrdup(result_pool, child_abspath), 222251881Speter inherited_props); 223251881Speter } 224251881Speter 225251881Speter 226251881Speter svn_pool_destroy(iterpool); 227251881Speter if (session_pool) 228251881Speter svn_pool_destroy(session_pool); 229251881Speter 230251881Speter return SVN_NO_ERROR; 231251881Speter 232251881Speter} 233251881Speter 234251881Spetersvn_error_t * 235251881Spetersvn_client__get_inheritable_props(apr_hash_t **wcroot_iprops, 236251881Speter const char *local_abspath, 237251881Speter svn_revnum_t revision, 238251881Speter svn_depth_t depth, 239251881Speter svn_ra_session_t *ra_session, 240251881Speter svn_client_ctx_t *ctx, 241251881Speter apr_pool_t *result_pool, 242251881Speter apr_pool_t *scratch_pool) 243251881Speter{ 244251881Speter const char *old_session_url; 245251881Speter svn_error_t *err; 246251881Speter 247289180Speter *wcroot_iprops = NULL; 248289180Speter 249251881Speter if (!SVN_IS_VALID_REVNUM(revision)) 250251881Speter return SVN_NO_ERROR; 251251881Speter 252251881Speter if (ra_session) 253251881Speter SVN_ERR(svn_ra_get_session_url(ra_session, &old_session_url, scratch_pool)); 254251881Speter 255251881Speter /* We just wrap a simple helper function, as it is to easy to leave the ra 256251881Speter session rooted at some wrong path without a wrapper like this. 257251881Speter 258251881Speter During development we had problems where some now deleted switched path 259251881Speter made the update try to update to that url instead of the intended url 260251881Speter */ 261251881Speter 262251881Speter err = get_inheritable_props(wcroot_iprops, local_abspath, revision, depth, 263251881Speter ra_session, ctx, result_pool, scratch_pool); 264251881Speter 265251881Speter if (ra_session) 266251881Speter { 267251881Speter err = svn_error_compose_create( 268251881Speter err, 269251881Speter svn_ra_reparent(ra_session, old_session_url, scratch_pool)); 270251881Speter } 271251881Speter return svn_error_trace(err); 272251881Speter} 273