]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_client/relocate.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.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
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 }