]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_wc/node.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_wc / node.c
1 /*
2  * node.c:  routines for getting information about nodes in the working copy.
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 /* A note about these functions:
25
26    We aren't really sure yet which bits of data libsvn_client needs about
27    nodes.  In wc-1, we just grab the entry, and then use whatever we want
28    from it.  Such a pattern is Bad.
29
30    This file is intended to hold functions which retrieve specific bits of
31    information about a node, and will hopefully give us a better idea about
32    what data libsvn_client needs, and how to best provide that data in 1.7
33    final.  As such, these functions should only be called from outside
34    libsvn_wc; any internal callers are encouraged to use the appropriate
35    information fetching function, such as svn_wc__db_read_info().
36 */
37
38 #include <apr_pools.h>
39 #include <apr_time.h>
40
41 #include "svn_pools.h"
42 #include "svn_dirent_uri.h"
43 #include "svn_path.h"
44 #include "svn_hash.h"
45 #include "svn_types.h"
46
47 #include "wc.h"
48 #include "props.h"
49 #include "entries.h"
50 #include "wc_db.h"
51
52 #include "svn_private_config.h"
53 #include "private/svn_wc_private.h"
54
55 \f
56 /* Set *CHILDREN_ABSPATHS to a new array of the full paths formed by joining
57  * each name in REL_CHILDREN onto DIR_ABSPATH.
58  *
59  * Allocate the output array and its elements in RESULT_POOL. */
60 static void
61 make_absolute(const apr_array_header_t **children_abspaths,
62               const char *dir_abspath,
63               const apr_array_header_t *rel_children,
64               apr_pool_t *result_pool)
65 {
66   apr_array_header_t *children;
67   int i;
68
69   children = apr_array_make(result_pool, rel_children->nelts,
70                             sizeof(const char *));
71   for (i = 0; i < rel_children->nelts; i++)
72     {
73       const char *name = APR_ARRAY_IDX(rel_children, i, const char *);
74       APR_ARRAY_PUSH(children, const char *) =
75                         svn_dirent_join(dir_abspath, name,
76                                         result_pool);
77     }
78
79   *children_abspaths = children;
80 }
81
82
83 svn_error_t *
84 svn_wc__node_get_children_of_working_node(const apr_array_header_t **children,
85                                           svn_wc_context_t *wc_ctx,
86                                           const char *dir_abspath,
87                                           apr_pool_t *result_pool,
88                                           apr_pool_t *scratch_pool)
89 {
90   const apr_array_header_t *child_names;
91
92   SVN_ERR(svn_wc__db_read_children_of_working_node(&child_names,
93                                                    wc_ctx->db, dir_abspath,
94                                                    scratch_pool, scratch_pool));
95   make_absolute(children, dir_abspath, child_names, result_pool);
96   return SVN_NO_ERROR;
97 }
98
99 svn_error_t *
100 svn_wc__node_get_not_present_children(const apr_array_header_t **children,
101                                       svn_wc_context_t *wc_ctx,
102                                       const char *dir_abspath,
103                                       apr_pool_t *result_pool,
104                                       apr_pool_t *scratch_pool)
105 {
106   const apr_array_header_t *child_names;
107
108   SVN_ERR(svn_wc__db_base_read_not_present_children(
109                                    &child_names,
110                                    wc_ctx->db, dir_abspath,
111                                    scratch_pool, scratch_pool));
112   make_absolute(children, dir_abspath, child_names, result_pool);
113   return SVN_NO_ERROR;
114 }
115
116 \f
117 svn_error_t *
118 svn_wc__node_get_repos_info(svn_revnum_t *revision,
119                             const char **repos_relpath,
120                             const char **repos_root_url,
121                             const char **repos_uuid,
122                             svn_wc_context_t *wc_ctx,
123                             const char *local_abspath,
124                             apr_pool_t *result_pool,
125                             apr_pool_t *scratch_pool)
126 {
127   return svn_error_trace(
128             svn_wc__db_read_repos_info(revision,
129                                        repos_relpath,
130                                        repos_root_url,
131                                        repos_uuid,
132                                        wc_ctx->db, local_abspath,
133                                        result_pool, scratch_pool));
134 }
135
136 /* Convert DB_KIND into the appropriate NODE_KIND value.
137  * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB
138  * even if DB_STATUS indicates that the node is hidden.
139  * Else, return svn_node_none for such nodes.
140  *
141  * ### This is a bit ugly. We should consider promoting svn_kind_t
142  * ### to the de-facto node kind type instead of converting between them
143  * ### in non-backwards compat code.
144  * ### See also comments at the definition of svn_kind_t.
145  *
146  * ### In reality, the previous comment is out of date, as there is
147  * ### now only one enumeration for node kinds, and that is
148  * ### svn_node_kind_t (svn_kind_t was merged with that). But it's
149  * ### still ugly.
150  */
151 static svn_error_t *
152 convert_db_kind_to_node_kind(svn_node_kind_t *node_kind,
153                              svn_node_kind_t db_kind,
154                              svn_wc__db_status_t db_status,
155                              svn_boolean_t show_hidden)
156 {
157   *node_kind = db_kind;
158
159   /* Make sure hidden nodes return svn_node_none. */
160   if (! show_hidden)
161     switch (db_status)
162       {
163         case svn_wc__db_status_not_present:
164         case svn_wc__db_status_server_excluded:
165         case svn_wc__db_status_excluded:
166           *node_kind = svn_node_none;
167
168         default:
169           break;
170       }
171
172   return SVN_NO_ERROR;
173 }
174
175 svn_error_t *
176 svn_wc_read_kind2(svn_node_kind_t *kind,
177                   svn_wc_context_t *wc_ctx,
178                   const char *local_abspath,
179                   svn_boolean_t show_deleted,
180                   svn_boolean_t show_hidden,
181                   apr_pool_t *scratch_pool)
182 {
183   svn_node_kind_t db_kind;
184
185   SVN_ERR(svn_wc__db_read_kind(&db_kind,
186                                wc_ctx->db, local_abspath,
187                                TRUE,
188                                show_deleted,
189                                show_hidden,
190                                scratch_pool));
191
192   if (db_kind == svn_node_dir)
193     *kind = svn_node_dir;
194   else if (db_kind == svn_node_file || db_kind == svn_node_symlink)
195     *kind = svn_node_file;
196   else
197     *kind = svn_node_none;
198
199   return SVN_NO_ERROR;
200 }
201
202 svn_error_t *
203 svn_wc__node_get_changed_info(svn_revnum_t *changed_rev,
204                               apr_time_t *changed_date,
205                               const char **changed_author,
206                               svn_wc_context_t *wc_ctx,
207                               const char *local_abspath,
208                               apr_pool_t *result_pool,
209                               apr_pool_t *scratch_pool)
210 {
211   return svn_error_trace(
212     svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, changed_rev,
213                          changed_date, changed_author, NULL, NULL, NULL,
214                          NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
215                          NULL, NULL, NULL, NULL, NULL, NULL, NULL,
216                          wc_ctx->db, local_abspath, result_pool,
217                          scratch_pool));
218 }
219
220 svn_error_t *
221 svn_wc__node_get_url(const char **url,
222                      svn_wc_context_t *wc_ctx,
223                      const char *local_abspath,
224                      apr_pool_t *result_pool,
225                      apr_pool_t *scratch_pool)
226 {
227   const char *repos_root_url;
228   const char *repos_relpath;
229
230   SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath, &repos_root_url,
231                                      NULL,
232                                      wc_ctx->db, local_abspath,
233                                      scratch_pool, scratch_pool));
234
235   *url = svn_path_url_add_component2(repos_root_url, repos_relpath,
236                                      result_pool);
237
238   return SVN_NO_ERROR;
239 }
240
241 /* A recursive node-walker, helper for svn_wc__internal_walk_children().
242  *
243  * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of
244  * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a
245  * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else
246  * ignore them. Restrict the depth of the walk to DEPTH.
247  *
248  * ### Is it possible for a subdirectory to be hidden and known to be a
249  *     directory?  If so, and if show_hidden is true, this will try to
250  *     recurse into it.  */
251 static svn_error_t *
252 walker_helper(svn_wc__db_t *db,
253               const char *dir_abspath,
254               svn_boolean_t show_hidden,
255               const apr_hash_t *changelist_filter,
256               svn_wc__node_found_func_t walk_callback,
257               void *walk_baton,
258               svn_depth_t depth,
259               svn_cancel_func_t cancel_func,
260               void *cancel_baton,
261               apr_pool_t *scratch_pool)
262 {
263   apr_pool_t *iterpool;
264   const apr_array_header_t *items;
265   int i;
266
267   if (depth == svn_depth_empty)
268     return SVN_NO_ERROR;
269
270   iterpool = svn_pool_create(scratch_pool);
271
272   SVN_ERR(svn_wc__db_read_children_walker_info(&items, db,
273                                                dir_abspath, scratch_pool,
274                                                iterpool));
275
276   for (i = 0; i < items->nelts; i++)
277     {
278       struct svn_wc__db_walker_info_t *wi =
279               APR_ARRAY_IDX(items, i, struct svn_wc__db_walker_info_t *);
280       const char *child_name = wi->name;
281       svn_node_kind_t child_kind = wi->kind;
282       svn_wc__db_status_t child_status = wi->status;
283       const char *child_abspath;
284
285       svn_pool_clear(iterpool);
286
287       /* See if someone wants to cancel this operation. */
288       if (cancel_func)
289         SVN_ERR(cancel_func(cancel_baton));
290
291       child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool);
292
293       if (!show_hidden)
294         switch (child_status)
295           {
296             case svn_wc__db_status_not_present:
297             case svn_wc__db_status_server_excluded:
298             case svn_wc__db_status_excluded:
299               continue;
300             default:
301               break;
302           }
303
304       /* Return the child, if appropriate. */
305       if ( (child_kind == svn_node_file
306              || depth >= svn_depth_immediates)
307            && svn_wc__internal_changelist_match(db, child_abspath,
308                                                 changelist_filter,
309                                                 scratch_pool) )
310         {
311           svn_node_kind_t kind;
312
313           SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind,
314                                                child_status, show_hidden));
315           /* ### We might want to pass child_status as well because at least
316            * ### one callee is asking for it.
317            * ### But is it OK to use an svn_wc__db type in this API?
318            * ###    Not yet, we need to get the node walker
319            * ###    libsvn_wc-internal first. -hkw */
320           SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool));
321         }
322
323       /* Recurse into this directory, if appropriate. */
324       if (child_kind == svn_node_dir
325             && depth >= svn_depth_immediates)
326         {
327           svn_depth_t depth_below_here = depth;
328
329           if (depth == svn_depth_immediates)
330             depth_below_here = svn_depth_empty;
331
332           SVN_ERR(walker_helper(db, child_abspath, show_hidden,
333                                 changelist_filter,
334                                 walk_callback, walk_baton,
335                                 depth_below_here,
336                                 cancel_func, cancel_baton,
337                                 iterpool));
338         }
339     }
340
341   svn_pool_destroy(iterpool);
342
343   return SVN_NO_ERROR;
344 }
345
346
347 svn_error_t *
348 svn_wc__internal_walk_children(svn_wc__db_t *db,
349                                const char *local_abspath,
350                                svn_boolean_t show_hidden,
351                                const apr_array_header_t *changelist_filter,
352                                svn_wc__node_found_func_t walk_callback,
353                                void *walk_baton,
354                                svn_depth_t walk_depth,
355                                svn_cancel_func_t cancel_func,
356                                void *cancel_baton,
357                                apr_pool_t *scratch_pool)
358 {
359   svn_node_kind_t db_kind;
360   svn_node_kind_t kind;
361   svn_wc__db_status_t status;
362   apr_hash_t *changelist_hash = NULL;
363   const char *changelist = NULL;
364
365   SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
366                  && walk_depth <= svn_depth_infinity);
367
368   if (changelist_filter && changelist_filter->nelts)
369     SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
370                                        scratch_pool));
371
372   /* Check if the node exists before the first callback */
373   SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
374                                NULL, NULL, NULL, NULL, NULL, NULL,
375                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
376                                changelist_hash ? &changelist : NULL,
377                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
378                                db, local_abspath, scratch_pool, scratch_pool));
379
380   SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
381
382   if (!changelist_hash
383       || (changelist && svn_hash_gets(changelist_hash, changelist)))
384     {
385       SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
386     }
387
388   if (db_kind == svn_node_file
389       || status == svn_wc__db_status_not_present
390       || status == svn_wc__db_status_excluded
391       || status == svn_wc__db_status_server_excluded)
392     return SVN_NO_ERROR;
393
394   if (db_kind == svn_node_dir)
395     {
396       return svn_error_trace(
397         walker_helper(db, local_abspath, show_hidden, changelist_hash,
398                       walk_callback, walk_baton,
399                       walk_depth, cancel_func, cancel_baton, scratch_pool));
400     }
401
402   return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
403                            _("'%s' has an unrecognized node kind"),
404                            svn_dirent_local_style(local_abspath,
405                                                   scratch_pool));
406 }
407
408 svn_error_t *
409 svn_wc__node_is_not_present(svn_boolean_t *is_not_present,
410                             svn_boolean_t *is_excluded,
411                             svn_boolean_t *is_server_excluded,
412                             svn_wc_context_t *wc_ctx,
413                             const char *local_abspath,
414                             svn_boolean_t base_only,
415                             apr_pool_t *scratch_pool)
416 {
417   svn_wc__db_status_t status;
418
419   if (base_only)
420     {
421       SVN_ERR(svn_wc__db_base_get_info(&status,
422                                        NULL, NULL, NULL, NULL, NULL, NULL,
423                                        NULL, NULL, NULL, NULL, NULL, NULL,
424                                        NULL, NULL, NULL,
425                                        wc_ctx->db, local_abspath,
426                                        scratch_pool, scratch_pool));
427     }
428   else
429     {
430       SVN_ERR(svn_wc__db_read_info(&status,
431                                    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
432                                    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
433                                    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
434                                    NULL, NULL, NULL, NULL, NULL,
435                                    wc_ctx->db, local_abspath,
436                                    scratch_pool, scratch_pool));
437     }
438
439   if (is_not_present)
440     *is_not_present = (status == svn_wc__db_status_not_present);
441
442   if (is_excluded)
443     *is_excluded = (status == svn_wc__db_status_excluded);
444
445   if (is_server_excluded)
446     *is_server_excluded = (status == svn_wc__db_status_server_excluded);
447
448   return SVN_NO_ERROR;
449 }
450
451 svn_error_t *
452 svn_wc__node_is_added(svn_boolean_t *is_added,
453                       svn_wc_context_t *wc_ctx,
454                       const char *local_abspath,
455                       apr_pool_t *scratch_pool)
456 {
457   svn_wc__db_status_t status;
458
459   SVN_ERR(svn_wc__db_read_info(&status,
460                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
461                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
462                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
463                                NULL, NULL, NULL, NULL, NULL,
464                                wc_ctx->db, local_abspath,
465                                scratch_pool, scratch_pool));
466   *is_added = (status == svn_wc__db_status_added);
467
468   return SVN_NO_ERROR;
469 }
470
471 svn_error_t *
472 svn_wc__node_has_working(svn_boolean_t *has_working,
473                          svn_wc_context_t *wc_ctx,
474                          const char *local_abspath,
475                          apr_pool_t *scratch_pool)
476 {
477   svn_wc__db_status_t status;
478
479   SVN_ERR(svn_wc__db_read_info(&status,
480                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
481                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
482                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
483                                NULL, NULL, NULL, NULL, has_working,
484                                wc_ctx->db, local_abspath,
485                                scratch_pool, scratch_pool));
486
487   return SVN_NO_ERROR;
488 }
489
490
491 svn_error_t *
492 svn_wc__node_get_base(svn_node_kind_t *kind,
493                       svn_revnum_t *revision,
494                       const char **repos_relpath,
495                       const char **repos_root_url,
496                       const char **repos_uuid,
497                       const char **lock_token,
498                       svn_wc_context_t *wc_ctx,
499                       const char *local_abspath,
500                       svn_boolean_t ignore_enoent,
501                       apr_pool_t *result_pool,
502                       apr_pool_t *scratch_pool)
503 {
504   svn_error_t *err;
505   svn_wc__db_status_t status;
506   svn_wc__db_lock_t *lock;
507   svn_node_kind_t db_kind;
508
509   err = svn_wc__db_base_get_info(&status, &db_kind, revision, repos_relpath,
510                                  repos_root_url, repos_uuid, NULL,
511                                  NULL, NULL, NULL, NULL, NULL,
512                                  lock_token ? &lock : NULL,
513                                  NULL, NULL, NULL,
514                                  wc_ctx->db, local_abspath,
515                                  result_pool, scratch_pool);
516
517   if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
518     return svn_error_trace(err);
519   else if (err
520            || (status != svn_wc__db_status_normal
521                && status != svn_wc__db_status_incomplete))
522     {
523       if (!ignore_enoent)
524         {
525           if (err)
526             return svn_error_trace(err);
527           else
528             return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
529                                      _("The node '%s' was not found."),
530                                      svn_dirent_local_style(local_abspath,
531                                                             scratch_pool));
532         }
533       svn_error_clear(err);
534
535       if (kind)
536         *kind = svn_node_unknown;
537       if (revision)
538         *revision = SVN_INVALID_REVNUM;
539       if (repos_relpath)
540         *repos_relpath = NULL;
541       if (repos_root_url)
542         *repos_root_url = NULL;
543       if (repos_uuid)
544         *repos_uuid = NULL;
545       if (lock_token)
546         *lock_token = NULL;
547       return SVN_NO_ERROR;
548     }
549
550   if (kind)
551     *kind = db_kind;
552   if (lock_token)
553     *lock_token = lock ? lock->token : NULL;
554
555   SVN_ERR_ASSERT(!revision || SVN_IS_VALID_REVNUM(*revision));
556   SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
557   SVN_ERR_ASSERT(!repos_root_url || *repos_root_url);
558   SVN_ERR_ASSERT(!repos_uuid || *repos_uuid);
559   return SVN_NO_ERROR;
560 }
561
562 svn_error_t *
563 svn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision,
564                                    svn_revnum_t *changed_rev,
565                                    apr_time_t *changed_date,
566                                    const char **changed_author,
567                                    svn_wc_context_t *wc_ctx,
568                                    const char *local_abspath,
569                                    apr_pool_t *result_pool,
570                                    apr_pool_t *scratch_pool)
571 {
572   svn_wc__db_status_t status;
573   svn_boolean_t have_base, have_more_work, have_work;
574
575   SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL,
576                                changed_rev, changed_date, changed_author,
577                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
578                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
579                                &have_base, &have_more_work, &have_work,
580                                wc_ctx->db, local_abspath,
581                                result_pool, scratch_pool));
582
583   if (!have_work
584       || ((!changed_rev || SVN_IS_VALID_REVNUM(*changed_rev))
585           && (!revision || SVN_IS_VALID_REVNUM(*revision)))
586       || ((status != svn_wc__db_status_added)
587           && (status != svn_wc__db_status_deleted)))
588     {
589       return SVN_NO_ERROR; /* We got everything we need */
590     }
591
592   if (have_base && !have_more_work)
593     SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
594                                      changed_rev, changed_date, changed_author,
595                                      NULL, NULL, NULL,
596                                      NULL, NULL, NULL, NULL,
597                                      wc_ctx->db, local_abspath,
598                                      result_pool, scratch_pool));
599   else if (status == svn_wc__db_status_deleted)
600     /* Check the information below a WORKING delete */
601     SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, changed_rev,
602                                           changed_date, changed_author, NULL,
603                                           NULL, NULL, NULL, NULL,
604                                           wc_ctx->db, local_abspath,
605                                           result_pool, scratch_pool));
606
607   return SVN_NO_ERROR;
608 }
609
610 svn_error_t *
611 svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx,
612                                        const char *local_abspath,
613                                        apr_pool_t *scratch_pool)
614 {
615   return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive(
616                               wc_ctx->db, local_abspath, scratch_pool));
617 }
618
619
620 svn_error_t *
621 svn_wc__node_get_lock_tokens_recursive(apr_hash_t **lock_tokens,
622                                        svn_wc_context_t *wc_ctx,
623                                        const char *local_abspath,
624                                        apr_pool_t *result_pool,
625                                        apr_pool_t *scratch_pool)
626 {
627   return svn_error_trace(svn_wc__db_base_get_lock_tokens_recursive(
628                               lock_tokens, wc_ctx->db, local_abspath,
629                               result_pool, scratch_pool));
630 }
631
632 svn_error_t *
633 svn_wc__get_excluded_subtrees(apr_hash_t **server_excluded_subtrees,
634                               svn_wc_context_t *wc_ctx,
635                               const char *local_abspath,
636                               apr_pool_t *result_pool,
637                               apr_pool_t *scratch_pool)
638 {
639   return svn_error_trace(
640            svn_wc__db_get_excluded_subtrees(server_excluded_subtrees,
641                                             wc_ctx->db,
642                                             local_abspath,
643                                             result_pool,
644                                             scratch_pool));
645 }
646
647 svn_error_t *
648 svn_wc__internal_get_origin(svn_boolean_t *is_copy,
649                             svn_revnum_t *revision,
650                             const char **repos_relpath,
651                             const char **repos_root_url,
652                             const char **repos_uuid,
653                             svn_depth_t *depth,
654                             const char **copy_root_abspath,
655                             svn_wc__db_t *db,
656                             const char *local_abspath,
657                             svn_boolean_t scan_deleted,
658                             apr_pool_t *result_pool,
659                             apr_pool_t *scratch_pool)
660 {
661   const char *original_repos_relpath;
662   const char *original_repos_root_url;
663   const char *original_repos_uuid;
664   svn_revnum_t original_revision;
665   svn_wc__db_status_t status;
666   svn_boolean_t have_more_work;
667   svn_boolean_t op_root;
668
669   const char *tmp_repos_relpath;
670
671   if (copy_root_abspath)
672     *copy_root_abspath = NULL;
673   if (!repos_relpath)
674     repos_relpath = &tmp_repos_relpath;
675
676   SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
677                                repos_root_url, repos_uuid, NULL, NULL, NULL,
678                                depth, NULL, NULL,
679                                &original_repos_relpath,
680                                &original_repos_root_url,
681                                &original_repos_uuid, &original_revision,
682                                NULL, NULL, NULL, NULL, NULL, &op_root, NULL,
683                                NULL, NULL, &have_more_work, is_copy,
684                                db, local_abspath, result_pool, scratch_pool));
685
686   if (*repos_relpath)
687     {
688       return SVN_NO_ERROR; /* Returned BASE information */
689     }
690
691   if (status == svn_wc__db_status_deleted && !scan_deleted)
692     {
693       if (is_copy)
694         *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */
695
696       return SVN_NO_ERROR; /* No info */
697     }
698
699   if (original_repos_relpath)
700     {
701       /* We an have a copy */
702       *repos_relpath = original_repos_relpath;
703       if (revision)
704         *revision = original_revision;
705       if (repos_root_url)
706         *repos_root_url = original_repos_root_url;
707       if (repos_uuid)
708         *repos_uuid = original_repos_uuid;
709
710       if (copy_root_abspath == NULL)
711         return SVN_NO_ERROR;
712       else if (op_root)
713         {
714           *copy_root_abspath = apr_pstrdup(result_pool, local_abspath);
715           return SVN_NO_ERROR;
716         }
717     }
718
719   {
720     svn_boolean_t scan_working = FALSE;
721
722     if (status == svn_wc__db_status_added
723         || (status == svn_wc__db_status_deleted && have_more_work))
724       scan_working = TRUE;
725
726     if (scan_working)
727       {
728         const char *op_root_abspath;
729
730         SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL,
731                                          NULL, NULL, &original_repos_relpath,
732                                          repos_root_url,
733                                          repos_uuid, revision,
734                                          db, local_abspath,
735                                          result_pool, scratch_pool));
736
737         if (status == svn_wc__db_status_added)
738           {
739             if (is_copy)
740               *is_copy = FALSE;
741             return SVN_NO_ERROR; /* Local addition */
742           }
743
744         /* We don't know how the following error condition can be fulfilled
745          * but we have seen that happening in the wild.  Better to create
746          * an error than a SEGFAULT. */
747         if (status == svn_wc__db_status_incomplete && !original_repos_relpath)
748           return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
749                                _("Incomplete copy information on path '%s'."),
750                                    svn_dirent_local_style(local_abspath,
751                                                           scratch_pool));
752
753         *repos_relpath = svn_relpath_join(
754                                 original_repos_relpath,
755                                 svn_dirent_skip_ancestor(op_root_abspath,
756                                                          local_abspath),
757                                 result_pool);
758         if (copy_root_abspath)
759           *copy_root_abspath = op_root_abspath;
760       }
761     else /* Deleted, excluded, not-present, server-excluded, ... */
762       {
763         if (is_copy)
764           *is_copy = FALSE;
765
766         SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath,
767                                          repos_root_url, repos_uuid, NULL,
768                                          NULL, NULL, NULL, NULL, NULL, NULL,
769                                          NULL, NULL, NULL,
770                                          db, local_abspath,
771                                          result_pool, scratch_pool));
772       }
773
774     return SVN_NO_ERROR;
775   }
776 }
777
778 svn_error_t *
779 svn_wc__node_get_origin(svn_boolean_t *is_copy,
780                         svn_revnum_t *revision,
781                         const char **repos_relpath,
782                         const char **repos_root_url,
783                         const char **repos_uuid,
784                         svn_depth_t *depth,
785                         const char **copy_root_abspath,
786                         svn_wc_context_t *wc_ctx,
787                         const char *local_abspath,
788                         svn_boolean_t scan_deleted,
789                         apr_pool_t *result_pool,
790                         apr_pool_t *scratch_pool)
791 {
792   return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision,
793                            repos_relpath, repos_root_url, repos_uuid,
794                            depth, copy_root_abspath,
795                            wc_ctx->db, local_abspath, scan_deleted,
796                            result_pool, scratch_pool));
797 }
798
799 svn_error_t *
800 svn_wc__node_get_commit_status(svn_boolean_t *added,
801                                svn_boolean_t *deleted,
802                                svn_boolean_t *is_replace_root,
803                                svn_boolean_t *is_op_root,
804                                svn_revnum_t *revision,
805                                svn_revnum_t *original_revision,
806                                const char **original_repos_relpath,
807                                svn_wc_context_t *wc_ctx,
808                                const char *local_abspath,
809                                apr_pool_t *result_pool,
810                                apr_pool_t *scratch_pool)
811 {
812   svn_wc__db_status_t status;
813   svn_boolean_t have_base;
814   svn_boolean_t have_more_work;
815   svn_boolean_t op_root;
816
817   /* ### All of this should be handled inside a single read transaction */
818   SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL,
819                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
820                                original_repos_relpath, NULL, NULL,
821                                original_revision, NULL, NULL, NULL,
822                                NULL, NULL,
823                                &op_root, NULL, NULL,
824                                &have_base, &have_more_work, NULL,
825                                wc_ctx->db, local_abspath,
826                                result_pool, scratch_pool));
827
828   if (added)
829     *added = (status == svn_wc__db_status_added);
830   if (deleted)
831     *deleted = (status == svn_wc__db_status_deleted);
832   if (is_op_root)
833     *is_op_root = op_root;
834
835   if (is_replace_root)
836     {
837       if (status == svn_wc__db_status_added
838           && op_root
839           && (have_base || have_more_work))
840         SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL,
841                                               wc_ctx->db, local_abspath,
842                                               scratch_pool));
843       else
844         *is_replace_root = FALSE;
845     }
846
847   /* Retrieve some information from BASE which is needed for replacing
848      and/or deleting BASE nodes. */
849   if (have_base
850       && !have_more_work
851       && op_root
852       && (revision && !SVN_IS_VALID_REVNUM(*revision)))
853     {
854       SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
855                                        NULL, NULL, NULL, NULL, NULL, NULL,
856                                        NULL, NULL, NULL, NULL,
857                                        wc_ctx->db, local_abspath,
858                                        scratch_pool, scratch_pool));
859     }
860
861   return SVN_NO_ERROR;
862 }
863
864 svn_error_t *
865 svn_wc__node_get_md5_from_sha1(const svn_checksum_t **md5_checksum,
866                                svn_wc_context_t *wc_ctx,
867                                const char *wri_abspath,
868                                const svn_checksum_t *sha1_checksum,
869                                apr_pool_t *result_pool,
870                                apr_pool_t *scratch_pool)
871 {
872   return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum,
873                                                      wc_ctx->db,
874                                                      wri_abspath,
875                                                      sha1_checksum,
876                                                      result_pool,
877                                                      scratch_pool));
878 }
879
880 svn_error_t *
881 svn_wc__get_not_present_descendants(const apr_array_header_t **descendants,
882                                     svn_wc_context_t *wc_ctx,
883                                     const char *local_abspath,
884                                     apr_pool_t *result_pool,
885                                     apr_pool_t *scratch_pool)
886 {
887   return svn_error_trace(
888                 svn_wc__db_get_not_present_descendants(descendants,
889                                                        wc_ctx->db,
890                                                        local_abspath,
891                                                        result_pool,
892                                                        scratch_pool));
893 }
894
895 svn_error_t *
896 svn_wc__rename_wc(svn_wc_context_t *wc_ctx,
897                   const char *from_abspath,
898                   const char *dst_abspath,
899                   apr_pool_t *scratch_pool)
900 {
901   const char *wcroot_abspath;
902   SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, from_abspath,
903                                 scratch_pool, scratch_pool));
904
905   if (! strcmp(from_abspath, wcroot_abspath))
906     {
907       SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool));
908
909       SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool));
910     }
911   else
912     return svn_error_createf(
913                     SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
914                     _("'%s' is not the root of the working copy '%s'"),
915                     svn_dirent_local_style(from_abspath, scratch_pool),
916                     svn_dirent_local_style(wcroot_abspath, scratch_pool));
917
918   return SVN_NO_ERROR;
919 }
920
921 svn_error_t *
922 svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
923                                svn_node_kind_t *kind,
924                                svn_boolean_t *deleted,
925                                svn_boolean_t *excluded,
926                                svn_depth_t *parent_depth,
927                                svn_wc_context_t *wc_ctx,
928                                const char *local_abspath,
929                                svn_boolean_t no_wcroot_check,
930                                apr_pool_t *scratch_pool)
931 {
932   svn_wc__db_status_t status;
933   svn_node_kind_t db_kind;
934   svn_node_kind_t disk_kind;
935   svn_error_t *err;
936
937   *obstruction_state = svn_wc_notify_state_inapplicable;
938   if (kind)
939     *kind = svn_node_none;
940   if (deleted)
941     *deleted = FALSE;
942   if (excluded)
943     *excluded = FALSE;
944   if (parent_depth)
945     *parent_depth = svn_depth_unknown;
946
947   SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
948
949   err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
950                              NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
951                              NULL, NULL, NULL, NULL, NULL, NULL, NULL,
952                              NULL, NULL, NULL, NULL, NULL,
953                              wc_ctx->db, local_abspath,
954                              scratch_pool, scratch_pool);
955
956   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
957     {
958       svn_error_clear(err);
959
960       if (disk_kind != svn_node_none)
961         {
962           /* Nothing in the DB, but something on disk */
963           *obstruction_state = svn_wc_notify_state_obstructed;
964           return SVN_NO_ERROR;
965         }
966
967       err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
968                                  NULL, NULL, NULL, parent_depth, NULL, NULL,
969                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
970                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
971                                  NULL,
972                                  wc_ctx->db, svn_dirent_dirname(local_abspath,
973                                                                 scratch_pool),
974                                  scratch_pool, scratch_pool);
975
976       if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
977         {
978           svn_error_clear(err);
979           /* No versioned parent; we can't add a node here */
980           *obstruction_state = svn_wc_notify_state_obstructed;
981           return SVN_NO_ERROR;
982         }
983       else
984         SVN_ERR(err);
985
986       if (db_kind != svn_node_dir
987           || (status != svn_wc__db_status_normal
988               && status != svn_wc__db_status_added))
989         {
990           /* The parent doesn't allow nodes to be added below it */
991           *obstruction_state = svn_wc_notify_state_obstructed;
992         }
993
994       return SVN_NO_ERROR;
995     }
996   else
997     SVN_ERR(err);
998
999   /* Check for obstructing working copies */
1000   if (!no_wcroot_check
1001       && db_kind == svn_node_dir
1002       && status == svn_wc__db_status_normal)
1003     {
1004       svn_boolean_t is_root;
1005       SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath,
1006                                    scratch_pool));
1007
1008       if (is_root)
1009         {
1010           /* Callers should handle this as unversioned */
1011           *obstruction_state = svn_wc_notify_state_obstructed;
1012           return SVN_NO_ERROR;
1013         }
1014     }
1015
1016   if (kind)
1017     SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE));
1018
1019   switch (status)
1020     {
1021       case svn_wc__db_status_deleted:
1022         if (deleted)
1023           *deleted = TRUE;
1024         /* Fall through to svn_wc__db_status_not_present */
1025       case svn_wc__db_status_not_present:
1026         if (disk_kind != svn_node_none)
1027           *obstruction_state = svn_wc_notify_state_obstructed;
1028         break;
1029
1030       case svn_wc__db_status_excluded:
1031       case svn_wc__db_status_server_excluded:
1032         if (excluded)
1033           *excluded = TRUE;
1034         /* fall through */
1035       case svn_wc__db_status_incomplete:
1036         *obstruction_state = svn_wc_notify_state_missing;
1037         break;
1038
1039       case svn_wc__db_status_added:
1040       case svn_wc__db_status_normal:
1041         if (disk_kind == svn_node_none)
1042           *obstruction_state = svn_wc_notify_state_missing;
1043         else
1044           {
1045             svn_node_kind_t expected_kind;
1046
1047             SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind,
1048                                                  status, FALSE));
1049
1050             if (disk_kind != expected_kind)
1051               *obstruction_state = svn_wc_notify_state_obstructed;
1052           }
1053         break;
1054       default:
1055         SVN_ERR_MALFUNCTION();
1056     }
1057
1058   return SVN_NO_ERROR;
1059 }
1060
1061
1062 svn_error_t *
1063 svn_wc__node_was_moved_away(const char **moved_to_abspath,
1064                             const char **op_root_abspath,
1065                             svn_wc_context_t *wc_ctx,
1066                             const char *local_abspath,
1067                             apr_pool_t *result_pool,
1068                             apr_pool_t *scratch_pool)
1069 {
1070   svn_wc__db_status_t status;
1071
1072   if (moved_to_abspath)
1073     *moved_to_abspath = NULL;
1074   if (op_root_abspath)
1075     *op_root_abspath = NULL;
1076
1077   SVN_ERR(svn_wc__db_read_info(&status,
1078                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1079                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1080                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1081                                NULL, NULL, NULL, NULL, NULL,
1082                                wc_ctx->db, local_abspath,
1083                                scratch_pool, scratch_pool));
1084
1085   if (status == svn_wc__db_status_deleted)
1086     SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL,
1087                                      op_root_abspath, wc_ctx->db,
1088                                      local_abspath,
1089                                      result_pool, scratch_pool));
1090
1091   return SVN_NO_ERROR;
1092 }
1093
1094
1095 svn_error_t *
1096 svn_wc__node_was_moved_here(const char **moved_from_abspath,
1097                             const char **delete_op_root_abspath,
1098                             svn_wc_context_t *wc_ctx,
1099                             const char *local_abspath,
1100                             apr_pool_t *result_pool,
1101                             apr_pool_t *scratch_pool)
1102 {
1103   svn_error_t *err;
1104
1105   if (moved_from_abspath)
1106     *moved_from_abspath = NULL;
1107   if (delete_op_root_abspath)
1108     *delete_op_root_abspath = NULL;
1109
1110   err = svn_wc__db_scan_moved(moved_from_abspath, NULL, NULL,
1111                               delete_op_root_abspath,
1112                               wc_ctx->db, local_abspath,
1113                               result_pool, scratch_pool);
1114
1115   if (err)
1116     {
1117       /* Return error for not added nodes */
1118       if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
1119         return svn_error_trace(err);
1120
1121       /* Path not moved here */
1122       svn_error_clear(err);
1123       return SVN_NO_ERROR;
1124     }
1125
1126   return SVN_NO_ERROR;
1127 }