diff options
Diffstat (limited to 'contrib/subversion/subversion/libsvn_fs/editor.c')
-rw-r--r-- | contrib/subversion/subversion/libsvn_fs/editor.c | 838 |
1 files changed, 0 insertions, 838 deletions
diff --git a/contrib/subversion/subversion/libsvn_fs/editor.c b/contrib/subversion/subversion/libsvn_fs/editor.c deleted file mode 100644 index c24c154e59cf..000000000000 --- a/contrib/subversion/subversion/libsvn_fs/editor.c +++ /dev/null @@ -1,838 +0,0 @@ -/* - * editor.c: Editor for modifying FS transactions - * - * ==================================================================== - * 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_fs.h" -#include "svn_props.h" -#include "svn_path.h" - -#include "svn_private_config.h" - -#include "fs-loader.h" - -#include "private/svn_fspath.h" -#include "private/svn_fs_private.h" -#include "private/svn_editor.h" - - -struct edit_baton { - /* The transaction associated with this editor. */ - svn_fs_txn_t *txn; - - /* Has this editor been completed? */ - svn_boolean_t completed; - - /* We sometimes need the cancellation beyond what svn_editor_t provides */ - svn_cancel_func_t cancel_func; - void *cancel_baton; - - /* The pool that the txn lives within. When we create a ROOT, it will - be allocated within a subpool of this. The root will be closed in - complete/abort and that subpool will be destroyed. - - This pool SHOULD NOT be used for any allocations. */ - apr_pool_t *txn_pool; - - /* This is the root from the txn. Use get_root() to fetch/create this - member as appropriate. */ - svn_fs_root_t *root; -}; - -#define FSPATH(relpath, pool) apr_pstrcat(pool, "/", relpath, SVN_VA_NULL) - -static svn_error_t * -get_root(svn_fs_root_t **root, - struct edit_baton *eb) -{ - if (eb->root == NULL) - SVN_ERR(svn_fs_txn_root(&eb->root, eb->txn, eb->txn_pool)); - *root = eb->root; - return SVN_NO_ERROR; -} - - -/* Apply each property in PROPS to the node at FSPATH in ROOT. */ -static svn_error_t * -add_new_props(svn_fs_root_t *root, - const char *fspath, - apr_hash_t *props, - apr_pool_t *scratch_pool) -{ - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - apr_hash_index_t *hi; - - /* ### it would be nice to have svn_fs_set_node_props(). but since we - ### don't... add each property to the node. this is a new node, so - ### we don't need to worry about deleting props. just adding. */ - - for (hi = apr_hash_first(scratch_pool, props); hi; - hi = apr_hash_next(hi)) - { - const char *name = apr_hash_this_key(hi); - const svn_string_t *value = apr_hash_this_val(hi); - - svn_pool_clear(iterpool); - - SVN_ERR(svn_fs_change_node_prop(root, fspath, name, value, iterpool)); - } - - svn_pool_destroy(iterpool); - return SVN_NO_ERROR; -} - - -static svn_error_t * -alter_props(svn_fs_root_t *root, - const char *fspath, - apr_hash_t *props, - apr_pool_t *scratch_pool) -{ - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - apr_hash_t *old_props; - apr_array_header_t *propdiffs; - int i; - - SVN_ERR(svn_fs_node_proplist(&old_props, root, fspath, scratch_pool)); - - SVN_ERR(svn_prop_diffs(&propdiffs, props, old_props, scratch_pool)); - - for (i = 0; i < propdiffs->nelts; ++i) - { - const svn_prop_t *prop = &APR_ARRAY_IDX(propdiffs, i, svn_prop_t); - - svn_pool_clear(iterpool); - - /* Add, change, or delete properties. */ - SVN_ERR(svn_fs_change_node_prop(root, fspath, prop->name, prop->value, - iterpool)); - } - - svn_pool_destroy(iterpool); - return SVN_NO_ERROR; -} - - -static svn_error_t * -set_text(svn_fs_root_t *root, - const char *fspath, - const svn_checksum_t *checksum, - svn_stream_t *contents, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *scratch_pool) -{ - svn_stream_t *fs_contents; - - /* ### We probably don't have an MD5 checksum, so no digest is available - ### for svn_fs_apply_text() to validate. It would be nice to have an - ### FS API that takes our CHECKSUM/CONTENTS pair (and PROPS!). */ - SVN_ERR(svn_fs_apply_text(&fs_contents, root, fspath, - NULL /* result_checksum */, - scratch_pool)); - SVN_ERR(svn_stream_copy3(contents, fs_contents, - cancel_func, cancel_baton, - scratch_pool)); - - return SVN_NO_ERROR; -} - - -/* The caller wants to modify REVISION of FSPATH. Is that allowed? */ -static svn_error_t * -can_modify(svn_fs_root_t *txn_root, - const char *fspath, - svn_revnum_t revision, - apr_pool_t *scratch_pool) -{ - svn_revnum_t created_rev; - - /* Out-of-dateness check: compare the created-rev of the node - in the txn against the created-rev of FSPATH. */ - SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, fspath, - scratch_pool)); - - /* Uncommitted nodes (eg. a descendant of a copy/move destination) - have no (committed) revision number. Let the caller go ahead and - modify these nodes. - - Note: strictly speaking, they might be performing an "illegal" edit - in certain cases, but let's just assume they're Good Little Boys. - - If CREATED_REV is invalid, that means it's already mutable in the - txn, which means it has already passed this out-of-dateness check. - (Usually, this happens when looking at a parent directory of an - already-modified node) */ - if (!SVN_IS_VALID_REVNUM(created_rev)) - return SVN_NO_ERROR; - - /* If the node is immutable (has a revision), then the caller should - have supplied a valid revision number [that they expect to change]. - The checks further below will determine the out-of-dateness of the - specified revision. */ - /* ### ugh. descendants of copy/move destinations carry along - ### their original immutable state and (thus) a valid CREATED_REV. - ### but they are logically uncommitted, so the caller will pass - ### SVN_INVALID_REVNUM. (technically, the caller could provide - ### ORIGINAL_REV, but that is semantically incorrect for the Ev2 - ### API). - ### - ### for now, we will assume the caller knows what they are doing - ### and an invalid revision implies such a descendant. in the - ### future, we could examine the ancestor chain looking for a - ### copy/move-here node and allow the modification (and the - ### converse: if no such ancestor, the caller must specify the - ### correct/intended revision to modify). - */ -#if 1 - if (!SVN_IS_VALID_REVNUM(revision)) - return SVN_NO_ERROR; -#else - if (!SVN_IS_VALID_REVNUM(revision)) - /* ### use a custom error code? */ - return svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL, - _("Revision for modifying '%s' is required"), - fspath); -#endif - - if (revision < created_rev) - { - /* We asked to change a node that is *older* than what we found - in the transaction. The client is out of date. */ - return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL, - _("'%s' is out of date; try updating"), - fspath); - } - - if (revision > created_rev) - { - /* We asked to change a node that is *newer* than what we found - in the transaction. Given that the transaction was based off - of 'youngest', then either: - - the caller asked to modify a future node - - the caller has committed more revisions since this txn - was constructed, and is asking to modify a node in one - of those new revisions. - In either case, the node may not have changed in those new - revisions; use the node's ID to determine this case. */ - svn_fs_root_t *rev_root; - svn_fs_node_relation_t relation; - - /* Get the ID from the future/new revision. */ - SVN_ERR(svn_fs_revision_root(&rev_root, svn_fs_root_fs(txn_root), - revision, scratch_pool)); - SVN_ERR(svn_fs_node_relation(&relation, txn_root, fspath, rev_root, - fspath, scratch_pool)); - svn_fs_close_root(rev_root); - - /* Has the target node changed in the future? */ - if (relation != svn_fs_node_unchanged) - { - /* Restarting the commit will base the txn on the future/new - revision, allowing the modification at REVISION. */ - /* ### use a custom error code */ - return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL, - _("'%s' has been modified since the " - "commit began (restart the commit)"), - fspath); - } - } - - return SVN_NO_ERROR; -} - - -/* Can we create a node at FSPATH in TXN_ROOT? If something already exists - at that path, then the client MAY be out of date. We then have to see if - the path was created/modified in this transaction. IOW, it is new and - can be replaced without problem. - - Note: the editor protocol disallows double-modifications. This is to - ensure somebody does not accidentally overwrite another file due to - being out-of-date. */ -static svn_error_t * -can_create(svn_fs_root_t *txn_root, - const char *fspath, - apr_pool_t *scratch_pool) -{ - svn_node_kind_t kind; - const char *cur_fspath; - - SVN_ERR(svn_fs_check_path(&kind, txn_root, fspath, scratch_pool)); - if (kind == svn_node_none) - return SVN_NO_ERROR; - - /* ### I'm not sure if this works perfectly. We might have an ancestor - ### that was modified as a result of a change on a cousin. We might - ### misinterpret that as a *-here node which brought along this - ### child. Need to write a test to verify. We may also be able to - ### test the ancestor to determine if it has been *-here in this - ### txn, or just a simple modification. */ - - /* Are any of the parents copied/moved-here? */ - for (cur_fspath = fspath; - strlen(cur_fspath) > 1; /* not the root */ - cur_fspath = svn_fspath__dirname(cur_fspath, scratch_pool)) - { - svn_revnum_t created_rev; - - SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, cur_fspath, - scratch_pool)); - if (!SVN_IS_VALID_REVNUM(created_rev)) - { - /* The node has no created revision, meaning it is uncommitted. - Thus, it was created in this transaction, or it has already - been modified in some way (implying it has already passed a - modification check. */ - /* ### verify the node has been *-here ?? */ - return SVN_NO_ERROR; - } - } - - return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL, - _("'%s' already exists, so may be out" - " of date; try updating"), - fspath); -} - - -/* This implements svn_editor_cb_add_directory_t */ -static svn_error_t * -add_directory_cb(void *baton, - const char *relpath, - const apr_array_header_t *children, - apr_hash_t *props, - svn_revnum_t replaces_rev, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *fspath = FSPATH(relpath, scratch_pool); - svn_fs_root_t *root; - - /* Note: we ignore CHILDREN. We have no "incomplete" state to worry about, - so we don't need to be aware of what children will be created. */ - - SVN_ERR(get_root(&root, eb)); - - if (SVN_IS_VALID_REVNUM(replaces_rev)) - { - SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool)); - SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); - } - else - { - SVN_ERR(can_create(root, fspath, scratch_pool)); - } - - SVN_ERR(svn_fs_make_dir(root, fspath, scratch_pool)); - SVN_ERR(add_new_props(root, fspath, props, scratch_pool)); - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_add_file_t */ -static svn_error_t * -add_file_cb(void *baton, - const char *relpath, - const svn_checksum_t *checksum, - svn_stream_t *contents, - apr_hash_t *props, - svn_revnum_t replaces_rev, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *fspath = FSPATH(relpath, scratch_pool); - svn_fs_root_t *root; - - SVN_ERR(get_root(&root, eb)); - - if (SVN_IS_VALID_REVNUM(replaces_rev)) - { - SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool)); - SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); - } - else - { - SVN_ERR(can_create(root, fspath, scratch_pool)); - } - - SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool)); - - SVN_ERR(set_text(root, fspath, checksum, contents, - eb->cancel_func, eb->cancel_baton, scratch_pool)); - SVN_ERR(add_new_props(root, fspath, props, scratch_pool)); - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_add_symlink_t */ -static svn_error_t * -add_symlink_cb(void *baton, - const char *relpath, - const char *target, - apr_hash_t *props, - svn_revnum_t replaces_rev, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *fspath = FSPATH(relpath, scratch_pool); - svn_fs_root_t *root; - - SVN_ERR(get_root(&root, eb)); - - if (SVN_IS_VALID_REVNUM(replaces_rev)) - { - SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool)); - SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); - } - else - { - SVN_ERR(can_create(root, fspath, scratch_pool)); - } - - /* ### we probably need to construct a file with specific contents - ### (until the FS grows some symlink APIs) */ -#if 0 - SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool)); - SVN_ERR(svn_fs_apply_text(&fs_contents, root, fspath, - NULL /* result_checksum */, - scratch_pool)); - /* ### SVN_ERR(svn_stream_printf(fs_contents, ..., scratch_pool)); */ - apr_hash_set(props, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING, - SVN_PROP_SPECIAL_VALUE); - - SVN_ERR(add_new_props(root, fspath, props, scratch_pool)); -#endif - - SVN__NOT_IMPLEMENTED(); -} - - -/* This implements svn_editor_cb_add_absent_t */ -static svn_error_t * -add_absent_cb(void *baton, - const char *relpath, - svn_node_kind_t kind, - svn_revnum_t replaces_rev, - apr_pool_t *scratch_pool) -{ - /* This is a programming error. Code should not attempt to create these - kinds of nodes within the FS. */ - /* ### use a custom error code */ - return svn_error_create( - SVN_ERR_UNSUPPORTED_FEATURE, NULL, - _("The filesystem does not support 'absent' nodes")); -} - - -/* This implements svn_editor_cb_alter_directory_t */ -static svn_error_t * -alter_directory_cb(void *baton, - const char *relpath, - svn_revnum_t revision, - const apr_array_header_t *children, - apr_hash_t *props, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *fspath = FSPATH(relpath, scratch_pool); - svn_fs_root_t *root; - - /* Note: we ignore CHILDREN. We have no "incomplete" state to worry about, - so we don't need to be aware of what children will be created. */ - - SVN_ERR(get_root(&root, eb)); - SVN_ERR(can_modify(root, fspath, revision, scratch_pool)); - - if (props) - SVN_ERR(alter_props(root, fspath, props, scratch_pool)); - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_alter_file_t */ -static svn_error_t * -alter_file_cb(void *baton, - const char *relpath, - svn_revnum_t revision, - const svn_checksum_t *checksum, - svn_stream_t *contents, - apr_hash_t *props, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *fspath = FSPATH(relpath, scratch_pool); - svn_fs_root_t *root; - - SVN_ERR(get_root(&root, eb)); - SVN_ERR(can_modify(root, fspath, revision, scratch_pool)); - - if (contents != NULL) - { - SVN_ERR_ASSERT(checksum != NULL); - SVN_ERR(set_text(root, fspath, checksum, contents, - eb->cancel_func, eb->cancel_baton, scratch_pool)); - } - - if (props != NULL) - { - SVN_ERR(alter_props(root, fspath, props, scratch_pool)); - } - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_alter_symlink_t */ -static svn_error_t * -alter_symlink_cb(void *baton, - const char *relpath, - svn_revnum_t revision, - const char *target, - apr_hash_t *props, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - - SVN_UNUSED(eb); - SVN__NOT_IMPLEMENTED(); -} - - -/* This implements svn_editor_cb_delete_t */ -static svn_error_t * -delete_cb(void *baton, - const char *relpath, - svn_revnum_t revision, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *fspath = FSPATH(relpath, scratch_pool); - svn_fs_root_t *root; - - SVN_ERR(get_root(&root, eb)); - SVN_ERR(can_modify(root, fspath, revision, scratch_pool)); - - SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_copy_t */ -static svn_error_t * -copy_cb(void *baton, - const char *src_relpath, - svn_revnum_t src_revision, - const char *dst_relpath, - svn_revnum_t replaces_rev, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *src_fspath = FSPATH(src_relpath, scratch_pool); - const char *dst_fspath = FSPATH(dst_relpath, scratch_pool); - svn_fs_root_t *root; - svn_fs_root_t *src_root; - - SVN_ERR(get_root(&root, eb)); - - /* Check if we can we replace the maybe-specified destination (revision). */ - if (SVN_IS_VALID_REVNUM(replaces_rev)) - { - SVN_ERR(can_modify(root, dst_fspath, replaces_rev, scratch_pool)); - SVN_ERR(svn_fs_delete(root, dst_fspath, scratch_pool)); - } - else - { - SVN_ERR(can_create(root, dst_fspath, scratch_pool)); - } - - SVN_ERR(svn_fs_revision_root(&src_root, svn_fs_root_fs(root), src_revision, - scratch_pool)); - SVN_ERR(svn_fs_copy(src_root, src_fspath, root, dst_fspath, scratch_pool)); - svn_fs_close_root(src_root); - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_move_t */ -static svn_error_t * -move_cb(void *baton, - const char *src_relpath, - svn_revnum_t src_revision, - const char *dst_relpath, - svn_revnum_t replaces_rev, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - const char *src_fspath = FSPATH(src_relpath, scratch_pool); - const char *dst_fspath = FSPATH(dst_relpath, scratch_pool); - svn_fs_root_t *root; - svn_fs_root_t *src_root; - - SVN_ERR(get_root(&root, eb)); - - /* Check if we delete the specified source (revision), and can we replace - the maybe-specified destination (revision). */ - SVN_ERR(can_modify(root, src_fspath, src_revision, scratch_pool)); - if (SVN_IS_VALID_REVNUM(replaces_rev)) - { - SVN_ERR(can_modify(root, dst_fspath, replaces_rev, scratch_pool)); - SVN_ERR(svn_fs_delete(root, dst_fspath, scratch_pool)); - } - else - { - SVN_ERR(can_create(root, dst_fspath, scratch_pool)); - } - - /* ### would be nice to have svn_fs_move() */ - - /* Copy the src to the dst. */ - SVN_ERR(svn_fs_revision_root(&src_root, svn_fs_root_fs(root), src_revision, - scratch_pool)); - SVN_ERR(svn_fs_copy(src_root, src_fspath, root, dst_fspath, scratch_pool)); - svn_fs_close_root(src_root); - - /* Notice: we're deleting the src repos path from the dst root. */ - SVN_ERR(svn_fs_delete(root, src_fspath, scratch_pool)); - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_complete_t */ -static svn_error_t * -complete_cb(void *baton, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - - /* Watch out for a following call to svn_fs_editor_commit(). Note that - we are likely here because svn_fs_editor_commit() was called, and it - invoked svn_editor_complete(). */ - eb->completed = TRUE; - - if (eb->root != NULL) - { - svn_fs_close_root(eb->root); - eb->root = NULL; - } - - return SVN_NO_ERROR; -} - - -/* This implements svn_editor_cb_abort_t */ -static svn_error_t * -abort_cb(void *baton, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = baton; - svn_error_t *err; - - /* Don't allow a following call to svn_fs_editor_commit(). */ - eb->completed = TRUE; - - if (eb->root != NULL) - { - svn_fs_close_root(eb->root); - eb->root = NULL; - } - - /* ### should we examine the error and attempt svn_fs_purge_txn() ? */ - err = svn_fs_abort_txn(eb->txn, scratch_pool); - - /* For safety, clear the now-useless txn. */ - eb->txn = NULL; - - return svn_error_trace(err); -} - - -static svn_error_t * -make_editor(svn_editor_t **editor, - svn_fs_txn_t *txn, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - static const svn_editor_cb_many_t editor_cbs = { - add_directory_cb, - add_file_cb, - add_symlink_cb, - add_absent_cb, - alter_directory_cb, - alter_file_cb, - alter_symlink_cb, - delete_cb, - copy_cb, - move_cb, - complete_cb, - abort_cb - }; - struct edit_baton *eb = apr_pcalloc(result_pool, sizeof(*eb)); - - eb->txn = txn; - eb->cancel_func = cancel_func; - eb->cancel_baton = cancel_baton; - eb->txn_pool = result_pool; - - SVN_ERR(svn_editor_create(editor, eb, cancel_func, cancel_baton, - result_pool, scratch_pool)); - SVN_ERR(svn_editor_setcb_many(*editor, &editor_cbs, scratch_pool)); - - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_fs__editor_create(svn_editor_t **editor, - const char **txn_name, - svn_fs_t *fs, - apr_uint32_t flags, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - svn_revnum_t revision; - svn_fs_txn_t *txn; - - SVN_ERR(svn_fs_youngest_rev(&revision, fs, scratch_pool)); - SVN_ERR(svn_fs_begin_txn2(&txn, fs, revision, flags, result_pool)); - SVN_ERR(svn_fs_txn_name(txn_name, txn, result_pool)); - return svn_error_trace(make_editor(editor, txn, - cancel_func, cancel_baton, - result_pool, scratch_pool)); -} - - -svn_error_t * -svn_fs__editor_create_for(svn_editor_t **editor, - svn_fs_t *fs, - const char *txn_name, - svn_cancel_func_t cancel_func, - void *cancel_baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - svn_fs_txn_t *txn; - - SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, result_pool)); - return svn_error_trace(make_editor(editor, txn, - cancel_func, cancel_baton, - result_pool, scratch_pool)); -} - - -svn_error_t * -svn_fs__editor_commit(svn_revnum_t *revision, - svn_error_t **post_commit_err, - const char **conflict_path, - svn_editor_t *editor, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - struct edit_baton *eb = svn_editor_get_baton(editor); - const char *inner_conflict_path; - svn_error_t *err = NULL; - - /* make sure people are using the correct sequencing. */ - if (eb->completed) - return svn_error_create(SVN_ERR_FS_INCORRECT_EDITOR_COMPLETION, - NULL, NULL); - - *revision = SVN_INVALID_REVNUM; - *post_commit_err = NULL; - *conflict_path = NULL; - - /* Clean up internal resources (eg. eb->root). This also allows the - editor infrastructure to know this editor is "complete". */ - err = svn_editor_complete(editor); - if (err) - { - svn_fs_txn_t *txn = eb->txn; - - eb->txn = NULL; - return svn_error_trace(svn_error_compose_create( - err, - svn_fs_abort_txn(txn, scratch_pool))); - } - - /* Note: docco for svn_fs_commit_txn() states that CONFLICT_PATH will - be allocated in the txn's pool. But it lies. Regardless, we want - it placed into RESULT_POOL. */ - - err = svn_fs_commit_txn(&inner_conflict_path, - revision, - eb->txn, - scratch_pool); - if (SVN_IS_VALID_REVNUM(*revision)) - { - if (err) - { - /* Case 3. ERR is a post-commit (cleanup) error. */ - - /* Pass responsibility via POST_COMMIT_ERR. */ - *post_commit_err = err; - err = SVN_NO_ERROR; - } - /* else: Case 1. */ - } - else - { - SVN_ERR_ASSERT(err != NULL); - if (err->apr_err == SVN_ERR_FS_CONFLICT) - { - /* Case 2. */ - - /* Copy this into the correct pool (see note above). */ - *conflict_path = apr_pstrdup(result_pool, inner_conflict_path); - - /* Return success. The caller should inspect CONFLICT_PATH to - determine this particular case. */ - svn_error_clear(err); - err = SVN_NO_ERROR; - } - /* else: Case 4. */ - - /* Abort the TXN. Nobody wants to use it. */ - /* ### should we examine the error and attempt svn_fs_purge_txn() ? */ - err = svn_error_compose_create( - err, - svn_fs_abort_txn(eb->txn, scratch_pool)); - } - - /* For safety, clear the now-useless txn. */ - eb->txn = NULL; - - return svn_error_trace(err); -} |