2 * relocate.c: wrapper around wc relocation functionality.
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
24 /* ==================================================================== */
31 #include "svn_client.h"
32 #include "svn_pools.h"
33 #include "svn_error.h"
34 #include "svn_dirent_uri.h"
38 #include "private/svn_wc_private.h"
40 #include "svn_private_config.h"
45 /* Repository root and UUID for a repository. */
52 struct validator_baton_t
54 svn_client_ctx_t *ctx;
56 apr_array_header_t *url_uuids;
63 validator_func(void *baton,
69 struct validator_baton_t *b = baton;
70 struct url_uuid_t *url_uuid = NULL;
71 const char *disable_checks;
73 apr_array_header_t *uuids = b->url_uuids;
76 for (i = 0; i < uuids->nelts; ++i)
78 struct url_uuid_t *uu = &APR_ARRAY_IDX(uuids, i,
80 if (svn_uri__is_ancestor(uu->root, url))
87 disable_checks = getenv("SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_RELOCATE_VALIDATION");
88 if (disable_checks && (strcmp(disable_checks, "yes") == 0))
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);
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. */
102 apr_pool_t *sesspool = svn_pool_create(pool);
104 url_uuid = &APR_ARRAY_PUSH(uuids, struct url_uuid_t);
105 SVN_ERR(svn_client_get_repos_root(&url_uuid->root,
110 svn_pool_destroy(sesspool);
113 /* Make sure the url is a repository root if desired. */
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"),
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);
131 svn_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,
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;
145 /* Populate our validator callback baton, and call the relocate code. */
147 vb.path = wcroot_dir;
148 vb.url_uuids = apr_array_make(pool, 1, sizeof(struct url_uuid_t));
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"),
156 SVN_ERR(svn_dirent_get_absolute(&local_abspath, wcroot_dir, pool));
158 /* If we're ignoring externals, just relocate and get outta here. */
159 if (ignore_externals)
161 return svn_error_trace(svn_wc_relocate4(ctx->wc_ctx, local_abspath,
162 from_prefix, to_prefix,
163 validator_func, &vb, pool));
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));
170 /* Perform the relocation. */
171 SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from_prefix, to_prefix,
172 validator_func, &vb, pool));
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));
179 /* Relocate externals, too (if any). */
180 SVN_ERR(svn_wc__externals_defined_below(&externals_hash,
181 ctx->wc_ctx, local_abspath,
183 if (! apr_hash_count(externals_hash))
186 iterpool = svn_pool_create(pool);
188 for (hi = apr_hash_first(pool, externals_hash);
190 hi = apr_hash_next(hi))
192 svn_node_kind_t kind;
193 const char *this_abspath = apr_hash_this_key(hi);
195 svn_pool_clear(iterpool);
197 SVN_ERR(svn_wc__read_external_info(&kind, NULL, NULL, NULL, NULL,
199 local_abspath, this_abspath,
200 FALSE, iterpool, iterpool));
202 if (kind == svn_node_dir)
204 const char *this_repos_root_url;
207 err = svn_client_get_repos_root(&this_repos_root_url, NULL /* uuid */,
208 this_abspath, ctx, iterpool, iterpool);
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)
215 svn_error_clear(err);
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 */,
227 svn_pool_destroy(iterpool);