You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ar...@apache.org on 2012/07/30 08:39:38 UTC

svn commit: r1367002 [11/21] - in /subversion/branches/svn-bisect: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/ notes/api-errata/1.7/ notes/http-and-webdav/...

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/dump.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/dump.c Mon Jul 30 06:39:28 2012
@@ -105,6 +105,9 @@ struct edit_baton
   svn_fs_root_t *fs_root;
   svn_revnum_t current_rev;
 
+  /* The fs, so we can grab historic information if needed. */
+  svn_fs_t *fs;
+
   /* True if dumped nodes should output deltas instead of full text. */
   svn_boolean_t use_deltas;
 
@@ -114,13 +117,13 @@ struct edit_baton
   /* The first revision dumped in this dumpstream. */
   svn_revnum_t oldest_dumped_rev;
 
-  /* Set to true if any references to revisions older than
+  /* If not NULL, set to true if any references to revisions older than
      OLDEST_DUMPED_REV were found in the dumpstream. */
-  svn_boolean_t found_old_reference;
+  svn_boolean_t *found_old_reference;
 
-  /* Set to true if any mergeinfo was dumped which contains revisions
-     older than OLDEST_DUMPED_REV. */
-  svn_boolean_t found_old_mergeinfo;
+  /* If not NULL, set to true if any mergeinfo was dumped which contains
+     revisions older than OLDEST_DUMPED_REV. */
+  svn_boolean_t *found_old_mergeinfo;
 
   /* reusable buffer for writing file contents */
   char buffer[SVN__STREAM_CHUNK_SIZE];
@@ -389,7 +392,8 @@ dump_node(struct edit_baton *eb,
                        " into an empty repository"
                        " will fail."),
                      cmp_rev, eb->oldest_dumped_rev);
-              eb->found_old_reference = TRUE;
+              if (eb->found_old_reference)
+                *eb->found_old_reference = TRUE;
               eb->notify_func(eb->notify_baton, notify, pool);
             }
 
@@ -494,7 +498,8 @@ dump_node(struct edit_baton *eb,
                       "mergeinfo."),
                     eb->oldest_dumped_rev);
 
-                  eb->found_old_mergeinfo = TRUE;
+                  if (eb->found_old_mergeinfo)
+                    *eb->found_old_mergeinfo = TRUE;
                   eb->notify_func(eb->notify_baton, notify, pool);
                 }
             }
@@ -849,6 +854,96 @@ change_dir_prop(void *parent_baton,
   return SVN_NO_ERROR;
 }
 
+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_error_t *err;
+  svn_fs_root_t *fs_root;
+
+  if (!SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = eb->current_rev - 1;
+
+  SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs, base_revision, 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_kind_t *kind,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  svn_node_kind_t node_kind;
+  svn_fs_root_t *fs_root;
+
+  if (!SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = eb->current_rev - 1;
+
+  SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs, base_revision, scratch_pool));
+
+  SVN_ERR(svn_fs_check_path(&node_kind, fs_root, path, scratch_pool));
+  *kind = svn__kind_from_node_kind(node_kind, FALSE);
+
+  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_error_t *err;
+  svn_fs_root_t *fs_root;
+
+  if (!SVN_IS_VALID_REVNUM(base_revision))
+    base_revision = eb->current_rev - 1;
+
+  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;
+}
 
 
 static svn_error_t *
@@ -858,6 +953,10 @@ get_dump_editor(const svn_delta_editor_t
                 svn_revnum_t to_rev,
                 const char *root_path,
                 svn_stream_t *stream,
+                svn_boolean_t *found_old_reference,
+                svn_boolean_t *found_old_mergeinfo,
+                svn_error_t *(*custom_close_directory)(void *dir_baton,
+                                  apr_pool_t *scratch_pool),
                 svn_repos_notify_func_t notify_func,
                 void *notify_baton,
                 svn_revnum_t oldest_dumped_rev,
@@ -881,16 +980,22 @@ get_dump_editor(const svn_delta_editor_t
   eb->bufsize = sizeof(eb->buffer);
   eb->path = apr_pstrdup(pool, root_path);
   SVN_ERR(svn_fs_revision_root(&(eb->fs_root), fs, to_rev, pool));
+  eb->fs = fs;
   eb->current_rev = to_rev;
   eb->use_deltas = use_deltas;
   eb->verify = verify;
+  eb->found_old_reference = found_old_reference;
+  eb->found_old_mergeinfo = found_old_mergeinfo;
 
   /* Set up the editor. */
   dump_editor->open_root = open_root;
   dump_editor->delete_entry = delete_entry;
   dump_editor->add_directory = add_directory;
   dump_editor->open_directory = open_directory;
-  dump_editor->close_directory = close_directory;
+  if (custom_close_directory)
+    dump_editor->close_directory = custom_close_directory;
+  else
+    dump_editor->close_directory = close_directory;
   dump_editor->change_dir_prop = change_dir_prop;
   dump_editor->add_file = add_file;
   dump_editor->open_file = open_file;
@@ -898,6 +1003,11 @@ get_dump_editor(const svn_delta_editor_t
   *edit_baton = eb;
   *editor = dump_editor;
 
+  shim_callbacks->fetch_kind_func = fetch_kind_func;
+  shim_callbacks->fetch_props_func = fetch_props_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,
                                    shim_callbacks, pool, pool));
 
@@ -1098,7 +1208,9 @@ svn_repos_dump_fs3(svn_repos_t *repos,
          non-incremental dump. */
       use_deltas_for_rev = use_deltas && (incremental || i != start_rev);
       SVN_ERR(get_dump_editor(&dump_editor, &dump_edit_baton, fs, to_rev,
-                              "", stream, notify_func, notify_baton,
+                              "", stream, &found_old_reference,
+                              &found_old_mergeinfo, NULL,
+                              notify_func, notify_baton,
                               start_rev, use_deltas_for_rev, FALSE, subpool));
 
       /* Drive the editor in one way or another. */
@@ -1127,6 +1239,10 @@ svn_repos_dump_fs3(svn_repos_t *repos,
           SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                     dump_editor, dump_edit_baton,
                                     NULL, NULL, subpool));
+
+          /* While our editor close_edit implementation is a no-op, we still
+             do this for completeness. */
+          SVN_ERR(dump_editor->close_edit(dump_edit_baton, subpool));
         }
 
     loop_end:
@@ -1135,14 +1251,6 @@ svn_repos_dump_fs3(svn_repos_t *repos,
           notify->revision = to_rev;
           notify_func(notify_baton, notify, subpool);
         }
-
-      if (dump_edit_baton) /* We never get an edit baton for r0. */
-        {
-          if (((struct edit_baton *)dump_edit_baton)->found_old_reference)
-            found_old_reference = TRUE;
-          if (((struct edit_baton *)dump_edit_baton)->found_old_mergeinfo)
-            found_old_mergeinfo = TRUE;
-        }
     }
 
   if (notify_func)
@@ -1287,10 +1395,9 @@ svn_repos_verify_fs2(svn_repos_t *repos,
                                "(youngest revision is %ld)"),
                              end_rev, youngest);
 
-  /* Verify global/auxiliary data before verifying revisions. */
-  if (start_rev == 0)
-    SVN_ERR(svn_fs_verify(svn_fs_path(fs, pool), cancel_func, cancel_baton,
-                          pool));
+  /* Verify global/auxiliary data and backend-specific data first. */
+  SVN_ERR(svn_fs_verify(svn_fs_path(fs, pool), cancel_func, cancel_baton,
+                        start_rev, end_rev, pool));
 
   /* Create a notify object that we can reuse within the loop. */
   if (notify_func)
@@ -1311,12 +1418,13 @@ svn_repos_verify_fs2(svn_repos_t *repos,
       /* Get cancellable dump editor, but with our close_directory handler. */
       SVN_ERR(get_dump_editor((const svn_delta_editor_t **)&dump_editor,
                               &dump_edit_baton, fs, rev, "",
-                              svn_stream_empty(pool),
+                              svn_stream_empty(iterpool),
+                              NULL, NULL,
+                              verify_close_directory,
                               notify_func, notify_baton,
                               start_rev,
                               FALSE, TRUE, /* use_deltas, verify */
                               iterpool));
-      dump_editor->close_directory = verify_close_directory;
       SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
                                                 dump_editor, dump_edit_baton,
                                                 &cancel_editor,
@@ -1327,6 +1435,10 @@ svn_repos_verify_fs2(svn_repos_t *repos,
       SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                 cancel_editor, cancel_edit_baton,
                                 NULL, NULL, iterpool));
