Win32: fix an incorrect error status being propagated to the caller in case
[svn/apache.git] / subversion / libsvn_wc / relocate.c
blobe4b335b5b9713461da38884534592d16e88e9a59
1 /*
2 * relocate.c: do wc repos relocation
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
20 * under the License.
21 * ====================================================================
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"
32 #include "wc.h"
33 #include "props.h"
35 #include "svn_private_config.h"
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. */
42 static const char *
43 url_remove_final_relpath(const char *url,
44 const char *relpath,
45 apr_pool_t *result_pool,
46 apr_pool_t *scratch_pool)
48 char *result = apr_pstrdup(result_pool, url);
49 char *result_end;
50 const char *relpath_end;
52 SVN_ERR_ASSERT_NO_RETURN(svn_path_is_url(url));
53 SVN_ERR_ASSERT_NO_RETURN(svn_relpath_is_canonical(relpath));
55 if (relpath[0] == 0)
56 return result;
58 relpath = svn_path_uri_encode(relpath, scratch_pool);
59 result_end = result + strlen(result) - 1;
60 relpath_end = relpath + strlen(relpath) - 1;
62 while (relpath_end >= relpath)
64 if (*result_end != *relpath_end)
65 return NULL;
67 relpath_end--;
68 result_end--;
71 if (*result_end != '/')
72 return NULL;
74 *result_end = 0;
76 return result;
79 svn_error_t *
80 svn_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)
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;
97 SVN_ERR(svn_wc__is_wcroot(&is_wc_root, wc_ctx, local_abspath,
98 scratch_pool));
99 if (! is_wc_root)
101 const char *wcroot_abspath;
102 svn_error_t *err;
104 err = svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db,
105 local_abspath, scratch_pool, scratch_pool);
106 if (err)
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));
114 else
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));
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));
134 if (kind != svn_node_dir)
135 return svn_error_create(SVN_ERR_CLIENT_INVALID_RELOCATION, NULL,
136 _("Cannot relocate a single file"));
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);
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);
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);
164 SVN_ERR(validator(validator_baton, uuid, new_url, new_repos_root,
165 scratch_pool));
167 return svn_error_trace(svn_wc__db_global_relocate(wc_ctx->db, local_abspath,
168 new_repos_root,
169 scratch_pool));