=== subversion/include/svn_error_codes.h
==================================================================
--- subversion/include/svn_error_codes.h  (revision 234)
+++ subversion/include/svn_error_codes.h  (revision 240)
@@ -788,6 +788,11 @@
               SVN_ERR_AUTHZ_CATEGORY_START + 3,
               "Invalid authz configuration")
 
+  /* @since New in 1.3 */
+  SVN_ERRDEF (SVN_ERR_AUTHZ_UNWRITABLE,
+              SVN_ERR_AUTHZ_CATEGORY_START + 4,
+              "Item is not writable")
+
   /* svndiff errors */
 
   SVN_ERRDEF (SVN_ERR_SVNDIFF_INVALID_HEADER,
=== subversion/include/svn_repos.h
==================================================================
--- subversion/include/svn_repos.h  (revision 234)
+++ subversion/include/svn_repos.h  (revision 240)
@@ -73,6 +73,63 @@
                                                 void *baton,
                                                 apr_pool_t *pool);
 
+
+/** An enum defining the kinds of access authz looks up.
+ *
+ * @since New in 1.3.
+ */
+typedef enum
+{
+  /** No access. */
+  svn_authz_none = 0,
+
+  /** Path can be read. */
+  svn_authz_read = 1,
+
+  /** Path can be altered. */
+  svn_authz_write = 2,
+
+  /** The other access credentials are recursive. */
+  svn_authz_recursive = 4
+} svn_repos_authz_access_t;
+
+
+/** Callback type for checking authorization on paths produced by
+ * the repository commit editor.
+ *
+ * Set @a *allowed to TRUE to indicate that the @a required_access on
+ * @a path in @a root is authorized, or set it to FALSE to indicate
+ * unauthorized (presumable according to state stored in @a baton).
+ *
+ * This callback is very similar to svn_repos_authz_func_t, with the
+ * exception of the addition of the @a required_access parameter.
+ * This is due to historical reasons: when authz was first implemented
+ * for svn_repos_dir_delta(), it seemed there would need only checks
+ * for read and write operations, hence the svn_repos_authz_func_t
+ * callback prototype and usage scenario.  But it was then realized
+ * that lookups due to copying needed to be recursive, and that
+ * brute-force recursive lookups didn't square with the O(1)
+ * performances a copy operation should have.
+ *
+ * So a special way to ask for a recursive lookup was introduced.  The
+ * commit editor needs this capability to retain acceptable
+ * performance.  Instead of revving the existing callback, causing
+ * unnecessary revving of functions that don't actually need the
+ * extended functionality, this second, more complete callback was
+ * introduced, for use by the commit editor.
+ *
+ * Some day, it would be nice to reunite these two callbacks and do
+ * the necessary revving anyway, but for the time being, this dual
+ * callback mechanism will do.
+ */
+typedef svn_error_t *(*svn_repos_authz_callback_t)
+  (svn_repos_authz_access_t required,
+   svn_boolean_t *allowed,
+   svn_fs_root_t *root,
+   const char *path,
+   void *baton,
+   apr_pool_t *pool);
+
 /**
  * A callback function type for use in svn_repos_get_file_revs().
  * @a baton is provided by the caller, @a path is the pathname of the file
@@ -585,6 +642,11 @@
  * Iff @a log_msg is not @c NULL, store it as the log message
  * associated with the commit transaction.
  *
+ * Iff @a authz_callback is provided, check read/write authorizations
+ * on paths accessed by editor operations.  An operation which fails
+ * due to authz will return SVN_ERR_AUTHZ_UNREADABLE or
+ * SVN_ERR_AUTHZ_UNWRITABLE.
+ *
  * Calling @a (*editor)->close_edit completes the commit.  Before
  * @c close_edit returns, but after the commit has succeeded, it will
  * invoke @a callback with the new revision number, the commit date (as a
@@ -599,8 +661,29 @@
  * NULL).  Callers who supply their own transactions are responsible
  * for cleaning them up (either by committing them, or aborting them).
  *
- * @since New in 1.2.
+ * @since New in 1.3.
  */
