2 * node.c: routines for getting information about nodes in the working copy.
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
24 /* A note about these functions:
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.
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().
38 #include <apr_pools.h>
41 #include "svn_pools.h"
42 #include "svn_dirent_uri.h"
45 #include "svn_types.h"
52 #include "svn_private_config.h"
53 #include "private/svn_wc_private.h"
56 /* Set *CHILDREN_ABSPATHS to a new array of the full paths formed by joining
57 * each name in REL_CHILDREN onto DIR_ABSPATH. If SHOW_HIDDEN is false then
58 * omit any paths that are reported as 'hidden' by svn_wc__db_node_hidden().
60 * Allocate the output array and its elements in RESULT_POOL. */
62 filter_and_make_absolute(const apr_array_header_t **children_abspaths,
63 svn_wc_context_t *wc_ctx,
64 const char *dir_abspath,
65 const apr_array_header_t *rel_children,
66 svn_boolean_t show_hidden,
67 apr_pool_t *result_pool,
68 apr_pool_t *scratch_pool)
70 apr_array_header_t *children;
73 children = apr_array_make(result_pool, rel_children->nelts,
74 sizeof(const char *));
75 for (i = 0; i < rel_children->nelts; i++)
77 const char *child_abspath = svn_dirent_join(dir_abspath,
78 APR_ARRAY_IDX(rel_children,
83 /* Don't add hidden nodes to *CHILDREN if we don't want them. */
86 svn_boolean_t child_is_hidden;
88 SVN_ERR(svn_wc__db_node_hidden(&child_is_hidden, wc_ctx->db,
89 child_abspath, scratch_pool));
94 APR_ARRAY_PUSH(children, const char *) = child_abspath;
97 *children_abspaths = children;
104 svn_wc__node_get_children_of_working_node(const apr_array_header_t **children,
105 svn_wc_context_t *wc_ctx,
106 const char *dir_abspath,
107 svn_boolean_t show_hidden,
108 apr_pool_t *result_pool,
109 apr_pool_t *scratch_pool)
111 const apr_array_header_t *rel_children;
113 SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
114 wc_ctx->db, dir_abspath,
115 scratch_pool, scratch_pool));
116 SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
117 rel_children, show_hidden,
118 result_pool, scratch_pool));
123 svn_wc__node_get_children(const apr_array_header_t **children,
124 svn_wc_context_t *wc_ctx,
125 const char *dir_abspath,
126 svn_boolean_t show_hidden,
127 apr_pool_t *result_pool,
128 apr_pool_t *scratch_pool)
130 const apr_array_header_t *rel_children;
132 SVN_ERR(svn_wc__db_read_children(&rel_children, wc_ctx->db, dir_abspath,
133 scratch_pool, scratch_pool));
134 SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
135 rel_children, show_hidden,
136 result_pool, scratch_pool));
142 svn_wc__internal_get_repos_info(svn_revnum_t *revision,
143 const char **repos_relpath,
144 const char **repos_root_url,
145 const char **repos_uuid,
147 const char *local_abspath,
148 apr_pool_t *result_pool,
149 apr_pool_t *scratch_pool)
151 svn_wc__db_status_t status;
152 svn_boolean_t have_work;
154 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
155 repos_root_url, repos_uuid,
156 NULL, NULL, NULL, NULL, NULL, NULL,
157 NULL, NULL, NULL, NULL, NULL, NULL,
158 NULL, NULL, NULL, NULL, NULL, NULL,
159 NULL, NULL, &have_work,
161 result_pool, scratch_pool));
163 if ((repos_relpath ? *repos_relpath != NULL : TRUE)
164 && (repos_root_url ? *repos_root_url != NULL: TRUE)
165 && (repos_uuid ? *repos_uuid != NULL : TRUE))
166 return SVN_NO_ERROR; /* We got the requested information */
168 if (!have_work) /* not-present, (server-)excluded? */
170 return SVN_NO_ERROR; /* Can't fetch more */
173 if (status == svn_wc__db_status_deleted)
175 const char *base_del_abspath, *wrk_del_abspath;
177 SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, NULL,
178 &wrk_del_abspath, NULL,
180 scratch_pool, scratch_pool));
182 if (base_del_abspath)
184 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, repos_relpath,
185 repos_root_url, repos_uuid, NULL,
186 NULL, NULL, NULL, NULL, NULL, NULL,
188 db, base_del_abspath,
189 result_pool, scratch_pool));
191 /* If we have a repos_relpath, it is of the op-root */
193 *repos_relpath = svn_relpath_join(*repos_relpath,
194 svn_dirent_skip_ancestor(base_del_abspath,
197 /* We keep revision as SVN_INVALID_REVNUM */
199 else if (wrk_del_abspath)
201 const char *op_root_abspath = NULL;
203 SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
204 ? &op_root_abspath : NULL,
205 repos_relpath, repos_root_url,
206 repos_uuid, NULL, NULL, NULL, NULL,
207 db, svn_dirent_dirname(
210 result_pool, scratch_pool));
212 /* If we have a repos_relpath, it is of the op-root */
214 *repos_relpath = svn_relpath_join(
216 svn_dirent_skip_ancestor(op_root_abspath,
221 else /* added, or WORKING incomplete */
223 const char *op_root_abspath = NULL;
225 /* We have an addition. scan_addition() will find the intended
226 repository location by scanning up the tree. */
227 SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
228 ? &op_root_abspath : NULL,
229 repos_relpath, repos_root_url,
230 repos_uuid, NULL, NULL, NULL, NULL,
232 result_pool, scratch_pool));
235 SVN_ERR_ASSERT(repos_root_url == NULL || *repos_root_url != NULL);
236 SVN_ERR_ASSERT(repos_uuid == NULL || *repos_uuid != NULL);
241 svn_wc__node_get_repos_info(svn_revnum_t *revision,
242 const char **repos_relpath,
243 const char **repos_root_url,
244 const char **repos_uuid,
245 svn_wc_context_t *wc_ctx,
246 const char *local_abspath,
247 apr_pool_t *result_pool,
248 apr_pool_t *scratch_pool)
250 return svn_error_trace(
251 svn_wc__internal_get_repos_info(revision,
255 wc_ctx->db, local_abspath,
256 result_pool, scratch_pool));
259 /* Convert DB_KIND into the appropriate NODE_KIND value.
260 * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB
261 * even if DB_STATUS indicates that the node is hidden.
262 * Else, return svn_node_none for such nodes.
264 * ### This is a bit ugly. We should consider promoting svn_kind_t
265 * ### to the de-facto node kind type instead of converting between them
266 * ### in non-backwards compat code.
267 * ### See also comments at the definition of svn_kind_t.
269 * ### In reality, the previous comment is out of date, as there is
270 * ### now only one enumeration for node kinds, and that is
271 * ### svn_node_kind_t (svn_kind_t was merged with that). But it's
275 convert_db_kind_to_node_kind(svn_node_kind_t *node_kind,
276 svn_node_kind_t db_kind,
277 svn_wc__db_status_t db_status,
278 svn_boolean_t show_hidden)
280 *node_kind = db_kind;
282 /* Make sure hidden nodes return svn_node_none. */
286 case svn_wc__db_status_not_present:
287 case svn_wc__db_status_server_excluded:
288 case svn_wc__db_status_excluded:
289 *node_kind = svn_node_none;
299 svn_wc_read_kind2(svn_node_kind_t *kind,
300 svn_wc_context_t *wc_ctx,
301 const char *local_abspath,
302 svn_boolean_t show_deleted,
303 svn_boolean_t show_hidden,
304 apr_pool_t *scratch_pool)
306 svn_node_kind_t db_kind;
308 SVN_ERR(svn_wc__db_read_kind(&db_kind,
309 wc_ctx->db, local_abspath,
315 if (db_kind == svn_node_dir)
316 *kind = svn_node_dir;
317 else if (db_kind == svn_node_file || db_kind == svn_node_symlink)
318 *kind = svn_node_file;
320 *kind = svn_node_none;
326 svn_wc__node_get_depth(svn_depth_t *depth,
327 svn_wc_context_t *wc_ctx,
328 const char *local_abspath,
329 apr_pool_t *scratch_pool)
331 return svn_error_trace(
332 svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
333 NULL, NULL, depth, NULL, NULL, NULL, NULL,
334 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
335 NULL, NULL, NULL, NULL, NULL, NULL,
336 wc_ctx->db, local_abspath, scratch_pool,
341 svn_wc__node_get_changed_info(svn_revnum_t *changed_rev,
342 apr_time_t *changed_date,
343 const char **changed_author,
344 svn_wc_context_t *wc_ctx,
345 const char *local_abspath,
346 apr_pool_t *result_pool,
347 apr_pool_t *scratch_pool)
349 return svn_error_trace(
350 svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, changed_rev,
351 changed_date, changed_author, NULL, NULL, NULL,
352 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
353 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
354 wc_ctx->db, local_abspath, result_pool,
359 svn_wc__node_get_url(const char **url,
360 svn_wc_context_t *wc_ctx,
361 const char *local_abspath,
362 apr_pool_t *result_pool,
363 apr_pool_t *scratch_pool)
365 return svn_error_trace(svn_wc__db_read_url(url, wc_ctx->db, local_abspath,
366 result_pool, scratch_pool));
369 /* A recursive node-walker, helper for svn_wc__internal_walk_children().
371 * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of
372 * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a
373 * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else
374 * ignore them. Restrict the depth of the walk to DEPTH.
376 * ### Is it possible for a subdirectory to be hidden and known to be a
377 * directory? If so, and if show_hidden is true, this will try to
378 * recurse into it. */
380 walker_helper(svn_wc__db_t *db,
381 const char *dir_abspath,
382 svn_boolean_t show_hidden,
383 const apr_hash_t *changelist_filter,
384 svn_wc__node_found_func_t walk_callback,
387 svn_cancel_func_t cancel_func,
389 apr_pool_t *scratch_pool)
391 apr_hash_t *rel_children_info;
392 apr_hash_index_t *hi;
393 apr_pool_t *iterpool;
395 if (depth == svn_depth_empty)
398 SVN_ERR(svn_wc__db_read_children_walker_info(&rel_children_info, db,
399 dir_abspath, scratch_pool,
403 iterpool = svn_pool_create(scratch_pool);
404 for (hi = apr_hash_first(scratch_pool, rel_children_info);
406 hi = apr_hash_next(hi))
408 const char *child_name = svn__apr_hash_index_key(hi);
409 struct svn_wc__db_walker_info_t *wi = svn__apr_hash_index_val(hi);
410 svn_node_kind_t child_kind = wi->kind;
411 svn_wc__db_status_t child_status = wi->status;
412 const char *child_abspath;
414 svn_pool_clear(iterpool);
416 /* See if someone wants to cancel this operation. */
418 SVN_ERR(cancel_func(cancel_baton));
420 child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool);
423 switch (child_status)
425 case svn_wc__db_status_not_present:
426 case svn_wc__db_status_server_excluded:
427 case svn_wc__db_status_excluded:
433 /* Return the child, if appropriate. */
434 if ( (child_kind == svn_node_file
435 || depth >= svn_depth_immediates)
436 && svn_wc__internal_changelist_match(db, child_abspath,
440 svn_node_kind_t kind;
442 SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind,
443 child_status, show_hidden));
444 /* ### We might want to pass child_status as well because at least
445 * ### one callee is asking for it.
446 * ### But is it OK to use an svn_wc__db type in this API?
447 * ### Not yet, we need to get the node walker
448 * ### libsvn_wc-internal first. -hkw */
449 SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool));
452 /* Recurse into this directory, if appropriate. */
453 if (child_kind == svn_node_dir
454 && depth >= svn_depth_immediates)
456 svn_depth_t depth_below_here = depth;
458 if (depth == svn_depth_immediates)
459 depth_below_here = svn_depth_empty;
461 SVN_ERR(walker_helper(db, child_abspath, show_hidden,
463 walk_callback, walk_baton,
465 cancel_func, cancel_baton,
470 svn_pool_destroy(iterpool);
477 svn_wc__internal_walk_children(svn_wc__db_t *db,
478 const char *local_abspath,
479 svn_boolean_t show_hidden,
480 const apr_array_header_t *changelist_filter,
481 svn_wc__node_found_func_t walk_callback,
483 svn_depth_t walk_depth,
484 svn_cancel_func_t cancel_func,
486 apr_pool_t *scratch_pool)
488 svn_node_kind_t db_kind;
489 svn_node_kind_t kind;
490 svn_wc__db_status_t status;
491 apr_hash_t *changelist_hash = NULL;
493 SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
494 && walk_depth <= svn_depth_infinity);
496 if (changelist_filter && changelist_filter->nelts)
497 SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
500 /* Check if the node exists before the first callback */
501 SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
502 NULL, NULL, NULL, NULL, NULL, NULL,
503 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
504 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
505 db, local_abspath, scratch_pool, scratch_pool));
507 SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
509 if (svn_wc__internal_changelist_match(db, local_abspath,
510 changelist_hash, scratch_pool))
511 SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
513 if (db_kind == svn_node_file
514 || status == svn_wc__db_status_not_present
515 || status == svn_wc__db_status_excluded
516 || status == svn_wc__db_status_server_excluded)
519 if (db_kind == svn_node_dir)
521 return svn_error_trace(
522 walker_helper(db, local_abspath, show_hidden, changelist_hash,
523 walk_callback, walk_baton,
524 walk_depth, cancel_func, cancel_baton, scratch_pool));
527 return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
528 _("'%s' has an unrecognized node kind"),
529 svn_dirent_local_style(local_abspath,
534 svn_wc__node_is_status_deleted(svn_boolean_t *is_deleted,
535 svn_wc_context_t *wc_ctx,
536 const char *local_abspath,
537 apr_pool_t *scratch_pool)
539 svn_wc__db_status_t status;
541 SVN_ERR(svn_wc__db_read_info(&status,
542 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
543 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
544 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
545 NULL, NULL, NULL, NULL, NULL,
546 wc_ctx->db, local_abspath,
547 scratch_pool, scratch_pool));
549 *is_deleted = (status == svn_wc__db_status_deleted);
555 svn_wc__node_get_deleted_ancestor(const char **deleted_ancestor_abspath,
556 svn_wc_context_t *wc_ctx,
557 const char *local_abspath,
558 apr_pool_t *result_pool,
559 apr_pool_t *scratch_pool)
561 svn_wc__db_status_t status;
563 *deleted_ancestor_abspath = NULL;
565 SVN_ERR(svn_wc__db_read_info(&status,
566 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
567 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
568 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
569 NULL, NULL, NULL, NULL, NULL,
570 wc_ctx->db, local_abspath,
571 scratch_pool, scratch_pool));
573 if (status == svn_wc__db_status_deleted)
574 SVN_ERR(svn_wc__db_scan_deletion(deleted_ancestor_abspath, NULL, NULL,
575 NULL, wc_ctx->db, local_abspath,
576 result_pool, scratch_pool));
582 svn_wc__node_is_not_present(svn_boolean_t *is_not_present,
583 svn_boolean_t *is_excluded,
584 svn_boolean_t *is_server_excluded,
585 svn_wc_context_t *wc_ctx,
586 const char *local_abspath,
587 svn_boolean_t base_only,
588 apr_pool_t *scratch_pool)
590 svn_wc__db_status_t status;
594 SVN_ERR(svn_wc__db_base_get_info(&status,
595 NULL, NULL, NULL, NULL, NULL, NULL,
596 NULL, NULL, NULL, NULL, NULL, NULL,
598 wc_ctx->db, local_abspath,
599 scratch_pool, scratch_pool));
603 SVN_ERR(svn_wc__db_read_info(&status,
604 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
605 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
606 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
607 NULL, NULL, NULL, NULL, NULL,
608 wc_ctx->db, local_abspath,
609 scratch_pool, scratch_pool));
613 *is_not_present = (status == svn_wc__db_status_not_present);
616 *is_excluded = (status == svn_wc__db_status_excluded);
618 if (is_server_excluded)
619 *is_server_excluded = (status == svn_wc__db_status_server_excluded);
625 svn_wc__node_is_added(svn_boolean_t *is_added,
626 svn_wc_context_t *wc_ctx,
627 const char *local_abspath,
628 apr_pool_t *scratch_pool)
630 svn_wc__db_status_t status;
632 SVN_ERR(svn_wc__db_read_info(&status,
633 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
634 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
635 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
636 NULL, NULL, NULL, NULL, NULL,
637 wc_ctx->db, local_abspath,
638 scratch_pool, scratch_pool));
639 *is_added = (status == svn_wc__db_status_added);
645 svn_wc__node_has_working(svn_boolean_t *has_working,
646 svn_wc_context_t *wc_ctx,
647 const char *local_abspath,
648 apr_pool_t *scratch_pool)
650 svn_wc__db_status_t status;
652 SVN_ERR(svn_wc__db_read_info(&status,
653 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
654 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
655 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
656 NULL, NULL, NULL, NULL, has_working,
657 wc_ctx->db, local_abspath,
658 scratch_pool, scratch_pool));
665 svn_wc__node_get_base(svn_node_kind_t *kind,
666 svn_revnum_t *revision,
667 const char **repos_relpath,
668 const char **repos_root_url,
669 const char **repos_uuid,
670 const char **lock_token,
671 svn_wc_context_t *wc_ctx,
672 const char *local_abspath,
673 svn_boolean_t ignore_enoent,
674 svn_boolean_t show_hidden,
675 apr_pool_t *result_pool,
676 apr_pool_t *scratch_pool)
679 svn_wc__db_status_t status;
680 svn_wc__db_lock_t *lock;
681 svn_node_kind_t db_kind;
683 err = svn_wc__db_base_get_info(&status, &db_kind, revision, repos_relpath,
684 repos_root_url, repos_uuid, NULL,
685 NULL, NULL, NULL, NULL, NULL,
686 lock_token ? &lock : NULL,
688 wc_ctx->db, local_abspath,
689 result_pool, scratch_pool);
691 if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
692 return svn_error_trace(err);
694 || (!err && !show_hidden
695 && (status != svn_wc__db_status_normal
696 && status != svn_wc__db_status_incomplete)))
701 return svn_error_trace(err);
703 return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
704 _("The node '%s' was not found."),
705 svn_dirent_local_style(local_abspath,
708 svn_error_clear(err);
711 *kind = svn_node_unknown;
713 *revision = SVN_INVALID_REVNUM;
715 *repos_relpath = NULL;
717 *repos_root_url = NULL;
728 *lock_token = lock ? lock->token : NULL;
730 SVN_ERR_ASSERT(!revision || SVN_IS_VALID_REVNUM(*revision));
731 SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
732 SVN_ERR_ASSERT(!repos_root_url || *repos_root_url);
733 SVN_ERR_ASSERT(!repos_uuid || *repos_uuid);
738 svn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision,
739 svn_revnum_t *changed_rev,
740 apr_time_t *changed_date,
741 const char **changed_author,
742 svn_wc_context_t *wc_ctx,
743 const char *local_abspath,
744 apr_pool_t *result_pool,
745 apr_pool_t *scratch_pool)
747 svn_wc__db_status_t status;
748 svn_boolean_t have_base, have_more_work, have_work;
750 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL,
751 changed_rev, changed_date, changed_author,
752 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
753 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
754 &have_base, &have_more_work, &have_work,
755 wc_ctx->db, local_abspath,
756 result_pool, scratch_pool));
759 || ((!changed_rev || SVN_IS_VALID_REVNUM(*changed_rev))
760 && (!revision || SVN_IS_VALID_REVNUM(*revision)))
761 || ((status != svn_wc__db_status_added)
762 && (status != svn_wc__db_status_deleted)))
764 return SVN_NO_ERROR; /* We got everything we need */
767 if (have_base && !have_more_work)
768 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
769 changed_rev, changed_date, changed_author,
771 NULL, NULL, NULL, NULL,
772 wc_ctx->db, local_abspath,
773 result_pool, scratch_pool));
774 else if (status == svn_wc__db_status_deleted)
775 /* Check the information below a WORKING delete */
776 SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, changed_rev,
777 changed_date, changed_author, NULL,
778 NULL, NULL, NULL, NULL,
779 wc_ctx->db, local_abspath,
780 result_pool, scratch_pool));
786 svn_wc__internal_node_get_schedule(svn_wc_schedule_t *schedule,
787 svn_boolean_t *copied,
789 const char *local_abspath,
790 apr_pool_t *scratch_pool)
792 svn_wc__db_status_t status;
793 svn_boolean_t op_root;
794 svn_boolean_t have_base;
795 svn_boolean_t have_work;
796 svn_boolean_t have_more_work;
797 const char *copyfrom_relpath;
800 *schedule = svn_wc_schedule_normal;
804 SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
805 NULL, NULL, NULL, NULL, NULL, ©from_relpath,
806 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
807 &op_root, NULL, NULL,
808 &have_base, &have_more_work, &have_work,
809 db, local_abspath, scratch_pool, scratch_pool));
813 case svn_wc__db_status_not_present:
814 case svn_wc__db_status_server_excluded:
815 case svn_wc__db_status_excluded:
816 /* We used status normal in the entries world. */
818 *schedule = svn_wc_schedule_normal;
820 case svn_wc__db_status_normal:
821 case svn_wc__db_status_incomplete:
824 case svn_wc__db_status_deleted:
827 *schedule = svn_wc_schedule_delete;
832 if (have_more_work || !have_base)
836 const char *work_del_abspath;
838 /* Find out details of our deletion. */
839 SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
840 &work_del_abspath, NULL,
842 scratch_pool, scratch_pool));
844 if (work_del_abspath)
845 *copied = TRUE; /* Working deletion */
849 case svn_wc__db_status_added:
857 *schedule = svn_wc_schedule_normal;
863 *copied = (copyfrom_relpath != NULL);
866 *schedule = svn_wc_schedule_add;
870 /* Check for replaced */
871 if (have_base || have_more_work)
873 svn_wc__db_status_t below_working;
874 SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work,
879 /* If the node is not present or deleted (read: not present
880 in working), then the node is not a replacement */
881 if (below_working != svn_wc__db_status_not_present
882 && below_working != svn_wc__db_status_deleted)
884 *schedule = svn_wc_schedule_replace;
891 SVN_ERR_MALFUNCTION();
898 svn_wc__node_get_schedule(svn_wc_schedule_t *schedule,
899 svn_boolean_t *copied,
900 svn_wc_context_t *wc_ctx,
901 const char *local_abspath,
902 apr_pool_t *scratch_pool)
904 return svn_error_trace(
905 svn_wc__internal_node_get_schedule(schedule,
913 svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx,
914 const char *local_abspath,
915 apr_pool_t *scratch_pool)
917 return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive(
918 wc_ctx->db, local_abspath, scratch_pool));
923 svn_wc__node_get_lock_tokens_recursive(apr_hash_t **lock_tokens,
924 svn_wc_context_t *wc_ctx,
925 const char *local_abspath,
926 apr_pool_t *result_pool,
927 apr_pool_t *scratch_pool)
929 return svn_error_trace(svn_wc__db_base_get_lock_tokens_recursive(
930 lock_tokens, wc_ctx->db, local_abspath,
931 result_pool, scratch_pool));
935 svn_wc__get_excluded_subtrees(apr_hash_t **server_excluded_subtrees,
936 svn_wc_context_t *wc_ctx,
937 const char *local_abspath,
938 apr_pool_t *result_pool,
939 apr_pool_t *scratch_pool)
941 return svn_error_trace(
942 svn_wc__db_get_excluded_subtrees(server_excluded_subtrees,
950 svn_wc__internal_get_origin(svn_boolean_t *is_copy,
951 svn_revnum_t *revision,
952 const char **repos_relpath,
953 const char **repos_root_url,
954 const char **repos_uuid,
955 const char **copy_root_abspath,
957 const char *local_abspath,
958 svn_boolean_t scan_deleted,
959 apr_pool_t *result_pool,
960 apr_pool_t *scratch_pool)
962 const char *original_repos_relpath;
963 const char *original_repos_root_url;
964 const char *original_repos_uuid;
965 svn_revnum_t original_revision;
966 svn_wc__db_status_t status;
968 const char *tmp_repos_relpath;
971 repos_relpath = &tmp_repos_relpath;
973 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
974 repos_root_url, repos_uuid, NULL, NULL, NULL,
976 &original_repos_relpath,
977 &original_repos_root_url,
978 &original_repos_uuid, &original_revision,
979 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
981 db, local_abspath, result_pool, scratch_pool));
985 return SVN_NO_ERROR; /* Returned BASE information */
988 if (status == svn_wc__db_status_deleted && !scan_deleted)
991 *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */
993 return SVN_NO_ERROR; /* No info */
996 if (original_repos_relpath)
998 *repos_relpath = original_repos_relpath;
1000 *revision = original_revision;
1002 *repos_root_url = original_repos_root_url;
1004 *repos_uuid = original_repos_uuid;
1006 if (copy_root_abspath == NULL)
1007 return SVN_NO_ERROR;
1011 svn_boolean_t scan_working = FALSE;
1013 if (status == svn_wc__db_status_added)
1014 scan_working = TRUE;
1015 else if (status == svn_wc__db_status_deleted)
1017 svn_boolean_t have_base;
1018 /* Is this a BASE or a WORKING delete? */
1019 SVN_ERR(svn_wc__db_info_below_working(&have_base, &scan_working,
1020 &status, db, local_abspath,
1026 const char *op_root_abspath;
1028 SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL,
1029 NULL, NULL, &original_repos_relpath,
1031 repos_uuid, revision,
1033 result_pool, scratch_pool));
1035 if (status == svn_wc__db_status_added)
1039 return SVN_NO_ERROR; /* Local addition */
1042 /* We don't know how the following error condition can be fulfilled
1043 * but we have seen that happening in the wild. Better to create
1044 * an error than a SEGFAULT. */
1045 if (status == svn_wc__db_status_incomplete && !original_repos_relpath)
1046 return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
1047 _("Incomplete copy information on path '%s'."),
1048 svn_dirent_local_style(local_abspath,
1051 *repos_relpath = svn_relpath_join(
1052 original_repos_relpath,
1053 svn_dirent_skip_ancestor(op_root_abspath,
1056 if (copy_root_abspath)
1057 *copy_root_abspath = op_root_abspath;
1059 else /* Deleted, excluded, not-present, server-excluded, ... */
1064 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath,
1065 repos_root_url, repos_uuid, NULL,
1066 NULL, NULL, NULL, NULL, NULL, NULL,
1069 result_pool, scratch_pool));
1072 return SVN_NO_ERROR;
1077 svn_wc__node_get_origin(svn_boolean_t *is_copy,
1078 svn_revnum_t *revision,
1079 const char **repos_relpath,
1080 const char **repos_root_url,
1081 const char **repos_uuid,
1082 const char **copy_root_abspath,
1083 svn_wc_context_t *wc_ctx,
1084 const char *local_abspath,
1085 svn_boolean_t scan_deleted,
1086 apr_pool_t *result_pool,
1087 apr_pool_t *scratch_pool)
1089 return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision,
1090 repos_relpath, repos_root_url, repos_uuid,
1092 wc_ctx->db, local_abspath, scan_deleted,
1093 result_pool, scratch_pool));
1097 svn_wc__node_get_commit_status(svn_boolean_t *added,
1098 svn_boolean_t *deleted,
1099 svn_boolean_t *is_replace_root,
1100 svn_boolean_t *is_op_root,
1101 svn_revnum_t *revision,
1102 svn_revnum_t *original_revision,
1103 const char **original_repos_relpath,
1104 svn_wc_context_t *wc_ctx,
1105 const char *local_abspath,
1106 apr_pool_t *result_pool,
1107 apr_pool_t *scratch_pool)
1109 svn_wc__db_status_t status;
1110 svn_boolean_t have_base;
1111 svn_boolean_t have_more_work;
1112 svn_boolean_t op_root;
1114 /* ### All of this should be handled inside a single read transaction */
1115 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL,
1116 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1117 original_repos_relpath, NULL, NULL,
1118 original_revision, NULL, NULL, NULL,
1120 &op_root, NULL, NULL,
1121 &have_base, &have_more_work, NULL,
1122 wc_ctx->db, local_abspath,
1123 result_pool, scratch_pool));
1126 *added = (status == svn_wc__db_status_added);
1128 *deleted = (status == svn_wc__db_status_deleted);
1130 *is_op_root = op_root;
1132 if (is_replace_root)
1134 if (status == svn_wc__db_status_added
1136 && (have_base || have_more_work))
1137 SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL,
1138 wc_ctx->db, local_abspath,
1141 *is_replace_root = FALSE;
1144 /* Retrieve some information from BASE which is needed for replacing
1145 and/or deleting BASE nodes. */
1149 && (revision && !SVN_IS_VALID_REVNUM(*revision)))
1151 SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
1152 NULL, NULL, NULL, NULL, NULL, NULL,
1153 NULL, NULL, NULL, NULL,
1154 wc_ctx->db, local_abspath,
1155 scratch_pool, scratch_pool));
1158 return SVN_NO_ERROR;
1162 svn_wc__node_get_md5_from_sha1(const svn_checksum_t **md5_checksum,
1163 svn_wc_context_t *wc_ctx,
1164 const char *wri_abspath,
1165 const svn_checksum_t *sha1_checksum,
1166 apr_pool_t *result_pool,
1167 apr_pool_t *scratch_pool)
1169 return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum,
1178 svn_wc__get_not_present_descendants(const apr_array_header_t **descendants,
1179 svn_wc_context_t *wc_ctx,
1180 const char *local_abspath,
1181 apr_pool_t *result_pool,
1182 apr_pool_t *scratch_pool)
1184 return svn_error_trace(
1185 svn_wc__db_get_not_present_descendants(descendants,
1193 svn_wc__rename_wc(svn_wc_context_t *wc_ctx,
1194 const char *from_abspath,
1195 const char *dst_abspath,
1196 apr_pool_t *scratch_pool)
1198 const char *wcroot_abspath;
1199 SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, from_abspath,
1200 scratch_pool, scratch_pool));
1202 if (! strcmp(from_abspath, wcroot_abspath))
1204 SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool));
1206 SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool));
1209 return svn_error_createf(
1210 SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
1211 _("'%s' is not the root of the working copy '%s'"),
1212 svn_dirent_local_style(from_abspath, scratch_pool),
1213 svn_dirent_local_style(wcroot_abspath, scratch_pool));
1215 return SVN_NO_ERROR;
1219 svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
1220 svn_node_kind_t *kind,
1221 svn_boolean_t *deleted,
1222 svn_boolean_t *excluded,
1223 svn_depth_t *parent_depth,
1224 svn_wc_context_t *wc_ctx,
1225 const char *local_abspath,
1226 svn_boolean_t no_wcroot_check,
1227 apr_pool_t *scratch_pool)
1229 svn_wc__db_status_t status;
1230 svn_node_kind_t db_kind;
1231 svn_node_kind_t disk_kind;
1234 *obstruction_state = svn_wc_notify_state_inapplicable;
1236 *kind = svn_node_none;
1242 *parent_depth = svn_depth_unknown;
1244 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
1246 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
1247 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1248 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1249 NULL, NULL, NULL, NULL, NULL,
1250 wc_ctx->db, local_abspath,
1251 scratch_pool, scratch_pool);
1253 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
1255 svn_error_clear(err);
1257 if (disk_kind != svn_node_none)
1259 /* Nothing in the DB, but something on disk */
1260 *obstruction_state = svn_wc_notify_state_obstructed;
1261 return SVN_NO_ERROR;
1264 err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
1265 NULL, NULL, NULL, parent_depth, NULL, NULL,
1266 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1267 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
1269 wc_ctx->db, svn_dirent_dirname(local_abspath,
1271 scratch_pool, scratch_pool);
1273 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
1275 svn_error_clear(err);
1276 /* No versioned parent; we can't add a node here */
1277 *obstruction_state = svn_wc_notify_state_obstructed;
1278 return SVN_NO_ERROR;
1283 if (db_kind != svn_node_dir
1284 || (status != svn_wc__db_status_normal
1285 && status != svn_wc__db_status_added))
1287 /* The parent doesn't allow nodes to be added below it */
1288 *obstruction_state = svn_wc_notify_state_obstructed;
1291 return SVN_NO_ERROR;
1296 /* Check for obstructing working copies */
1297 if (!no_wcroot_check
1298 && db_kind == svn_node_dir
1299 && status == svn_wc__db_status_normal)
1301 svn_boolean_t is_root;
1302 SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath,
1307 /* Callers should handle this as unversioned */
1308 *obstruction_state = svn_wc_notify_state_obstructed;
1309 return SVN_NO_ERROR;
1314 SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE));
1318 case svn_wc__db_status_deleted:
1321 /* Fall through to svn_wc__db_status_not_present */
1322 case svn_wc__db_status_not_present:
1323 if (disk_kind != svn_node_none)
1324 *obstruction_state = svn_wc_notify_state_obstructed;
1327 case svn_wc__db_status_excluded:
1328 case svn_wc__db_status_server_excluded:
1332 case svn_wc__db_status_incomplete:
1333 *obstruction_state = svn_wc_notify_state_missing;
1336 case svn_wc__db_status_added:
1337 case svn_wc__db_status_normal:
1338 if (disk_kind == svn_node_none)
1339 *obstruction_state = svn_wc_notify_state_missing;
1342 svn_node_kind_t expected_kind;
1344 SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind,
1347 if (disk_kind != expected_kind)
1348 *obstruction_state = svn_wc_notify_state_obstructed;
1352 SVN_ERR_MALFUNCTION();
1355 return SVN_NO_ERROR;
1360 svn_wc__node_was_moved_away(const char **moved_to_abspath,
1361 const char **op_root_abspath,
1362 svn_wc_context_t *wc_ctx,
1363 const char *local_abspath,
1364 apr_pool_t *result_pool,
1365 apr_pool_t *scratch_pool)
1367 svn_boolean_t is_deleted;
1369 if (moved_to_abspath)
1370 *moved_to_abspath = NULL;
1371 if (op_root_abspath)
1372 *op_root_abspath = NULL;
1374 SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath,
1377 SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL,
1378 op_root_abspath, wc_ctx->db,
1380 result_pool, scratch_pool));
1382 return SVN_NO_ERROR;
1387 svn_wc__node_was_moved_here(const char **moved_from_abspath,
1388 const char **delete_op_root_abspath,
1389 svn_wc_context_t *wc_ctx,
1390 const char *local_abspath,
1391 apr_pool_t *result_pool,
1392 apr_pool_t *scratch_pool)
1396 if (moved_from_abspath)
1397 *moved_from_abspath = NULL;
1398 if (delete_op_root_abspath)
1399 *delete_op_root_abspath = NULL;
1401 err = svn_wc__db_scan_moved(moved_from_abspath, NULL, NULL,
1402 delete_op_root_abspath,
1403 wc_ctx->db, local_abspath,
1404 result_pool, scratch_pool);
1408 /* Return error for not added nodes */
1409 if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
1410 return svn_error_trace(err);
1412 /* Path not moved here */
1413 svn_error_clear(err);
1414 return SVN_NO_ERROR;
1417 return SVN_NO_ERROR;