diff options
Diffstat (limited to 'subversion/libsvn_wc/wcroot_anchor.c')
-rw-r--r-- | subversion/libsvn_wc/wcroot_anchor.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/subversion/libsvn_wc/wcroot_anchor.c b/subversion/libsvn_wc/wcroot_anchor.c new file mode 100644 index 0000000..913a61b --- /dev/null +++ b/subversion/libsvn_wc/wcroot_anchor.c @@ -0,0 +1,227 @@ +/* + * wcroot_anchor.c : wcroot and anchor functions + * + * ==================================================================== + * 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 <stdlib.h> +#include <string.h> + +#include "svn_types.h" +#include "svn_pools.h" +#include "svn_string.h" +#include "svn_dirent_uri.h" +#include "svn_error.h" +#include "svn_io.h" +#include "svn_private_config.h" + +#include "wc.h" + +#include "private/svn_wc_private.h" + +/* ABOUT ANCHOR AND TARGET, AND svn_wc_get_actual_target2() + + THE GOAL + + Note the following actions, where X is the thing we wish to update, + P is a directory whose repository URL is the parent of + X's repository URL, N is directory whose repository URL is *not* + the parent directory of X (including the case where N is not a + versioned resource at all): + + 1. `svn up .' from inside X. + 2. `svn up ...P/X' from anywhere. + 3. `svn up ...N/X' from anywhere. + + For the purposes of the discussion, in the '...N/X' situation, X is + said to be a "working copy (WC) root" directory. + + Now consider the four cases for X's type (file/dir) in the working + copy vs. the repository: + + A. dir in working copy, dir in repos. + B. dir in working copy, file in repos. + C. file in working copy, dir in repos. + D. file in working copy, file in repos. + + Here are the results we expect for each combination of the above: + + 1A. Successfully update X. + 1B. Error (you don't want to remove your current working + directory out from underneath the application). + 1C. N/A (you can't be "inside X" if X is a file). + 1D. N/A (you can't be "inside X" if X is a file). + + 2A. Successfully update X. + 2B. Successfully update X. + 2C. Successfully update X. + 2D. Successfully update X. + + 3A. Successfully update X. + 3B. Error (you can't create a versioned file X inside a + non-versioned directory). + 3C. N/A (you can't have a versioned file X in directory that is + not its repository parent). + 3D. N/A (you can't have a versioned file X in directory that is + not its repository parent). + + To summarize, case 2 always succeeds, and cases 1 and 3 always fail + (or can't occur) *except* when the target is a dir that remains a + dir after the update. + + ACCOMPLISHING THE GOAL + + Updates are accomplished by driving an editor, and an editor is + "rooted" on a directory. So, in order to update a file, we need to + break off the basename of the file, rooting the editor in that + file's parent directory, and then updating only that file, not the + other stuff in its parent directory. + + Secondly, we look at the case where we wish to update a directory. + This is typically trivial. However, one problematic case, exists + when we wish to update a directory that has been removed from the + repository and replaced with a file of the same name. If we root + our edit at the initial directory, there is no editor mechanism for + deleting that directory and replacing it with a file (this would be + like having an editor now anchored on a file, which is disallowed). + + All that remains is to have a function with the knowledge required + to properly decide where to root our editor, and what to act upon + with that now-rooted editor. Given a path to be updated, this + function should conditionally split that path into an "anchor" and + a "target", where the "anchor" is the directory at which the update + editor is rooted (meaning, editor->open_root() is called with + this directory in mind), and the "target" is the actual intended + subject of the update. + + svn_wc_get_actual_target2() is that function. + + So, what are the conditions? + + Case I: Any time X is '.' (implying it is a directory), we won't + lop off a basename. So we'll root our editor at X, and update all + of X. + + Cases II & III: Any time we are trying to update some path ...N/X, + we again will not lop off a basename. We can't root an editor at + ...N with X as a target, either because ...N isn't a versioned + resource at all (Case II) or because X is X is not a child of ...N + in the repository (Case III). We root at X, and update X. + + Cases IV-???: We lop off a basename when we are updating a + path ...P/X, rooting our editor at ...P and updating X, or when X + is missing from disk. + + These conditions apply whether X is a file or directory. + + --- + + As it turns out, commits need to have a similar check in place, + too, specifically for the case where a single directory is being + committed (we have to anchor at that directory's parent in case the + directory itself needs to be modified). +*/ + + +svn_error_t * +svn_wc_check_root(svn_boolean_t *is_wcroot, + svn_boolean_t *is_switched, + svn_node_kind_t *kind, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + apr_pool_t *scratch_pool) +{ + SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + + return svn_error_trace(svn_wc__db_is_switched(is_wcroot,is_switched, kind, + wc_ctx->db, local_abspath, + scratch_pool)); +} + +svn_error_t * +svn_wc__is_wcroot(svn_boolean_t *is_wcroot, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + apr_pool_t *scratch_pool) +{ + return svn_error_trace(svn_wc__db_is_wcroot(is_wcroot, + wc_ctx->db, + local_abspath, + scratch_pool)); +} + + +svn_error_t * +svn_wc__get_wcroot(const char **wcroot_abspath, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_wc__db_get_wcroot(wcroot_abspath, wc_ctx->db, + local_abspath, result_pool, scratch_pool); +} + + +svn_error_t * +svn_wc_get_actual_target2(const char **anchor, + const char **target, + svn_wc_context_t *wc_ctx, + const char *path, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_boolean_t is_wc_root, is_switched; + svn_node_kind_t kind; + const char *local_abspath; + svn_error_t *err; + + SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool)); + + err = svn_wc__db_is_switched(&is_wc_root, &is_switched, &kind, + wc_ctx->db, local_abspath, + scratch_pool); + + if (err) + { + if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND && + err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY) + return svn_error_trace(err); + + svn_error_clear(err); + is_wc_root = FALSE; + is_switched = FALSE; + } + + /* If PATH is not a WC root, or if it is a file, lop off a basename. */ + if (!(is_wc_root || is_switched) || (kind != svn_node_dir)) + { + svn_dirent_split(anchor, target, path, result_pool); + } + else + { + *anchor = apr_pstrdup(result_pool, path); + *target = ""; + } + + return SVN_NO_ERROR; +} |