summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_wc/node.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>2013-06-18 02:07:41 +0000
committerpeter <peter@FreeBSD.org>2013-06-18 02:07:41 +0000
commitd25dac7fcc6acc838b71bbda8916fd9665c709ab (patch)
tree135691142dc0e75a5e5d97b5074d03436435b8e0 /subversion/libsvn_wc/node.c
downloadFreeBSD-src-d25dac7fcc6acc838b71bbda8916fd9665c709ab.zip
FreeBSD-src-d25dac7fcc6acc838b71bbda8916fd9665c709ab.tar.gz
Import trimmed svn-1.8.0-rc3
Diffstat (limited to 'subversion/libsvn_wc/node.c')
-rw-r--r--subversion/libsvn_wc/node.c1418
1 files changed, 1418 insertions, 0 deletions
diff --git a/subversion/libsvn_wc/node.c b/subversion/libsvn_wc/node.c
new file mode 100644
index 0000000..a1d6b02
--- /dev/null
+++ b/subversion/libsvn_wc/node.c
@@ -0,0 +1,1418 @@
+/*
+ * node.c: routines for getting information about nodes in the working copy.
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+/* A note about these functions:
+
+ We aren't really sure yet which bits of data libsvn_client needs about
+ nodes. In wc-1, we just grab the entry, and then use whatever we want
+ from it. Such a pattern is Bad.
+
+ This file is intended to hold functions which retrieve specific bits of
+ information about a node, and will hopefully give us a better idea about
+ what data libsvn_client needs, and how to best provide that data in 1.7
+ final. As such, these functions should only be called from outside
+ libsvn_wc; any internal callers are encouraged to use the appropriate
+ information fetching function, such as svn_wc__db_read_info().
+*/
+
+#include <apr_pools.h>
+#include <apr_time.h>
+
+#include "svn_pools.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_hash.h"
+#include "svn_types.h"
+
+#include "wc.h"
+#include "props.h"
+#include "entries.h"
+#include "wc_db.h"
+
+#include "svn_private_config.h"
+#include "private/svn_wc_private.h"
+
+
+/* Set *CHILDREN_ABSPATHS to a new array of the full paths formed by joining
+ * each name in REL_CHILDREN onto DIR_ABSPATH. If SHOW_HIDDEN is false then
+ * omit any paths that are reported as 'hidden' by svn_wc__db_node_hidden().
+ *
+ * Allocate the output array and its elements in RESULT_POOL. */
+static svn_error_t *
+filter_and_make_absolute(const apr_array_header_t **children_abspaths,
+ svn_wc_context_t *wc_ctx,
+ const char *dir_abspath,
+ const apr_array_header_t *rel_children,
+ svn_boolean_t show_hidden,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *children;
+ int i;
+
+ children = apr_array_make(result_pool, rel_children->nelts,
+ sizeof(const char *));
+ for (i = 0; i < rel_children->nelts; i++)
+ {
+ const char *child_abspath = svn_dirent_join(dir_abspath,
+ APR_ARRAY_IDX(rel_children,
+ i,
+ const char *),
+ result_pool);
+
+ /* Don't add hidden nodes to *CHILDREN if we don't want them. */
+ if (!show_hidden)
+ {
+ svn_boolean_t child_is_hidden;
+
+ SVN_ERR(svn_wc__db_node_hidden(&child_is_hidden, wc_ctx->db,
+ child_abspath, scratch_pool));
+ if (child_is_hidden)
+ continue;
+ }
+
+ APR_ARRAY_PUSH(children, const char *) = child_abspath;
+ }
+
+ *children_abspaths = children;
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__node_get_children_of_working_node(const apr_array_header_t **children,
+ svn_wc_context_t *wc_ctx,
+ const char *dir_abspath,
+ svn_boolean_t show_hidden,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const apr_array_header_t *rel_children;
+
+ SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
+ wc_ctx->db, dir_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
+ rel_children, show_hidden,
+ result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_children(const apr_array_header_t **children,
+ svn_wc_context_t *wc_ctx,
+ const char *dir_abspath,
+ svn_boolean_t show_hidden,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const apr_array_header_t *rel_children;
+
+ SVN_ERR(svn_wc__db_read_children(&rel_children, wc_ctx->db, dir_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
+ rel_children, show_hidden,
+ result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__internal_get_repos_info(svn_revnum_t *revision,
+ const char **repos_relpath,
+ const char **repos_root_url,
+ const char **repos_uuid,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+ svn_boolean_t have_work;
+
+ SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
+ repos_root_url, repos_uuid,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, &have_work,
+ db, local_abspath,
+ result_pool, scratch_pool));
+
+ if ((repos_relpath ? *repos_relpath != NULL : TRUE)
+ && (repos_root_url ? *repos_root_url != NULL: TRUE)
+ && (repos_uuid ? *repos_uuid != NULL : TRUE))
+ return SVN_NO_ERROR; /* We got the requested information */
+
+ if (!have_work) /* not-present, (server-)excluded? */
+ {
+ return SVN_NO_ERROR; /* Can't fetch more */
+ }
+
+ if (status == svn_wc__db_status_deleted)
+ {
+ const char *base_del_abspath, *wrk_del_abspath;
+
+ SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, NULL,
+ &wrk_del_abspath, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (base_del_abspath)
+ {
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, repos_relpath,
+ repos_root_url, repos_uuid, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ db, base_del_abspath,
+ result_pool, scratch_pool));
+
+ /* If we have a repos_relpath, it is of the op-root */
+ if (repos_relpath)
+ *repos_relpath = svn_relpath_join(*repos_relpath,
+ svn_dirent_skip_ancestor(base_del_abspath,
+ local_abspath),
+ result_pool);
+ /* We keep revision as SVN_INVALID_REVNUM */
+ }
+ else if (wrk_del_abspath)
+ {
+ const char *op_root_abspath = NULL;
+
+ SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
+ ? &op_root_abspath : NULL,
+ repos_relpath, repos_root_url,
+ repos_uuid, NULL, NULL, NULL, NULL,
+ db, svn_dirent_dirname(
+ wrk_del_abspath,
+ scratch_pool),
+ result_pool, scratch_pool));
+
+ /* If we have a repos_relpath, it is of the op-root */
+ if (repos_relpath)
+ *repos_relpath = svn_relpath_join(
+ *repos_relpath,
+ svn_dirent_skip_ancestor(op_root_abspath,
+ local_abspath),
+ result_pool);
+ }
+ }
+ else /* added, or WORKING incomplete */
+ {
+ const char *op_root_abspath = NULL;
+
+ /* We have an addition. scan_addition() will find the intended
+ repository location by scanning up the tree. */
+ SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
+ ? &op_root_abspath : NULL,
+ repos_relpath, repos_root_url,
+ repos_uuid, NULL, NULL, NULL, NULL,
+ db, local_abspath,
+ result_pool, scratch_pool));
+ }
+
+ SVN_ERR_ASSERT(repos_root_url == NULL || *repos_root_url != NULL);
+ SVN_ERR_ASSERT(repos_uuid == NULL || *repos_uuid != NULL);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_repos_info(svn_revnum_t *revision,
+ const char **repos_relpath,
+ const char **repos_root_url,
+ const char **repos_uuid,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc__internal_get_repos_info(revision,
+ repos_relpath,
+ repos_root_url,
+ repos_uuid,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+}
+
+/* Convert DB_KIND into the appropriate NODE_KIND value.
+ * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB
+ * even if DB_STATUS indicates that the node is hidden.
+ * Else, return svn_node_none for such nodes.
+ *
+ * ### This is a bit ugly. We should consider promoting svn_kind_t
+ * ### to the de-facto node kind type instead of converting between them
+ * ### in non-backwards compat code.
+ * ### See also comments at the definition of svn_kind_t.
+ *
+ * ### In reality, the previous comment is out of date, as there is
+ * ### now only one enumeration for node kinds, and that is
+ * ### svn_node_kind_t (svn_kind_t was merged with that). But it's
+ * ### still ugly.
+ */
+static svn_error_t *
+convert_db_kind_to_node_kind(svn_node_kind_t *node_kind,
+ svn_node_kind_t db_kind,
+ svn_wc__db_status_t db_status,
+ svn_boolean_t show_hidden)
+{
+ *node_kind = db_kind;
+
+ /* Make sure hidden nodes return svn_node_none. */
+ if (! show_hidden)
+ switch (db_status)
+ {
+ case svn_wc__db_status_not_present:
+ case svn_wc__db_status_server_excluded:
+ case svn_wc__db_status_excluded:
+ *node_kind = svn_node_none;
+
+ default:
+ break;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc_read_kind2(svn_node_kind_t *kind,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_boolean_t show_deleted,
+ svn_boolean_t show_hidden,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t db_kind;
+
+ SVN_ERR(svn_wc__db_read_kind(&db_kind,
+ wc_ctx->db, local_abspath,
+ TRUE,
+ show_deleted,
+ show_hidden,
+ scratch_pool));
+
+ if (db_kind == svn_node_dir)
+ *kind = svn_node_dir;
+ else if (db_kind == svn_node_file || db_kind == svn_node_symlink)
+ *kind = svn_node_file;
+ else
+ *kind = svn_node_none;
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_depth(svn_depth_t *depth,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, depth, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath, scratch_pool,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_wc__node_get_changed_info(svn_revnum_t *changed_rev,
+ apr_time_t *changed_date,
+ const char **changed_author,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, changed_rev,
+ changed_date, changed_author, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath, result_pool,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_wc__node_get_url(const char **url,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(svn_wc__db_read_url(url, wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+}
+
+/* A recursive node-walker, helper for svn_wc__internal_walk_children().
+ *
+ * Call WALK_CALLBACK with WALK_BATON on all children (recursively) of
+ * DIR_ABSPATH in DB, but not on DIR_ABSPATH itself. DIR_ABSPATH must be a
+ * versioned directory. If SHOW_HIDDEN is true, visit hidden nodes, else
+ * ignore them. Restrict the depth of the walk to DEPTH.
+ *
+ * ### Is it possible for a subdirectory to be hidden and known to be a
+ * directory? If so, and if show_hidden is true, this will try to
+ * recurse into it. */
+static svn_error_t *
+walker_helper(svn_wc__db_t *db,
+ const char *dir_abspath,
+ svn_boolean_t show_hidden,
+ const apr_hash_t *changelist_filter,
+ svn_wc__node_found_func_t walk_callback,
+ void *walk_baton,
+ svn_depth_t depth,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *rel_children_info;
+ apr_hash_index_t *hi;
+ apr_pool_t *iterpool;
+
+ if (depth == svn_depth_empty)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_wc__db_read_children_walker_info(&rel_children_info, db,
+ dir_abspath, scratch_pool,
+ scratch_pool));
+
+
+ iterpool = svn_pool_create(scratch_pool);
+ for (hi = apr_hash_first(scratch_pool, rel_children_info);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *child_name = svn__apr_hash_index_key(hi);
+ struct svn_wc__db_walker_info_t *wi = svn__apr_hash_index_val(hi);
+ svn_node_kind_t child_kind = wi->kind;
+ svn_wc__db_status_t child_status = wi->status;
+ const char *child_abspath;
+
+ svn_pool_clear(iterpool);
+
+ /* See if someone wants to cancel this operation. */
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
+ child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool);
+
+ if (!show_hidden)
+ switch (child_status)
+ {
+ case svn_wc__db_status_not_present:
+ case svn_wc__db_status_server_excluded:
+ case svn_wc__db_status_excluded:
+ continue;
+ default:
+ break;
+ }
+
+ /* Return the child, if appropriate. */
+ if ( (child_kind == svn_node_file
+ || depth >= svn_depth_immediates)
+ && svn_wc__internal_changelist_match(db, child_abspath,
+ changelist_filter,
+ scratch_pool) )
+ {
+ svn_node_kind_t kind;
+
+ SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind,
+ child_status, show_hidden));
+ /* ### We might want to pass child_status as well because at least
+ * ### one callee is asking for it.
+ * ### But is it OK to use an svn_wc__db type in this API?
+ * ### Not yet, we need to get the node walker
+ * ### libsvn_wc-internal first. -hkw */
+ SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool));
+ }
+
+ /* Recurse into this directory, if appropriate. */
+ if (child_kind == svn_node_dir
+ && depth >= svn_depth_immediates)
+ {
+ svn_depth_t depth_below_here = depth;
+
+ if (depth == svn_depth_immediates)
+ depth_below_here = svn_depth_empty;
+
+ SVN_ERR(walker_helper(db, child_abspath, show_hidden,
+ changelist_filter,
+ walk_callback, walk_baton,
+ depth_below_here,
+ cancel_func, cancel_baton,
+ iterpool));
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__internal_walk_children(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_boolean_t show_hidden,
+ const apr_array_header_t *changelist_filter,
+ svn_wc__node_found_func_t walk_callback,
+ void *walk_baton,
+ svn_depth_t walk_depth,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t db_kind;
+ svn_node_kind_t kind;
+ svn_wc__db_status_t status;
+ apr_hash_t *changelist_hash = NULL;
+
+ SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
+ && walk_depth <= svn_depth_infinity);
+
+ if (changelist_filter && changelist_filter->nelts)
+ SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
+ scratch_pool));
+
+ /* Check if the node exists before the first callback */
+ SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ db, local_abspath, scratch_pool, scratch_pool));
+
+ SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
+
+ if (svn_wc__internal_changelist_match(db, local_abspath,
+ changelist_hash, scratch_pool))
+ SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
+
+ if (db_kind == svn_node_file
+ || status == svn_wc__db_status_not_present
+ || status == svn_wc__db_status_excluded
+ || status == svn_wc__db_status_server_excluded)
+ return SVN_NO_ERROR;
+
+ if (db_kind == svn_node_dir)
+ {
+ return svn_error_trace(
+ walker_helper(db, local_abspath, show_hidden, changelist_hash,
+ walk_callback, walk_baton,
+ walk_depth, cancel_func, cancel_baton, scratch_pool));
+ }
+
+ return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,
+ _("'%s' has an unrecognized node kind"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_wc__node_is_status_deleted(svn_boolean_t *is_deleted,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+
+ SVN_ERR(svn_wc__db_read_info(&status,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ *is_deleted = (status == svn_wc__db_status_deleted);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_deleted_ancestor(const char **deleted_ancestor_abspath,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+
+ *deleted_ancestor_abspath = NULL;
+
+ SVN_ERR(svn_wc__db_read_info(&status,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (status == svn_wc__db_status_deleted)
+ SVN_ERR(svn_wc__db_scan_deletion(deleted_ancestor_abspath, NULL, NULL,
+ NULL, wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_is_not_present(svn_boolean_t *is_not_present,
+ svn_boolean_t *is_excluded,
+ svn_boolean_t *is_server_excluded,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_boolean_t base_only,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+
+ if (base_only)
+ {
+ SVN_ERR(svn_wc__db_base_get_info(&status,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(svn_wc__db_read_info(&status,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+ }
+
+ if (is_not_present)
+ *is_not_present = (status == svn_wc__db_status_not_present);
+
+ if (is_excluded)
+ *is_excluded = (status == svn_wc__db_status_excluded);
+
+ if (is_server_excluded)
+ *is_server_excluded = (status == svn_wc__db_status_server_excluded);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_is_added(svn_boolean_t *is_added,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+
+ SVN_ERR(svn_wc__db_read_info(&status,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+ *is_added = (status == svn_wc__db_status_added);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_has_working(svn_boolean_t *has_working,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+
+ SVN_ERR(svn_wc__db_read_info(&status,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, has_working,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__node_get_base(svn_node_kind_t *kind,
+ svn_revnum_t *revision,
+ const char **repos_relpath,
+ const char **repos_root_url,
+ const char **repos_uuid,
+ const char **lock_token,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_boolean_t ignore_enoent,
+ svn_boolean_t show_hidden,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+ svn_wc__db_status_t status;
+ svn_wc__db_lock_t *lock;
+ svn_node_kind_t db_kind;
+
+ err = svn_wc__db_base_get_info(&status, &db_kind, revision, repos_relpath,
+ repos_root_url, repos_uuid, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ lock_token ? &lock : NULL,
+ NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool);
+
+ if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+ return svn_error_trace(err);
+ else if (err
+ || (!err && !show_hidden
+ && (status != svn_wc__db_status_normal
+ && status != svn_wc__db_status_incomplete)))
+ {
+ if (!ignore_enoent)
+ {
+ if (err)
+ return svn_error_trace(err);
+ else
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("The node '%s' was not found."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+ svn_error_clear(err);
+
+ if (kind)
+ *kind = svn_node_unknown;
+ if (revision)
+ *revision = SVN_INVALID_REVNUM;
+ if (repos_relpath)
+ *repos_relpath = NULL;
+ if (repos_root_url)
+ *repos_root_url = NULL;
+ if (repos_uuid)
+ *repos_uuid = NULL;
+ if (lock_token)
+ *lock_token = NULL;
+ return SVN_NO_ERROR;
+ }
+
+ if (kind)
+ *kind = db_kind;
+ if (lock_token)
+ *lock_token = lock ? lock->token : NULL;
+
+ SVN_ERR_ASSERT(!revision || SVN_IS_VALID_REVNUM(*revision));
+ SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
+ SVN_ERR_ASSERT(!repos_root_url || *repos_root_url);
+ SVN_ERR_ASSERT(!repos_uuid || *repos_uuid);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision,
+ svn_revnum_t *changed_rev,
+ apr_time_t *changed_date,
+ const char **changed_author,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+ svn_boolean_t have_base, have_more_work, have_work;
+
+ SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL,
+ changed_rev, changed_date, changed_author,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &have_base, &have_more_work, &have_work,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+
+ if (!have_work
+ || ((!changed_rev || SVN_IS_VALID_REVNUM(*changed_rev))
+ && (!revision || SVN_IS_VALID_REVNUM(*revision)))
+ || ((status != svn_wc__db_status_added)
+ && (status != svn_wc__db_status_deleted)))
+ {
+ return SVN_NO_ERROR; /* We got everything we need */
+ }
+
+ if (have_base && !have_more_work)
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
+ changed_rev, changed_date, changed_author,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+ else if (status == svn_wc__db_status_deleted)
+ /* Check the information below a WORKING delete */
+ SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, changed_rev,
+ changed_date, changed_author, NULL,
+ NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__internal_node_get_schedule(svn_wc_schedule_t *schedule,
+ svn_boolean_t *copied,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+ svn_boolean_t op_root;
+ svn_boolean_t have_base;
+ svn_boolean_t have_work;
+ svn_boolean_t have_more_work;
+ const char *copyfrom_relpath;
+
+ if (schedule)
+ *schedule = svn_wc_schedule_normal;
+ if (copied)
+ *copied = FALSE;
+
+ SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, &copyfrom_relpath,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &op_root, NULL, NULL,
+ &have_base, &have_more_work, &have_work,
+ db, local_abspath, scratch_pool, scratch_pool));
+
+ switch (status)
+ {
+ case svn_wc__db_status_not_present:
+ case svn_wc__db_status_server_excluded:
+ case svn_wc__db_status_excluded:
+ /* We used status normal in the entries world. */
+ if (schedule)
+ *schedule = svn_wc_schedule_normal;
+ break;
+ case svn_wc__db_status_normal:
+ case svn_wc__db_status_incomplete:
+ break;
+
+ case svn_wc__db_status_deleted:
+ {
+ if (schedule)
+ *schedule = svn_wc_schedule_delete;
+
+ if (!copied)
+ break;
+
+ if (have_more_work || !have_base)
+ *copied = TRUE;
+ else
+ {
+ const char *work_del_abspath;
+
+ /* Find out details of our deletion. */
+ SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
+ &work_del_abspath, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (work_del_abspath)
+ *copied = TRUE; /* Working deletion */
+ }
+ break;
+ }
+ case svn_wc__db_status_added:
+ {
+ if (!op_root)
+ {
+ if (copied)
+ *copied = TRUE;
+
+ if (schedule)
+ *schedule = svn_wc_schedule_normal;
+
+ break;
+ }
+
+ if (copied)
+ *copied = (copyfrom_relpath != NULL);
+
+ if (schedule)
+ *schedule = svn_wc_schedule_add;
+ else
+ break;
+
+ /* Check for replaced */
+ if (have_base || have_more_work)
+ {
+ svn_wc__db_status_t below_working;
+ SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work,
+ &below_working,
+ db, local_abspath,
+ scratch_pool));
+
+ /* If the node is not present or deleted (read: not present
+ in working), then the node is not a replacement */
+ if (below_working != svn_wc__db_status_not_present
+ && below_working != svn_wc__db_status_deleted)
+ {
+ *schedule = svn_wc_schedule_replace;
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ SVN_ERR_MALFUNCTION();
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_schedule(svn_wc_schedule_t *schedule,
+ svn_boolean_t *copied,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc__internal_node_get_schedule(schedule,
+ copied,
+ wc_ctx->db,
+ local_abspath,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(svn_wc__db_base_clear_dav_cache_recursive(
+ wc_ctx->db, local_abspath, scratch_pool));
+}
+
+
+svn_error_t *
+svn_wc__node_get_lock_tokens_recursive(apr_hash_t **lock_tokens,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(svn_wc__db_base_get_lock_tokens_recursive(
+ lock_tokens, wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_wc__get_excluded_subtrees(apr_hash_t **server_excluded_subtrees,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc__db_get_excluded_subtrees(server_excluded_subtrees,
+ wc_ctx->db,
+ local_abspath,
+ result_pool,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_wc__internal_get_origin(svn_boolean_t *is_copy,
+ svn_revnum_t *revision,
+ const char **repos_relpath,
+ const char **repos_root_url,
+ const char **repos_uuid,
+ const char **copy_root_abspath,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_boolean_t scan_deleted,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *original_repos_relpath;
+ const char *original_repos_root_url;
+ const char *original_repos_uuid;
+ svn_revnum_t original_revision;
+ svn_wc__db_status_t status;
+
+ const char *tmp_repos_relpath;
+
+ if (!repos_relpath)
+ repos_relpath = &tmp_repos_relpath;
+
+ SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
+ repos_root_url, repos_uuid, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ &original_repos_relpath,
+ &original_repos_root_url,
+ &original_repos_uuid, &original_revision,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, is_copy,
+ db, local_abspath, result_pool, scratch_pool));
+
+ if (*repos_relpath)
+ {
+ return SVN_NO_ERROR; /* Returned BASE information */
+ }
+
+ if (status == svn_wc__db_status_deleted && !scan_deleted)
+ {
+ if (is_copy)
+ *is_copy = FALSE; /* Deletes are stored in working; default to FALSE */
+
+ return SVN_NO_ERROR; /* No info */
+ }
+
+ if (original_repos_relpath)
+ {
+ *repos_relpath = original_repos_relpath;
+ if (revision)
+ *revision = original_revision;
+ if (repos_root_url)
+ *repos_root_url = original_repos_root_url;
+ if (repos_uuid)
+ *repos_uuid = original_repos_uuid;
+
+ if (copy_root_abspath == NULL)
+ return SVN_NO_ERROR;
+ }
+
+ {
+ svn_boolean_t scan_working = FALSE;
+
+ if (status == svn_wc__db_status_added)
+ scan_working = TRUE;
+ else if (status == svn_wc__db_status_deleted)
+ {
+ svn_boolean_t have_base;
+ /* Is this a BASE or a WORKING delete? */
+ SVN_ERR(svn_wc__db_info_below_working(&have_base, &scan_working,
+ &status, db, local_abspath,
+ scratch_pool));
+ }
+
+ if (scan_working)
+ {
+ const char *op_root_abspath;
+
+ SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL,
+ NULL, NULL, &original_repos_relpath,
+ repos_root_url,
+ repos_uuid, revision,
+ db, local_abspath,
+ result_pool, scratch_pool));
+
+ if (status == svn_wc__db_status_added)
+ {
+ if (is_copy)
+ *is_copy = FALSE;
+ return SVN_NO_ERROR; /* Local addition */
+ }
+
+ /* We don't know how the following error condition can be fulfilled
+ * but we have seen that happening in the wild. Better to create
+ * an error than a SEGFAULT. */
+ if (status == svn_wc__db_status_incomplete && !original_repos_relpath)
+ return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+ _("Incomplete copy information on path '%s'."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+
+ *repos_relpath = svn_relpath_join(
+ original_repos_relpath,
+ svn_dirent_skip_ancestor(op_root_abspath,
+ local_abspath),
+ result_pool);
+ if (copy_root_abspath)
+ *copy_root_abspath = op_root_abspath;
+ }
+ else /* Deleted, excluded, not-present, server-excluded, ... */
+ {
+ if (is_copy)
+ *is_copy = FALSE;
+
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath,
+ repos_root_url, repos_uuid, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ db, local_abspath,
+ result_pool, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+ }
+}
+
+svn_error_t *
+svn_wc__node_get_origin(svn_boolean_t *is_copy,
+ svn_revnum_t *revision,
+ const char **repos_relpath,
+ const char **repos_root_url,
+ const char **repos_uuid,
+ const char **copy_root_abspath,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_boolean_t scan_deleted,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision,
+ repos_relpath, repos_root_url, repos_uuid,
+ copy_root_abspath,
+ wc_ctx->db, local_abspath, scan_deleted,
+ result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_wc__node_get_commit_status(svn_boolean_t *added,
+ svn_boolean_t *deleted,
+ svn_boolean_t *is_replace_root,
+ svn_boolean_t *is_op_root,
+ svn_revnum_t *revision,
+ svn_revnum_t *original_revision,
+ const char **original_repos_relpath,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+ svn_boolean_t have_base;
+ svn_boolean_t have_more_work;
+ svn_boolean_t op_root;
+
+ /* ### All of this should be handled inside a single read transaction */
+ SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ original_repos_relpath, NULL, NULL,
+ original_revision, NULL, NULL, NULL,
+ NULL, NULL,
+ &op_root, NULL, NULL,
+ &have_base, &have_more_work, NULL,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
+
+ if (added)
+ *added = (status == svn_wc__db_status_added);
+ if (deleted)
+ *deleted = (status == svn_wc__db_status_deleted);
+ if (is_op_root)
+ *is_op_root = op_root;
+
+ if (is_replace_root)
+ {
+ if (status == svn_wc__db_status_added
+ && op_root
+ && (have_base || have_more_work))
+ SVN_ERR(svn_wc__db_node_check_replace(is_replace_root, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool));
+ else
+ *is_replace_root = FALSE;
+ }
+
+ /* Retrieve some information from BASE which is needed for replacing
+ and/or deleting BASE nodes. */
+ if (have_base
+ && !have_more_work
+ && op_root
+ && (revision && !SVN_IS_VALID_REVNUM(*revision)))
+ {
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_md5_from_sha1(const svn_checksum_t **md5_checksum,
+ svn_wc_context_t *wc_ctx,
+ const char *wri_abspath,
+ const svn_checksum_t *sha1_checksum,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(svn_wc__db_pristine_get_md5(md5_checksum,
+ wc_ctx->db,
+ wri_abspath,
+ sha1_checksum,
+ result_pool,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_wc__get_not_present_descendants(const apr_array_header_t **descendants,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc__db_get_not_present_descendants(descendants,
+ wc_ctx->db,
+ local_abspath,
+ result_pool,
+ scratch_pool));
+}
+
+svn_error_t *
+svn_wc__rename_wc(svn_wc_context_t *wc_ctx,
+ const char *from_abspath,
+ const char *dst_abspath,
+ apr_pool_t *scratch_pool)
+{
+ const char *wcroot_abspath;
+ SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath, wc_ctx->db, from_abspath,
+ scratch_pool, scratch_pool));
+
+ if (! strcmp(from_abspath, wcroot_abspath))
+ {
+ SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool));
+
+ SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool));
+ }
+ else
+ return svn_error_createf(
+ SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+ _("'%s' is not the root of the working copy '%s'"),
+ svn_dirent_local_style(from_abspath, scratch_pool),
+ svn_dirent_local_style(wcroot_abspath, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
+ svn_node_kind_t *kind,
+ svn_boolean_t *deleted,
+ svn_boolean_t *excluded,
+ svn_depth_t *parent_depth,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_boolean_t no_wcroot_check,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+ svn_node_kind_t db_kind;
+ svn_node_kind_t disk_kind;
+ svn_error_t *err;
+
+ *obstruction_state = svn_wc_notify_state_inapplicable;
+ if (kind)
+ *kind = svn_node_none;
+ if (deleted)
+ *deleted = FALSE;
+ if (excluded)
+ *excluded = FALSE;
+ if (parent_depth)
+ *parent_depth = svn_depth_unknown;
+
+ SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
+
+ err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+
+ if (disk_kind != svn_node_none)
+ {
+ /* Nothing in the DB, but something on disk */
+ *obstruction_state = svn_wc_notify_state_obstructed;
+ return SVN_NO_ERROR;
+ }
+
+ err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, parent_depth, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ wc_ctx->db, svn_dirent_dirname(local_abspath,
+ scratch_pool),
+ scratch_pool, scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ /* No versioned parent; we can't add a node here */
+ *obstruction_state = svn_wc_notify_state_obstructed;
+ return SVN_NO_ERROR;
+ }
+ else
+ SVN_ERR(err);
+
+ if (db_kind != svn_node_dir
+ || (status != svn_wc__db_status_normal
+ && status != svn_wc__db_status_added))
+ {
+ /* The parent doesn't allow nodes to be added below it */
+ *obstruction_state = svn_wc_notify_state_obstructed;
+ }
+
+ return SVN_NO_ERROR;
+ }
+ else
+ SVN_ERR(err);
+
+ /* Check for obstructing working copies */
+ if (!no_wcroot_check
+ && db_kind == svn_node_dir
+ && status == svn_wc__db_status_normal)
+ {
+ svn_boolean_t is_root;
+ SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath,
+ scratch_pool));
+
+ if (is_root)
+ {
+ /* Callers should handle this as unversioned */
+ *obstruction_state = svn_wc_notify_state_obstructed;
+ return SVN_NO_ERROR;
+ }
+ }
+
+ if (kind)
+ SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE));
+
+ switch (status)
+ {
+ case svn_wc__db_status_deleted:
+ if (deleted)
+ *deleted = TRUE;
+ /* Fall through to svn_wc__db_status_not_present */
+ case svn_wc__db_status_not_present:
+ if (disk_kind != svn_node_none)
+ *obstruction_state = svn_wc_notify_state_obstructed;
+ break;
+
+ case svn_wc__db_status_excluded:
+ case svn_wc__db_status_server_excluded:
+ if (excluded)
+ *excluded = TRUE;
+ /* fall through */
+ case svn_wc__db_status_incomplete:
+ *obstruction_state = svn_wc_notify_state_missing;
+ break;
+
+ case svn_wc__db_status_added:
+ case svn_wc__db_status_normal:
+ if (disk_kind == svn_node_none)
+ *obstruction_state = svn_wc_notify_state_missing;
+ else
+ {
+ svn_node_kind_t expected_kind;
+
+ SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind,
+ status, FALSE));
+
+ if (disk_kind != expected_kind)
+ *obstruction_state = svn_wc_notify_state_obstructed;
+ }
+ break;
+ default:
+ SVN_ERR_MALFUNCTION();
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__node_was_moved_away(const char **moved_to_abspath,
+ const char **op_root_abspath,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t is_deleted;
+
+ if (moved_to_abspath)
+ *moved_to_abspath = NULL;
+ if (op_root_abspath)
+ *op_root_abspath = NULL;
+
+ SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath,
+ scratch_pool));
+ if (is_deleted)
+ SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL,
+ op_root_abspath, wc_ctx->db,
+ local_abspath,
+ result_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__node_was_moved_here(const char **moved_from_abspath,
+ const char **delete_op_root_abspath,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+
+ if (moved_from_abspath)
+ *moved_from_abspath = NULL;
+ if (delete_op_root_abspath)
+ *delete_op_root_abspath = NULL;
+
+ err = svn_wc__db_scan_moved(moved_from_abspath, NULL, NULL,
+ delete_op_root_abspath,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool);
+
+ if (err)
+ {
+ /* Return error for not added nodes */
+ if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
+ return svn_error_trace(err);
+
+ /* Path not moved here */
+ svn_error_clear(err);
+ return SVN_NO_ERROR;
+ }
+
+ return SVN_NO_ERROR;
+}
OpenPOWER on IntegriCloud