+svn_error_t *
+svn_repos_get_commit_editor3 (const svn_delta_editor_t **editor,
+                              void **edit_baton,
+                              svn_repos_t *repos,
+                              svn_fs_txn_t *txn,
+                              const char *repos_url,
+                              const char *base_path,
+                              const char *user,
+                              const char *log_msg,
+                              svn_commit_callback_t commit_callback,
+                              void *commit_callback_baton,
+                              svn_repos_authz_callback_t authz_callback,
+                              void *authz_baton,
+                              apr_pool_t *pool);
+
+/**
+ * Similar to svn_repos_get_commit_editor3(), but with @a
+ * authz_callback and @a authz_baton set to @c NULL.
+ *
+ * @deprecated Provided for backward compatibility with the 1.2 API.
+ */
 svn_error_t *svn_repos_get_commit_editor2 (const svn_delta_editor_t **editor,
                                            void **edit_baton,
                                            svn_repos_t *repos,
@@ -1675,25 +1758,6 @@
 
 /** @} */
 
-/** An enum defining the kinds of access authz looks up.
- *
- * @since New in 1.3.
- */
-typedef enum
-{
-  /** No access. */
-  svn_authz_none = 0,
-
-  /** Path can be read. */
-  svn_authz_read = 1,
-
-  /** Path can be altered. */
-  svn_authz_write = 2,
-
-  /** The other access credentials are recursive. */
-  svn_authz_recursive = 4
-} svn_repos_authz_access_t;
-
 /** A data type which stores the authz information. 
  *
  * @since New in 1.3.
=== subversion/libsvn_ra_local/ra_plugin.c
==================================================================
--- subversion/libsvn_ra_local/ra_plugin.c  (revision 234)
+++ subversion/libsvn_ra_local/ra_plugin.c  (revision 240)
@@ -525,12 +525,12 @@
     }
               
   /* Get the repos commit-editor */     
-  SVN_ERR (svn_repos_get_commit_editor2
+  SVN_ERR (svn_repos_get_commit_editor3
            (editor, edit_baton, sess_baton->repos, NULL,
             svn_path_uri_decode (sess_baton->repos_url, pool),
             sess_baton->fs_path,
             sess_baton->username, log_msg,
-            deltify_etc, db, pool));
+            deltify_etc, db, NULL, NULL, pool));
 
   return SVN_NO_ERROR;
 }
=== subversion/tests/libsvn_repos/repos-test.c
==================================================================
--- subversion/tests/libsvn_repos/repos-test.c  (revision 234)
+++ subversion/tests/libsvn_repos/repos-test.c  (revision 240)
@@ -1258,7 +1258,266 @@
   return SVN_NO_ERROR;
 }
 
+
 
