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.
59 * Allocate the output array and its elements in RESULT_POOL. */
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)
66 apr_array_header_t *children;
69 children = apr_array_make(result_pool, rel_children->nelts,
70 sizeof(const char *));
71 for (i = 0; i < rel_children->nelts; i++)
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,
79 *children_abspaths = children;
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)
90 const apr_array_header_t *child_names;
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);
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)
106 const apr_array_header_t *child_names;
108 SVN_ERR(svn_wc__db_base_read_not_present_children(
110 wc_ctx->db, dir_abspath,
111 scratch_pool, scratch_pool));
112 make_absolute(children, dir_abspath, child_names, result_pool);
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)
127 return svn_error_trace(
128 svn_wc__db_read_repos_info(revision,
132 wc_ctx->db, local_abspath,
133 result_pool, scratch_pool));
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.
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.
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
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)
157 *node_kind = db_kind;
159 /* Make sure hidden nodes return svn_node_none. */
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;
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)
183 svn_node_kind_t db_kind;
185 SVN_ERR(svn_wc__db_read_kind(&db_kind,
186 wc_ctx->db, local_abspath,
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;
197 *kind = svn_node_none;
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)
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,
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)
227 const char *repos_root_url;
228 const char *repos_relpath;
230 SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath, &repos_root_url,
232 wc_ctx->db, local_abspath,
233 scratch_pool, scratch_pool));
235 *url = svn_path_url_add_component2(repos_root_url, repos_relpath,
241 /* A recursive node-walker, helper for svn_wc__internal_walk_children().
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.
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. */
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,
259 svn_cancel_func_t cancel_func,
261 apr_pool_t *scratch_pool)
263 apr_pool_t *iterpool;
264 const apr_array_header_t *items;
267 if (depth == svn_depth_empty)
270 iterpool = svn_pool_create(scratch_pool);
272 SVN_ERR(svn_wc__db_read_children_walker_info(&items, db,
273 dir_abspath, scratch_pool,
276 for (i = 0; i < items->nelts; i++)
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;
285 svn_pool_clear(iterpool);
287 /* See if someone wants to cancel this operation. */
289 SVN_ERR(cancel_func(cancel_baton));
291 child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool);
294 switch (child_status)
296 case svn_wc__db_status_not_present:
297 case svn_wc__db_status_server_excluded:
298 case svn_wc__db_status_excluded:
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,
311 svn_node_kind_t kind;
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));
323 /* Recurse into this directory, if appropriate. */
324 if (child_kind == svn_node_dir
325 && depth >= svn_depth_immediates)
327 svn_depth_t depth_below_here = depth;
329 if (depth == svn_depth_immediates)
330 depth_below_here = svn_depth_empty;
332 SVN_ERR(walker_helper(db, child_abspath, show_hidden,
334 walk_callback, walk_baton,
336 cancel_func, cancel_baton,
341 svn_pool_destroy(iterpool);
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,
354 svn_depth_t walk_depth,
355 svn_cancel_func_t cancel_func,
357 apr_pool_t *scratch_pool)
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;
365 SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
366 && walk_depth <= svn_depth_infinity);
368 if (changelist_filter && changelist_filter->nelts)
369 SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
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));
380 SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
383 || (changelist && svn_hash_gets(changelist_hash, changelist)))
385 SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
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)
394 if (db_kind == svn_node_dir)
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));
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,
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)
417 svn_wc__db_status_t status;
421 SVN_ERR(svn_wc__db_base_get_info(&status,
422 NULL, NULL, NULL, NULL, NULL, NULL,
423 NULL, NULL, NULL, NULL, NULL, NULL,
425 wc_ctx->db, local_abspath,
426 scratch_pool, scratch_pool));
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));
440 *is_not_present = (status == svn_wc__db_status_not_present);
443 *is_excluded = (status == svn_wc__db_status_excluded);
445 if (is_server_excluded)
446 *is_server_excluded = (status == svn_wc__db_status_server_excluded);
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)
457 svn_wc__db_status_t status;
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);
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)
477 svn_wc__db_status_t status;
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));
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)
505 svn_wc__db_status_t status;
506 svn_wc__db_lock_t *lock;
507 svn_node_kind_t db_kind;
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,
514 wc_ctx->db, local_abspath,
515 result_pool, scratch_pool);
517 if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
518 return svn_error_trace(err);
520 || (status != svn_wc__db_status_normal
521 && status != svn_wc__db_status_incomplete))
526 return svn_error_trace(err);
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,
533 svn_error_clear(err);
536 *kind = svn_node_unknown;
538 *revision = SVN_INVALID_REVNUM;
540 *repos_relpath = NULL;
542 *repos_root_url = NULL;
553 *lock_token = lock ? lock->token : NULL;
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);
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)
572 svn_wc__db_status_t status;
573 svn_boolean_t have_base, have_more_work, have_work;
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));
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)))
589 return SVN_NO_ERROR; /* We got everything we need */
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,
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));
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)
615 return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive(
616 wc_ctx->db, local_abspath, scratch_pool));
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)
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));
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)
639 return svn_error_trace(
640 svn_wc__db_get_excluded_subtrees(server_excluded_subtrees,
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,
654 const char **copy_root_abspath,
656 const char *local_abspath,
657 svn_boolean_t scan_deleted,
658 apr_pool_t *result_pool,
659 apr_pool_t *scratch_pool)
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;
669 const char *tmp_repos_relpath;
671 if (copy_root_abspath)
672 *copy_root_abspath = NULL;
674 repos_relpath = &tmp_repos_relpath;
676 SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
677 repos_root_url, repos_uuid, NULL, 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));
688 return SVN_NO_ERROR; /* Returned BASE information */
691 if (status == svn_wc__db_status_deleted && !scan_deleted)
694 *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */
696 return SVN_NO_ERROR; /* No info */
699 if (original_repos_relpath)
701 /* We an have a copy */
702 *repos_relpath = original_repos_relpath;
704 *revision = original_revision;
706 *repos_root_url = original_repos_root_url;
708 *repos_uuid = original_repos_uuid;
710 if (copy_root_abspath == NULL)
714 *copy_root_abspath = apr_pstrdup(result_pool, local_abspath);
720 svn_boolean_t scan_working = FALSE;
722 if (status == svn_wc__db_status_added
723 || (status == svn_wc__db_status_deleted && have_more_work))
728 const char *op_root_abspath;
730 SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL,
731 NULL, NULL, &original_repos_relpath,
733 repos_uuid, revision,
735 result_pool, scratch_pool));
737 if (status == svn_wc__db_status_added)
741 return SVN_NO_ERROR; /* Local addition */
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,
753 *repos_relpath = svn_relpath_join(
754 original_repos_relpath,
755 svn_dirent_skip_ancestor(op_root_abspath,
758 if (copy_root_abspath)
759 *copy_root_abspath = op_root_abspath;
761 else /* Deleted, excluded, not-present, server-excluded, ... */
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,
771 result_pool, scratch_pool));
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,
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)
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));
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)
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;
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,
823 &op_root, NULL, NULL,
824 &have_base, &have_more_work, NULL,
825 wc_ctx->db, local_abspath,
826 result_pool, scratch_pool));
829 *added = (status == svn_wc__db_status_added);
831 *deleted = (status == svn_wc__db_status_deleted);
833 *is_op_root = op_root;
837 if (status == svn_wc__db_status_added
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,
844 *is_replace_root = FALSE;
847 /* Retrieve some information from BASE which is needed for replacing
848 and/or deleting BASE nodes. */
852 && (revision && !SVN_IS_VALID_REVNUM(*revision)))
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));
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)
872 return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum,
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)
887 return svn_error_trace(
888 svn_wc__db_get_not_present_descendants(descendants,
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)
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));
905 if (! strcmp(from_abspath, wcroot_abspath))
907 SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool));
909 SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool));
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));
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)
932 svn_wc__db_status_t status;
933 svn_node_kind_t db_kind;
934 svn_node_kind_t disk_kind;
937 *obstruction_state = svn_wc_notify_state_inapplicable;
939 *kind = svn_node_none;
945 *parent_depth = svn_depth_unknown;
947 SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
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);
956 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
958 svn_error_clear(err);
960 if (disk_kind != svn_node_none)
962 /* Nothing in the DB, but something on disk */
963 *obstruction_state = svn_wc_notify_state_obstructed;
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,
972 wc_ctx->db, svn_dirent_dirname(local_abspath,
974 scratch_pool, scratch_pool);
976 if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
978 svn_error_clear(err);
979 /* No versioned parent; we can't add a node here */
980 *obstruction_state = svn_wc_notify_state_obstructed;
986 if (db_kind != svn_node_dir
987 || (status != svn_wc__db_status_normal
988 && status != svn_wc__db_status_added))
990 /* The parent doesn't allow nodes to be added below it */
991 *obstruction_state = svn_wc_notify_state_obstructed;
999 /* Check for obstructing working copies */
1000 if (!no_wcroot_check
1001 && db_kind == svn_node_dir
1002 && status == svn_wc__db_status_normal)
1004 svn_boolean_t is_root;
1005 SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath,
1010 /* Callers should handle this as unversioned */
1011 *obstruction_state = svn_wc_notify_state_obstructed;
1012 return SVN_NO_ERROR;
1017 SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE));
1021 case svn_wc__db_status_deleted:
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;
1030 case svn_wc__db_status_excluded:
1031 case svn_wc__db_status_server_excluded:
1035 case svn_wc__db_status_incomplete:
1036 *obstruction_state = svn_wc_notify_state_missing;
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;
1045 svn_node_kind_t expected_kind;
1047 SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind,
1050 if (disk_kind != expected_kind)
1051 *obstruction_state = svn_wc_notify_state_obstructed;
1055 SVN_ERR_MALFUNCTION();
1058 return SVN_NO_ERROR;
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)
1070 svn_wc__db_status_t status;
1072 if (moved_to_abspath)
1073 *moved_to_abspath = NULL;
1074 if (op_root_abspath)
1075 *op_root_abspath = NULL;
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));
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,
1089 result_pool, scratch_pool));
1091 return SVN_NO_ERROR;
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)
1105 if (moved_from_abspath)
1106 *moved_from_abspath = NULL;
1107 if (delete_op_root_abspath)
1108 *delete_op_root_abspath = NULL;
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);
1117 /* Return error for not added nodes */
1118 if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
1119 return svn_error_trace(err);
1121 /* Path not moved here */
1122 svn_error_clear(err);
1123 return SVN_NO_ERROR;
1126 return SVN_NO_ERROR;