]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/subversion/subversion/libsvn_client/relocate.c
Merge llvm trunk r366426, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / contrib / subversion / subversion / libsvn_client / relocate.c
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 \f
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 \f
43 /*** Code. ***/
44
45 /* Repository root and UUID for a repository. */
46 struct url_uuid_t
47 {
48   const char *root;
49   const char *uuid;
50 };
51
52 struct 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
62 static svn_error_t *
63 validator_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
130 svn_error_t *
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,
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   char *sig_from_prefix, *sig_to_prefix;
145   apr_size_t index_from, index_to;
146
147   /* Populate our validator callback baton, and call the relocate code. */
148   vb.ctx = ctx;
149   vb.path = wcroot_dir;
150   vb.url_uuids = apr_array_make(pool, 1, sizeof(struct url_uuid_t));
151   vb.pool = pool;
152
153   if (svn_path_is_url(wcroot_dir))
154     return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
155                              _("'%s' is not a local path"),
156                              wcroot_dir);
157
158   SVN_ERR(svn_dirent_get_absolute(&local_abspath, wcroot_dir, pool));
159
160   /* If we're ignoring externals, just relocate and get outta here. */
161   if (ignore_externals)
162     {
163       return svn_error_trace(svn_wc_relocate4(ctx->wc_ctx, local_abspath,
164                                               from_prefix, to_prefix,
165                                               validator_func, &vb, pool));
166     }
167
168   /* Fetch our current root URL. */
169   SVN_ERR(svn_client_get_repos_root(&old_repos_root_url, NULL /* uuid */,
170                                     local_abspath, ctx, pool, pool));
171
172   /* Perform the relocation. */
173   SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from_prefix, to_prefix,
174                            validator_func, &vb, pool));
175
176   /* Now fetch new current root URL. */
177   SVN_ERR(svn_client_get_repos_root(&new_repos_root_url, NULL /* uuid */,
178                                     local_abspath, ctx, pool, pool));
179
180
181   /* Relocate externals, too (if any). */
182   SVN_ERR(svn_wc__externals_defined_below(&externals_hash,
183                                           ctx->wc_ctx, local_abspath,
184                                           pool, pool));
185   if (! apr_hash_count(externals_hash))
186     return SVN_NO_ERROR;
187
188   /* A valid prefix for the main working copy may be too long to be
189      valid for an external.  Trim any common trailing characters to
190      leave the significant part that changes. */
191   sig_from_prefix = apr_pstrdup(pool, from_prefix);
192   sig_to_prefix = apr_pstrdup(pool, to_prefix);
193   index_from = strlen(sig_from_prefix);
194   index_to = strlen(sig_to_prefix);
195   while (index_from && index_to
196          && sig_from_prefix[index_from] == sig_to_prefix[index_to])
197     {
198       sig_from_prefix[index_from] = sig_to_prefix[index_to] = '\0';
199       --index_from;
200       --index_to;
201     }
202
203   iterpool = svn_pool_create(pool);
204
205   for (hi = apr_hash_first(pool, externals_hash);
206        hi != NULL;
207        hi = apr_hash_next(hi))
208     {
209       svn_node_kind_t kind;
210       const char *this_abspath = apr_hash_this_key(hi);
211
212       svn_pool_clear(iterpool);
213
214       SVN_ERR(svn_wc__read_external_info(&kind, NULL, NULL, NULL, NULL,
215                                          ctx->wc_ctx,
216                                          local_abspath, this_abspath,
217                                          FALSE, iterpool, iterpool));
218
219       if (kind == svn_node_dir)
220         {
221           const char *this_repos_root_url;
222           svn_error_t *err;
223
224           err = svn_client_get_repos_root(&this_repos_root_url, NULL /* uuid */,
225                                           this_abspath, ctx, iterpool, iterpool);
226
227           /* Ignore externals that aren't present in the working copy.
228            * This can happen if an external is deleted from disk accidentally,
229            * or if an external is configured on a locally added directory. */
230           if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
231             {
232               svn_error_clear(err);
233               continue;
234             }
235           SVN_ERR(err);
236
237           if (strcmp(old_repos_root_url, this_repos_root_url) == 0)
238             SVN_ERR(svn_client_relocate2(this_abspath,
239                                          sig_from_prefix, sig_to_prefix,
240                                          FALSE /* ignore_externals */,
241                                          ctx, iterpool));
242         }
243     }
244
245   svn_pool_destroy(iterpool);
246
247   return SVN_NO_ERROR;
248 }