summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_delta/editor.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_delta/editor.c')
-rw-r--r--subversion/libsvn_delta/editor.c956
1 files changed, 956 insertions, 0 deletions
diff --git a/subversion/libsvn_delta/editor.c b/subversion/libsvn_delta/editor.c
new file mode 100644
index 0000000..1dc94b2
--- /dev/null
+++ b/subversion/libsvn_delta/editor.c
@@ -0,0 +1,956 @@
+/*
+ * editor.c : editing trees of versioned resources
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ */
+
+#include <apr_pools.h>
+
+#include "svn_types.h"
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "svn_dirent_uri.h"
+
+#include "private/svn_editor.h"
+
+#ifdef SVN_DEBUG
+/* This enables runtime checks of the editor API constraints. This may
+ introduce additional memory and runtime overhead, and should not be used
+ in production builds.
+
+ ### Remove before release?
+
+ ### Disabled for now. If I call svn_editor_alter_directory(A) then
+ svn_editor_add_file(A/f) the latter fails on SHOULD_ALLOW_ADD.
+ If I modify svn_editor_alter_directory to MARK_ALLOW_ADD(child)
+ then if I call svn_editor_alter_directory(A) followed by
+ svn_editor_alter_directory(A/B/C) the latter fails on
+ VERIFY_PARENT_MAY_EXIST. */
+#if 0
+#define ENABLE_ORDERING_CHECK
+#endif
+#endif
+
+
+struct svn_editor_t
+{
+ void *baton;
+
+ /* Standard cancellation function. Called before each callback. */
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
+
+ /* Our callback functions match that of the set-many structure, so
+ just use that. */
+ svn_editor_cb_many_t funcs;
+
+ /* This pool is used as the scratch_pool for all callbacks. */
+ apr_pool_t *scratch_pool;
+
+#ifdef ENABLE_ORDERING_CHECK
+ svn_boolean_t within_callback;
+
+ apr_hash_t *pending_incomplete_children;
+ apr_hash_t *completed_nodes;
+ svn_boolean_t finished;
+
+ apr_pool_t *state_pool;
+#endif
+};
+
+
+#ifdef ENABLE_ORDERING_CHECK
+
+#define START_CALLBACK(editor) \
+ do { \
+ svn_editor_t *editor__tmp_e = (editor); \
+ SVN_ERR_ASSERT(!editor__tmp_e->within_callback); \
+ editor__tmp_e->within_callback = TRUE; \
+ } while (0)
+#define END_CALLBACK(editor) ((editor)->within_callback = FALSE)
+
+/* Marker to indicate no further changes are allowed on this node. */
+static const int marker_done = 0;
+#define MARKER_DONE (&marker_done)
+
+/* Marker indicating that add_* may be called for this path, or that it
+ can be the destination of a copy or move. For copy/move, the path
+ will switch to MARKER_ALLOW_ALTER, to enable further tweaks. */
+static const int marker_allow_add = 0;
+#define MARKER_ALLOW_ADD (&marker_allow_add)
+
+/* Marker indicating that alter_* may be called for this path. */
+static const int marker_allow_alter = 0;
+#define MARKER_ALLOW_ALTER (&marker_allow_alter)
+
+/* Just like MARKER_DONE, but also indicates that the node was created
+ via add_directory(). This allows us to verify that the CHILDREN param
+ was comprehensive. */
+static const int marker_added_dir = 0;
+#define MARKER_ADDED_DIR (&marker_added_dir)
+
+#define MARK_FINISHED(editor) ((editor)->finished = TRUE)
+#define SHOULD_NOT_BE_FINISHED(editor) SVN_ERR_ASSERT(!(editor)->finished)
+
+#define CLEAR_INCOMPLETE(editor, relpath) \
+ svn_hash_sets((editor)->pending_incomplete_children, relpath, NULL);
+
+#define MARK_RELPATH(editor, relpath, value) \
+ svn_hash_sets((editor)->completed_nodes, \
+ apr_pstrdup((editor)->state_pool, relpath), value)
+
+#define MARK_COMPLETED(editor, relpath) \
+ MARK_RELPATH(editor, relpath, MARKER_DONE)
+#define SHOULD_NOT_BE_COMPLETED(editor, relpath) \
+ SVN_ERR_ASSERT(svn_hash_gets((editor)->completed_nodes, relpath) == NULL)
+
+#define MARK_ALLOW_ADD(editor, relpath) \
+ MARK_RELPATH(editor, relpath, MARKER_ALLOW_ADD)
+#define SHOULD_ALLOW_ADD(editor, relpath) \
+ SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ADD, NULL))
+
+#define MARK_ALLOW_ALTER(editor, relpath) \
+ MARK_RELPATH(editor, relpath, MARKER_ALLOW_ALTER)
+#define SHOULD_ALLOW_ALTER(editor, relpath) \
+ SVN_ERR_ASSERT(allow_either(editor, relpath, MARKER_ALLOW_ALTER, NULL))
+
+#define MARK_ADDED_DIR(editor, relpath) \
+ MARK_RELPATH(editor, relpath, MARKER_ADDED_DIR)
+#define CHECK_UNKNOWN_CHILD(editor, relpath) \
+ SVN_ERR_ASSERT(check_unknown_child(editor, relpath))
+
+/* When a child is changed in some way, mark the parent directory as needing
+ to be "stable" (no future structural changes). IOW, only allow "alter" on
+ the parent. Prevents parent-add/delete/move after any child operation. */
+#define MARK_PARENT_STABLE(editor, relpath) \
+ mark_parent_stable(editor, relpath)
+
+/* If the parent is MARKER_ALLOW_ADD, then it has been moved-away, and we
+ know it does not exist. All other cases: it might exist. */
+#define VERIFY_PARENT_MAY_EXIST(editor, relpath) \
+ SVN_ERR_ASSERT(svn_hash_gets((editor)->completed_nodes, \
+ svn_relpath_dirname(relpath, \
+ (editor)->scratch_pool)) \
+ != MARKER_ALLOW_ADD)
+
+/* If the parent is MARKER_ADDED_DIR, then we should not be deleting
+ children(*). If the parent is MARKER_ALLOW_ADD, then it has been
+ moved-away, so children cannot exist. That leaves MARKER_DONE,
+ MARKER_ALLOW_ALTER, and NULL as possible values. Just assert that
+ we didn't get either of the bad ones.
+
+ (*) if the child as added via add_*(), then it would have been marked
+ as completed and delete/move-away already test against completed nodes.
+ This test is to beware of trying to delete "children" that are not
+ actually (and can't possibly be) present. */
+#define CHILD_DELETIONS_ALLOWED(editor, relpath) \
+ SVN_ERR_ASSERT(!allow_either(editor, \
+ svn_relpath_dirname(relpath, \
+ (editor)->scratch_pool), \
+ MARKER_ADDED_DIR, MARKER_ALLOW_ADD))
+
+static svn_boolean_t
+allow_either(const svn_editor_t *editor,
+ const char *relpath,
+ const void *marker1,
+ const void *marker2)
+{
+ void *value = svn_hash_gets(editor->completed_nodes, relpath);
+ return value == marker1 || value == marker2;
+}
+
+static svn_boolean_t
+check_unknown_child(const svn_editor_t *editor,
+ const char *relpath)
+{
+ const char *parent;
+
+ /* If we already know about the new child, then exit early. */
+ if (svn_hash_gets(editor->pending_incomplete_children, relpath) != NULL)
+ return TRUE;
+
+ parent = svn_relpath_dirname(relpath, editor->scratch_pool);
+
+ /* Was this parent created via svn_editor_add_directory() ? */
+ if (svn_hash_gets(editor->completed_nodes, parent)
+ == MARKER_ADDED_DIR)
+ {
+ /* Whoops. This child should have been listed in that add call,
+ and placed into ->pending_incomplete_children. */
+ return FALSE;
+ }
+
+ /* The parent was not added in this drive. */
+ return TRUE;
+}
+
+static void
+mark_parent_stable(const svn_editor_t *editor,
+ const char *relpath)
+{
+ const char *parent = svn_relpath_dirname(relpath, editor->scratch_pool);
+ const void *marker = svn_hash_gets(editor->completed_nodes, parent);
+
+ /* If RELPATH has already been marked (to disallow adds, or that it
+ has been fully-completed), then do nothing. */
+ if (marker == MARKER_ALLOW_ALTER
+ || marker == MARKER_DONE
+ || marker == MARKER_ADDED_DIR)
+ return;
+
+ /* If the marker is MARKER_ALLOW_ADD, then that means the parent was
+ moved away. There is no way to work on a child. That should have
+ been tested before we got here by VERIFY_PARENT_MAY_EXIST(). */
+ SVN_ERR_ASSERT_NO_RETURN(marker != MARKER_ALLOW_ADD);
+
+ /* MARKER is NULL. Upgrade it to MARKER_ALLOW_ALTER. */
+ MARK_RELPATH(editor, parent, MARKER_ALLOW_ALTER);
+}
+
+#else
+
+/* Be wary with the definition of these macros so that we don't
+ end up with "statement with no effect" warnings. Obviously, this
+ depends upon particular usage, which is easy to verify. */
+
+#define START_CALLBACK(editor) /* empty */
+#define END_CALLBACK(editor) /* empty */
+
+#define MARK_FINISHED(editor) /* empty */
+#define SHOULD_NOT_BE_FINISHED(editor) /* empty */
+
+#define CLEAR_INCOMPLETE(editor, relpath) /* empty */
+
+#define MARK_COMPLETED(editor, relpath) /* empty */
+#define SHOULD_NOT_BE_COMPLETED(editor, relpath) /* empty */
+
+#define MARK_ALLOW_ADD(editor, relpath) /* empty */
+#define SHOULD_ALLOW_ADD(editor, relpath) /* empty */
+
+#define MARK_ALLOW_ALTER(editor, relpath) /* empty */
+#define SHOULD_ALLOW_ALTER(editor, relpath) /* empty */
+
+#define MARK_ADDED_DIR(editor, relpath) /* empty */
+#define CHECK_UNKNOWN_CHILD(editor, relpath) /* empty */
+
+#define MARK_PARENT_STABLE(editor, relpath) /* empty */
+#define VERIFY_PARENT_MAY_EXIST(editor, relpath) /* empty */
+#define CHILD_DELETIONS_ALLOWED(editor, relpath) /* empty */
+
+#endif /* ENABLE_ORDERING_CHECK */
+
+
+svn_error_t *
+svn_editor_create(svn_editor_t **editor,
+ void *editor_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ *editor = apr_pcalloc(result_pool, sizeof(**editor));
+
+ (*editor)->baton = editor_baton;
+ (*editor)->cancel_func = cancel_func;
+ (*editor)->cancel_baton = cancel_baton;
+ (*editor)->scratch_pool = svn_pool_create(result_pool);
+
+#ifdef ENABLE_ORDERING_CHECK
+ (*editor)->pending_incomplete_children = apr_hash_make(result_pool);
+ (*editor)->completed_nodes = apr_hash_make(result_pool);
+ (*editor)->finished = FALSE;
+ (*editor)->state_pool = result_pool;
+#endif
+
+ return SVN_NO_ERROR;
+}
+
+
+void *
+svn_editor_get_baton(const svn_editor_t *editor)
+{
+ return editor->baton;
+}
+
+
+svn_error_t *
+svn_editor_setcb_add_directory(svn_editor_t *editor,
+ svn_editor_cb_add_directory_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_add_directory = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_add_file(svn_editor_t *editor,
+ svn_editor_cb_add_file_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_add_file = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_add_symlink(svn_editor_t *editor,
+ svn_editor_cb_add_symlink_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_add_symlink = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_add_absent(svn_editor_t *editor,
+ svn_editor_cb_add_absent_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_add_absent = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_alter_directory(svn_editor_t *editor,
+ svn_editor_cb_alter_directory_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_alter_directory = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_alter_file(svn_editor_t *editor,
+ svn_editor_cb_alter_file_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_alter_file = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_alter_symlink(svn_editor_t *editor,
+ svn_editor_cb_alter_symlink_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_alter_symlink = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_delete(svn_editor_t *editor,
+ svn_editor_cb_delete_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_delete = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_copy(svn_editor_t *editor,
+ svn_editor_cb_copy_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_copy = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_move(svn_editor_t *editor,
+ svn_editor_cb_move_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_move = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_rotate(svn_editor_t *editor,
+ svn_editor_cb_rotate_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_rotate = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_complete(svn_editor_t *editor,
+ svn_editor_cb_complete_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_complete = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_abort(svn_editor_t *editor,
+ svn_editor_cb_abort_t callback,
+ apr_pool_t *scratch_pool)
+{
+ editor->funcs.cb_abort = callback;
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_editor_setcb_many(svn_editor_t *editor,
+ const svn_editor_cb_many_t *many,
+ apr_pool_t *scratch_pool)
+{
+#define COPY_CALLBACK(NAME) if (many->NAME) editor->funcs.NAME = many->NAME
+
+ COPY_CALLBACK(cb_add_directory);
+ COPY_CALLBACK(cb_add_file);
+ COPY_CALLBACK(cb_add_symlink);
+ COPY_CALLBACK(cb_add_absent);
+ COPY_CALLBACK(cb_alter_directory);
+ COPY_CALLBACK(cb_alter_file);
+ COPY_CALLBACK(cb_alter_symlink);
+ COPY_CALLBACK(cb_delete);
+ COPY_CALLBACK(cb_copy);
+ COPY_CALLBACK(cb_move);
+ COPY_CALLBACK(cb_rotate);
+ COPY_CALLBACK(cb_complete);
+ COPY_CALLBACK(cb_abort);
+
+#undef COPY_CALLBACK
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+check_cancel(svn_editor_t *editor)
+{
+ svn_error_t *err = NULL;
+
+ if (editor->cancel_func)
+ {
+ START_CALLBACK(editor);
+ err = editor->cancel_func(editor->cancel_baton);
+ END_CALLBACK(editor);
+ }
+
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_add_directory(svn_editor_t *editor,
+ const char *relpath,
+ const apr_array_header_t *children,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SVN_ERR_ASSERT(children != NULL);
+ SVN_ERR_ASSERT(props != NULL);
+ /* ### validate children are just basenames? */
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ADD(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+ CHECK_UNKNOWN_CHILD(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_add_directory)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_add_directory(editor->baton, relpath, children,
+ props, replaces_rev,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_ADDED_DIR(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+ CLEAR_INCOMPLETE(editor, relpath);
+
+#ifdef ENABLE_ORDERING_CHECK
+ {
+ int i;
+ for (i = 0; i < children->nelts; i++)
+ {
+ const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
+ const char *child = svn_relpath_join(relpath, child_basename,
+ editor->state_pool);
+
+ svn_hash_sets(editor->pending_incomplete_children, child, "");
+ }
+ }
+#endif
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_add_file(svn_editor_t *editor,
+ const char *relpath,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SVN_ERR_ASSERT(checksum != NULL
+ && checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
+ SVN_ERR_ASSERT(contents != NULL);
+ SVN_ERR_ASSERT(props != NULL);
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ADD(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+ CHECK_UNKNOWN_CHILD(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_add_file)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_add_file(editor->baton, relpath,
+ checksum, contents, props,
+ replaces_rev, editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_COMPLETED(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+ CLEAR_INCOMPLETE(editor, relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_add_symlink(svn_editor_t *editor,
+ const char *relpath,
+ const char *target,
+ apr_hash_t *props,
+ svn_revnum_t replaces_rev)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SVN_ERR_ASSERT(props != NULL);
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ADD(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+ CHECK_UNKNOWN_CHILD(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_add_symlink)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_add_symlink(editor->baton, relpath, target, props,
+ replaces_rev, editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_COMPLETED(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+ CLEAR_INCOMPLETE(editor, relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_add_absent(svn_editor_t *editor,
+ const char *relpath,
+ svn_node_kind_t kind,
+ svn_revnum_t replaces_rev)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ADD(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+ CHECK_UNKNOWN_CHILD(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_add_absent)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_add_absent(editor->baton, relpath, kind,
+ replaces_rev, editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_COMPLETED(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+ CLEAR_INCOMPLETE(editor, relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_alter_directory(svn_editor_t *editor,
+ const char *relpath,
+ svn_revnum_t revision,
+ const apr_array_header_t *children,
+ apr_hash_t *props)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SVN_ERR_ASSERT(children != NULL || props != NULL);
+ /* ### validate children are just basenames? */
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ALTER(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_alter_directory)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_alter_directory(editor->baton,
+ relpath, revision,
+ children, props,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_COMPLETED(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+
+#ifdef ENABLE_ORDERING_CHECK
+ /* ### this is not entirely correct. we probably need to adjust the
+ ### check_unknown_child() function for this scenario. */
+#if 0
+ {
+ int i;
+ for (i = 0; i < children->nelts; i++)
+ {
+ const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
+ const char *child = svn_relpath_join(relpath, child_basename,
+ editor->state_pool);
+
+ apr_hash_set(editor->pending_incomplete_children, child,
+ APR_HASH_KEY_STRING, "");
+ /* Perhaps MARK_ALLOW_ADD(editor, child); ? */
+ }
+ }
+#endif
+#endif
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_alter_file(svn_editor_t *editor,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_hash_t *props,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SVN_ERR_ASSERT((checksum != NULL && contents != NULL)
+ || (checksum == NULL && contents == NULL));
+ SVN_ERR_ASSERT(props != NULL || checksum != NULL);
+ if (checksum)
+ SVN_ERR_ASSERT(checksum->kind == SVN_EDITOR_CHECKSUM_KIND);
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ALTER(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_alter_file)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_alter_file(editor->baton,
+ relpath, revision, props,
+ checksum, contents,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_COMPLETED(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_alter_symlink(svn_editor_t *editor,
+ const char *relpath,
+ svn_revnum_t revision,
+ apr_hash_t *props,
+ const char *target)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SVN_ERR_ASSERT(props != NULL || target != NULL);
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ALTER(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_alter_symlink)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_alter_symlink(editor->baton,
+ relpath, revision, props,
+ target,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_COMPLETED(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_delete(svn_editor_t *editor,
+ const char *relpath,
+ svn_revnum_t revision)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_NOT_BE_COMPLETED(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+ CHILD_DELETIONS_ALLOWED(editor, relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_delete)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_delete(editor->baton, relpath, revision,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_COMPLETED(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_copy(svn_editor_t *editor,
+ const char *src_relpath,
+ svn_revnum_t src_revision,
+ const char *dst_relpath,
+ svn_revnum_t replaces_rev)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(src_relpath));
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(dst_relpath));
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_ALLOW_ADD(editor, dst_relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, src_relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, dst_relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_copy)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_copy(editor->baton, src_relpath, src_revision,
+ dst_relpath, replaces_rev,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_ALLOW_ALTER(editor, dst_relpath);
+ MARK_PARENT_STABLE(editor, dst_relpath);
+ CLEAR_INCOMPLETE(editor, dst_relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_move(svn_editor_t *editor,
+ const char *src_relpath,
+ svn_revnum_t src_revision,
+ const char *dst_relpath,
+ svn_revnum_t replaces_rev)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(src_relpath));
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(dst_relpath));
+ SHOULD_NOT_BE_FINISHED(editor);
+ SHOULD_NOT_BE_COMPLETED(editor, src_relpath);
+ SHOULD_ALLOW_ADD(editor, dst_relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, src_relpath);
+ CHILD_DELETIONS_ALLOWED(editor, src_relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, dst_relpath);
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_move)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_move(editor->baton, src_relpath, src_revision,
+ dst_relpath, replaces_rev,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_ALLOW_ADD(editor, src_relpath);
+ MARK_PARENT_STABLE(editor, src_relpath);
+ MARK_ALLOW_ALTER(editor, dst_relpath);
+ MARK_PARENT_STABLE(editor, dst_relpath);
+ CLEAR_INCOMPLETE(editor, dst_relpath);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_rotate(svn_editor_t *editor,
+ const apr_array_header_t *relpaths,
+ const apr_array_header_t *revisions)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SHOULD_NOT_BE_FINISHED(editor);
+#ifdef ENABLE_ORDERING_CHECK
+ {
+ int i;
+ for (i = 0; i < relpaths->nelts; i++)
+ {
+ const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
+
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
+ SHOULD_NOT_BE_COMPLETED(editor, relpath);
+ VERIFY_PARENT_MAY_EXIST(editor, relpath);
+ CHILD_DELETIONS_ALLOWED(editor, relpath);
+ }
+ }
+#endif
+
+ SVN_ERR(check_cancel(editor));
+
+ if (editor->funcs.cb_rotate)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_rotate(editor->baton, relpaths, revisions,
+ editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+#ifdef ENABLE_ORDERING_CHECK
+ {
+ int i;
+ for (i = 0; i < relpaths->nelts; i++)
+ {
+ const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
+ MARK_ALLOW_ALTER(editor, relpath);
+ MARK_PARENT_STABLE(editor, relpath);
+ }
+ }
+#endif
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_complete(svn_editor_t *editor)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SHOULD_NOT_BE_FINISHED(editor);
+#ifdef ENABLE_ORDERING_CHECK
+ SVN_ERR_ASSERT(apr_hash_count(editor->pending_incomplete_children) == 0);
+#endif
+
+ if (editor->funcs.cb_complete)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_complete(editor->baton, editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_FINISHED(editor);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
+
+
+svn_error_t *
+svn_editor_abort(svn_editor_t *editor)
+{
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SHOULD_NOT_BE_FINISHED(editor);
+
+ if (editor->funcs.cb_abort)
+ {
+ START_CALLBACK(editor);
+ err = editor->funcs.cb_abort(editor->baton, editor->scratch_pool);
+ END_CALLBACK(editor);
+ }
+
+ MARK_FINISHED(editor);
+
+ svn_pool_clear(editor->scratch_pool);
+ return svn_error_trace(err);
+}
OpenPOWER on IntegriCloud