relocate.c revision 299742
1/* 2 * relocate.c: wrapper around wc relocation 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_wc.h" 31#include "svn_client.h" 32#include "svn_pools.h" 33#include "svn_error.h" 34#include "svn_dirent_uri.h" 35#include "svn_path.h" 36#include "client.h" 37 38#include "private/svn_wc_private.h" 39 40#include "svn_private_config.h" 41 42 43/*** Code. ***/ 44 45/* Repository root and UUID for a repository. */ 46struct url_uuid_t 47{ 48 const char *root; 49 const char *uuid; 50}; 51 52struct validator_baton_t 53{ 54 svn_client_ctx_t *ctx; 55 const char *path; 56 apr_array_header_t *url_uuids; 57 apr_pool_t *pool; 58 59}; 60 61 62static svn_error_t * 63validator_func(void *baton, 64 const char *uuid, 65 const char *url, 66 const char *root_url, 67 apr_pool_t *pool) 68{ 69 struct validator_baton_t *b = baton; 70 struct url_uuid_t *url_uuid = NULL; 71 const char *disable_checks; 72 73 apr_array_header_t *uuids = b->url_uuids; 74 int i; 75 76 for (i = 0; i < uuids->nelts; ++i) 77 { 78 struct url_uuid_t *uu = &APR_ARRAY_IDX(uuids, i, 79 struct url_uuid_t); 80 if (svn_uri__is_ancestor(uu->root, url)) 81 { 82 url_uuid = uu; 83 break; 84 } 85 } 86 87 disable_checks = getenv("SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_RELOCATE_VALIDATION"); 88 if (disable_checks && (strcmp(disable_checks, "yes") == 0)) 89 { 90 /* Lie about URL_UUID's components, claiming they match the 91 expectations of the validation code below. */ 92 url_uuid = apr_pcalloc(pool, sizeof(*url_uuid)); 93 url_uuid->root = apr_pstrdup(pool, root_url); 94 url_uuid->uuid = apr_pstrdup(pool, uuid); 95 } 96 97 /* We use an RA session in a subpool to get the UUID of the 98 repository at the new URL so we can force the RA session to close 99 by destroying the subpool. */ 100 if (! url_uuid) 101 { 102 apr_pool_t *sesspool = svn_pool_create(pool); 103 104 url_uuid = &APR_ARRAY_PUSH(uuids, struct url_uuid_t); 105 SVN_ERR(svn_client_get_repos_root(&url_uuid->root, 106 &url_uuid->uuid, 107 url, b->ctx, 108 pool, sesspool)); 109 110 svn_pool_destroy(sesspool); 111 } 112 113 /* Make sure the url is a repository root if desired. */ 114 if (root_url 115 && strcmp(root_url, url_uuid->root) != 0) 116 return svn_error_createf(SVN_ERR_CLIENT_INVALID_RELOCATION, NULL, 117 _("'%s' is not the root of the repository"), 118 url); 119 120 /* Make sure the UUIDs match. */ 121 if (uuid && strcmp(uuid, url_uuid->uuid) != 0) 122 return svn_error_createf 123 (SVN_ERR_CLIENT_INVALID_RELOCATION, NULL, 124 _("The repository at '%s' has uuid '%s', but the WC has '%s'"), 125 url, url_uuid->uuid, uuid); 126 127 return SVN_NO_ERROR; 128} 129 130svn_error_t * 131svn_client_relocate2(const char *wcroot_dir, 132 const char *from_prefix, 133 const char *to_prefix, 134 svn_boolean_t ignore_externals, 135 svn_client_ctx_t *ctx, 136 apr_pool_t *pool) 137{ 138 struct validator_baton_t vb; 139 const char *local_abspath; 140 apr_hash_t *externals_hash = NULL; 141 apr_hash_index_t *hi; 142 apr_pool_t *iterpool = NULL; 143 const char *old_repos_root_url, *new_repos_root_url; 144 145 /* Populate our validator callback baton, and call the relocate code. */ 146 vb.ctx = ctx; 147 vb.path = wcroot_dir; 148 vb.url_uuids = apr_array_make(pool, 1, sizeof(struct url_uuid_t)); 149 vb.pool = pool; 150 151 if (svn_path_is_url(wcroot_dir)) 152 return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, 153 _("'%s' is not a local path"), 154 wcroot_dir); 155 156 SVN_ERR(svn_dirent_get_absolute(&local_abspath, wcroot_dir, pool)); 157 158 /* If we're ignoring externals, just relocate and get outta here. */ 159 if (ignore_externals) 160 { 161 return svn_error_trace(svn_wc_relocate4(ctx->wc_ctx, local_abspath, 162 from_prefix, to_prefix, 163 validator_func, &vb, pool)); 164 } 165 166 /* Fetch our current root URL. */ 167 SVN_ERR(svn_client_get_repos_root(&old_repos_root_url, NULL /* uuid */, 168 local_abspath, ctx, pool, pool)); 169 170 /* Perform the relocation. */ 171 SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from_prefix, to_prefix, 172 validator_func, &vb, pool)); 173 174 /* Now fetch new current root URL. */ 175 SVN_ERR(svn_client_get_repos_root(&new_repos_root_url, NULL /* uuid */, 176 local_abspath, ctx, pool, pool)); 177 178 179 /* Relocate externals, too (if any). */ 180 SVN_ERR(svn_wc__externals_defined_below(&externals_hash, 181 ctx->wc_ctx, local_abspath, 182 pool, pool)); 183 if (! apr_hash_count(externals_hash)) 184 return SVN_NO_ERROR; 185 186 iterpool = svn_pool_create(pool); 187 188 for (hi = apr_hash_first(pool, externals_hash); 189 hi != NULL; 190 hi = apr_hash_next(hi)) 191 { 192 svn_node_kind_t kind; 193 const char *this_abspath = apr_hash_this_key(hi); 194 195 svn_pool_clear(iterpool); 196 197 SVN_ERR(svn_wc__read_external_info(&kind, NULL, NULL, NULL, NULL, 198 ctx->wc_ctx, 199 local_abspath, this_abspath, 200 FALSE, iterpool, iterpool)); 201 202 if (kind == svn_node_dir) 203 { 204 const char *this_repos_root_url; 205 svn_error_t *err; 206 207 err = svn_client_get_repos_root(&this_repos_root_url, NULL /* uuid */, 208 this_abspath, ctx, iterpool, iterpool); 209 210 /* Ignore externals that aren't present in the working copy. 211 * This can happen if an external is deleted from disk accidentally, 212 * or if an external is configured on a locally added directory. */ 213 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 214 { 215 svn_error_clear(err); 216 continue; 217 } 218 SVN_ERR(err); 219 220 if (strcmp(old_repos_root_url, this_repos_root_url) == 0) 221 SVN_ERR(svn_client_relocate2(this_abspath, from_prefix, to_prefix, 222 FALSE /* ignore_externals */, 223 ctx, iterpool)); 224 } 225 } 226 227 svn_pool_destroy(iterpool); 228 229 return SVN_NO_ERROR; 230} 231