+      /* While our editor close_edit implementation is a no-op, we still
+         do this for completeness. */
+      SVN_ERR(cancel_editor->close_edit(cancel_edit_baton, iterpool));
+
       SVN_ERR(svn_fs_revision_proplist(&props, fs, rev, iterpool));
 
       if (notify_func)

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/fs-wrap.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/fs-wrap.c Mon Jul 30 06:39:28 2012
@@ -61,7 +61,7 @@ svn_repos_fs_commit_txn(const char **con
     return err;
 
   /* Run post-commit hooks. */
-  if ((err2 = svn_repos__hooks_post_commit(repos, *new_rev, pool)))
+  if ((err2 = svn_repos__hooks_post_commit(repos, *new_rev, txn_name, pool)))
     {
       err2 = svn_error_create
                (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err2,

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/hooks.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/hooks.c Mon Jul 30 06:39:28 2012
@@ -159,6 +159,37 @@ check_hook_result(const char *name, cons
                           failure_message->data);
 }
 
+/* Copy the environment given as key/value pairs of ENV_HASH into
+ * an array of C strings allocated in RESULT_POOL.
+ * If the hook environment is empty, return NULL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static const char **
+env_from_env_hash(apr_hash_t *env_hash,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+  const char **env;
+  const char **envp;
+  
+  if (!env_hash || apr_hash_count(env_hash) == 0)
+    return NULL;
+
+  env = apr_palloc(result_pool,
+                   sizeof(const char *) * (apr_hash_count(env_hash) + 1));
+  envp = env;
+  for (hi = apr_hash_first(scratch_pool, env_hash); hi; hi = apr_hash_next(hi))
+    {
+      *envp = apr_psprintf(result_pool, "%s=%s",
+                           (const char *)svn__apr_hash_index_key(hi),
+                           (const char *)svn__apr_hash_index_val(hi));
+      envp++;
+    }
+  *envp = NULL;
+
+  return env;
+}
+
 /* NAME, CMD and ARGS are the name, path to and arguments for the hook
    program that is to be run.  The hook's exit status will be checked,
    and if an error occurred the hook's stderr output will be added to
@@ -174,6 +205,7 @@ run_hook_cmd(svn_string_t **result,
              const char *name,
              const char *cmd,
              const char **args,
+             apr_hash_t *hooks_env,
              apr_file_t *stdin_handle,
              apr_pool_t *pool)
 {
@@ -196,9 +228,10 @@ run_hook_cmd(svn_string_t **result,
             (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
     }
 
-  err = svn_io_start_cmd2(&cmd_proc, ".", cmd, args, FALSE,
-                          FALSE, stdin_handle, result != NULL, null_handle,
-                          TRUE, NULL, pool);
+  err = svn_io_start_cmd3(&cmd_proc, ".", cmd, args,
+                          env_from_env_hash(hooks_env, pool, pool),
+                          FALSE, FALSE, stdin_handle, result != NULL,
+                          null_handle, TRUE, NULL, pool);
 
   if (err)
     {
@@ -358,8 +391,8 @@ svn_repos__hooks_start_commit(svn_repos_
       args[3] = capabilities_string;
       args[4] = NULL;
 
-      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_START_COMMIT, hook, args, NULL,
-                           pool));
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_START_COMMIT, hook, args,
+                           repos->hooks_env, NULL, pool));
     }
 
   return SVN_NO_ERROR;
@@ -438,7 +471,7 @@ svn_repos__hooks_pre_commit(svn_repos_t 
                                  APR_READ, APR_OS_DEFAULT, pool));
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_COMMIT, hook, args,
-                           stdin_handle, pool));
+                           repos->hooks_env, stdin_handle, pool));
     }
 
   return SVN_NO_ERROR;
@@ -448,6 +481,7 @@ svn_repos__hooks_pre_commit(svn_repos_t 
 svn_error_t  *
 svn_repos__hooks_post_commit(svn_repos_t *repos,
                              svn_revnum_t rev,
+                             const char *txn_name,
                              apr_pool_t *pool)
 {
   const char *hook = svn_repos_post_commit_hook(repos, pool);
@@ -459,15 +493,16 @@ svn_repos__hooks_post_commit(svn_repos_t
     }
   else if (hook)
     {
-      const char *args[4];
+      const char *args[5];
 
       args[0] = hook;
       args[1] = svn_dirent_local_style(svn_repos_path(repos, pool), pool);
       args[2] = apr_psprintf(pool, "%ld", rev);
-      args[3] = NULL;
+      args[3] = txn_name;
+      args[4] = NULL;
 
-      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_COMMIT, hook, args, NULL,
-                           pool));
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_COMMIT, hook, args,
+                           repos->hooks_env, NULL, pool));
     }
 
   return SVN_NO_ERROR;
@@ -514,8 +549,8 @@ svn_repos__hooks_pre_revprop_change(svn_
       args[5] = action_string;
       args[6] = NULL;
 
-      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_REVPROP_CHANGE, hook, args,
-                           stdin_handle, pool));
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_REVPROP_CHANGE, hook,
+                           args, repos->hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -577,7 +612,7 @@ svn_repos__hooks_post_revprop_change(svn
       args[6] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_REVPROP_CHANGE, hook,
-                           args, stdin_handle, pool));
+                           args, repos->hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -615,8 +650,8 @@ svn_repos__hooks_pre_lock(svn_repos_t *r
       args[5] = steal_lock ? "1" : "0";
       args[6] = NULL;
 
-      SVN_ERR(run_hook_cmd(&buf, SVN_REPOS__HOOK_PRE_LOCK, hook, args, NULL,
-                           pool));
+      SVN_ERR(run_hook_cmd(&buf, SVN_REPOS__HOOK_PRE_LOCK, hook, args,
+                           repos->hooks_env, NULL, pool));
 
       if (token)
         /* No validation here; the FS will take care of that. */
@@ -660,7 +695,7 @@ svn_repos__hooks_post_lock(svn_repos_t *
       args[4] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_LOCK, hook, args,
-                           stdin_handle, pool));
+                           repos->hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }
@@ -696,8 +731,8 @@ svn_repos__hooks_pre_unlock(svn_repos_t 
       args[5] = break_lock ? "1" : "0";
       args[6] = NULL;
 
-      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_UNLOCK, hook, args, NULL,
-                           pool));
+      SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_PRE_UNLOCK, hook, args,
+                           repos->hooks_env, NULL, pool));
     }
 
   return SVN_NO_ERROR;
@@ -734,7 +769,7 @@ svn_repos__hooks_post_unlock(svn_repos_t
       args[4] = NULL;
 
       SVN_ERR(run_hook_cmd(NULL, SVN_REPOS__HOOK_POST_UNLOCK, hook, args,
-                           stdin_handle, pool));
+                           repos->hooks_env, stdin_handle, pool));
 
       SVN_ERR(svn_io_file_close(stdin_handle, pool));
     }

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/load-fs-vtable.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/load-fs-vtable.c Mon Jul 30 06:39:28 2012
@@ -160,12 +160,12 @@ change_rev_prop(svn_repos_t *repos,
                 apr_pool_t *pool)
 {
   if (validate_props)
-    return svn_fs_change_rev_prop2(svn_repos_fs(repos), revision, name,
-                                   NULL, value, pool);
-  else
     return svn_repos_fs_change_rev_prop4(repos, revision, NULL, name,
                                          NULL, value, FALSE, FALSE,
                                          NULL, NULL, pool);
+  else
+    return svn_fs_change_rev_prop2(svn_repos_fs(repos), revision, name,
+                                   NULL, value, pool);
 }
 
 /* Change property NAME to VALUE for PATH in TXN_ROOT.  If
@@ -487,7 +487,7 @@ new_revision_record(void **revision_bato
      several separate operations. It is highly susceptible to race conditions.
      Calculate the revision 'offset' for finding copyfrom sources.
      It might be positive or negative. */
