diff options
Diffstat (limited to 'subversion/libsvn_wc/relocate.c')
-rw-r--r-- | subversion/libsvn_wc/relocate.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/subversion/libsvn_wc/relocate.c b/subversion/libsvn_wc/relocate.c new file mode 100644 index 0000000..4a9df67 --- /dev/null +++ b/subversion/libsvn_wc/relocate.c @@ -0,0 +1,170 @@ +/* + * relocate.c: do wc repos relocation + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + + + +#include "svn_wc.h" +#include "svn_error.h" +#include "svn_pools.h" +#include "svn_dirent_uri.h" +#include "svn_path.h" + +#include "wc.h" +#include "props.h" + +#include "svn_private_config.h" + + +/* If the components of RELPATH exactly match (after being + URI-encoded) the final components of URL, return a copy of URL + minus those components allocated in RESULT_POOL; otherwise, return + NULL. */ +static const char * +url_remove_final_relpath(const char *url, + const char *relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + char *result = apr_pstrdup(result_pool, url); + char *result_end; + const char *relpath_end; + + SVN_ERR_ASSERT_NO_RETURN(svn_path_is_url(url)); + SVN_ERR_ASSERT_NO_RETURN(svn_relpath_is_canonical(relpath)); + + if (relpath[0] == 0) + return result; + + relpath = svn_path_uri_encode(relpath, scratch_pool); + result_end = result + strlen(result) - 1; + relpath_end = relpath + strlen(relpath) - 1; + + while (relpath_end >= relpath) + { + if (*result_end != *relpath_end) + return NULL; + + relpath_end--; + result_end--; + } + + if (*result_end != '/') + return NULL; + + *result_end = 0; + + return result; +} + +svn_error_t * +svn_wc_relocate4(svn_wc_context_t *wc_ctx, + const char *local_abspath, + const char *from, + const char *to, + svn_wc_relocation_validator3_t validator, + void *validator_baton, + apr_pool_t *scratch_pool) +{ + svn_node_kind_t kind; + const char *repos_relpath; + const char *old_repos_root, *old_url; + const char *new_repos_root, *new_url; + size_t from_len; + size_t old_url_len; + const char *uuid; + svn_boolean_t is_wc_root; + + SVN_ERR(svn_wc__is_wcroot(&is_wc_root, wc_ctx, local_abspath, + scratch_pool)); + if (! is_wc_root) + { + const char *wcroot_abspath; + svn_error_t *err; + + err = svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, + local_abspath, scratch_pool, scratch_pool); + if (err) + { + svn_error_clear(err); + return svn_error_createf( + SVN_ERR_WC_INVALID_OP_ON_CWD, NULL, + _("Cannot relocate '%s' as it is not the root of a working copy"), + svn_dirent_local_style(local_abspath, scratch_pool)); + } + else + { + return svn_error_createf( + SVN_ERR_WC_INVALID_OP_ON_CWD, NULL, + _("Cannot relocate '%s' as it is not the root of a working copy; " + "try relocating '%s' instead"), + svn_dirent_local_style(local_abspath, scratch_pool), + svn_dirent_local_style(wcroot_abspath, scratch_pool)); + } + } + + SVN_ERR(svn_wc__db_read_info(NULL, &kind, NULL, &repos_relpath, + &old_repos_root, &uuid, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + wc_ctx->db, local_abspath, scratch_pool, + scratch_pool)); + + if (kind != svn_node_dir) + return svn_error_create(SVN_ERR_CLIENT_INVALID_RELOCATION, NULL, + _("Cannot relocate a single file")); + + old_url = svn_path_url_add_component2(old_repos_root, repos_relpath, + scratch_pool); + old_url_len = strlen(old_url); + from_len = strlen(from); + if ((from_len > old_url_len) || (strncmp(old_url, from, strlen(from)) != 0)) + return svn_error_createf(SVN_ERR_WC_INVALID_RELOCATION, NULL, + _("Invalid source URL prefix: '%s' (does not " + "overlap target's URL '%s')"), + from, old_url); + + if (old_url_len == from_len) + new_url = to; + else + new_url = apr_pstrcat(scratch_pool, to, old_url + from_len, (char *)NULL); + if (! svn_path_is_url(new_url)) + return svn_error_createf(SVN_ERR_WC_INVALID_RELOCATION, NULL, + _("Invalid relocation destination: '%s' " + "(not a URL)"), new_url); + + new_repos_root = url_remove_final_relpath(new_url, repos_relpath, + scratch_pool, scratch_pool); + if (!new_repos_root) + return svn_error_createf(SVN_ERR_WC_INVALID_RELOCATION, NULL, + _("Invalid relocation destination: '%s' " + "(does not point to target)" ), new_url); + + SVN_ERR(validator(validator_baton, uuid, new_url, new_repos_root, + scratch_pool)); + + return svn_error_trace(svn_wc__db_global_relocate(wc_ctx->db, local_abspath, + new_repos_root, + scratch_pool)); +} |