+/* Callback for the commit editor tests that relays requests to
+   authz. */
+svn_error_t *commit_authz_cb (svn_repos_authz_access_t required,
+                              svn_boolean_t *allowed,
+                              svn_fs_root_t *root,
+                              const char *path,
+                              void *baton,
+                              apr_pool_t *pool)
+{
+  svn_authz_t *authz_file = baton;
+
+  return svn_repos_authz_check_access (authz_file, "test", path,
+                                       "plato", required, allowed,
+                                       pool);
+}
+
+
+
+/* Test that the commit editor is taking authz into account
+   properly */
+svn_error_t *
+commit_editor_authz  (const char **msg,
+                      svn_boolean_t msg_only,
+                      svn_test_opts_t *opts,
+                      apr_pool_t *pool)
+{
+  svn_repos_t *repos;
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  svn_revnum_t youngest_rev;
+  void *edit_baton;
+  void *root_baton, *dir_baton, *dir2_baton, *file_baton;
+  svn_error_t *err;
+  const svn_delta_editor_t *editor;
+  svn_authz_t *authz_file;
+  apr_pool_t *subpool = svn_pool_create (pool);
+  const char *authz_contents;
+
+  *msg = "test authz in the commit editor";
+
+  if (msg_only)
+    return SVN_NO_ERROR;
+
+  /* The Test Plan
+   *
+   * We create a greek tree repository, then create a commit editor
+   * and try to perform various operations that will run into authz
+   * callbacks.  Check that all operations are properly
+   * authorized/denied when necessary.  We don't try to be exhaustive
+   * in the kinds of authz lookups.  We just make sure that the editor
+   * replies to the calls in a way that proves it is doing authz
+   * lookups.
+  */
+
+  /* Create a filesystem and repository. */
+  SVN_ERR (svn_test__create_repos (&repos, "test-repo-commit-authz",
+                                   opts->fs_type, subpool));
+  fs = svn_repos_fs (repos);
+
+  /* Prepare a txn to receive the greek tree. */
+  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, subpool));
+  SVN_ERR (svn_fs_txn_root (&txn_root, txn, subpool));
+  SVN_ERR (svn_test__create_greek_tree (txn_root, subpool));
+  SVN_ERR (svn_repos_fs_commit_txn (NULL, repos, &youngest_rev, txn, subpool));
+
+  /* Load the authz rules for the greek tree. */
+  authz_contents =
+    APR_EOL_STR
+    APR_EOL_STR
+    "[/]"
+    APR_EOL_STR
+    "plato = r"
+    APR_EOL_STR
+    APR_EOL_STR
+    "[/A]"
+    APR_EOL_STR
+    "plato = rw"
+    APR_EOL_STR
+    APR_EOL_STR
+    "[/A/alpha]"
+    APR_EOL_STR
+    "plato = "
+    APR_EOL_STR
+    APR_EOL_STR
+    "[/A/C]"
+    APR_EOL_STR
+    APR_EOL_STR
+    "plato = "
+    APR_EOL_STR
+    APR_EOL_STR
+    "[/A/D]"
+    APR_EOL_STR
+    "plato = rw"
+    APR_EOL_STR
+    APR_EOL_STR
+    "[/A/D/G]"
+    APR_EOL_STR
+    "plato = r"
+    ;
+
+  SVN_ERR (authz_get_handle (&authz_file, authz_contents, subpool));
+
+  /* Create a new commit editor in which we're going to play with
+     authz */
+  SVN_ERR (svn_repos_get_commit_editor3 (&editor, &edit_baton, repos,
+                                         NULL, "file://test", "/",
+                                         "plato", "test commit", NULL,
+                                         NULL, commit_authz_cb, authz_file,
+                                         subpool));
+
+  /* Start fiddling.  First get the root, which is readonly.  All
+     write operations fail because of the root's permissions. */
+  SVN_ERR (editor->open_root (edit_baton, 1, subpool, &root_baton));
+
+  /* Test denied file deletion. */
+  err = editor->delete_entry ("/iota", SVN_INVALID_REVNUM, root_baton, subpool);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Test authorized file open. */
+  SVN_ERR (editor->open_file ("/iota", root_baton, SVN_INVALID_REVNUM,
+                              subpool, &file_baton));
+
+  /* Test unauthorized file prop set. */
+  err = editor->change_file_prop (file_baton, "svn:test",
+                                  svn_string_create ("test", subpool),
+                                  subpool);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Test denied file addition. */
+  err = editor->add_file ("/alpha", root_baton, NULL, SVN_INVALID_REVNUM,
+                          subpool, &file_baton);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Test denied file copy. */
+  err = editor->add_file ("/alpha", root_baton, "file://test/A/B/lambda",
+                          youngest_rev, subpool, &file_baton);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Test denied directory addition. */
+  err = editor->add_directory ("/I", root_baton, NULL,
+                               SVN_INVALID_REVNUM, subpool, &dir_baton);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Test denied directory copy. */
+  err = editor->add_directory ("/J", root_baton, "file://test/A/D",
+                               youngest_rev, subpool, &dir_baton);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Open directory /A, to which we have read/write access. */
+  SVN_ERR (editor->open_directory ("/A", root_baton,
+                                   SVN_INVALID_REVNUM,
+                                   pool, &dir_baton));
+
+  /* Test denied file addition.  Denied because of a conflicting rule
+     on the file path itself. */
+  err = editor->add_file ("/A/alpha", dir_baton, NULL,
+                          SVN_INVALID_REVNUM, subpool, &file_baton);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Test authorized file addition. */
+  SVN_ERR (editor->add_file ("/A/B/theta", dir_baton, NULL,
+                             SVN_INVALID_REVNUM, subpool,
+                             &file_baton));
+
+  /* Test authorized file deletion. */
+  SVN_ERR (editor->delete_entry ("/A/mu", SVN_INVALID_REVNUM, dir_baton,
+                                 subpool));
+
+  /* Test authorized directory creation. */
+  SVN_ERR (editor->add_directory ("/A/E", dir_baton, NULL,
+                                  SVN_INVALID_REVNUM, subpool,
+                                  &dir2_baton));
+
+  /* Test authorized copy of a tree. */
+  SVN_ERR (editor->add_directory ("/A/J", dir_baton, "file://test/A/D",
+                                  youngest_rev, subpool,
+                                  &dir2_baton));
+
+  /* Test denied access to a directory. */
+  err = editor->open_directory ("/A/C", dir_baton, SVN_INVALID_REVNUM,
+                                subpool, &dir2_baton);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNREADABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNREADABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Open /A/D.  This should be granted. */
+  SVN_ERR (editor->open_directory ("/A/D", dir_baton, SVN_INVALID_REVNUM,
+                                   subpool, &dir_baton));
+
+  /* Test denied recursive deletion. */
+  err = editor->delete_entry ("/A/D/G", SVN_INVALID_REVNUM, dir_baton,
+                              subpool);
+  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
+    return svn_error_createf (SVN_ERR_TEST_FAILED, err,
+                              "Got %s error instead of expected "
+                              "SVN_ERR_AUTHZ_UNWRITABLE",
+                              err ? "unexpected" : "no");
+  svn_error_clear (err);
+
+  /* Test authorized recursive deletion. */
+  SVN_ERR (editor->delete_entry ("/A/D/H", SVN_INVALID_REVNUM,
+                                 dir_baton, subpool));
+
+  /* Test authorized propset (open the file first). */
+  SVN_ERR (editor->open_file ("/A/D/gamma", dir_baton, SVN_INVALID_REVNUM,
+                              subpool, &file_baton));
+  SVN_ERR (editor->change_file_prop (file_baton, "svn:test",
+                                     svn_string_create("test", subpool),
+                                     subpool));
+
+  /* Done. */
+  editor->abort_edit (edit_baton, subpool);
+  svn_pool_destroy (subpool);
+
+  return SVN_NO_ERROR;
+}
+
+
+
 /* The test table.  */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -1270,5 +1529,6 @@
     SVN_TEST_PASS (node_locations),
     SVN_TEST_PASS (rmlocks),
     SVN_TEST_PASS (authz),
