]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/subversion/subversion/libsvn_wc/wcroot_anchor.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / subversion / subversion / libsvn_wc / wcroot_anchor.c
1 /*
2  * wcroot_anchor.c :  wcroot and anchor functions
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 \f
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "svn_types.h"
30 #include "svn_pools.h"
31 #include "svn_string.h"
32 #include "svn_dirent_uri.h"
33 #include "svn_error.h"
34 #include "svn_io.h"
35 #include "svn_private_config.h"
36
37 #include "wc.h"
38
39 #include "private/svn_wc_private.h"
40
41 /* ABOUT ANCHOR AND TARGET, AND svn_wc_get_actual_target2()
42
43    THE GOAL
44
45    Note the following actions, where X is the thing we wish to update,
46    P is a directory whose repository URL is the parent of
47    X's repository URL, N is directory whose repository URL is *not*
48    the parent directory of X (including the case where N is not a
49    versioned resource at all):
50
51       1.  `svn up .' from inside X.
52       2.  `svn up ...P/X' from anywhere.
53       3.  `svn up ...N/X' from anywhere.
54
55    For the purposes of the discussion, in the '...N/X' situation, X is
56    said to be a "working copy (WC) root" directory.
57
58    Now consider the four cases for X's type (file/dir) in the working
59    copy vs. the repository:
60
61       A.  dir in working copy, dir in repos.
62       B.  dir in working copy, file in repos.
63       C.  file in working copy, dir in repos.
64       D.  file in working copy, file in repos.
65
66    Here are the results we expect for each combination of the above:
67
68       1A. Successfully update X.
69       1B. Error (you don't want to remove your current working
70           directory out from underneath the application).
71       1C. N/A (you can't be "inside X" if X is a file).
72       1D. N/A (you can't be "inside X" if X is a file).
73
74       2A. Successfully update X.
75       2B. Successfully update X.
76       2C. Successfully update X.
77       2D. Successfully update X.
78
79       3A. Successfully update X.
80       3B. Error (you can't create a versioned file X inside a
81           non-versioned directory).
82       3C. N/A (you can't have a versioned file X in directory that is
83           not its repository parent).
84       3D. N/A (you can't have a versioned file X in directory that is
85           not its repository parent).
86
87    To summarize, case 2 always succeeds, and cases 1 and 3 always fail
88    (or can't occur) *except* when the target is a dir that remains a
89    dir after the update.
90
91    ACCOMPLISHING THE GOAL
92
93    Updates are accomplished by driving an editor, and an editor is
94    "rooted" on a directory.  So, in order to update a file, we need to
95    break off the basename of the file, rooting the editor in that
96    file's parent directory, and then updating only that file, not the
97    other stuff in its parent directory.
98
99    Secondly, we look at the case where we wish to update a directory.
100    This is typically trivial.  However, one problematic case, exists
101    when we wish to update a directory that has been removed from the
102    repository and replaced with a file of the same name.  If we root
103    our edit at the initial directory, there is no editor mechanism for
104    deleting that directory and replacing it with a file (this would be
105    like having an editor now anchored on a file, which is disallowed).
106
107    All that remains is to have a function with the knowledge required
108    to properly decide where to root our editor, and what to act upon
109    with that now-rooted editor.  Given a path to be updated, this
110    function should conditionally split that path into an "anchor" and
111    a "target", where the "anchor" is the directory at which the update
112    editor is rooted (meaning, editor->open_root() is called with
113    this directory in mind), and the "target" is the actual intended
114    subject of the update.
115
116    svn_wc_get_actual_target2() is that function.
117
118    So, what are the conditions?
119
120    Case I: Any time X is '.' (implying it is a directory), we won't
121    lop off a basename.  So we'll root our editor at X, and update all
122    of X.
123
124    Cases II & III: Any time we are trying to update some path ...N/X,
125    we again will not lop off a basename.  We can't root an editor at
126    ...N with X as a target, either because ...N isn't a versioned
127    resource at all (Case II) or because X is X is not a child of ...N
128    in the repository (Case III).  We root at X, and update X.
129
130    Cases IV-???: We lop off a basename when we are updating a
131    path ...P/X, rooting our editor at ...P and updating X, or when X
132    is missing from disk.
133
134    These conditions apply whether X is a file or directory.
135
136    ---
137
138    As it turns out, commits need to have a similar check in place,
139    too, specifically for the case where a single directory is being
140    committed (we have to anchor at that directory's parent in case the
141    directory itself needs to be modified).
142 */
143
144
145 svn_error_t *
146 svn_wc_check_root(svn_boolean_t *is_wcroot,
147                   svn_boolean_t *is_switched,
148                   svn_node_kind_t *kind,
149                   svn_wc_context_t *wc_ctx,
150                   const char *local_abspath,
151                   apr_pool_t *scratch_pool)
152 {
153   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
154
155   return svn_error_trace(svn_wc__db_is_switched(is_wcroot,is_switched, kind,
156                                                 wc_ctx->db, local_abspath,
157                                                 scratch_pool));
158 }
159
160 svn_error_t *
161 svn_wc__is_wcroot(svn_boolean_t *is_wcroot,
162                   svn_wc_context_t *wc_ctx,
163                   const char *local_abspath,
164                   apr_pool_t *scratch_pool)
165 {
166   return svn_error_trace(svn_wc__db_is_wcroot(is_wcroot,
167                                               wc_ctx->db,
168                                               local_abspath,
169                                               scratch_pool));
170 }
171
172
173 svn_error_t *
174 svn_wc__get_wcroot(const char **wcroot_abspath,
175                    svn_wc_context_t *wc_ctx,
176                    const char *local_abspath,
177                    apr_pool_t *result_pool,
178                    apr_pool_t *scratch_pool)
179 {
180   return svn_wc__db_get_wcroot(wcroot_abspath, wc_ctx->db,
181                                local_abspath, result_pool, scratch_pool);
182 }
183
184
185 svn_error_t *
186 svn_wc_get_actual_target2(const char **anchor,
187                           const char **target,
188                           svn_wc_context_t *wc_ctx,
189                           const char *path,
190                           apr_pool_t *result_pool,
191                           apr_pool_t *scratch_pool)
192 {
193   svn_boolean_t is_wc_root, is_switched;
194   svn_node_kind_t kind;
195   const char *local_abspath;
196   svn_error_t *err;
197
198   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
199
200   err = svn_wc__db_is_switched(&is_wc_root, &is_switched, &kind,
201                                wc_ctx->db, local_abspath,
202                                scratch_pool);
203
204   if (err)
205     {
206       if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND &&
207           err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
208         return svn_error_trace(err);
209
210       svn_error_clear(err);
211       is_wc_root = FALSE;
212       is_switched = FALSE;
213     }
214
215   /* If PATH is not a WC root, or if it is a file, lop off a basename. */
216   if (!(is_wc_root || is_switched) || (kind != svn_node_dir))
217     {
218       svn_dirent_split(anchor, target, path, result_pool);
219     }
220   else
221     {
222       *anchor = apr_pstrdup(result_pool, path);
223       *target = "";
224     }
225
226   return SVN_NO_ERROR;
227 }