1/* 2 * relocate.c: do wc repos relocation 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#include "svn_wc.h" 27#include "svn_error.h" 28#include "svn_pools.h" 29#include "svn_dirent_uri.h" 30#include "svn_path.h" 31 32#include "wc.h" 33#include "props.h" 34 35#include "svn_private_config.h" 36 37 38/* If the components of RELPATH exactly match (after being 39 URI-encoded) the final components of URL, return a copy of URL 40 minus those components allocated in RESULT_POOL; otherwise, return 41 NULL. */ 42static const char * 43url_remove_final_relpath(const char *url, 44 const char *relpath, 45 apr_pool_t *result_pool, 46 apr_pool_t *scratch_pool) 47{ 48 char *result = apr_pstrdup(result_pool, url); 49 char *result_end; 50 const char *relpath_end; 51 52 SVN_ERR_ASSERT_NO_RETURN(svn_path_is_url(url)); 53 SVN_ERR_ASSERT_NO_RETURN(svn_relpath_is_canonical(relpath)); 54 55 if (relpath[0] == 0) 56 return result; 57 58 relpath = svn_path_uri_encode(relpath, scratch_pool); 59 result_end = result + strlen(result) - 1; 60 relpath_end = relpath + strlen(relpath) - 1; 61 62 while (relpath_end >= relpath) 63 { 64 if (*result_end != *relpath_end) 65 return NULL; 66 67 relpath_end--; 68 result_end--; 69 } 70 71 if (*result_end != '/') 72 return NULL; 73 74 *result_end = 0; 75 76 return result; 77} 78 79svn_error_t * 80svn_wc_relocate4(svn_wc_context_t *wc_ctx, 81 const char *local_abspath, 82 const char *from, 83 const char *to, 84 svn_wc_relocation_validator3_t validator, 85 void *validator_baton, 86 apr_pool_t *scratch_pool) 87{ 88 svn_node_kind_t kind; 89 const char *repos_relpath; 90 const char *old_repos_root, *old_url; 91 const char *new_repos_root, *new_url; 92 size_t from_len; 93 size_t old_url_len; 94 const char *uuid; 95 svn_boolean_t is_wc_root; 96 97 SVN_ERR(svn_wc__is_wcroot(&is_wc_root, wc_ctx, local_abspath, 98 scratch_pool)); 99 if (! is_wc_root) 100 { 101 const char *wcroot_abspath; 102 svn_error_t *err; 103 104 err = svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, 105 local_abspath, scratch_pool, scratch_pool); 106 if (err) 107 { 108 svn_error_clear(err); 109 return svn_error_createf( 110 SVN_ERR_WC_INVALID_OP_ON_CWD, NULL, 111 _("Cannot relocate '%s' as it is not the root of a working copy"), 112 svn_dirent_local_style(local_abspath, scratch_pool)); 113 } 114 else 115 { 116 return svn_error_createf( 117 SVN_ERR_WC_INVALID_OP_ON_CWD, NULL, 118 _("Cannot relocate '%s' as it is not the root of a working copy; " 119 "try relocating '%s' instead"), 120 svn_dirent_local_style(local_abspath, scratch_pool), 121 svn_dirent_local_style(wcroot_abspath, scratch_pool)); 122 } 123 } 124 125 SVN_ERR(svn_wc__db_read_info(NULL, &kind, NULL, &repos_relpath, 126 &old_repos_root, &uuid, 127 NULL, NULL, NULL, NULL, NULL, NULL, 128 NULL, NULL, NULL, NULL, NULL, NULL, 129 NULL, NULL, NULL, NULL, NULL, NULL, 130 NULL, NULL, NULL, 131 wc_ctx->db, local_abspath, scratch_pool, 132 scratch_pool)); 133 134 if (kind != svn_node_dir) 135 return svn_error_create(SVN_ERR_CLIENT_INVALID_RELOCATION, NULL, 136 _("Cannot relocate a single file")); 137 138 old_url = svn_path_url_add_component2(old_repos_root, repos_relpath, 139 scratch_pool); 140 old_url_len = strlen(old_url); 141 from_len = strlen(from); 142 if ((from_len > old_url_len) || (strncmp(old_url, from, strlen(from)) != 0)) 143 return svn_error_createf(SVN_ERR_WC_INVALID_RELOCATION, NULL, 144 _("Invalid source URL prefix: '%s' (does not " 145 "overlap target's URL '%s')"), 146 from, old_url); 147 148 if (old_url_len == from_len) 149 new_url = to; 150 else 151 new_url = apr_pstrcat(scratch_pool, to, old_url + from_len, SVN_VA_NULL); 152 if (! svn_path_is_url(new_url)) 153 return svn_error_createf(SVN_ERR_WC_INVALID_RELOCATION, NULL, 154 _("Invalid relocation destination: '%s' " 155 "(not a URL)"), new_url); 156 157 new_repos_root = url_remove_final_relpath(new_url, repos_relpath, 158 scratch_pool, scratch_pool); 159 if (!new_repos_root) 160 return svn_error_createf(SVN_ERR_WC_INVALID_RELOCATION, NULL, 161 _("Invalid relocation destination: '%s' " 162 "(does not point to target)" ), new_url); 163 164 SVN_ERR(validator(validator_baton, uuid, new_url, new_repos_root, 165 scratch_pool)); 166 167 return svn_error_trace(svn_wc__db_global_relocate(wc_ctx->db, local_abspath, 168 new_repos_root, 169 scratch_pool)); 170} 171