aboutsummaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_repos/commit.c
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2018-05-08 03:44:38 +0000
committerPeter Wemm <peter@FreeBSD.org>2018-05-08 03:44:38 +0000
commit3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch)
tree7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_repos/commit.c
parenta55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff)
downloadsrc-3faf8d6bffc5d0fb2525ba37bb504c53366caf9d.tar.gz
src-3faf8d6bffc5d0fb2525ba37bb504c53366caf9d.zip
Import Subversion-1.10.0vendor/subversion/subversion-1.10.0
Notes
Notes: svn path=/vendor/subversion/dist/; revision=333347 svn path=/vendor/subversion/subversion-1.10.0/; revision=333348; tag=vendor/subversion/subversion-1.10.0
Diffstat (limited to 'subversion/libsvn_repos/commit.c')
-rw-r--r--subversion/libsvn_repos/commit.c140
1 files changed, 93 insertions, 47 deletions
diff --git a/subversion/libsvn_repos/commit.c b/subversion/libsvn_repos/commit.c
index 1190acc29fc5..6ce4cc6f7ffd 100644
--- a/subversion/libsvn_repos/commit.c
+++ b/subversion/libsvn_repos/commit.c
@@ -124,6 +124,7 @@ struct dir_baton
svn_revnum_t base_rev; /* the revision I'm based on */
svn_boolean_t was_copied; /* was this directory added with history? */
apr_pool_t *pool; /* my personal pool, in which I am allocated. */
+ svn_boolean_t checked_write; /* TRUE after successfull write check */
};
@@ -131,6 +132,7 @@ struct file_baton
{
struct edit_baton *edit_baton;
const char *path; /* the -absolute- path to this file in the fs */
+ svn_boolean_t checked_write; /* TRUE after successfull write check */
};
@@ -171,6 +173,30 @@ out_of_date(const char *path, svn_node_kind_t kind)
path);
}
+/* Perform an out of date check for base_rev against created rev,
+ and a sanity check of base_rev. */
+static svn_error_t *
+check_out_of_date(struct edit_baton *eb,
+ const char *path,
+ svn_node_kind_t kind,
+ svn_revnum_t base_rev,
+ svn_revnum_t created_rev)
+{
+ if (base_rev < created_rev)
+ {
+ return out_of_date(path, kind);
+ }
+ else if (base_rev > created_rev)
+ {
+ if (base_rev > svn_fs_txn_base_revision(eb->txn))
+ return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld"),
+ base_rev);
+ }
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
invoke_commit_cb(svn_commit_callback2_t commit_cb,
@@ -184,15 +210,16 @@ invoke_commit_cb(svn_commit_callback2_t commit_cb,
/* const */ svn_string_t *date;
/* const */ svn_string_t *author;
svn_commit_info_t *commit_info;
+ apr_hash_t *revprops;
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));
+ SVN_ERR(svn_fs_revision_proplist2(&revprops, fs, revision,
+ TRUE, scratch_pool, scratch_pool));
+
+ date = svn_hash_gets(revprops, SVN_PROP_REVISION_DATE);
+ author = svn_hash_gets(revprops, SVN_PROP_REVISION_AUTHOR);
commit_info = svn_create_commit_info(scratch_pool);
@@ -298,7 +325,6 @@ add_file_or_directory(const char *path,
const char *fs_path;
svn_fs_root_t *copy_root;
svn_node_kind_t kind;
- size_t repos_url_len;
svn_repos_authz_access_t required;
/* Copy requires recursive write access to the destination path
@@ -320,14 +346,12 @@ add_file_or_directory(const char *path,
/* For now, require that the url come from the same repository
that this commit is operating on. */
copy_path = svn_path_uri_decode(copy_path, subpool);
- repos_url_len = strlen(eb->repos_url_decoded);
- if (strncmp(copy_path, eb->repos_url_decoded, repos_url_len) != 0)
+ fs_path = svn_cstring_skip_prefix(copy_path, eb->repos_url_decoded);
+ if (!fs_path)
return svn_error_createf
(SVN_ERR_FS_GENERAL, NULL,
_("Source url '%s' is from different repository"), copy_path);
- fs_path = apr_pstrdup(subpool, copy_path + repos_url_len);
-
/* Now use the "fs_path" as an absolute path within the
repository to make the copy from. */
SVN_ERR(svn_fs_revision_root(&copy_root, eb->fs,
@@ -364,14 +388,18 @@ add_file_or_directory(const char *path,
/* Build a new child baton. */
if (is_dir)
{
- *return_baton = make_dir_baton(eb, pb, full_path, was_copied,
- SVN_INVALID_REVNUM, pool);
+ struct dir_baton *new_db = make_dir_baton(eb, pb, full_path, was_copied,
+ SVN_INVALID_REVNUM, pool);
+
+ new_db->checked_write = TRUE; /* Just created */
+ *return_baton = new_db;
}
else
{
struct file_baton *new_fb = apr_pcalloc(pool, sizeof(*new_fb));
new_fb->edit_baton = eb;
new_fb->path = full_path;
+ new_fb->checked_write = TRUE; /* Just created */
*return_baton = new_fb;
}
@@ -392,9 +420,9 @@ open_root(void *edit_baton,
struct edit_baton *eb = edit_baton;
svn_revnum_t youngest;
- /* Ignore BASE_REVISION. We always build our transaction against
- HEAD. However, we will keep it in our dir baton for out of
- dateness checks. */
+ /* We always build our transaction against HEAD. However, we will
+ sanity-check BASE_REVISION and keep it in our dir baton for out
+ of dateness checks. */
SVN_ERR(svn_fs_youngest_rev(&youngest, eb->fs, eb->pool));
if (base_revision > youngest)
@@ -448,7 +476,6 @@ delete_entry(const char *path,
struct dir_baton *parent = parent_baton;
struct edit_baton *eb = parent->edit_baton;
svn_node_kind_t kind;
- svn_revnum_t cr_rev;
svn_repos_authz_access_t required = svn_authz_write;
const char *full_path;
@@ -473,14 +500,18 @@ delete_entry(const char *path,
/* 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 svn_error_trace(out_of_date(full_path, kind));
+ if (SVN_IS_VALID_REVNUM(revision))
+ {
+ svn_revnum_t cr_rev;
+
+ SVN_ERR(svn_fs_node_created_rev(&cr_rev, eb->txn_root, full_path, pool));
+ SVN_ERR(check_out_of_date(eb, full_path, kind, revision, cr_rev));
+ }
/* This routine is a mindless wrapper. We call svn_fs_delete()
because that will delete files and recursively delete
directories. */
- return svn_fs_delete(eb->txn_root, full_path, pool);
+ return svn_error_trace(svn_fs_delete(eb->txn_root, full_path, pool));
}
@@ -535,18 +566,23 @@ apply_textdelta(void *file_baton,
void **handler_baton)
{
struct file_baton *fb = file_baton;
+ struct edit_baton *eb = fb->edit_baton;
- /* Check for write authorization. */
- SVN_ERR(check_authz(fb->edit_baton, fb->path,
- fb->edit_baton->txn_root,
- svn_authz_write, pool));
+ if (!fb->checked_write)
+ {
+ /* Check for write authorization. */
+ SVN_ERR(check_authz(eb, fb->path, eb->txn_root,
+ svn_authz_write, pool));
+ fb->checked_write = TRUE;
+ }
- return svn_fs_apply_textdelta(handler, handler_baton,
- fb->edit_baton->txn_root,
- fb->path,
- base_checksum,
- NULL,
- pool);
+ return svn_error_trace(
+ svn_fs_apply_textdelta(handler, handler_baton,
+ eb->txn_root,
+ fb->path,
+ base_checksum,
+ NULL,
+ pool));
}
@@ -590,8 +626,9 @@ 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 svn_error_trace(out_of_date(full_path, svn_node_file));
+ if (SVN_IS_VALID_REVNUM(base_revision))
+ SVN_ERR(check_out_of_date(eb, full_path, svn_node_file,
+ base_revision, cr_rev));
/* Build a new file baton */
new_fb = apr_pcalloc(pool, sizeof(*new_fb));
@@ -616,9 +653,13 @@ change_file_prop(void *file_baton,
struct file_baton *fb = file_baton;
struct edit_baton *eb = fb->edit_baton;
- /* Check for write authorization. */
- SVN_ERR(check_authz(eb, fb->path, eb->txn_root,
- svn_authz_write, pool));
+ if (!fb->checked_write)
+ {
+ /* Check for write authorization. */
+ SVN_ERR(check_authz(eb, fb->path, eb->txn_root,
+ svn_authz_write, pool));
+ fb->checked_write = TRUE;
+ }
return svn_repos_fs_change_node_prop(eb->txn_root, fb->path,
name, value, pool);
@@ -663,19 +704,24 @@ change_dir_prop(void *dir_baton,
struct edit_baton *eb = db->edit_baton;
/* Check for write authorization. */
- SVN_ERR(check_authz(eb, db->path, eb->txn_root,
- svn_authz_write, pool));
-
- if (SVN_IS_VALID_REVNUM(db->base_rev))
+ if (!db->checked_write)
{
- /* Subversion rule: propchanges can only happen on a directory
- which is up-to-date. */
- svn_revnum_t created_rev;
- SVN_ERR(svn_fs_node_created_rev(&created_rev,
- eb->txn_root, db->path, pool));
-
- if (db->base_rev < created_rev)
- return svn_error_trace(out_of_date(db->path, svn_node_dir));
+ SVN_ERR(check_authz(eb, db->path, eb->txn_root,
+ svn_authz_write, pool));
+
+ if (SVN_IS_VALID_REVNUM(db->base_rev))
+ {
+ /* Subversion rule: propchanges can only happen on a directory
+ which is up-to-date. */
+ svn_revnum_t created_rev;
+ SVN_ERR(svn_fs_node_created_rev(&created_rev,
+ eb->txn_root, db->path, pool));
+
+ SVN_ERR(check_out_of_date(eb, db->path, svn_node_dir,
+ db->base_rev, created_rev));
+ }
+
+ db->checked_write = TRUE; /* Skip on further prop changes */
}
return svn_repos_fs_change_node_prop(eb->txn_root, db->path,