+    SVN_TEST_PASS (commit_editor_authz),
     SVN_TEST_NULL
   };
=== subversion/libsvn_repos/commit.c
==================================================================
--- subversion/libsvn_repos/commit.c  (revision 234)
+++ subversion/libsvn_repos/commit.c  (revision 240)
@@ -50,15 +50,22 @@
   const char *log_msg;
 
   /* Callback to run when the commit is done. */
-  svn_commit_callback_t callback;
-  void *callback_baton;
+  svn_commit_callback_t commit_callback;
+  void *commit_callback_baton;
 
+  /* Callback to check authorizations on paths. */
+  svn_repos_authz_callback_t authz_callback;
+  void *authz_baton;
+
   /* The already-open svn repository to commit to. */
   svn_repos_t *repos;
 
   /* URL to the root of the open repository. */
   const char *repos_url;
 
+  /* The name of the repository (here for convenience). */
+  const char *repos_name;
+
   /* The filesystem associated with the REPOS above (here for
      convenience). */
   svn_fs_t *fs;
@@ -124,6 +131,33 @@
 
 
 
+/* If EDITOR_BATON contains a valid authz callback, verify that the
+   REQUIRED access to PATH in ROOT is authorized.  Return an error
+   appropriate for throwing out of the commit editor with SVN_ERR.  If
+   no authz callback is present in EDITOR_BATON, then authorize all
+   paths.  Use POOL for temporary allocation only. */
+static svn_error_t *
+check_authz (struct edit_baton *editor_baton, const char *path,
+             svn_fs_root_t *root, svn_repos_authz_access_t required,
+             apr_pool_t *pool)
+{
+  if (editor_baton->authz_callback)
+    {
+      svn_boolean_t allowed;
+
+      editor_baton->authz_callback (required, &allowed, root, path,
+                                    editor_baton->authz_baton, 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;
+}
+
+
 /*** Editor functions ***/
 
 static svn_error_t *
@@ -173,7 +207,10 @@
     }
   SVN_ERR (svn_fs_txn_name (&(eb->txn_name), eb->txn, eb->pool));
   SVN_ERR (svn_fs_txn_root (&(eb->txn_root), eb->txn, eb->pool));
-  
+
+  /* Check read access to root */
+  SVN_ERR(check_authz (eb, "/", eb->txn_root, svn_authz_read, pool));
+
   /* Create a root dir baton.  The `base_path' field is an -absolute-
      path in the filesystem, upon which all further editor paths are
      based. */
@@ -201,11 +238,21 @@
   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 = svn_path_join (eb->base_path, path, pool);
 
   /* Check PATH in our transaction.  */
   SVN_ERR (svn_fs_check_path (&kind, eb->txn_root, full_path, pool));
 
+  /* Deletion requires a recursive write access, as well as write
+     access to the parent directory. */
+  if (kind == svn_node_dir)
+    required |= svn_authz_recursive;
+  SVN_ERR (check_authz (eb, full_path, eb->txn_root,
+                        required, pool));
+  SVN_ERR (check_authz (eb, parent->path, eb->txn_root,
+                        svn_authz_write, pool));
+
   /* If PATH doesn't exist in the txn, that's fine (merge
      allows this). */
   if (kind == svn_node_none)
@@ -254,6 +301,14 @@
       svn_node_kind_t kind;
       int repos_url_len;
 
+      /* Copy requires recursive write access to the destination path
+         and write access to the parent path. */
+      SVN_ERR (check_authz (eb, full_path, eb->txn_root,
+                            svn_authz_write | svn_authz_recursive,
+                            subpool));
+      SVN_ERR (check_authz (eb, pb->path, eb->txn_root,
+                            svn_authz_write, subpool));
+
       /* Check PATH in our transaction.  Make sure it does not exist
          unless its parent directory was copied (in which case, the
          thing might have been copied in as well), else return an
@@ -277,6 +332,13 @@
          repository to make the copy from. */      
       SVN_ERR (svn_fs_revision_root (&copy_root, eb->fs,
                                      copy_revision, subpool));
+
+      /* Copy also requires recursive read access to the source
+         path. */
+      SVN_ERR(check_authz (eb, fs_path, copy_root,
+                           svn_authz_read | svn_authz_recursive,
+                           subpool));
+
       SVN_ERR (svn_fs_copy (copy_root, fs_path,
                             eb->txn_root, full_path, subpool));
       was_copied = TRUE;
@@ -285,7 +347,13 @@
     {
       /* No ancestry given, just make a new directory.  We don't
          bother with an out-of-dateness check here because
-         svn_fs_make_dir will error out if PATH already exists.  */      
+         svn_fs_make_dir will error out if PATH already exists.
+         Verify write access to the full path and the parent
+         directory. */
+      SVN_ERR (check_authz (eb, full_path, eb->txn_root,
+                            svn_authz_write, subpool));
+      SVN_ERR (check_authz (eb, pb->path, eb->txn_root,
+                            svn_authz_write, subpool));
       SVN_ERR (svn_fs_make_dir (eb->txn_root, full_path, subpool));
     }
 
@@ -320,6 +388,10 @@
   svn_node_kind_t kind;
   const char *full_path = svn_path_join (eb->base_path, path, pool);
 
+  /* Check for read authorization. */
+  SVN_ERR (check_authz (eb, full_path, eb->txn_root,
+                        svn_authz_read, pool));
+
   /* Check PATH in our transaction.  If it does not exist,
      return a 'Path not present' error. */
   SVN_ERR (svn_fs_check_path (&kind, eb->txn_root, full_path, pool));
@@ -350,6 +422,12 @@
                  void **handler_baton)
 {
   struct file_baton *fb = file_baton;
+
+  /* Check for write authorization. */
+  SVN_ERR (check_authz (fb->edit_baton, fb->path,
+                        fb->edit_baton->txn_root,
+                        svn_authz_write, pool));
+
   return svn_fs_apply_textdelta (handler, handler_baton, 
                                  fb->edit_baton->txn_root, 
                                  fb->path,
@@ -388,6 +466,13 @@
       svn_node_kind_t kind;
       int repos_url_len;
 
+      /* Copy requires recursive write to the destination path and
+         parent path. */
+      SVN_ERR (check_authz (eb, full_path, eb->txn_root,
+                           svn_authz_write, subpool));
+      SVN_ERR (check_authz (eb, pb->path, eb->txn_root,
+                            svn_authz_write, subpool));
+
       /* Check PATH in our transaction.  Make sure it does not exist
          unless its parent directory was copied (in which case, the
          thing might have been copied in as well), else return an
@@ -411,6 +496,11 @@
          repository to make the copy from. */      
       SVN_ERR (svn_fs_revision_root (&copy_root, eb->fs,
                                      copy_revision, subpool));
+
+      /* Copy also requires read access to the source */
+      SVN_ERR(check_authz (eb, fs_path, copy_root,
+                           svn_authz_read, subpool));
+
       SVN_ERR (svn_fs_copy (copy_root, fs_path, 
                             eb->txn_root, full_path, subpool));
     }
@@ -419,7 +509,12 @@
       /* No ancestry given, just make a new, empty file.  Note that we
          don't perform an existence check here like the copy-from case
          does -- that's because svn_fs_make_file() already errors out
-         if the file already exists.  */
+         if the file already exists.  Verify write access to the full
+         path and to the parent. */
+      SVN_ERR (check_authz (eb, full_path, eb->txn_root, svn_authz_write,
+                            subpool));
+      SVN_ERR (check_authz (eb, pb->path, eb->txn_root, svn_authz_write,
+                            subpool));
       SVN_ERR (svn_fs_make_file (eb->txn_root, full_path, subpool));
     }
 