-  rb->rev_offset = (apr_int32_t) (rb->rev) - (head_rev + 1);
+  rb->rev_offset = (apr_int32_t) ((rb->rev) - (head_rev + 1));
 
   if ((rb->rev > 0) && (! rb->skipped))
     {
@@ -787,6 +787,10 @@ delete_node_property(void *baton,
   struct node_baton *nb = baton;
   struct revision_baton *rb = nb->rb;
 
+  /* If we're skipping this revision, we're done here. */
+  if (rb->skipped)
+    return SVN_NO_ERROR;
+
   return change_node_prop(rb->txn_root, nb->path, name, NULL,
                           rb->pb->validate_props, nb->pool);
 }
@@ -830,7 +834,10 @@ apply_textdelta(svn_txdelta_window_handl
 
   /* If we're skipping this revision, we're done here. */
   if (rb->skipped)
-    return SVN_NO_ERROR;
+    {
+      *handler = NULL;
+      return SVN_NO_ERROR;
+    }
 
   return svn_fs_apply_textdelta(handler, handler_baton,
                                 rb->txn_root, nb->path,
@@ -851,7 +858,10 @@ set_fulltext(svn_stream_t **stream,
 
   /* If we're skipping this revision, we're done here. */
   if (rb->skipped)
-    return SVN_NO_ERROR;
+    {
+      *stream = NULL;
+      return SVN_NO_ERROR;
+    }
 
   return svn_fs_apply_text(stream,
                            rb->txn_root, nb->path,
@@ -890,19 +900,28 @@ close_revision(void *baton)
   const char *conflict_msg = NULL;
   svn_revnum_t committed_rev;
   svn_error_t *err;
+  const char *txn_name;
 
   /* If we're skipping this revision or it has an invalid revision
      number, we're done here. */
   if (rb->skipped || (rb->rev <= 0))
     return SVN_NO_ERROR;
 
+  /* Get the txn name, if it will be needed. */
+  if (pb->use_pre_commit_hook || pb->use_post_commit_hook)
+    {
+      err = svn_fs_txn_name(&txn_name, rb->txn, rb->pool);
+      if (err)
+        {
+          svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
+          return svn_error_trace(err);
+        }
+    }
+
   /* Run the pre-commit hook, if so commanded. */
   if (pb->use_pre_commit_hook)
     {
-      const char *txn_name;
-      err = svn_fs_txn_name(&txn_name, rb->txn, rb->pool);
-      if (! err)
-        err = svn_repos__hooks_pre_commit(pb->repos, txn_name, rb->pool);
+      err = svn_repos__hooks_pre_commit(pb->repos, txn_name, rb->pool);
       if (err)
         {
           svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
@@ -935,7 +954,7 @@ close_revision(void *baton)
   if (pb->use_post_commit_hook)
     {
       if ((err = svn_repos__hooks_post_commit(pb->repos, committed_rev,
-                                              rb->pool)))
+                                              txn_name, rb->pool)))
         return svn_error_create
           (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
            _("Commit succeeded, but post-commit hook failed"));

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/log.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/log.c Mon Jul 30 06:39:28 2012
@@ -264,6 +264,43 @@ detect_changed(apr_hash_t **changed,
                                              : svn_tristate_false;
       item->props_modified = change->prop_mod ? svn_tristate_true
                                               : svn_tristate_false;
+
+      /* Pre-1.6 revision files don't store the change path kind, so fetch
+         it manually. */
+      if (item->node_kind == svn_node_unknown)
+        {
+          svn_fs_root_t *check_root = root;
+          const char *check_path = path;
+
+          /* Deleted items don't exist so check earlier revision.  We
+             know the parent must exist and could be a copy */
+          if (change->change_kind == svn_fs_path_change_delete)
+            {
+              svn_fs_history_t *history;
+              svn_revnum_t prev_rev;
+              const char *parent_path, *name;
+
+              svn_fspath__split(&parent_path, &name, path, subpool);
+
+              SVN_ERR(svn_fs_node_history(&history, root, parent_path,
+                                          subpool));
+
+              /* Two calls because the first call returns the original
+                 revision as the deleted child means it is 'interesting' */
+              SVN_ERR(svn_fs_history_prev(&history, history, TRUE, subpool));
+              SVN_ERR(svn_fs_history_prev(&history, history, TRUE, subpool));
+
+              SVN_ERR(svn_fs_history_location(&parent_path, &prev_rev, history,
+                                              subpool));
+              SVN_ERR(svn_fs_revision_root(&check_root, fs, prev_rev, subpool));
+              check_path = svn_fspath__join(parent_path, name, subpool);
+            }
+
+          SVN_ERR(svn_fs_check_path(&item->node_kind, check_root, check_path,
+                                    subpool));
+        }
+
+
       if ((action == 'A') || (action == 'R'))
         {
           const char *copyfrom_path;
@@ -1115,7 +1152,6 @@ send_log(svn_revnum_t rev,
       && log_target_history_as_mergeinfo
       && apr_hash_count(log_target_history_as_mergeinfo))
     {
-      svn_boolean_t path_is_in_history = FALSE;
       apr_hash_index_t *hi;
       apr_pool_t *subpool = svn_pool_create(pool);
 
@@ -1128,10 +1164,12 @@ send_log(svn_revnum_t rev,
            hi;
            hi = apr_hash_next(hi))
         {
+          svn_boolean_t path_is_in_history = FALSE;
           const char *changed_path = svn__apr_hash_index_key(hi);
           apr_hash_index_t *hi2;
           apr_pool_t *inner_subpool = svn_pool_create(subpool);
 
+          /* Look at each path on the log target's mergeinfo. */
           for (hi2 = apr_hash_first(inner_subpool,
                                     log_target_history_as_mergeinfo);
                hi2;
@@ -1142,6 +1180,8 @@ send_log(svn_revnum_t rev,
               apr_array_header_t *rangelist =
                 svn__apr_hash_index_val(hi2);
 
+              /* Check whether CHANGED_PATH at revision REV is a child of 
+                 a (path, revision) tuple in LOG_TARGET_HISTORY_AS_MERGEINFO. */
               if (svn_fspath__skip_ancestor(mergeinfo_path, changed_path))
                 {
                   int i;
@@ -2228,17 +2268,40 @@ svn_repos_get_logs4(svn_repos_t *repos,
       int i;
       apr_pool_t *iterpool = svn_pool_create(pool);
 
+      /* If we are provided an authz callback function, use it to
+         verify that the user has read access to the root path in the
+         first of our revisions.
+
+         ### FIXME:  Strictly speaking, we should be checking this
+         ### access in every revision along the line.  But currently,
+         ### there are no known authz implementations which concern
+         ### themselves with per-revision access.  */
+      if (authz_read_func)
+        {
+          svn_boolean_t readable;
+          svn_fs_root_t *rev_root;
+
+          SVN_ERR(svn_fs_revision_root(&rev_root, fs, 
+                                       descending_order ? end : start, pool));
+          SVN_ERR(authz_read_func(&readable, rev_root, "",
+                                  authz_read_baton, pool));
+          if (! readable)
+            return svn_error_create(SVN_ERR_AUTHZ_UNREADABLE, NULL, NULL);
+        }
+
       send_count = end - start + 1;
       if (limit && send_count > limit)
         send_count = limit;
       for (i = 0; i < send_count; ++i)
         {
-          svn_revnum_t rev = start + i;
+          svn_revnum_t rev;
 
           svn_pool_clear(iterpool);
 
           if (descending_order)
             rev = end - i;
+          else
+            rev = start + i;
           SVN_ERR(send_log(rev, fs, NULL, NULL, discover_changed_paths, FALSE,
                            FALSE, revprops, FALSE, receiver,
                            receiver_baton, authz_read_func,

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/replay.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/replay.c Mon Jul 30 06:39:28 2012
@@ -352,6 +352,116 @@ is_within_base_path(const char *path, co
   return FALSE;
 }
 
+/* Given PATH deleted under ROOT, return in READABLE whether the path was
+   readable prior to the deletion.  Consult COPIES (a stack of 'struct
+   copy_info') and AUTHZ_READ_FUNC. */
+static svn_error_t *
+was_readable(svn_boolean_t *readable,
+             svn_fs_root_t *root,
+             const char *path,
+             apr_array_header_t *copies,
+             svn_repos_authz_func_t authz_read_func,
+             void *authz_read_baton,
+             apr_pool_t *result_pool,
+             apr_pool_t *scratch_pool)
+{
+  svn_fs_root_t *inquire_root;
+  const char *inquire_path;
+  struct copy_info *info = NULL;
+  const char *relpath;
+
+  /* Short circuit. */
+  if (! authz_read_func)
+    {
+      *readable = TRUE;
+      return SVN_NO_ERROR;
+    }
+
+  if (copies->nelts != 0)
+    info = APR_ARRAY_IDX(copies, copies->nelts - 1, struct copy_info *);
+
+  /* Are we under a copy? */
+  if (info && (relpath = svn_relpath_skip_ancestor(info->path, path)))
+    {
+      SVN_ERR(svn_fs_revision_root(&inquire_root, svn_fs_root_fs(root),
+                                   info->copyfrom_rev, scratch_pool));
+      inquire_path = svn_fspath__join(info->copyfrom_path, relpath,
+                                      scratch_pool);
+    }
+  else
+    {
+      /* Compute the revision that ROOT is based on.  (Note that ROOT is not
+         r0's root, since this function is only called for deletions.)
+         ### Need a more succinct way to express this */
+      svn_revnum_t inquire_rev = SVN_INVALID_REVNUM;
+      if (svn_fs_is_txn_root(root))
+        inquire_rev = svn_fs_txn_root_base_revision(root);
+      if (svn_fs_is_revision_root(root))
+        inquire_rev =  svn_fs_revision_root_revision(root)-1;
+      SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(inquire_rev));
+
+      SVN_ERR(svn_fs_revision_root(&inquire_root, svn_fs_root_fs(root),
+                                   inquire_rev, scratch_pool));
+      inquire_path = path;
+    }
+
+  SVN_ERR(authz_read_func(readable, inquire_root, inquire_path,
+                          authz_read_baton, result_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Initialize COPYFROM_ROOT, COPYFROM_PATH, and COPYFROM_REV with the
+   revision root, fspath, and revnum of the copyfrom of CHANGE, which
+   corresponds to PATH under ROOT.  If the copyfrom info is valid
+   (i.e., is not (NULL, SVN_INVALID_REVNUM)), then initialize SRC_READABLE
+   too, consulting AUTHZ_READ_FUNC and AUTHZ_READ_BATON if provided. */
+static svn_error_t *
+fill_copyfrom(svn_fs_root_t **copyfrom_root,
+              const char **copyfrom_path,
+              svn_revnum_t *copyfrom_rev,
+              svn_boolean_t *src_readable,
+              svn_fs_root_t *root,
+              svn_fs_path_change2_t *change,
+              svn_repos_authz_func_t authz_read_func,
+              void *authz_read_baton,
+              const char *path,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
+{
+  if (! change->copyfrom_known)
+    {
+      SVN_ERR(svn_fs_copied_from(&(change->copyfrom_rev),
+                                 &(change->copyfrom_path),
+                                 root, path, result_pool));
+      change->copyfrom_known = TRUE;
+    }
+  *copyfrom_rev = change->copyfrom_rev;
+  *copyfrom_path = change->copyfrom_path;
+
+  if (*copyfrom_path && SVN_IS_VALID_REVNUM(*copyfrom_rev))
+    {
+      SVN_ERR(svn_fs_revision_root(copyfrom_root,
+                                   svn_fs_root_fs(root),
+                                   *copyfrom_rev, result_pool));
+
+      if (authz_read_func)
+        {
+          SVN_ERR(authz_read_func(src_readable, *copyfrom_root,
+                                  *copyfrom_path,
+                                  authz_read_baton, result_pool));
+        }
+      else
+        *src_readable = TRUE;
+    }
+  else
+    {
+      *copyfrom_root = NULL;
+      /* SRC_READABLE left uninitialized */
+    }
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 path_driver_cb_func(void **dir_baton,
                     void *parent_baton,
@@ -368,7 +478,6 @@ path_driver_cb_func(void **dir_baton,
   void *file_baton = NULL;
   svn_revnum_t copyfrom_rev;
   const char *copyfrom_path;
-  svn_boolean_t src_readable = TRUE;
   svn_fs_root_t *source_root = cb->compare_root;
   const char *source_fspath = NULL;
   const char *base_path = cb->base_path;
@@ -384,9 +493,9 @@ path_driver_cb_func(void **dir_baton,
   while (cb->copies->nelts > 0
          && ! svn_dirent_is_ancestor(APR_ARRAY_IDX(cb->copies,
                                                    cb->copies->nelts - 1,
-                                                   struct copy_info).path,
+                                                   struct copy_info *)->path,
                                      edit_path))
-    cb->copies->nelts--;
+    apr_array_pop(cb->copies);
 
   change = apr_hash_get(cb->changed_paths, edit_path, APR_HASH_KEY_STRING);
   if (! change)
@@ -419,8 +528,18 @@ path_driver_cb_func(void **dir_baton,
 
   /* Handle any deletions. */
   if (do_delete)
-    SVN_ERR(editor->delete_entry(edit_path, SVN_INVALID_REVNUM,
-                                 parent_baton, pool));
+    {
+      svn_boolean_t readable;
+
+      /* Issue #4121: delete under under a copy, of a path that was unreadable
+         at its pre-copy location. */
+      SVN_ERR(was_readable(&readable, root, edit_path, cb->copies,
+                            cb->authz_read_func, cb->authz_read_baton,
+                            pool, pool));
+      if (readable)
+        SVN_ERR(editor->delete_entry(edit_path, SVN_INVALID_REVNUM,
+                                     parent_baton, pool));
+    }
 
   /* Fetch the node kind if it makes sense to do so. */
   if (! do_delete || do_add)
@@ -437,31 +556,14 @@ path_driver_cb_func(void **dir_baton,
   /* Handle any adds/opens. */
   if (do_add)
     {
-      svn_fs_root_t *copyfrom_root = NULL;
-      /* Was this node copied? */
-      if (! change->copyfrom_known)
-        {
-          SVN_ERR(svn_fs_copied_from(&(change->copyfrom_rev),
-                                     &(change->copyfrom_path),
-                                     root, edit_path, pool));
-          change->copyfrom_known = TRUE;
-        }
-      copyfrom_rev = change->copyfrom_rev;
-      copyfrom_path = change->copyfrom_path;
+      svn_boolean_t src_readable;
+      svn_fs_root_t *copyfrom_root;
 
-      if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev))
-        {
-          SVN_ERR(svn_fs_revision_root(&copyfrom_root,
-                                       svn_fs_root_fs(root),
-                                       copyfrom_rev, pool));
-
-          if (cb->authz_read_func)
-            {
-              SVN_ERR(cb->authz_read_func(&src_readable, copyfrom_root,
-                                          copyfrom_path,
-                                          cb->authz_read_baton, pool));
-            }
-        }
+      /* Was this node copied? */
+      SVN_ERR(fill_copyfrom(&copyfrom_root, &copyfrom_path, &copyfrom_rev,
+                            &src_readable, root, change,
+                            cb->authz_read_func, cb->authz_read_baton,
+                            edit_path, pool, pool));
 
       /* If we have a copyfrom path, and we can't read it or we're just
          ignoring it, or the copyfrom rev is prior to the low water mark
@@ -511,11 +613,13 @@ path_driver_cb_func(void **dir_baton,
              (possibly nested) copy operation. */
           if (change->node_kind == svn_node_dir)
             {
-              struct copy_info *info = &APR_ARRAY_PUSH(cb->copies,
-                                                       struct copy_info);
+              struct copy_info *info = apr_pcalloc(cb->pool, sizeof(*info));
+
               info->path = apr_pstrdup(cb->pool, edit_path);
               info->copyfrom_path = apr_pstrdup(cb->pool, copyfrom_path);
               info->copyfrom_rev = copyfrom_rev;
+
+              APR_ARRAY_PUSH(cb->copies, struct copy_info *) = info;
             }
 
           /* Save the source so that we can use it later, when we
@@ -531,11 +635,13 @@ path_driver_cb_func(void **dir_baton,
              past... */
           if (change->node_kind == svn_node_dir && cb->copies->nelts > 0)
             {
-              struct copy_info *info = &APR_ARRAY_PUSH(cb->copies,
-                                                       struct copy_info);
+              struct copy_info *info = apr_pcalloc(cb->pool, sizeof(*info));
+
               info->path = apr_pstrdup(cb->pool, edit_path);
               info->copyfrom_path = NULL;
               info->copyfrom_rev = SVN_INVALID_REVNUM;
+
+              APR_ARRAY_PUSH(cb->copies, struct copy_info *) = info;
             }
           source_root = NULL;
           source_fspath = NULL;
@@ -568,9 +674,9 @@ path_driver_cb_func(void **dir_baton,
          delta source. */
       if (cb->copies->nelts > 0)
         {
-          struct copy_info *info = &APR_ARRAY_IDX(cb->copies,
-                                                  cb->copies->nelts - 1,
-                                                  struct copy_info);
+          struct copy_info *info = APR_ARRAY_IDX(cb->copies,
+                                                 cb->copies->nelts - 1,
+                                                 struct copy_info *);
           if (info->copyfrom_path)
             {
               const char *relpath = svn_relpath_skip_ancestor(info->path,
@@ -597,45 +703,31 @@ path_driver_cb_func(void **dir_baton,
     {
       if (change->prop_mod)
         {
-          if (cb->compare_root)
-            {
-              apr_array_header_t *prop_diffs;
-              apr_hash_t *old_props;
-              apr_hash_t *new_props;
-              int i;
-
-              if (source_root)
-                SVN_ERR(svn_fs_node_proplist(&old_props, source_root,
-                                             source_fspath, pool));
-              else
-                old_props = apr_hash_make(pool);
-
-              SVN_ERR(svn_fs_node_proplist(&new_props, root, edit_path, pool));
-
-              SVN_ERR(svn_prop_diffs(&prop_diffs, new_props, old_props,
-                                     pool));
-
-              for (i = 0; i < prop_diffs->nelts; ++i)
-                {
-                  svn_prop_t *pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
-                   if (change->node_kind == svn_node_dir)
-                     SVN_ERR(editor->change_dir_prop(*dir_baton, pc->name,
-                                                     pc->value, pool));
-                   else if (change->node_kind == svn_node_file)
-                     SVN_ERR(editor->change_file_prop(file_baton, pc->name,
-                                                      pc->value, pool));
-                }
-            }
+          apr_array_header_t *prop_diffs;
+          apr_hash_t *old_props;
+          apr_hash_t *new_props;
+          int i;
+
+          if (source_root)
+            SVN_ERR(svn_fs_node_proplist(&old_props, source_root,
+                                         source_fspath, pool));
           else
+            old_props = apr_hash_make(pool);
+
+          SVN_ERR(svn_fs_node_proplist(&new_props, root, edit_path, pool));
+
+          SVN_ERR(svn_prop_diffs(&prop_diffs, new_props, old_props,
+                                 pool));
+
+          for (i = 0; i < prop_diffs->nelts; ++i)
             {
-              /* Just do a dummy prop change to signal that there are *any*
-                 propmods. */
-              if (change->node_kind == svn_node_dir)
-                SVN_ERR(editor->change_dir_prop(*dir_baton, "", NULL,
-                                                pool));
-              else if (change->node_kind == svn_node_file)
-                SVN_ERR(editor->change_file_prop(file_baton, "", NULL,
-                                                 pool));
+              svn_prop_t *pc = &APR_ARRAY_IDX(prop_diffs, i, svn_prop_t);
+               if (change->node_kind == svn_node_dir)
+                 SVN_ERR(editor->change_dir_prop(*dir_baton, pc->name,
+                                                 pc->value, pool));
+               else if (change->node_kind == svn_node_file)
+                 SVN_ERR(editor->change_file_prop(file_baton, pc->name,
+                                                  pc->value, pool));
             }
         }
 
@@ -806,7 +898,7 @@ svn_repos_replay2(svn_fs_root_t *root,
                                    pool));
     }
 
-  cb_baton.copies = apr_array_make(pool, 4, sizeof(struct copy_info));
+  cb_baton.copies = apr_array_make(pool, 4, sizeof(struct copy_info *));
   cb_baton.pool = pool;
 
   /* Determine the revision to use throughout the edit, and call

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/reporter.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/reporter.c Mon Jul 30 06:39:28 2012
@@ -898,6 +898,21 @@ update_entry(report_baton_t *b, svn_revn
       SVN_ERR(svn_repos_deleted_rev(svn_fs_root_fs(b->t_root), t_path,
                                     s_rev, b->t_rev, &deleted_rev,
                                     pool));
+
+      if (!SVN_IS_VALID_REVNUM(deleted_rev))
+        {
+          /* Two possibilities: either the thing doesn't exist in S_REV; or
+             it wasn't deleted between S_REV and B->T_REV.  In the first case,
+             I think we should leave DELETED_REV as SVN_INVALID_REVNUM, but
+             in the second, it should be set to B->T_REV-1 for the call to
+             delete_entry() below. */
+          svn_node_kind_t kind;
+
+          SVN_ERR(svn_fs_check_path(&kind, b->t_root, t_path, pool));
+          if (kind != svn_node_none)
+            deleted_rev = b->t_rev - 1;
+        }
+
       SVN_ERR(b->editor->delete_entry(e_path, deleted_rev, dir_baton,
                                       pool));
       s_path = NULL;

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/repos.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/repos.c Mon Jul 30 06:39:28 2012
@@ -165,6 +165,12 @@ svn_repos_post_revprop_change_hook(svn_r
                        pool);
 }
 
+void
+svn_repos_hooks_setenv(svn_repos_t *repos,
+                       apr_hash_t *hooks_env)
+{
+  repos->hooks_env = hooks_env;
+}
 
 static svn_error_t *
 create_repos_dir(const char *path, apr_pool_t *pool)
@@ -736,6 +742,7 @@ PREWRITTEN_HOOKS_TEXT
 "#"                                                                          NL
 "#   [1] REPOS-PATH   (the path to this repository)"                         NL
 "#   [2] REV          (the number of the revision just committed)"           NL
+"#   [3] TXN-NAME     (the name of the transaction that has become REV)"     NL
 "#"                                                                          NL
 "# The default working directory for the invocation is undefined, so"        NL
 "# the program should set one explicitly if it cares."                       NL
@@ -765,6 +772,7 @@ PREWRITTEN_HOOKS_TEXT
 ""                                                                           NL
 "REPOS=\"$1\""                                                               NL
 "REV=\"$2\""                                                                 NL
+"TXN_NAME=\"$3\""                                                            NL
                                                                              NL
 "mailer.py commit \"$REPOS\" \"$REV\" /path/to/mailer.conf"                  NL;
 
@@ -1040,7 +1048,17 @@ create_conf(svn_repos_t *repos, apr_pool
 "### to the effective key length for encryption (e.g. 128 means 128-bit"     NL
 "### encryption). The values below are the defaults."                        NL
 "# min-encryption = 0"                                                       NL
-"# max-encryption = 256"                                                     NL;
+"# max-encryption = 256"                                                     NL
+""                                                                           NL
+"[hooks-env]"                                                                NL
+"### Options in this section define environment variables for use by"        NL
+"### hook scripts run by svnserve."                                          NL
+#ifdef WIN32
+"# PATH = C:\\Program Files\\Subversion\\bin"                                NL
+#else
+"# PATH = /bin:/sbin:/usr/bin:/usr/sbin"                                     NL
+#endif
+"# LC_CTYPE = en_US.UTF-8"                                                   NL;
 
     SVN_ERR_W(svn_io_file_create(svn_repos_svnserve_conf(repos, pool),
                                  svnserve_conf_contents, pool),
@@ -1694,31 +1712,38 @@ svn_error_t *svn_repos_db_logfiles(apr_a
   return SVN_NO_ERROR;
 }
 
-/** Hot copy structure copy context.
- */
+/* Baton for hotcopy_structure(). */
 struct hotcopy_ctx_t {
   const char *dest;     /* target location to construct */
   size_t src_len; /* len of the source path*/
+
+  /* As in svn_repos_hotcopy2() */
+  svn_boolean_t incremental;
+  svn_cancel_func_t cancel_func;
+  void *cancel_baton;
 };
 
-/** Called by (svn_io_dir_walk2).
- * Copies the repository structure with exception of @c SVN_REPOS__DB_DIR,
- * @c SVN_REPOS__LOCK_DIR and @c SVN_REPOS__FORMAT.
- * Those directories and files are handled separetly.
- * @a baton is a pointer to (struct hotcopy_ctx_t) specifying
- * destination path to copy to and the length of the source path.
+/* Copy the repository structure of PATH to BATON->DEST, with exception of
+ * @c SVN_REPOS__DB_DIR, @c SVN_REPOS__LOCK_DIR and @c SVN_REPOS__FORMAT;
+ * those directories and files are handled separately.
  *
- * @copydoc svn_io_dir_walk2()
+ * BATON is a (struct hotcopy_ctx_t *).  BATON->SRC_LEN is the length
+ * of PATH.
+ *
+ * Implements svn_io_walk_func_t.
  */
 static svn_error_t *hotcopy_structure(void *baton,
                                       const char *path,
                                       const apr_finfo_t *finfo,
                                       apr_pool_t *pool)
 {
-  const struct hotcopy_ctx_t *ctx = ((struct hotcopy_ctx_t *) baton);
+  const struct hotcopy_ctx_t *ctx = baton;
   const char *sub_path;
   const char *target;
 
+  if (ctx->cancel_func)
+    SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+
   if (strlen(path) == ctx->src_len)
     {
       sub_path = "";
@@ -1748,7 +1773,17 @@ static svn_error_t *hotcopy_structure(vo
   target = svn_dirent_join(ctx->dest, sub_path, pool);
 
   if (finfo->filetype == APR_DIR)
-    return create_repos_dir(target, pool);
+    {
+      svn_error_t *err;
+
+      err = create_repos_dir(target, pool);
+      if (ctx->incremental && err && err->apr_err == SVN_ERR_DIR_NOT_EMPTY)
+        {
+          svn_error_clear(err);
+          err = SVN_NO_ERROR;
+        }
+      return svn_error_trace(err);
+    }
   else if (finfo->filetype == APR_REG)
     return svn_io_copy_file(path, target, TRUE, pool);
   else if (finfo->filetype == APR_LNK)
@@ -1777,17 +1812,29 @@ lock_db_logs_file(svn_repos_t *repos,
 
 /* Make a copy of a repository with hot backup of fs. */
 svn_error_t *
-svn_repos_hotcopy(const char *src_path,
-                  const char *dst_path,
-                  svn_boolean_t clean_logs,
-                  apr_pool_t *pool)
+svn_repos_hotcopy2(const char *src_path,
+                   const char *dst_path,
+                   svn_boolean_t clean_logs,
+                   svn_boolean_t incremental,
+                   svn_cancel_func_t cancel_func,
+                   void *cancel_baton,
+                   apr_pool_t *pool)
 {
   svn_repos_t *src_repos;
   svn_repos_t *dst_repos;
   struct hotcopy_ctx_t hotcopy_context;
+  svn_error_t *err;
+  const char *src_abspath;
+  const char *dst_abspath;
+
+  SVN_ERR(svn_dirent_get_absolute(&src_abspath, src_path, pool));
+  SVN_ERR(svn_dirent_get_absolute(&dst_abspath, dst_path, pool));
+  if (strcmp(src_abspath, dst_abspath) == 0)
+    return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+                             _("Hotcopy source and destination are equal"));
 
   /* Try to open original repository */
-  SVN_ERR(get_repos(&src_repos, src_path,
+  SVN_ERR(get_repos(&src_repos, src_abspath,
                     FALSE, FALSE,
                     FALSE,    /* don't try to open the db yet. */
                     NULL,
@@ -1804,9 +1851,12 @@ svn_repos_hotcopy(const char *src_path,
   /* Copy the repository to a new path, with exception of
      specially handled directories */
 
-  hotcopy_context.dest = dst_path;
-  hotcopy_context.src_len = strlen(src_path);
-  SVN_ERR(svn_io_dir_walk2(src_path,
+  hotcopy_context.dest = dst_abspath;
+  hotcopy_context.src_len = strlen(src_abspath);
+  hotcopy_context.incremental = incremental;
+  hotcopy_context.cancel_func = cancel_func;
+  hotcopy_context.cancel_baton = cancel_baton;
+  SVN_ERR(svn_io_dir_walk2(src_abspath,
                            0,
                            hotcopy_structure,
                            &hotcopy_context,
@@ -1815,20 +1865,35 @@ svn_repos_hotcopy(const char *src_path,
   /* Prepare dst_repos object so that we may create locks,
      so that we may open repository */
 
-  dst_repos = create_svn_repos_t(dst_path, pool);
+  dst_repos = create_svn_repos_t(dst_abspath, pool);
   dst_repos->fs_type = src_repos->fs_type;
   dst_repos->format = src_repos->format;
 
-  SVN_ERR(create_locks(dst_repos, pool));
+  err = create_locks(dst_repos, pool);
+  if (err)
+    {
+      if (incremental && err->apr_err == SVN_ERR_DIR_NOT_EMPTY)
+        svn_error_clear(err);
+      else
+        return svn_error_trace(err);
+    }
 
-  SVN_ERR(svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT, pool));
+  err = svn_io_dir_make_sgid(dst_repos->db_path, APR_OS_DEFAULT, pool);
+  if (err)
+    {
+      if (incremental && APR_STATUS_IS_EEXIST(err->apr_err))
+        svn_error_clear(err);
+      else
+        return svn_error_trace(err);
+    }
 
   /* Exclusively lock the new repository.
      No one should be accessing it at the moment */
   SVN_ERR(lock_repos(dst_repos, TRUE, FALSE, pool));
 
-  SVN_ERR(svn_fs_hotcopy(src_repos->db_path, dst_repos->db_path,
-                         clean_logs, pool));
+  SVN_ERR(svn_fs_hotcopy2(src_repos->db_path, dst_repos->db_path,
+                          clean_logs, incremental,
+                          cancel_func, cancel_baton, pool));
 
   /* Destination repository is ready.  Stamp it with a format number. */
   return svn_io_write_version_file
@@ -1836,6 +1901,16 @@ svn_repos_hotcopy(const char *src_path,
            dst_repos->format, pool);
 }
 
+svn_error_t *
+svn_repos_hotcopy(const char *src_path,
+                  const char *dst_path,
+                  svn_boolean_t clean_logs,
+                  apr_pool_t *pool)
+{
+  return svn_error_trace(svn_repos_hotcopy2(src_path, dst_path, clean_logs,
+                                            FALSE, NULL, NULL, pool));
+}
+
 /* Return the library version number. */
 const svn_version_t *
 svn_repos_version(void)

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/repos.h?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/repos.h Mon Jul 30 06:39:28 2012
@@ -140,6 +140,10 @@ struct svn_repos_t
      sufficiently well-informed internal code may just compare against
      those constants' addresses, therefore). */
   apr_hash_t *repository_capabilities;
+
+  /* The environment inherited to hook scripts. If NULL, hooks run
+   * in an empty environment. */
+  apr_hash_t *hooks_env;
 };
 
 
@@ -175,6 +179,7 @@ svn_repos__hooks_pre_commit(svn_repos_t 
 svn_error_t *
 svn_repos__hooks_post_commit(svn_repos_t *repos,
                              svn_revnum_t rev,
+                             const char *txn_name,
                              apr_pool_t *pool);
 
 /* Run the pre-revprop-change hook for REPOS.  Use POOL for any

Modified: subversion/branches/svn-bisect/subversion/libsvn_repos/rev_hunt.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_repos/rev_hunt.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_repos/rev_hunt.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_repos/rev_hunt.c Mon Jul 30 06:39:28 2012
@@ -1252,8 +1252,8 @@ find_merged_revisions(apr_array_header_t
   const apr_array_header_t *old;
   apr_array_header_t *new_merged_path_revs;
   apr_pool_t *iterpool, *last_pool;
-  apr_array_header_t *merged_path_revisions = apr_array_make(pool, 0,
-                                                sizeof(struct path_revision *));
+  apr_array_header_t *merged_path_revisions =
+    apr_array_make(pool, 0, sizeof(struct path_revision *));
 
   old = mainline_path_revisions;
   iterpool = svn_pool_create(pool);

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/auth.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/auth.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/auth.c Mon Jul 30 06:39:28 2012
@@ -35,13 +35,20 @@
 #include "svn_dso.h"
 #include "svn_version.h"
 
-/* The good way to think of this machinery is as a set of tables.
+/* AN OVERVIEW
+   ===========
 
-   - Each type of credentials selects a single table.
+   A good way to think of this machinery is as a set of tables.
 
-   - In a given table, each row is a 'provider' capable of returning
-     the same type of credentials.  Each column represents a
-     provider's repeated attempts to provide credentials.
+     - Each type of credentials selects a single table.
+
+     - In a given table, each row is a 'provider' capable of returning
+       the same type of credentials.  Each column represents a
+       provider's repeated attempts to provide credentials.
+
+
+   Fetching Credentials from Providers
+   -----------------------------------
 
    When the caller asks for a particular type of credentials, the
    machinery in this file walks over the appropriate table.  It starts
@@ -55,6 +62,23 @@
 
    Note that the caller cannot see the table traversal, and thus has
    no idea when we switch providers.
+
+
+   Storing Credentials with Providers
+   ----------------------------------
+
+   When the server has validated a set of credentials, and when
+   credential caching is enabled, we have the chance to store those
+   credentials for later use.  The provider which provided the working
+   credentials is the first one given the opportunity to (re)cache
+   those credentials.  Its save_credentials() function is invoked with
+   the working credentials.  If that provider reports that it
+   successfully stored the credentials, we're done.  Otherwise, we
+   walk the providers (rows) for that type of credentials in order
+   from the top of the table, allowing each in turn the opportunity to
+   store the credentials.  When one reports that it has done so
+   successfully -- or when we run out of providers (rows) to try --
+   the table walk ends.
 */
 
 

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/cache-inprocess.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/cache-inprocess.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/cache-inprocess.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/cache-inprocess.c Mon Jul 30 06:39:28 2012
@@ -213,15 +213,16 @@ inprocess_cache_get(void **value_p,
                     apr_pool_t *result_pool)
 {
   inprocess_cache_t *cache = cache_void;
-  char* buffer;
+  char* buffer = NULL;
   apr_size_t size;
 
-  SVN_MUTEX__WITH_LOCK(cache->mutex,
-                       inprocess_cache_get_internal(&buffer,
-                                                    &size,
-                                                    cache,
-                                                    key,
-                                                    result_pool));
+  if (key)
+    SVN_MUTEX__WITH_LOCK(cache->mutex,
+                         inprocess_cache_get_internal(&buffer,
+                                                      &size,
+                                                      cache,
+                                                      key,
+                                                      result_pool));
     
   /* deserialize the buffer content. Usually, this will directly
      modify the buffer content directly.
@@ -400,11 +401,12 @@ inprocess_cache_set(void *cache_void,
 {
   inprocess_cache_t *cache = cache_void;
 
-  SVN_MUTEX__WITH_LOCK(cache->mutex,
-                       inprocess_cache_set_internal(cache,
-                                                    key,
-                                                    value,
-                                                    scratch_pool));
+  if (key)
+    SVN_MUTEX__WITH_LOCK(cache->mutex,
+                         inprocess_cache_set_internal(cache,
+                                                      key,
+                                                      value,
+                                                      scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -482,14 +484,17 @@ inprocess_cache_get_partial(void **value
 {
   inprocess_cache_t *cache = cache_void;
 
-  SVN_MUTEX__WITH_LOCK(cache->mutex,
-                       inprocess_cache_get_partial_internal(value_p,
-                                                            found,
-                                                            cache,
-                                                            key,
-                                                            func,
-                                                            baton,
-                                                            result_pool));
+  if (key)
+    SVN_MUTEX__WITH_LOCK(cache->mutex,
+                         inprocess_cache_get_partial_internal(value_p,
+                                                              found,
+                                                              cache,
+                                                              key,
+                                                              func,
+                                                              baton,
+                                                              result_pool));
+  else
+    *found = FALSE;
 
   return SVN_NO_ERROR;
 }
@@ -526,12 +531,13 @@ inprocess_cache_set_partial(void *cache_
 {
   inprocess_cache_t *cache = cache_void;
 
-  SVN_MUTEX__WITH_LOCK(cache->mutex,
-                       inprocess_cache_set_partial_internal(cache,
-                                                            key,
-                                                            func,
-                                                            baton,
-                                                            scratch_pool));
+  if (key)
+    SVN_MUTEX__WITH_LOCK(cache->mutex,
+                         inprocess_cache_set_partial_internal(cache,
+                                                              key,
+                                                              func,
+                                                              baton,
+                                                              scratch_pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/cache-membuffer.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/cache-membuffer.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/cache-membuffer.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/cache-membuffer.c Mon Jul 30 06:39:28 2012
@@ -304,7 +304,7 @@ typedef struct entry_t
   /* Size of the serialized item data. May be 0.
    * Only valid for used entries.
    */
-  apr_uint32_t size;
+  apr_size_t size;
 
   /* Number of (read) hits for this entry. Will be reset upon write.
    * Only valid for used entries.
@@ -589,6 +589,9 @@ get_group_index(svn_membuffer_t **cache,
   svn_checksum_t *checksum;
   svn_error_t *err;
 
+  if (key == NULL)
+    return NO_INDEX;
+  
   err = svn_checksum(&checksum, svn_checksum_md5, key, len, pool);
   if (err != NULL)
   {
@@ -1363,11 +1366,12 @@ membuffer_cache_get_partial(svn_membuffe
 
   group_index = get_group_index(&cache, key, key_len, to_find, result_pool);
 
-  SVN_MUTEX__WITH_LOCK(cache->mutex,
-                       membuffer_cache_get_partial_internal
-                           (cache, group_index, to_find, item, found,
-                            deserializer, baton, DEBUG_CACHE_MEMBUFFER_TAG
-                            result_pool));
+  if (group_index != NO_INDEX)
+    SVN_MUTEX__WITH_LOCK(cache->mutex,
+                         membuffer_cache_get_partial_internal
+                             (cache, group_index, to_find, item, found,
+                              deserializer, baton, DEBUG_CACHE_MEMBUFFER_TAG
+                              result_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1499,11 +1503,12 @@ membuffer_cache_set_partial(svn_membuffe
    */
   group_index = get_group_index(&cache, key, key_len, to_find, scratch_pool);
 
-  SVN_MUTEX__WITH_LOCK(cache->mutex,
-                       membuffer_cache_set_partial_internal
-                           (cache, group_index, to_find, func, baton,
-                            DEBUG_CACHE_MEMBUFFER_TAG_ARG
-                            scratch_pool));
+  if (group_index != NO_INDEX)
+    SVN_MUTEX__WITH_LOCK(cache->mutex,
+                         membuffer_cache_set_partial_internal
+                             (cache, group_index, to_find, func, baton,
+                              DEBUG_CACHE_MEMBUFFER_TAG_ARG
+                              scratch_pool));
 
   /* done here -> unlock the cache
    */
@@ -1567,6 +1572,9 @@ typedef struct svn_membuffer_cache_t
    */
   int alloc_counter;
 
+  /* if enabled, this will serialize the access to this instance.
+   */
+  svn_mutex__t *mutex;
 #ifdef SVN_DEBUG_CACHE_MEMBUFFER
 
   /* Invariant tag info for all items stored by this cache instance.
@@ -1594,17 +1602,25 @@ combine_key(const void *prefix,
             apr_size_t *full_key_len,
             apr_pool_t *pool)
 {
-  if (key_len == APR_HASH_KEY_STRING)
-    key_len = strlen((const char *) key);
+  if (key == NULL)
+    {
+      *full_key = NULL;
+      *full_key_len = 0;
+    }
+  else
+    {
+      if (key_len == APR_HASH_KEY_STRING)
+        key_len = strlen((const char *) key);
 
-  *full_key_len = prefix_len + key_len;
-  *full_key = apr_palloc(pool, *full_key_len);
+      *full_key_len = prefix_len + key_len;
+      *full_key = apr_palloc(pool, *full_key_len);
 
-  memcpy(*full_key, prefix, prefix_len);
-  memcpy((char *)*full_key + prefix_len, key, key_len);
+      memcpy(*full_key, prefix, prefix_len);
+      memcpy((char *)*full_key + prefix_len, key, key_len);
+    }
 }
 
-/* Implement svn_cache__vtable_t.get
+/* Implement svn_cache__vtable_t.get (not thread-safe)
  */
 static svn_error_t *
 svn_membuffer_cache_get(void **value_p,
@@ -1655,7 +1671,7 @@ svn_membuffer_cache_get(void **value_p,
   return SVN_NO_ERROR;
 }
 
-/* Implement svn_cache__vtable_t.set
+/* Implement svn_cache__vtable_t.set (not thread-safe)
  */
 static svn_error_t *
 svn_membuffer_cache_set(void *cache_void,
@@ -1716,7 +1732,7 @@ svn_membuffer_cache_iter(svn_boolean_t *
                           _("Can't iterate a membuffer-based cache"));
 }
 
-/* Implement svn_cache__vtable_t.get_partial
+/* Implement svn_cache__vtable_t.get_partial (not thread-safe)
  */
 static svn_error_t *
 svn_membuffer_cache_get_partial(void **value_p,
@@ -1761,7 +1777,7 @@ svn_membuffer_cache_get_partial(void **v
   return SVN_NO_ERROR;
 }
 
-/* Implement svn_cache__vtable_t.set_partial
+/* Implement svn_cache__vtable_t.set_partial (not thread-safe)
  */
 static svn_error_t *
 svn_membuffer_cache_set_partial(void *cache_void,
@@ -1797,6 +1813,7 @@ svn_membuffer_cache_set_partial(void *ca
 }
 
 /* Implement svn_cache__vtable_t.is_cachable
+ * (thread-safe even without mutex)
  */
 static svn_boolean_t
 svn_membuffer_cache_is_cachable(void *cache_void, apr_size_t size)
@@ -1828,6 +1845,7 @@ svn_membuffer_get_segment_info(svn_membu
 }
 
 /* Implement svn_cache__vtable_t.get_info
+ * (thread-safe even without mutex)
  */
 static svn_error_t *
 svn_membuffer_cache_get_info(void *cache_void,
@@ -1862,7 +1880,7 @@ svn_membuffer_cache_get_info(void *cache
 }
 
 
-/* the v-table for membuffer-based caches
+/* the v-table for membuffer-based caches (single-threaded access)
  */
 static svn_cache__vtable_t membuffer_cache_vtable = {
   svn_membuffer_cache_get,
@@ -1874,6 +1892,100 @@ static svn_cache__vtable_t membuffer_cac
   svn_membuffer_cache_get_info
 };
 
+/* Implement svn_cache__vtable_t.get and serialize all cache access.
+ */
+static svn_error_t *
+svn_membuffer_cache_get_synced(void **value_p,
+                               svn_boolean_t *found,
+                               void *cache_void,
+                               const void *key,
+                               apr_pool_t *result_pool)
+{
+  svn_membuffer_cache_t *cache = cache_void;
+  SVN_MUTEX__WITH_LOCK(cache->mutex, 
+                       svn_membuffer_cache_get(value_p,
+                                               found,
+                                               cache_void,
+                                               key,
+                                               result_pool));
+  
+  return SVN_NO_ERROR;
+}
+
+/* Implement svn_cache__vtable_t.set and serialize all cache access.
+ */
+static svn_error_t *
+svn_membuffer_cache_set_synced(void *cache_void,
+                               const void *key,
+                               void *value,
+                               apr_pool_t *scratch_pool)
+{
+  svn_membuffer_cache_t *cache = cache_void;
+  SVN_MUTEX__WITH_LOCK(cache->mutex, 
+                       svn_membuffer_cache_set(cache_void,
+                                               key,
+                                               value,
+                                               scratch_pool));
+  
+  return SVN_NO_ERROR;
+}
+
+/* Implement svn_cache__vtable_t.get_partial and serialize all cache access.
+ */
+static svn_error_t *
+svn_membuffer_cache_get_partial_synced(void **value_p,
+                                       svn_boolean_t *found,
+                                       void *cache_void,
+                                       const void *key,
+                                       svn_cache__partial_getter_func_t func,
+                                       void *baton,
+                                       apr_pool_t *result_pool)
+{
+  svn_membuffer_cache_t *cache = cache_void;
+  SVN_MUTEX__WITH_LOCK(cache->mutex, 
+                       svn_membuffer_cache_get_partial(value_p,
+                                                       found,
+                                                       cache_void,
+                                                       key,
+                                                       func,
+                                                       baton,
+                                                       result_pool));
+  
+  return SVN_NO_ERROR;
+}
+
+/* Implement svn_cache__vtable_t.set_partial and serialize all cache access.
+ */
+static svn_error_t *
+svn_membuffer_cache_set_partial_synced(void *cache_void,
+                                       const void *key,
+                                       svn_cache__partial_setter_func_t func,
+                                       void *baton,
+                                       apr_pool_t *scratch_pool)
+{
+  svn_membuffer_cache_t *cache = cache_void;
+  SVN_MUTEX__WITH_LOCK(cache->mutex, 
+                       svn_membuffer_cache_set_partial(cache_void,
+                                                       key,
+                                                       func,
+                                                       baton,
+                                                       scratch_pool));
+  
+  return SVN_NO_ERROR;
+}
+
+/* the v-table for membuffer-based caches with multi-threading support)
+ */
+static svn_cache__vtable_t membuffer_cache_synced_vtable = {
+  svn_membuffer_cache_get_synced,
+  svn_membuffer_cache_set_synced,
+  svn_membuffer_cache_iter,               /* no sync required */
+  svn_membuffer_cache_is_cachable,        /* no sync required */
+  svn_membuffer_cache_get_partial_synced,
+  svn_membuffer_cache_set_partial_synced,
+  svn_membuffer_cache_get_info            /* no sync required */
+};
+
 /* standard serialization function for svn_stringbuf_t items.
  * Implements svn_cache__serialize_func_t.
  */
@@ -1900,8 +2012,10 @@ deserialize_svn_stringbuf(void **item,
                           apr_size_t buffer_size,
                           apr_pool_t *result_pool)
 {
-  svn_string_t *value_str = apr_palloc(result_pool, sizeof(svn_string_t));
+  svn_stringbuf_t *value_str = apr_palloc(result_pool, sizeof(svn_stringbuf_t));
 
+  value_str->pool = result_pool;
+  value_str->blocksize = buffer_size;
   value_str->data = buffer;
   value_str->len = buffer_size-1;
   *item = value_str;
@@ -1918,6 +2032,7 @@ svn_cache__create_membuffer_cache(svn_ca
                                   svn_cache__deserialize_func_t deserializer,
                                   apr_ssize_t klen,
                                   const char *prefix,
+                                  svn_boolean_t thread_safe,
                                   apr_pool_t *pool)
 {
   svn_checksum_t *checksum;
@@ -1941,6 +2056,8 @@ svn_cache__create_membuffer_cache(svn_ca
   cache->pool = svn_pool_create(pool);
   cache->alloc_counter = 0;
 
+  SVN_ERR(svn_mutex__init(&cache->mutex, thread_safe, pool));
+  
   /* for performance reasons, we don't actually store the full prefix but a
    * hash value of it
    */
@@ -1961,7 +2078,8 @@ svn_cache__create_membuffer_cache(svn_ca
 
   /* initialize the generic cache wrapper
    */
-  wrapper->vtable = &membuffer_cache_vtable;
+  wrapper->vtable = thread_safe ? &membuffer_cache_synced_vtable 
+                                : &membuffer_cache_vtable;
   wrapper->cache_internal = cache;
   wrapper->error_handler = 0;
   wrapper->error_baton = 0;

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/cache-memcache.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/cache-memcache.c Mon Jul 30 06:39:28 2012
@@ -141,8 +141,15 @@ memcache_internal_get(char **data,
   memcache_t *cache = cache_void;
   apr_status_t apr_err;
   const char *mc_key;
-  apr_pool_t *subpool = svn_pool_create(pool);
+  apr_pool_t *subpool;
 
+  if (key == NULL)
+    {
+      *found = FALSE;
+      return SVN_NO_ERROR;
+    }
+  
+  subpool = svn_pool_create(pool);
   SVN_ERR(build_key(&mc_key, cache, key, subpool));
 
   apr_err = apr_memcache_getp(cache->memcache,
@@ -244,6 +251,9 @@ memcache_set(void *cache_void,
   apr_size_t data_len;
   svn_error_t *err;
 
+  if (key == NULL)
+    return SVN_NO_ERROR;
+  
   if (cache->serialize_func)
     {
       SVN_ERR((cache->serialize_func)(&data, &data_len, value, subpool));

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/checksum.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/checksum.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/checksum.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/checksum.c Mon Jul 30 06:39:28 2012
@@ -423,3 +423,27 @@ svn_checksum_mismatch_err(const svn_chec
                 svn_checksum_to_cstring_display(expected, scratch_pool),
                 svn_checksum_to_cstring_display(actual, scratch_pool));
 }
+
+svn_boolean_t
+svn_checksum_is_empty_checksum(svn_checksum_t *checksum)
+{
+  /* By definition, the NULL checksum matches all others, including the
+     empty one. */
+  if (!checksum)
+    return TRUE;
+
+  switch (checksum->kind)
+    {
+      case svn_checksum_md5:
+        return svn_md5__digests_match(checksum->digest,
+                                      svn_md5__empty_string_digest());
+
+      case svn_checksum_sha1:
+        return svn_sha1__digests_match(checksum->digest,
+                                       svn_sha1__empty_string_digest());
+
+      default:
+        /* We really shouldn't get here, but if we do... */
+        return FALSE;
+    }
+}

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/cmdline.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/cmdline.c Mon Jul 30 06:39:28 2012
@@ -226,7 +226,7 @@ svn_cmdline_init(const char *progname, F
   /* Create a pool for use by the UTF-8 routines.  It will be cleaned
      up by APR at exit time. */
   pool = svn_pool_create(NULL);
-  svn_utf_initialize(pool);
+  svn_utf_initialize2(pool, FALSE);
 
   if ((err = svn_nls_init()))
     {

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/config.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/config.c Mon Jul 30 06:39:28 2012
@@ -974,5 +974,13 @@ svn_config_get_server_setting_bool(svn_c
 svn_boolean_t
 svn_config_has_section(svn_config_t *cfg, const char *section)
 {
-  return apr_hash_get(cfg->sections, section, APR_HASH_KEY_STRING) != NULL;
+  cfg_section_t *sec;
+
+  /* Canonicalize the hash key */
+  svn_stringbuf_set(cfg->tmp_key, section);
+  if (! cfg->section_names_case_sensitive)
+    make_hash_key(cfg->tmp_key->data);
+
+  sec = apr_hash_get(cfg->sections, cfg->tmp_key->data, APR_HASH_KEY_STRING);
+  return sec != NULL;
 }

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/config_file.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/config_file.c Mon Jul 30 06:39:28 2012
@@ -766,16 +766,20 @@ svn_config_ensure(const char *config_dir
         "###                              to authenticate against a"         NL
         "###                              Subversion server may be cached"   NL
         "###                              to disk in any way."               NL
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
         "###   store-plaintext-passwords  Specifies whether passwords may"   NL
         "###                              be cached on disk unencrypted."    NL
+#endif
         "###   store-ssl-client-cert-pp   Specifies whether passphrase used" NL
         "###                              to authenticate against a client"  NL
         "###                              certificate may be cached to disk" NL
         "###                              in any way"                        NL
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
         "###   store-ssl-client-cert-pp-plaintext"                           NL
         "###                              Specifies whether client cert"     NL
         "###                              passphrases may be cached on disk" NL
         "###                              unencrypted (i.e., as plaintext)." NL
+#endif
         "###   store-auth-creds           Specifies whether any auth info"   NL
         "###                              (passwords as well as server certs)"
                                                                              NL
@@ -783,15 +787,14 @@ svn_config_ensure(const char *config_dir
         "###   username                   Specifies the default username."   NL
         "###"                                                                NL
         "### Set store-passwords to 'no' to avoid storing passwords on disk" NL
-        "### in any way, including in password stores. It defaults to 'yes',"
-                                                                             NL
-        "### but Subversion will never save your password to disk in plaintext"
-                                                                             NL
-        "### unless you tell it to."                                         NL
+        "### in any way, including in password stores.  It defaults to"      NL
+        "### 'yes', but Subversion will never save your password to disk in" NL
+        "### plaintext unless explicitly configured to do so."               NL
         "### Note that this option only prevents saving of *new* passwords;" NL
         "### it doesn't invalidate existing passwords.  (To do that, remove" NL
         "### the cache files by hand as described in the Subversion book.)"  NL
         "###"                                                                NL
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
         "### Set store-plaintext-passwords to 'no' to avoid storing"         NL
         "### passwords in unencrypted form in the auth/ area of your config" NL
         "### directory. Set it to 'yes' to allow Subversion to store"        NL
@@ -801,11 +804,12 @@ svn_config_ensure(const char *config_dir
         "### this option has no effect if either 'store-passwords' or "      NL
         "### 'store-auth-creds' is set to 'no'."                             NL
         "###"                                                                NL
+#endif
         "### Set store-ssl-client-cert-pp to 'no' to avoid storing ssl"      NL
         "### client certificate passphrases in the auth/ area of your"       NL
         "### config directory.  It defaults to 'yes', but Subversion will"   NL
-        "### never save your passphrase to disk in plaintext unless you tell"NL
-        "### it to via 'store-ssl-client-cert-pp-plaintext' (see below)."    NL
+        "### never save your passphrase to disk in plaintext unless"         NL
+        "### explicitly configured to do so."                                NL
         "###"                                                                NL
         "### Note store-ssl-client-cert-pp only prevents the saving of *new*"NL
         "### passphrases; it doesn't invalidate existing passphrases.  To do"NL
@@ -814,6 +818,7 @@ svn_config_ensure(const char *config_dir
         "###                    svn.serverconfig.netmodel.html\\"            NL
         "###                    #svn.serverconfig.netmodel.credcache"        NL
         "###"                                                                NL
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
         "### Set store-ssl-client-cert-pp-plaintext to 'no' to avoid storing"NL
         "### passphrases in unencrypted form in the auth/ area of your"      NL
         "### config directory.  Set it to 'yes' to allow Subversion to"      NL
@@ -823,6 +828,7 @@ svn_config_ensure(const char *config_dir
         "### this option has no effect if either 'store-auth-creds' or "     NL
         "### 'store-ssl-client-cert-pp' is set to 'no'."                     NL
         "###"                                                                NL
+#endif
         "### Set store-auth-creds to 'no' to avoid storing any Subversion"   NL
         "### credentials in the auth/ area of your config directory."        NL
         "### Note that this includes SSL server certificates."               NL
@@ -858,7 +864,9 @@ svn_config_ensure(const char *config_dir
         "# http-auth-types = basic;digest;negotiate"                         NL
 #endif
         "# neon-debug-mask = 130"                                            NL
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
         "# store-plaintext-passwords = no"                                   NL
+#endif
         "# username = harry"                                                 NL
         ""                                                                   NL
         "### Information for the second group:"                              NL
@@ -904,9 +912,12 @@ svn_config_ensure(const char *config_dir
         "#"                                                                  NL
         "# Password / passphrase caching parameters:"                        NL
         "# store-passwords = no"                                             NL
-        "# store-plaintext-passwords = no"                                   NL
         "# store-ssl-client-cert-pp = no"                                    NL
-        "# store-ssl-client-cert-pp-plaintext = no"                          NL;
+#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
+        "# store-plaintext-passwords = no"                                   NL
+        "# store-ssl-client-cert-pp-plaintext = no"                          NL
+#endif
+        ;
 
       err = svn_io_file_open(&f, path,
                              (APR_WRITE | APR_CREATE | APR_EXCL),
@@ -1039,7 +1050,7 @@ svn_config_ensure(const char *config_dir
         "### path separator.  A single backslash will be treated as an"      NL
         "### escape for the following character."                            NL
         ""                                                                   NL
-        "### Section for configuring miscelleneous Subversion options."      NL
+        "### Section for configuring miscellaneous Subversion options."      NL
         "[miscellany]"                                                       NL
         "### Set global-ignores to a set of whitespace-delimited globs"      NL
         "### which Subversion will ignore in its 'status' output, and"       NL

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/debug.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/debug.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/debug.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/debug.c Mon Jul 30 06:39:28 2012
@@ -27,10 +27,13 @@
 #include <stdarg.h>
 
 #include "svn_types.h"
+#include "svn_string.h"
 
 #include "private/svn_debug.h"
 
 
+#define DBG_FLAG "DBG: "
+
 /* This will be tweaked by the preamble code.  */
 static FILE * volatile debug_output = NULL;
 
@@ -59,21 +62,63 @@ svn_dbg__preamble(const char *file, long
       else
         ++slash;
 
-      fprintf(output, "DBG: %s:%4ld: ", slash, line);
+      fprintf(output, DBG_FLAG "%s:%4ld: ", slash, line);
     }
 }
 
 
-void
-svn_dbg__printf(const char *fmt, ...)
+static void
+print_line(const char *fmt, va_list ap)
 {
   FILE *output = debug_output;
-  va_list ap;
 
   if (output == NULL || quiet_mode())
     return;
 
-  va_start(ap, fmt);
   (void) vfprintf(output, fmt, ap);
+}
+
+
+void
+svn_dbg__printf(const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  print_line(fmt, ap);
   va_end(ap);
 }
+
+
+void
+svn_dbg__print_props(apr_hash_t *props,
+                     const char *header_fmt,
+                     ...)
+{
+/* We only build this code if SVN_DEBUG is defined. */
+#ifdef SVN_DEBUG
+
+  apr_hash_index_t *hi;
+  va_list ap;
+
+  va_start(ap, header_fmt);
+  print_line(header_fmt, ap);
+  va_end(ap);
+
+  if (props == NULL)
+    {
+      SVN_DBG(("    (null)\n"));
+      return;
+    }
+
+  for (hi = apr_hash_first(apr_hash_pool_get(props), props); hi;
+        hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_string_t *val = svn__apr_hash_index_val(hi);
+
+      SVN_DBG(("    '%s' -> '%s'\n", name, val->data));
+    }
+#endif /* SVN_DEBUG */
+}
+

Modified: subversion/branches/svn-bisect/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_subr/deprecated.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_subr/deprecated.c Mon Jul 30 06:39:28 2012
@@ -39,6 +39,7 @@
 #include "svn_pools.h"
 #include "svn_dso.h"
 #include "svn_mergeinfo.h"
+#include "svn_utf.h"
 #include "svn_xml.h"
 
 #include "opt.h"
@@ -766,6 +767,25 @@ svn_io_get_dirents(apr_hash_t **dirents,
 }
 
 svn_error_t *
+svn_io_start_cmd2(apr_proc_t *cmd_proc,
+                  const char *path,
+                  const char *cmd,
+                  const char *const *args,
+                  svn_boolean_t inherit,
+                  svn_boolean_t infile_pipe,
+                  apr_file_t *infile,
+                  svn_boolean_t outfile_pipe,
+                  apr_file_t *outfile,
+                  svn_boolean_t errfile_pipe,
+                  apr_file_t *errfile,
+                  apr_pool_t *pool)
+{
+  return svn_io_start_cmd3(cmd_proc, path, cmd, args, NULL, inherit,
+                           infile_pipe, infile, outfile_pipe, outfile,
+                           errfile_pipe, errfile, pool);
+}
+
+svn_error_t *
 svn_io_start_cmd(apr_proc_t *cmd_proc,
                  const char *path,
                  const char *cmd,
@@ -1173,3 +1193,9 @@ svn_xml_make_header(svn_stringbuf_t **st
 {
   svn_xml_make_header2(str, NULL, pool);
 }
+
+void
+svn_utf_initialize(apr_pool_t *pool)
+{
+  svn_utf_initialize2(pool, FALSE);
+}