=== subversion/include/svn_repos.h
==================================================================
--- subversion/include/svn_repos.h	(revision 32695)
+++ subversion/include/svn_repos.h	(local)
@@ -1618,6 +1618,9 @@
  * hook, return the original error wrapped with
  * SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED.  If the caller sees this
  * error, it knows that the lock succeeded anyway.
+ *
+ * The pre-lock hook can also return a different token for the lock to
+ * be used, instead of @a token.
  */
 svn_error_t *
 svn_repos_fs_lock(svn_lock_t **lock,
=== subversion/libsvn_repos/fs-wrap.c
==================================================================
--- subversion/libsvn_repos/fs-wrap.c	(revision 32695)
+++ subversion/libsvn_repos/fs-wrap.c	(local)
@@ -447,7 +447,7 @@
 {
   svn_error_t *err;
   svn_fs_access_t *access_ctx = NULL;
-  const char *username = NULL;
+  const char *username = NULL, *new_token = NULL;
   apr_array_header_t *paths;
 
   /* Setup an array of paths in anticipation of the ra layers handling
@@ -467,9 +467,9 @@
 
   /* Run pre-lock hook.  This could throw error, preventing
      svn_fs_lock() from happening. */
-  SVN_ERR(svn_repos__hooks_pre_lock(repos, path, username, comment,
+  SVN_ERR(svn_repos__hooks_pre_lock(repos, &new_token, path, username, comment,
                                     steal_lock, pool));
-
+  token = (new_token && *new_token) ? new_token : token;
   /* Lock. */
   SVN_ERR(svn_fs_lock(lock, repos->fs, path, token, comment, is_dav_comment,
                       expiration_date, current_rev, steal_lock, pool));
=== subversion/libsvn_repos/hooks.c
==================================================================
--- subversion/libsvn_repos/hooks.c	(revision 32695)
+++ subversion/libsvn_repos/hooks.c	(local)
@@ -157,15 +157,21 @@
    the returned error.
 
    If STDIN_HANDLE is non-null, pass it as the hook's stdin, else pass
-   no stdin to the hook. */
+   no stdin to the hook.
+
+   If RESULT is non-null, set *RESULT to the stdout of the hook or to
+   the empty string if the hook generates no output on stdout.
+*/
 static svn_error_t *
-run_hook_cmd(const char *name,
+run_hook_cmd(const svn_string_t **result,
+             const char *name,
              const char *cmd,
              const char **args,
              apr_file_t *stdin_handle,
              apr_pool_t *pool)
 {
   apr_file_t *read_errhandle, *write_errhandle, *null_handle;
+  apr_file_t *read_outhandle, *write_outhandle;  
   apr_status_t apr_err;
   svn_error_t *err;
   apr_proc_t cmd_proc;
@@ -195,16 +201,39 @@
       (apr_err, _("Can't make pipe write handle non-inherited for hook '%s'"),
        cmd);
 
+  if (result)
+    {
+      /* Create a pipe to access stdout of the child. */
+      apr_err = apr_file_pipe_create(&read_outhandle, &write_outhandle, pool);
+      if (apr_err)
+        return svn_error_wrap_apr
+          (apr_err, _("Can't create pipe for hook '%s'"), cmd);
 
-  /* Redirect stdout to the null device */
-  apr_err = apr_file_open(&null_handle, SVN_NULL_DEVICE_NAME, APR_WRITE,
-                          APR_OS_DEFAULT, pool);
-  if (apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
+      apr_err = apr_file_inherit_unset(read_outhandle);
+      if (apr_err)
+        return svn_error_wrap_apr
+          (apr_err,
+           _("Can't make pipe read handle non-inherited for hook '%s'"), cmd);
 
+      apr_err = apr_file_inherit_unset(write_outhandle);
+      if (apr_err)
+        return svn_error_wrap_apr
+          (apr_err,
+           _("Can't make pipe write handle non-inherited for hook '%s'"), cmd);
+    }
+  else
+    {
+      /* Redirect stdout to the null device */
+        apr_err = apr_file_open(&null_handle, SVN_NULL_DEVICE_NAME, APR_WRITE,
+                                APR_OS_DEFAULT, pool);
+        if (apr_err)
+          return svn_error_wrap_apr
+            (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
+    }
+
   err = svn_io_start_cmd(&cmd_proc, ".", cmd, args, FALSE,
-                         stdin_handle, null_handle, write_errhandle, pool);
+                         stdin_handle, result ? write_outhandle : null_handle,
+                         write_errhandle, pool);
 
   /* This seems to be done automatically if we pass the third parameter of
      apr_procattr_child_in/out_set(), but svn_io_run_cmd()'s interface does
@@ -215,6 +244,14 @@
     return svn_error_wrap_apr
       (apr_err, _("Error closing write end of stderr pipe"));
 
+  if (result)
+    {
+      apr_err = apr_file_close(write_outhandle);
+      if (!err && apr_err)
+        return svn_error_wrap_apr
+          (apr_err, _("Error closing write end of stderr pipe"));
+    }
+
   if (err)
     {
       err = svn_error_createf
@@ -233,10 +270,24 @@
     return svn_error_wrap_apr
       (apr_err, _("Error closing read end of stderr pipe"));
 
-  apr_err = apr_file_close(null_handle);
-  if (!err && apr_err)
-    return svn_error_wrap_apr(apr_err, _("Error closing null file"));
+  if (result)
+    {
+      svn_stringbuf_t *native_stdout;
+      SVN_ERR(svn_stringbuf_from_aprfile(&native_stdout, read_outhandle, pool));
+      apr_err = apr_file_close(read_outhandle);
+      if (!err && apr_err)
+        return svn_error_wrap_apr
+          (apr_err, _("Error closing read end of stderr pipe"));
 
+      *result = svn_string_create_from_buf(native_stdout, pool);
+    }
+  else
+    {
+      apr_err = apr_file_close(null_handle);
+      if (!err && apr_err)
+        return svn_error_wrap_apr(apr_err, _("Error closing null file"));
+    }
+
   return err;
 }
 
@@ -361,7 +412,7 @@
       args[3] = capabilities_string;
       args[4] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_START_COMMIT, hook, args, NULL,
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_START_COMMIT, hook, args, NULL,
                            pool));
     }
 
@@ -443,7 +494,7 @@
         SVN_ERR(svn_io_file_open(&stdin_handle, SVN_NULL_DEVICE_NAME,
                                  APR_READ, APR_OS_DEFAULT, pool));
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_PRE_COMMIT, hook, args,
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_COMMIT, hook, args,
                            stdin_handle, pool));
     }
 
@@ -472,7 +523,7 @@
       args[2] = apr_psprintf(pool, "%ld", rev);
       args[3] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_POST_COMMIT, hook, args, NULL,
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_COMMIT, hook, args, NULL,
                            pool));
     }
 
@@ -520,7 +571,7 @@
       args[5] = action_string;
       args[6] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_PRE_REVPROP_CHANGE, hook, args,
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_REVPROP_CHANGE, hook, args,
                            stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
@@ -582,8 +633,8 @@
       args[5] = action_string;
       args[6] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_POST_REVPROP_CHANGE, hook, args,
-                           stdin_handle, pool));
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_REVPROP_CHANGE, hook,
+                           args, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -595,6 +646,7 @@
 
 svn_error_t  *
 svn_repos__hooks_pre_lock(svn_repos_t *repos,
+                          const char **token,
                           const char *path,
                           const char *username,
                           const char *comment,
@@ -620,7 +672,8 @@
       args[5] = steal_lock ? "1" : "0";
       args[6] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_PRE_LOCK, hook, args, NULL, pool));
+      SVN_ERR(run_hook_cmd(token, SVN_REPOS__HOOK_PRE_LOCK, hook, args, NULL,
+                           pool));
     }
 
   return SVN_NO_ERROR;
@@ -656,8 +709,8 @@
       args[3] = NULL;
       args[4] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_POST_LOCK, hook, args, stdin_handle,
-                           pool));
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_LOCK, hook, args,
+                           stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -693,7 +746,7 @@
       args[5] = break_lock ? "1" : "0";
       args[6] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_PRE_UNLOCK, hook, args, NULL,
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_UNLOCK, hook, args, NULL,
                            pool));
     }
 
@@ -730,7 +783,7 @@
       args[3] = NULL;
       args[4] = NULL;
 
-      SVN_ERR(run_hook_cmd(SVN_REPOS__HOOK_POST_UNLOCK, hook, args,
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_UNLOCK, hook, args,
                            stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
=== subversion/libsvn_repos/repos.c
==================================================================
--- subversion/libsvn_repos/repos.c	(revision 32695)
+++ subversion/libsvn_repos/repos.c	(local)
@@ -549,6 +549,11 @@
 "#   [4] COMMENT      (the comment of the lock)"                             NL
 "#   [5] STEAL-LOCK   (1 if the user is trying to steal the lock, else 0)"   NL
 "#"                                                                          NL
+"# If the hook program outputs anything in stdout, the output string will"   NL
+"# be used as the lock token for this lock operation.  If you choose to use" NL
+"# this feature, you must guarantee the tokens generated are unique across"  NL
+"# the repository each time"                                                 NL
+"#"                                                                          NL
 "# The default working directory for the invocation is undefined, so"        NL
 "# the program should set one explicitly if it cares."                       NL
 "#"                                                                          NL
=== subversion/libsvn_repos/repos.h
==================================================================
--- subversion/libsvn_repos/repos.h	(revision 32695)
+++ subversion/libsvn_repos/repos.h	(local)
@@ -223,10 +223,16 @@
    PATH is the path being locked, USERNAME is the person doing it,
    COMMENT is the comment of the lock, and is treated as an empty
    string when NULL is given.  STEAL-LOCK is a flag if the user is
-   stealing the lock.  */
+   stealing the lock.
 
+   If TOKEN is non-null, set *TOKEN to a new lock token generated by
+   the pre-lock hook if any (see the pre-lock hook template for more
+   information).  If TOKEN is non-null but the hook does not return
+   any token, then set *TOKEN to empty string. */
+
 svn_error_t *
 svn_repos__hooks_pre_lock(svn_repos_t *repos,
+                          const char **token,
                           const char *path,
                           const char *username,
                           const char *comment,