@@ -452,6 +547,10 @@
   apr_pool_t *subpool = svn_pool_create (pool);
   const char *full_path = svn_path_join (eb->base_path, path, pool);
 
+  /* Check for read authorization. */
+  SVN_ERR (check_authz (eb, full_path, eb->txn_root,
+                        svn_authz_read, subpool));
+
   /* Get this node's creation revision (doubles as an existence check). */
   SVN_ERR (svn_fs_node_created_rev (&cr_rev, eb->txn_root, full_path, 
                                     subpool));
@@ -484,6 +583,11 @@
 {
   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));
+
   return svn_repos_fs_change_node_prop (eb->txn_root, fb->path, 
                                         name, value, pool);
 }
@@ -530,6 +634,10 @@
   struct dir_baton *db = 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))
     {
       /* Subversion rule:  propchanges can only happen on a directory
@@ -615,10 +723,10 @@
                                     eb->pool);
 
     if (! err2)
-      err2 = (*eb->callback) (new_revision, 
+      err2 = (*eb->commit_callback) (new_revision, 
                               date ? date->data : NULL, 
                               author ? author->data : NULL,
-                              eb->callback_baton);
+                              eb->commit_callback_baton);
     if (err2)
       {
         svn_error_clear (err);
@@ -647,7 +755,7 @@
 /*** Public interfaces. ***/
 
 svn_error_t *
-svn_repos_get_commit_editor2 (const svn_delta_editor_t **editor,
+svn_repos_get_commit_editor3 (const svn_delta_editor_t **editor,
                               void **edit_baton,
                               svn_repos_t *repos,
                               svn_fs_txn_t *txn,
@@ -655,8 +763,10 @@
                               const char *base_path,
                               const char *user,
                               const char *log_msg,
-                              svn_commit_callback_t callback,
-                              void *callback_baton,
+                              svn_commit_callback_t commit_callback,
+                              void *commit_callback_baton,
+                              svn_repos_authz_callback_t authz_callback,
+                              void *authz_baton,
                               apr_pool_t *pool)
 {
   svn_delta_editor_t *e = svn_delta_default_editor (pool);
@@ -681,11 +791,15 @@
   eb->pool = subpool;
   eb->user = user ? apr_pstrdup (subpool, user) : NULL;
   eb->log_msg = apr_pstrdup (subpool, log_msg);
-  eb->callback = callback;
-  eb->callback_baton = callback_baton;
+  eb->commit_callback = commit_callback;
+  eb->commit_callback_baton = commit_callback_baton;
+  eb->authz_callback = authz_callback;
+  eb->authz_baton = authz_baton;
   eb->base_path = apr_pstrdup (subpool, base_path);
   eb->repos = repos;
   eb->repos_url = repos_url;
+  eb->repos_name = svn_path_basename (svn_repos_path (repos, subpool),
+                                      subpool);
   eb->fs = svn_repos_fs (repos);
   eb->txn = txn;
   eb->txn_owner = txn ? FALSE : TRUE;
@@ -698,6 +812,26 @@
 
 
 svn_error_t *
+svn_repos_get_commit_editor2 (const svn_delta_editor_t **editor,
+                              void **edit_baton,
+                              svn_repos_t *repos,
+                              svn_fs_txn_t *txn,
+                              const char *repos_url,
+                              const char *base_path,
+                              const char *user,
+                              const char *log_msg,
+                              svn_commit_callback_t callback,
+                              void *callback_baton,
+                              apr_pool_t *pool)
+{
+  return svn_repos_get_commit_editor3 (editor, edit_baton, repos, txn,
+                                       repos_url, base_path, user,
+                                       log_msg, callback, callback_baton,
+                                       NULL, NULL, pool);
+}
+
+
+svn_error_t *
 svn_repos_get_commit_editor (const svn_delta_editor_t **editor,
                              void **edit_baton,
                              svn_repos_t *repos,
@@ -709,7 +843,8 @@
                              void *callback_baton,
                              apr_pool_t *pool)
 {
-  return svn_repos_get_commit_editor2 (editor, edit_baton, repos, NULL,
-                                       repos_url, base_path, user, log_msg, 
-                                       callback, callback_baton, pool);
+  return svn_repos_get_commit_editor3 (editor, edit_baton, repos, NULL,
+                                       repos_url, base_path, user,
+                                       log_msg,  callback, callback_baton,
+                                       NULL, NULL, pool);
 }
=== subversion/svnserve/serve.c
==================================================================
--- subversion/svnserve/serve.c  (revision 234)
+++ subversion/svnserve/serve.c  (revision 240)
@@ -752,11 +752,11 @@
   ccb.date = &date;
   ccb.author = &author;
   /* ### Note that svn_repos_get_commit_editor actually wants a decoded URL. */
-  SVN_CMD_ERR(svn_repos_get_commit_editor2
+  SVN_CMD_ERR(svn_repos_get_commit_editor3
               (&editor, &edit_baton, b->repos, NULL,
                svn_path_uri_decode(b->repos_url, pool),
                b->fs_path, b->user,
-               log_msg, commit_done, &ccb, pool));
+               log_msg, commit_done, &ccb, NULL, NULL, pool));
   SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, ""));
   SVN_ERR(svn_ra_svn_drive_editor(conn, pool, editor, edit_baton, &aborted));
   if (!aborted)


