summaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc/wcroot_anchor.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc/wcroot_anchor.c')
-rw-r--r--subversion/libsvn_wc/wcroot_anchor.c227
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;
+}