summaryrefslogtreecommitdiff
path: root/subversion/libsvn_repos/commit.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2015-03-18 13:33:26 +0000
committer <>2015-07-08 14:41:01 +0000
commitbb0ef45f7c46b0ae221b26265ef98a768c33f820 (patch)
tree98bae10dde41c746c51ae97ec4f879e330415aa7 /subversion/libsvn_repos/commit.c
parent239dfafe71711b2f4c43d7b90a1228d7bdc5195e (diff)
downloadsubversion-tarball-bb0ef45f7c46b0ae221b26265ef98a768c33f820.tar.gz
Imported from /home/lorry/working-area/delta_subversion-tarball/subversion-1.8.13.tar.gz.subversion-1.8.13
Diffstat (limited to 'subversion/libsvn_repos/commit.c')
-rw-r--r--subversion/libsvn_repos/commit.c636
1 files changed, 589 insertions, 47 deletions
diff --git a/subversion/libsvn_repos/commit.c b/subversion/libsvn_repos/commit.c
index c8032e3..22cf873 100644
--- a/subversion/libsvn_repos/commit.c
+++ b/subversion/libsvn_repos/commit.c
@@ -26,6 +26,7 @@
#include <apr_pools.h>
#include <apr_file_io.h>
+#include "svn_hash.h"
#include "svn_compat.h"
#include "svn_pools.h"
#include "svn_error.h"
@@ -35,12 +36,17 @@
#include "svn_fs.h"
#include "svn_repos.h"
#include "svn_checksum.h"
+#include "svn_ctype.h"
#include "svn_props.h"
#include "svn_mergeinfo.h"
-#include "repos.h"
#include "svn_private_config.h"
+
+#include "repos.h"
+
#include "private/svn_fspath.h"
+#include "private/svn_fs_private.h"
#include "private/svn_repos_private.h"
+#include "private/svn_editor.h"
@@ -128,6 +134,29 @@ struct file_baton
};
+struct ev2_baton
+{
+ /* The repository we are editing. */
+ svn_repos_t *repos;
+
+ /* The authz baton for checks; NULL to skip authz. */
+ svn_authz_t *authz;
+
+ /* The repository name and user for performing authz checks. */
+ const char *authz_repos_name;
+ const char *authz_user;
+
+ /* Callback to provide info about the committed revision. */
+ svn_commit_callback2_t commit_cb;
+ void *commit_baton;
+
+ /* The FS txn editor */
+ svn_editor_t *inner;
+
+ /* The name of the open transaction (so we know what to commit) */
+ const char *txn_name;
+};
+
/* Create and return a generic out-of-dateness error. */
static svn_error_t *
@@ -143,6 +172,40 @@ out_of_date(const char *path, svn_node_kind_t kind)
}
+static svn_error_t *
+invoke_commit_cb(svn_commit_callback2_t commit_cb,
+ void *commit_baton,
+ svn_fs_t *fs,
+ svn_revnum_t revision,
+ const char *post_commit_errstr,
+ apr_pool_t *scratch_pool)
+{
+ /* FS interface returns non-const values. */
+ /* const */ svn_string_t *date;
+ /* const */ svn_string_t *author;
+ svn_commit_info_t *commit_info;
+
+ if (commit_cb == NULL)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_fs_revision_prop(&date, fs, revision, SVN_PROP_REVISION_DATE,
+ scratch_pool));
+ SVN_ERR(svn_fs_revision_prop(&author, fs, revision,
+ SVN_PROP_REVISION_AUTHOR,
+ scratch_pool));
+
+ commit_info = svn_create_commit_info(scratch_pool);
+
+ /* fill up the svn_commit_info structure */
+ commit_info->revision = revision;
+ commit_info->date = date ? date->data : NULL;
+ commit_info->author = author ? author->data : NULL;
+ commit_info->post_commit_err = post_commit_errstr;
+
+ return svn_error_trace(commit_cb(commit_info, commit_baton, scratch_pool));
+}
+
+
/* If EDITOR_BATON contains a valid authz callback, verify that the
REQUIRED access to PATH in ROOT is authorized. Return an error
@@ -196,7 +259,6 @@ make_dir_baton(struct edit_baton *edit_baton,
return db;
}
-
/* This function is the shared guts of add_file() and add_directory(),
which see for the meanings of the parameters. The only extra
parameter here is IS_DIR, which is TRUE when adding a directory,
@@ -216,6 +278,9 @@ add_file_or_directory(const char *path,
svn_boolean_t was_copied = FALSE;
const char *full_path;
+ /* Reject paths which contain control characters (related to issue #4340). */
+ SVN_ERR(svn_path_check_valid(path, pool));
+
full_path = svn_fspath__join(eb->base_path,
svn_relpath_canonicalize(path, pool), pool);
@@ -247,7 +312,7 @@ add_file_or_directory(const char *path,
out-of-dateness error. */
SVN_ERR(svn_fs_check_path(&kind, eb->txn_root, full_path, subpool));
if ((kind != svn_node_none) && (! pb->was_copied))
- return out_of_date(full_path, kind);
+ return svn_error_trace(out_of_date(full_path, kind));
/* For now, require that the url come from the same repository
that this commit is operating on. */
@@ -396,13 +461,13 @@ delete_entry(const char *path,
/* If PATH doesn't exist in the txn, the working copy is out of date. */
if (kind == svn_node_none)
- return out_of_date(full_path, kind);
+ return svn_error_trace(out_of_date(full_path, kind));
/* Now, make sure we're deleting the node we *think* we're
deleting, else return an out-of-dateness error. */
SVN_ERR(svn_fs_node_created_rev(&cr_rev, eb->txn_root, full_path, pool));
if (SVN_IS_VALID_REVNUM(revision) && (revision < cr_rev))
- return out_of_date(full_path, kind);
+ return svn_error_trace(out_of_date(full_path, kind));
/* This routine is a mindless wrapper. We call svn_fs_delete()
because that will delete files and recursively delete
@@ -518,7 +583,7 @@ open_file(const char *path,
/* If the node our caller has is an older revision number than the
one in our transaction, return an out-of-dateness error. */
if (SVN_IS_VALID_REVNUM(base_revision) && (base_revision < cr_rev))
- return out_of_date(full_path, svn_node_file);
+ return svn_error_trace(out_of_date(full_path, svn_node_file));
/* Build a new file baton */
new_fb = apr_pcalloc(pool, sizeof(*new_fb));
@@ -602,7 +667,7 @@ change_dir_prop(void *dir_baton,
eb->txn_root, db->path, pool));
if (db->base_rev < created_rev)
- return out_of_date(db->path, svn_node_dir);
+ return svn_error_trace(out_of_date(db->path, svn_node_dir));
}
return svn_repos_fs_change_node_prop(eb->txn_root, db->path,
@@ -631,7 +696,8 @@ svn_repos__post_commit_error_str(svn_error_t *err,
else
hook_err2 = hook_err1;
- /* This implementation counts on svn_repos_fs_commit_txn() returning
+ /* This implementation counts on svn_repos_fs_commit_txn() and
+ libsvn_repos/commit.c:complete_cb() returning
svn_fs_commit_txn() as the parent error with a child
SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED error. If the parent error
is SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED then there was no error
@@ -695,6 +761,13 @@ close_edit(void *edit_baton,
if (SVN_IS_VALID_REVNUM(new_revision))
{
+ /* The actual commit succeeded, i.e. the transaction does no longer
+ exist and we can't use txn_root for conflict resolution etc.
+
+ Since close_edit is supposed to release resources, do it now. */
+ if (eb->txn_root)
+ svn_fs_close_root(eb->txn_root);
+
if (err)
{
/* If the error was in post-commit, then the commit itself
@@ -703,8 +776,14 @@ close_edit(void *edit_baton,
display it as a warning) and clear the error. */
post_commit_err = svn_repos__post_commit_error_str(err, pool);
svn_error_clear(err);
- err = SVN_NO_ERROR;
}
+
+ /* Make sure a future abort doesn't perform
+ any work. This may occur if the commit
+ callback returns an error! */
+
+ eb->txn = NULL;
+ eb->txn_root = NULL;
}
else
{
@@ -730,41 +809,19 @@ close_edit(void *edit_baton,
svn_fs_abort_txn(eb->txn, pool)));
}
- /* Pass new revision information to the caller's callback. */
- {
- svn_string_t *date, *author;
- svn_commit_info_t *commit_info;
+ /* At this point, the post-commit error has been converted to a string.
+ That information will be passed to a callback, if provided. If the
+ callback invocation fails in some way, that failure is returned here.
+ IOW, the post-commit error information is low priority compared to
+ other gunk here. */
- /* Even if there was a post-commit hook failure, it's more serious
- if one of the calls here fails, so we explicitly check for errors
- here, while saving the possible post-commit error for later. */
-
- err = svn_fs_revision_prop(&date, svn_repos_fs(eb->repos),
- new_revision, SVN_PROP_REVISION_DATE,
- pool);
- if (! err)
- {
- err = svn_fs_revision_prop(&author, svn_repos_fs(eb->repos),
- new_revision, SVN_PROP_REVISION_AUTHOR,
- pool);
- }
-
- if ((! err) && eb->commit_callback)
- {
- commit_info = svn_create_commit_info(pool);
-
- /* fill up the svn_commit_info structure */
- commit_info->revision = new_revision;
- commit_info->date = date ? date->data : NULL;
- commit_info->author = author ? author->data : NULL;
- commit_info->post_commit_err = post_commit_err;
- err = (*eb->commit_callback)(commit_info,
- eb->commit_callback_baton,
- pool);
- }
- }
-
- return svn_error_trace(err);
+ /* Pass new revision information to the caller's callback. */
+ return svn_error_trace(invoke_commit_cb(eb->commit_callback,
+ eb->commit_callback_baton,
+ eb->repos->fs,
+ new_revision,
+ post_commit_err,
+ pool));
}
@@ -778,10 +835,102 @@ abort_edit(void *edit_baton,
eb->txn_aborted = TRUE;
+ /* Since abort_edit is supposed to release resources, do it now. */
+ if (eb->txn_root)
+ svn_fs_close_root(eb->txn_root);
+
return svn_error_trace(svn_fs_abort_txn(eb->txn, pool));
}
+static svn_error_t *
+fetch_props_func(apr_hash_t **props,
+ void *baton,
+ const char *path,
+ svn_revnum_t base_revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ svn_fs_root_t *fs_root;
+ svn_error_t *err;
+
+ SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs,
+ svn_fs_txn_base_revision(eb->txn),
+ scratch_pool));
+ err = svn_fs_node_proplist(props, fs_root, path, result_pool);
+ if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ *props = apr_hash_make(result_pool);
+ return SVN_NO_ERROR;
+ }
+ else if (err)
+ return svn_error_trace(err);
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_kind_func(svn_node_kind_t *kind,
+ void *baton,
+ const char *path,
+ svn_revnum_t base_revision,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ svn_fs_root_t *fs_root;
+
+ if (!SVN_IS_VALID_REVNUM(base_revision))
+ base_revision = svn_fs_txn_base_revision(eb->txn);
+
+ SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs, base_revision, scratch_pool));
+
+ SVN_ERR(svn_fs_check_path(kind, fs_root, path, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_base_func(const char **filename,
+ void *baton,
+ const char *path,
+ svn_revnum_t base_revision,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ svn_stream_t *contents;
+ svn_stream_t *file_stream;
+ const char *tmp_filename;
+ svn_fs_root_t *fs_root;
+ svn_error_t *err;
+
+ if (!SVN_IS_VALID_REVNUM(base_revision))
+ base_revision = svn_fs_txn_base_revision(eb->txn);
+
+ SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs, base_revision, scratch_pool));
+
+ err = svn_fs_file_contents(&contents, fs_root, path, scratch_pool);
+ if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ *filename = NULL;
+ return SVN_NO_ERROR;
+ }
+ else if (err)
+ return svn_error_trace(err);
+ SVN_ERR(svn_stream_open_unique(&file_stream, &tmp_filename, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(contents, file_stream, NULL, NULL, scratch_pool));
+
+ *filename = apr_pstrdup(result_pool, tmp_filename);
+
+ return SVN_NO_ERROR;
+}
+
+
/*** Public interfaces. ***/
@@ -793,8 +942,8 @@ svn_repos_get_commit_editor5(const svn_delta_editor_t **editor,
const char *repos_url,
const char *base_path,
apr_hash_t *revprop_table,
- svn_commit_callback2_t callback,
- void *callback_baton,
+ svn_commit_callback2_t commit_callback,
+ void *commit_baton,
svn_repos_authz_callback_t authz_callback,
void *authz_baton,
apr_pool_t *pool)
@@ -802,6 +951,8 @@ svn_repos_get_commit_editor5(const svn_delta_editor_t **editor,
svn_delta_editor_t *e;
apr_pool_t *subpool = svn_pool_create(pool);
struct edit_baton *eb;
+ svn_delta_shim_callbacks_t *shim_callbacks =
+ svn_delta_shim_callbacks_default(pool);
/* Do a global authz access lookup. Users with no write access
whatsoever to the repository don't get a commit editor. */
@@ -837,8 +988,8 @@ svn_repos_get_commit_editor5(const svn_delta_editor_t **editor,
/* Set up the edit baton. */
eb->pool = subpool;
eb->revprop_table = svn_prop_hash_dup(revprop_table, subpool);
- eb->commit_callback = callback;
- eb->commit_callback_baton = callback_baton;
+ eb->commit_callback = commit_callback;
+ eb->commit_callback_baton = commit_baton;
eb->authz_callback = authz_callback;
eb->authz_baton = authz_baton;
eb->base_path = svn_fspath__canonicalize(base_path, subpool);
@@ -853,5 +1004,396 @@ svn_repos_get_commit_editor5(const svn_delta_editor_t **editor,
*edit_baton = eb;
*editor = e;
+ shim_callbacks->fetch_props_func = fetch_props_func;
+ shim_callbacks->fetch_kind_func = fetch_kind_func;
+ shim_callbacks->fetch_base_func = fetch_base_func;
+ shim_callbacks->fetch_baton = eb;
+
+ SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+ eb->repos_url, eb->base_path,
+ shim_callbacks, pool, pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+#if 0
+static svn_error_t *
+ev2_check_authz(const struct ev2_baton *eb,
+ const char *relpath,
+ svn_repos_authz_access_t required,
+ apr_pool_t *scratch_pool)
+{
+ const char *fspath;
+ svn_boolean_t allowed;
+
+ if (eb->authz == NULL)
+ return SVN_NO_ERROR;
+
+ if (relpath)
+ fspath = apr_pstrcat(scratch_pool, "/", relpath, NULL);
+ else
+ fspath = NULL;
+
+ SVN_ERR(svn_repos_authz_check_access(eb->authz, eb->authz_repos_name, fspath,
+ eb->authz_user, required,
+ &allowed, scratch_pool));
+ if (!allowed)
+ return svn_error_create(required & svn_authz_write
+ ? SVN_ERR_AUTHZ_UNWRITABLE
+ : SVN_ERR_AUTHZ_UNREADABLE,
+ NULL, "Access denied");
+
+ return SVN_NO_ERROR;
+}
+#endif
+
+
+/* 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 ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_add_directory(eb->inner, relpath, children, props,
+ replaces_rev));
+ 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 ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_add_file(eb->inner, relpath, checksum, contents, props,
+ replaces_rev));
+ 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 ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_add_symlink(eb->inner, relpath, target, props,
+ replaces_rev));
+ return SVN_NO_ERROR;
+}
+
+
+/* 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)
+{
+ struct ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_add_absent(eb->inner, relpath, kind, replaces_rev));
+ return SVN_NO_ERROR;
+}
+
+
+/* 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 ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_alter_directory(eb->inner, relpath, revision,
+ children, props));
+ 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,
+ apr_hash_t *props,
+ const svn_checksum_t *checksum,
+ svn_stream_t *contents,
+ apr_pool_t *scratch_pool)
+{
+ struct ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_alter_file(eb->inner, relpath, revision, props,
+ checksum, contents));
+ 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,
+ apr_hash_t *props,
+ const char *target,
+ apr_pool_t *scratch_pool)
+{
+ struct ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_alter_symlink(eb->inner, relpath, revision, props,
+ target));
+ return SVN_NO_ERROR;
+}
+
+
+/* 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 ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_delete(eb->inner, relpath, revision));
+ 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 ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_copy(eb->inner, src_relpath, src_revision, dst_relpath,
+ replaces_rev));
+ 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 ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_move(eb->inner, src_relpath, src_revision, dst_relpath,
+ replaces_rev));
+ return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_rotate_t */
+static svn_error_t *
+rotate_cb(void *baton,
+ const apr_array_header_t *relpaths,
+ const apr_array_header_t *revisions,
+ apr_pool_t *scratch_pool)
+{
+ struct ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_rotate(eb->inner, relpaths, revisions));
+ 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 ev2_baton *eb = baton;
+ svn_revnum_t revision;
+ svn_error_t *post_commit_err;
+ const char *conflict_path;
+ svn_error_t *err;
+ const char *post_commit_errstr;
+ apr_hash_t *hooks_env;
+
+ /* Parse the hooks-env file (if any). */
+ SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, eb->repos->hooks_env_path,
+ scratch_pool, scratch_pool));
+
+ /* The transaction has been fully edited. Let the pre-commit hook
+ have a look at the thing. */
+ SVN_ERR(svn_repos__hooks_pre_commit(eb->repos, hooks_env,
+ eb->txn_name, scratch_pool));
+
+ /* Hook is done. Let's do the actual commit. */
+ SVN_ERR(svn_fs__editor_commit(&revision, &post_commit_err, &conflict_path,
+ eb->inner, scratch_pool, scratch_pool));
+
+ /* Did a conflict occur during the commit process? */
+ if (conflict_path != NULL)
+ return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
+ _("Conflict at '%s'"), conflict_path);
+
+ /* Since did not receive an error during the commit process, and no
+ conflict was specified... we committed a revision. Run the hooks.
+ Other errors may have occurred within the FS (specified by the
+ POST_COMMIT_ERR localvar), but we need to run the hooks. */
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
+ err = svn_repos__hooks_post_commit(eb->repos, hooks_env, revision,
+ eb->txn_name, scratch_pool);
+ if (err)
+ err = svn_error_create(SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
+ _("Commit succeeded, but post-commit hook failed"));
+
+ /* Combine the FS errors with the hook errors, and stringify. */
+ err = svn_error_compose_create(post_commit_err, err);
+ if (err)
+ {
+ post_commit_errstr = svn_repos__post_commit_error_str(err, scratch_pool);
+ svn_error_clear(err);
+ }
+ else
+ {
+ post_commit_errstr = NULL;
+ }
+
+ return svn_error_trace(invoke_commit_cb(eb->commit_cb, eb->commit_baton,
+ eb->repos->fs, revision,
+ post_commit_errstr,
+ scratch_pool));
+}
+
+
+/* This implements svn_editor_cb_abort_t */
+static svn_error_t *
+abort_cb(void *baton,
+ apr_pool_t *scratch_pool)
+{
+ struct ev2_baton *eb = baton;
+
+ SVN_ERR(svn_editor_abort(eb->inner));
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+apply_revprops(svn_fs_t *fs,
+ const char *txn_name,
+ apr_hash_t *revprops,
+ apr_pool_t *scratch_pool)
+{
+ svn_fs_txn_t *txn;
+ const apr_array_header_t *revprops_array;
+
+ /* The FS editor has a TXN inside it, but we can't access it. Open another
+ based on the TXN_NAME. */
+ SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, scratch_pool));
+
+ /* Validate and apply the revision properties. */
+ revprops_array = svn_prop_hash_to_array(revprops, scratch_pool);
+ SVN_ERR(svn_repos_fs_change_txn_props(txn, revprops_array, scratch_pool));
+
+ /* ### do we need to force the txn to close, or is it enough to wait
+ ### for the pool to be cleared? */
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_repos__get_commit_ev2(svn_editor_t **editor,
+ svn_repos_t *repos,
+ svn_authz_t *authz,
+ const char *authz_repos_name,
+ const char *authz_user,
+ apr_hash_t *revprops,
+ svn_commit_callback2_t commit_cb,
+ void *commit_baton,
+ 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,
+ rotate_cb,
+ complete_cb,
+ abort_cb
+ };
+ struct ev2_baton *eb;
+ const svn_string_t *author;
+ apr_hash_t *hooks_env;
+
+ /* Parse the hooks-env file (if any). */
+ SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
+ scratch_pool, scratch_pool));
+
+ /* Can the user modify the repository at all? */
+ /* ### check against AUTHZ. */
+
+ author = svn_hash_gets(revprops, SVN_PROP_REVISION_AUTHOR);
+
+ eb = apr_palloc(result_pool, sizeof(*eb));
+ eb->repos = repos;
+ eb->authz = authz;
+ eb->authz_repos_name = authz_repos_name;
+ eb->authz_user = authz_user;
+ eb->commit_cb = commit_cb;
+ eb->commit_baton = commit_baton;
+
+ SVN_ERR(svn_fs__editor_create(&eb->inner, &eb->txn_name,
+ repos->fs, SVN_FS_TXN_CHECK_LOCKS,
+ cancel_func, cancel_baton,
+ result_pool, scratch_pool));
+
+ /* The TXN has been created. Go ahead and apply all revision properties. */
+ SVN_ERR(apply_revprops(repos->fs, eb->txn_name, revprops, scratch_pool));
+
+ /* Okay... some access is allowed. Let's run the start-commit hook. */
+ SVN_ERR(svn_repos__hooks_start_commit(repos, hooks_env,
+ author ? author->data : NULL,
+ repos->client_capabilities,
+ eb->txn_name, scratch_pool));
+
+ /* Wrap the FS editor within our editor. */
+ 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;
}