subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1331076 [2/8] - in /subversion/branches/ev2-export: ./ build/generator/ build/generator/templates/ notes/ notes/merge-tracking/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ su...
Date Thu, 26 Apr 2012 20:37:20 GMT
Modified: subversion/branches/ev2-export/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/compat.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/compat.c Thu Apr 26 20:37:17 2012
@@ -159,15 +159,12 @@ struct ev2_file_baton
 
 enum action_code_t
 {
-  ACTION_MOVE,
   ACTION_MKDIR,
   ACTION_COPY,
   ACTION_PROPSET,
   ACTION_PUT,
-  ACTION_ADD,
   ACTION_DELETE,
-  ACTION_ADD_ABSENT,
-  ACTION_UNLOCK
+  ACTION_ADD_ABSENT
 };
 
 struct path_action
@@ -198,8 +195,17 @@ struct change_node
 
   svn_kind_t kind;  /* the NEW kind of this node  */
 
-  /* The revision we're trying to change. Replace it, modify it, etc.  */
-  svn_revnum_t base_revision;
+  /* We need two revisions: one to specify the revision we are altering,
+     and a second to specify the revision to delete/replace. These are
+     mutually exclusive, but they need to be separate to ensure we don't
+     confuse the operation on this node. For example, we may delete a
+     node and replace it we use DELETING for REPLACES_REV, and ignore
+     the value placed into CHANGING when properties were set/changed
+     on the new node. Or we simply change a node (setting CHANGING),
+     and DELETING remains SVN_INVALID_REVNUM, indicating we are not
+     attempting to replace a node.  */
+  svn_revnum_t changing;
+  svn_revnum_t deleting;
 
   apr_hash_t *props;  /* new/final set of props to apply  */
 
@@ -210,6 +216,9 @@ struct change_node
      RESTRUCTURE must be RESTRUCTURE_ADD.  */
   const char *copyfrom_path;
   svn_revnum_t copyfrom_rev;
+
+  /* Record whether an incoming propchange unlocked this node.  */
+  svn_boolean_t unlock;
 };
 
 
@@ -271,7 +280,8 @@ locate_change(struct ev2_edit_baton *eb,
 
   /* Return an empty change. Callers will tweak as needed.  */
   change = apr_pcalloc(eb->edit_pool, sizeof(*change));
-  change->base_revision = SVN_INVALID_REVNUM;
+  change->changing = SVN_INVALID_REVNUM;
+  change->deleting = SVN_INVALID_REVNUM;
 
   apr_hash_set(eb->changes, relpath, APR_HASH_KEY_STRING, change);
 
@@ -293,9 +303,10 @@ apply_propedit(struct ev2_edit_baton *eb
   SVN_ERR_ASSERT(change->kind == svn_kind_unknown || change->kind == kind);
   change->kind = kind;
 
-  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(change->base_revision)
-                 || change->base_revision == base_revision);
-  change->base_revision = base_revision;
+  /* We're now changing the node. Record the revision.  */
+  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(change->changing)
+                 || change->changing == base_revision);
+  change->changing = base_revision;
 
   if (change->props == NULL)
     {
@@ -377,7 +388,6 @@ process_actions(struct ev2_edit_baton *e
 {
   apr_hash_t *props = NULL;
   svn_boolean_t need_add = FALSE;
-  svn_boolean_t need_delete = FALSE;
   svn_boolean_t need_copy = FALSE;
   const char *copyfrom_path;
   svn_revnum_t copyfrom_rev;
@@ -388,7 +398,6 @@ process_actions(struct ev2_edit_baton *e
   svn_revnum_t props_base_revision = SVN_INVALID_REVNUM;
   svn_revnum_t text_base_revision = SVN_INVALID_REVNUM;
   svn_kind_t kind = svn_kind_unknown;
-  int i;
 
   if (*path == '/')
     {
@@ -396,72 +405,68 @@ process_actions(struct ev2_edit_baton *e
       *eb->found_abs_paths = TRUE;
     }
 
-  /* Go through all of our actions, populating various datastructures
-   * dependent on them. */
-  for (i = 0; i < actions->nelts; i++)
+  SVN_ERR_ASSERT(change != NULL);
+  if (change != NULL)
     {
-      const struct path_action *action = APR_ARRAY_IDX(actions, i,
-                                                       struct path_action *);
+      if (change->unlock)
+        SVN_ERR(eb->do_unlock(eb->unlock_baton, path, scratch_pool));
+
+      if (change->action == RESTRUCTURE_DELETE)
+        {
+          /* If the action was left as RESTRUCTURE_DELETE, then a
+             replacement is not occurring. Just do the delete and bail.  */
+          SVN_ERR(svn_editor_delete(eb->editor, path, change->deleting));
+
+          /* No further work possible on this node.  */
+          return SVN_NO_ERROR;
+        }
+      if (change->action == RESTRUCTURE_ADD_ABSENT)
+        {
+          SVN_ERR(svn_editor_add_absent(eb->editor, path, change->kind,
+                                        change->deleting));
+
+          /* No further work possible on this node.  */
+          return SVN_NO_ERROR;
+        }
 
-      switch (action->action)
+      if (change->action == RESTRUCTURE_ADD)
         {
-          case ACTION_DELETE:
+          kind = change->kind;
+
+          /* An add might be a replace. Grab the revnum we're replacing.  */
+          delete_revnum = change->deleting;
+
+          if (kind == svn_kind_dir)
             {
-              delete_revnum = *((svn_revnum_t *) action->args);
-              need_delete = TRUE;
-              break;
+              children = get_children(eb, path, scratch_pool);
             }
-
-          case ACTION_ADD:
+          else
             {
-              kind = *((svn_kind_t *) action->args);
-              need_add = TRUE;
-
-              if (kind == svn_kind_dir)
+              /* If this file is copied here, then we don't need CONTENTS.
+                 Otherwise, the contents comes from apply_txdelta() and has
+                 been saved at CONTENTS_ABSPATH. If apply_txdelta() was not
+                 called, then we're adding an empty file.  */
+              if (change->copyfrom_path == NULL
+                  && change->contents_abspath == NULL)
                 {
-                  children = get_children(eb, path, scratch_pool);
-                }
-              else
-                {
-                  /* The default is an empty file. */
                   contents = svn_stream_empty(scratch_pool);
                   checksum = svn_checksum_empty_checksum(svn_checksum_sha1,
                                                          scratch_pool);
                 }
-              break;
             }
 
-          case ACTION_COPY:
+          if (change->copyfrom_path != NULL)
             {
-              struct copy_args *c_args = action->args;
-
-              copyfrom_path = c_args->copyfrom_path;
-              copyfrom_rev = c_args->copyfrom_rev;
               need_copy = TRUE;
-              break;
+              copyfrom_path = change->copyfrom_path;
+              copyfrom_rev = change->copyfrom_rev;
             }
-
-          case ACTION_ADD_ABSENT:
-            {
-              kind = *((svn_kind_t *) action->args);
-              SVN_ERR(svn_editor_add_absent(eb->editor, path, kind,
-                                            SVN_INVALID_REVNUM));
-              break;
-            }
-
-          case ACTION_UNLOCK:
+          else
             {
-              SVN_ERR(eb->do_unlock(eb->unlock_baton, path, scratch_pool));
-              break;
+              need_add = TRUE;
             }
-
-          default:
-            SVN_ERR_MALFUNCTION();
         }
-    }
 
-  if (change != NULL)
-    {
       if (change->contents_abspath != NULL)
         {
           /* We can only set text on files. */
@@ -474,7 +479,7 @@ process_actions(struct ev2_edit_baton *e
           SVN_ERR(svn_stream_open_readonly(&contents, change->contents_abspath,
                                            scratch_pool, scratch_pool));
 
-          text_base_revision = change->base_revision;
+          text_base_revision = change->changing;
         }
 
       if (change->props != NULL)
@@ -482,20 +487,13 @@ process_actions(struct ev2_edit_baton *e
           /* ### validate we aren't overwriting KIND?  */
           kind = change->kind;
           props = change->props;
-          props_base_revision = change->base_revision;
+          props_base_revision = change->changing;
         }
     }
 
   /* We've now got a wholistic view of what has happened to this node,
    * so we can call our own editor APIs on it. */
 
-  if (need_delete && !need_add && !need_copy)
-    {
-      /* If we're only doing a delete, do it here. */
-      SVN_ERR(svn_editor_delete(eb->editor, path, delete_revnum));
-      return SVN_NO_ERROR;
-    }
-
   if (need_add)
     {
       if (props == NULL)
@@ -512,6 +510,7 @@ process_actions(struct ev2_edit_baton *e
                                       props, delete_revnum));
         }
 
+      /* No further work possible on this node.  */
       return SVN_NO_ERROR;
     }
 
@@ -519,8 +518,14 @@ process_actions(struct ev2_edit_baton *e
     {
       SVN_ERR(svn_editor_copy(eb->editor, copyfrom_path, copyfrom_rev, path,
                               delete_revnum));
+      /* Fall through to possibly make changes post-copy.  */
     }
 
+#if 0
+  /* There *should* be work for this node. But it seems that isn't true
+     in some cases. Future investigation...  */
+  SVN_ERR_ASSERT(need_copy || props || contents);
+#endif
   if (props || contents)
     {
       /* We fetched and modified the props or content in some way. Apply 'em
@@ -639,30 +644,21 @@ ev2_delete_entry(const char *path,
                  apr_pool_t *scratch_pool)
 {
   struct ev2_dir_baton *pb = parent_baton;
-  svn_revnum_t *revnum = apr_palloc(pb->eb->edit_pool, sizeof(*revnum));
+  svn_revnum_t base_revision;
   const char *relpath = map_to_repos_relpath(pb->eb, path, scratch_pool);
   struct change_node *change = locate_change(pb->eb, relpath);
 
   if (SVN_IS_VALID_REVNUM(revision))
-    *revnum = revision;
+    base_revision = revision;
   else
-    *revnum = pb->base_revision;
+    base_revision = pb->base_revision;
 
-  SVN_ERR(add_action(pb->eb, relpath, ACTION_DELETE, revnum));
-
-  /* ### note: cannot switch to CHANGES just yet. the action loop needs
-     ### to see a delete action, and set NEED_DELETE. that is used for
-     ### the file properties. once fileprops are converted, then we
-     ### can fully switch over.  */
-
-  /* ### assert that RESTRUCTURE is NONE?  */
+  SVN_ERR_ASSERT(change->action == RESTRUCTURE_NONE);
   change->action = RESTRUCTURE_DELETE;
 
-#if 0
-  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(change->base_revision)
-                 || change->base_revision == revision);
-  change->base_revision = revision;
-#endif
+  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(change->deleting)
+                 || change->deleting == base_revision);
+  change->deleting = base_revision;
 
   return SVN_NO_ERROR;
 }
@@ -684,6 +680,7 @@ ev2_add_directory(const char *path,
 
   /* ### assert that RESTRUCTURE is NONE or DELETE?  */
   change->action = RESTRUCTURE_ADD;
+  change->kind = svn_kind_dir;
 
   cb->eb = pb->eb;
   cb->path = apr_pstrdup(result_pool, relpath);
@@ -692,12 +689,6 @@ ev2_add_directory(const char *path,
 
   if (!copyfrom_path)
     {
-      /* A simple add. */
-      svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
-
-      *kind = svn_kind_dir;
-      SVN_ERR(add_action(pb->eb, relpath, ACTION_ADD, kind));
-
       if (pb->copyfrom_relpath)
         {
           const char *name = svn_relpath_basename(relpath, scratch_pool);
@@ -715,10 +706,6 @@ ev2_add_directory(const char *path,
                                                    pb->eb->edit_pool);
       change->copyfrom_rev = copyfrom_revision;
 
-      args->copyfrom_path = change->copyfrom_path;
-      args->copyfrom_rev = change->copyfrom_rev;
-      SVN_ERR(add_action(pb->eb, relpath, ACTION_COPY, args));
-
       cb->copyfrom_relpath = change->copyfrom_path;
       cb->copyfrom_rev = change->copyfrom_rev;
     }
@@ -784,11 +771,12 @@ ev2_absent_directory(const char *path,
                      apr_pool_t *scratch_pool)
 {
   struct ev2_dir_baton *pb = parent_baton;
-  svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
   const char *relpath = map_to_repos_relpath(pb->eb, path, scratch_pool);
+  struct change_node *change = locate_change(pb->eb, relpath);
 
-  *kind = svn_kind_dir;
-  SVN_ERR(add_action(pb->eb, relpath, ACTION_ADD_ABSENT, kind));
+  /* ### assert that RESTRUCTURE is NONE or DELETE?  */
+  change->action = RESTRUCTURE_ADD_ABSENT;
+  change->kind = svn_kind_dir;
 
   return SVN_NO_ERROR;
 }
@@ -810,6 +798,7 @@ ev2_add_file(const char *path,
 
   /* ### assert that RESTRUCTURE is NONE or DELETE?  */
   change->action = RESTRUCTURE_ADD;
+  change->kind = svn_kind_file;
 
   fb->eb = pb->eb;
   fb->path = apr_pstrdup(result_pool, relpath);
@@ -818,14 +807,8 @@ ev2_add_file(const char *path,
 
   if (!copyfrom_path)
     {
-      /* A simple add. */
-      svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
-
       /* Don't bother fetching the base, as in an add we don't have a base. */
       fb->delta_base = NULL;
-
-      *kind = svn_kind_file;
-      SVN_ERR(add_action(pb->eb, relpath, ACTION_ADD, kind));
     }
   else
     {
@@ -841,10 +824,6 @@ ev2_add_file(const char *path,
                                       change->copyfrom_path,
                                       change->copyfrom_rev,
                                       result_pool, scratch_pool));
-
-      args->copyfrom_path = change->copyfrom_path;
-      args->copyfrom_rev = change->copyfrom_rev;
-      SVN_ERR(add_action(pb->eb, relpath, ACTION_COPY, args));
     }
 
   return SVN_NO_ERROR;
@@ -936,9 +915,9 @@ ev2_apply_textdelta(void *file_baton,
 
   change = locate_change(fb->eb, fb->path);
   SVN_ERR_ASSERT(change->contents_abspath == NULL);
-  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(change->base_revision)
-                 || change->base_revision == fb->base_revision);
-  change->base_revision = fb->base_revision;
+  SVN_ERR_ASSERT(!SVN_IS_VALID_REVNUM(change->changing)
+                 || change->changing == fb->base_revision);
+  change->changing = fb->base_revision;
 
   if (! fb->delta_base)
     hb->source = svn_stream_empty(handler_pool);
@@ -975,7 +954,13 @@ ev2_change_file_prop(void *file_baton,
     {
       /* We special case the lock token propery deletion, which is the
          server's way of telling the client to unlock the path. */
-      SVN_ERR(add_action(fb->eb, fb->path, ACTION_UNLOCK, NULL));
+
+      /* ### this duplicates much of apply_propedit(). fix in future.  */
+      const char *relpath = map_to_repos_relpath(fb->eb, fb->path,
+                                                 scratch_pool);
+      struct change_node *change = locate_change(fb->eb, relpath);
+
+      change->unlock = TRUE;
     }
 
   SVN_ERR(apply_propedit(fb->eb, fb->path, svn_kind_file, fb->base_revision,
@@ -998,11 +983,12 @@ ev2_absent_file(const char *path,
                 apr_pool_t *scratch_pool)
 {
   struct ev2_dir_baton *pb = parent_baton;
-  svn_kind_t *kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
   const char *relpath = map_to_repos_relpath(pb->eb, path, scratch_pool);
+  struct change_node *change = locate_change(pb->eb, relpath);
 
-  *kind = svn_kind_file;
-  SVN_ERR(add_action(pb->eb, relpath, ACTION_ADD_ABSENT, kind));
+  /* ### assert that RESTRUCTURE is NONE or DELETE?  */
+  change->action = RESTRUCTURE_ADD_ABSENT;
+  change->kind = svn_kind_file;
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/editor.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/editor.c Thu Apr 26 20:37:17 2012
@@ -221,6 +221,13 @@ svn_editor_create(svn_editor_t **editor,
 }
 
 
+void *
+svn_editor_get_baton(const svn_editor_t *editor)
+{
+  return editor->baton;
+}
+
+
 svn_error_t *
 svn_editor_setcb_add_directory(svn_editor_t *editor,
                                svn_editor_cb_add_directory_t callback,

Modified: subversion/branches/ev2-export/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs/editor.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs/editor.c Thu Apr 26 20:37:17 2012
@@ -29,43 +29,376 @@
 #include "svn_editor.h"
 #include "svn_fs.h"
 
+#include "svn_private_config.h"
+
 #include "fs-loader.h"
 
 
 struct edit_baton {
+  /* The transaction associated with this editor.  */
   svn_fs_txn_t *txn;
-  svn_boolean_t no_autocommit;
+
+  /* Has this editor been completed?  */
+  svn_boolean_t completed;
+
+  /* We sometimes need the cancellation beyond what svn_editor_t provides  */
+  svn_cancel_func_t cancel_func;
+  void *cancel_baton;
+
+  /* The pool that the txn lives within. When we create a ROOT, it will
+     be allocated within a subpool of this. The root will be closed in
+     complete/abort and that subpool will be destroyed.
+
+     This pool SHOULD NOT be used for any allocations.  */
+  apr_pool_t *txn_pool;
+
+  /* This is the root from the txn. Use get_root() to fetch/create this
+     member as appropriate.  */
+  svn_fs_root_t *root;
 };
 
+#define FSPATH(relpath, pool) apr_pstrcat(pool, "/", relpath, NULL)
+#define UNUSED(x) ((void)(x))
+
+
+static svn_error_t *
+get_root(svn_fs_root_t **root,
+         struct edit_baton *eb)
+{
+  if (eb->root == NULL)
+    SVN_ERR(svn_fs_txn_root(&eb->root, eb->txn, eb->txn_pool));
+  *root = eb->root;
+  return SVN_NO_ERROR;
+}
+
+
+/* Apply each property in PROPS to the node at FSPATH in ROOT.  */
+static svn_error_t *
+add_new_props(svn_fs_root_t *root,
+              const char *fspath,
+              apr_hash_t *props,
+              apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_index_t *hi;
+
+  /* ### it would be nice to have svn_fs_set_node_props(). but since we
+     ### don't... add each property to the node. this is a new node, so
+     ### we don't need to worry about deleting props. just adding.  */
+
+  for (hi = apr_hash_first(scratch_pool, props); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      const svn_string_t *value = svn__apr_hash_index_val(hi);
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(svn_fs_change_node_prop(root, fspath, name, value, iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_directory_t */
+static svn_error_t *
+add_directory_cb(void *baton,
+                 const char *relpath,
+                 const apr_array_header_t *children,
+                 apr_hash_t *props,
+                 svn_revnum_t replaces_rev,
+                 apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  const char *fspath = FSPATH(relpath, scratch_pool);
+  svn_fs_root_t *root;
+
+  /* Note: we ignore CHILDREN. We have no "incomplete" state to worry about,
+     so we don't need to be aware of what children will be created.  */
+
+  SVN_ERR(get_root(&root, eb));
+
+  /* ### validate REPLACES_REV  */
+
+  SVN_ERR(svn_fs_make_dir(root, fspath, scratch_pool));
+  SVN_ERR(add_new_props(root, fspath, props, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_file_t */
+static svn_error_t *
+add_file_cb(void *baton,
+            const char *relpath,
+            const svn_checksum_t *checksum,
+            svn_stream_t *contents,
+            apr_hash_t *props,
+            svn_revnum_t replaces_rev,
+            apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  const char *fspath = FSPATH(relpath, scratch_pool);
+  svn_fs_root_t *root;
+  svn_stream_t *fs_contents;
+
+  SVN_ERR(get_root(&root, eb));
+
+  /* ### do something with CHECKSUM  */
+  /* ### validate REPLACES_REV  */
+
+  SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool));
+
+  /* ### We probably don't have an MD5 checksum, so no digest is available
+     ### for svn_fs_apply_text() to validate. It would be nice to have an
+     ### FS API that takes our CONTENTS/CHECKSUM pair (and PROPS!).  */
+  SVN_ERR(svn_fs_apply_text(&fs_contents, root, fspath,
+                            NULL /* result_checksum */,
+                            scratch_pool));
+  SVN_ERR(svn_stream_copy3(contents, fs_contents,
+                           eb->cancel_func, eb->cancel_baton,
+                           scratch_pool));
+
+  SVN_ERR(add_new_props(root, fspath, props, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_symlink_t */
+static svn_error_t *
+add_symlink_cb(void *baton,
+               const char *relpath,
+               const char *target,
+               apr_hash_t *props,
+               svn_revnum_t replaces_rev,
+               apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  const char *fspath = FSPATH(relpath, scratch_pool);
+  svn_fs_root_t *root;
+  svn_stream_t *fs_contents;
+
+  SVN_ERR(get_root(&root, eb));
+
+  /* ### validate REPLACES_REV  */
+
+  /* ### we probably need to construct a file with specific contents
+     ### (until the FS grows some symlink APIs)  */
+#if 0
+  SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool));
+  SVN_ERR(svn_fs_apply_text(&fs_contents, root, fspath,
+                            NULL /* result_checksum */,
+                            scratch_pool));
+  /* ### SVN_ERR(svn_stream_printf(fs_contents, ..., scratch_pool));  */
+  apr_hash_set(props, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING,
+               SVN_PROP_SPECIAL_VALUE);
+
+  SVN_ERR(add_new_props(root, fspath, props, scratch_pool));
+#endif
+  UNUSED(fspath); UNUSED(fs_contents);
+
+  SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_add_absent_t */
+static svn_error_t *
+add_absent_cb(void *baton,
+              const char *relpath,
+              svn_kind_t kind,
+              svn_revnum_t replaces_rev,
+              apr_pool_t *scratch_pool)
+{
+  /* This is a programming error. Code should not attempt to create these
+     kinds of nodes within the FS.  */
+  return svn_error_create(
+           SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+           N_("The filesystem does not support 'absent' nodes"));
+}
+
+
+/* This implements svn_editor_cb_alter_directory_t */
+static svn_error_t *
+alter_directory_cb(void *baton,
+                   const char *relpath,
+                   svn_revnum_t revision,
+                   apr_hash_t *props,
+                   apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_alter_file_t */
+static svn_error_t *
+alter_file_cb(void *baton,
+              const char *relpath,
+              svn_revnum_t revision,
+              apr_hash_t *props,
+              const svn_checksum_t *checksum,
+              svn_stream_t *contents,
+              apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_alter_symlink_t */
+static svn_error_t *
+alter_symlink_cb(void *baton,
+                 const char *relpath,
+                 svn_revnum_t revision,
+                 apr_hash_t *props,
+                 const char *target,
+                 apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_delete_t */
+static svn_error_t *
+delete_cb(void *baton,
+          const char *relpath,
+          svn_revnum_t revision,
+          apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_copy_t */
+static svn_error_t *
+copy_cb(void *baton,
+        const char *src_relpath,
+        svn_revnum_t src_revision,
+        const char *dst_relpath,
+        svn_revnum_t replaces_rev,
+        apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_move_t */
+static svn_error_t *
+move_cb(void *baton,
+        const char *src_relpath,
+        svn_revnum_t src_revision,
+        const char *dst_relpath,
+        svn_revnum_t replaces_rev,
+        apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_rotate_t */
+static svn_error_t *
+rotate_cb(void *baton,
+          const apr_array_header_t *relpaths,
+          const apr_array_header_t *revisions,
+          apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  UNUSED(eb); SVN__NOT_IMPLEMENTED();
+}
+
+
+/* This implements svn_editor_cb_complete_t */
+static svn_error_t *
+complete_cb(void *baton,
+            apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+
+  /* Watch out for a following call to svn_fs_editor_commit(). Note that
+     we are likely here because svn_fs_editor_commit() was called, and it
+     invoked svn_editor_complete().  */
+  eb->completed = TRUE;
+
+  if (eb->root != NULL)
+    {
+      svn_fs_close_root(eb->root);
+      eb->root = NULL;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_abort_t */
+static svn_error_t *
+abort_cb(void *baton,
+         apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  svn_error_t *err;
+
+  /* Don't allow a following call to svn_fs_editor_commit().  */
+  eb->completed = TRUE;
+
+  if (eb->root != NULL)
+    {
+      svn_fs_close_root(eb->root);
+      eb->root = NULL;
+    }
+
+  /* ### should we examine the error and attempt svn_fs_purge_txn() ?  */
+  err = svn_fs_abort_txn(eb->txn, scratch_pool);
+
+  /* For safety, clear the now-useless txn.  */
+  eb->txn = NULL;
+
+  return svn_error_trace(err);
+}
+
 
 static svn_error_t *
 make_editor(svn_editor_t **editor,
             svn_fs_txn_t *txn,
-            svn_boolean_t no_autocommit,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
             apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
 {
   static const svn_editor_cb_many_t editor_cbs = {
-    NULL /* add_directory_cb */,
-    NULL /* add_file_cb */,
-    NULL /* add_symlink_cb */,
-    NULL /* add_absent_cb */,
-    NULL /* alter_directory_cb */,
-    NULL /* alter_file_cb */,
-    NULL /* alter_symlink_cb */,
-    NULL /* delete_cb */,
-    NULL /* copy_cb */,
-    NULL /* move_cb */,
-    NULL /* rotate_cb */,
-    NULL /* complete_cb */,
-    NULL /* abort_cb */
+    add_directory_cb,
+    add_file_cb,
+    add_symlink_cb,
+    add_absent_cb,
+    alter_directory_cb,
+    alter_file_cb,
+    alter_symlink_cb,
+    delete_cb,
+    copy_cb,
+    move_cb,
+    rotate_cb,
+    complete_cb,
+    abort_cb
   };
-  struct edit_baton *eb = apr_palloc(result_pool, sizeof(*eb));
+  struct edit_baton *eb = apr_pcalloc(result_pool, sizeof(*eb));
 
   eb->txn = txn;
-  eb->no_autocommit = no_autocommit;
+  eb->cancel_func = cancel_func;
+  eb->cancel_baton = cancel_baton;
+  eb->txn_pool = result_pool;
 
   SVN_ERR(svn_editor_create(editor, eb, cancel_func, cancel_baton,
                             result_pool, scratch_pool));
@@ -79,19 +412,19 @@ svn_error_t *
 svn_fs_editor_create(svn_editor_t **editor,
                      const char **txn_name,
                      svn_fs_t *fs,
-                     svn_revnum_t revision,
                      apr_uint32_t flags,
                      svn_cancel_func_t cancel_func,
                      void *cancel_baton,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
+  svn_revnum_t revision;
   svn_fs_txn_t *txn;
-  svn_boolean_t no_autocommit = (flags & SVN_FS_TXN_NO_AUTOCOMMIT) != 0;
 
+  SVN_ERR(svn_fs_youngest_rev(&revision, fs, scratch_pool));
   SVN_ERR(svn_fs_begin_txn2(&txn, fs, revision, flags, result_pool));
   SVN_ERR(svn_fs_txn_name(txn_name, txn, result_pool));
-  return svn_error_trace(make_editor(editor, txn, no_autocommit,
+  return svn_error_trace(make_editor(editor, txn,
                                      cancel_func, cancel_baton,
                                      result_pool, scratch_pool));
 }
@@ -109,8 +442,84 @@ svn_fs_editor_create_for(svn_editor_t **
   svn_fs_txn_t *txn;
 
   SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, result_pool));
-  return svn_error_trace(make_editor(editor, txn, TRUE /* no_autocommit */,
+  return svn_error_trace(make_editor(editor, txn,
                                      cancel_func, cancel_baton,
                                      result_pool, scratch_pool));
 }
 
+
+svn_error_t *
+svn_fs_editor_commit(svn_revnum_t *revision,
+                     svn_error_t **post_commit_err,
+                     const char **conflict_path,
+                     svn_editor_t *editor,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = svn_editor_get_baton(editor);
+  const char *inner_conflict_path;
+  svn_error_t *err = NULL;
+
+  /* make sure people are using the correct sequencing.  */
+  if (eb->completed)
+    return svn_error_create(SVN_ERR_FS_INCORRECT_EDITOR_COMPLETION,
+                            NULL, NULL);
+
+  *revision = SVN_INVALID_REVNUM;
+  *post_commit_err = NULL;
+  *conflict_path = NULL;
+
+  /* Clean up internal resources (eg. eb->root). This also allows the
+     editor infrastructure to know this editor is "complete".  */
+  err = svn_editor_complete(editor);
+
+  /* Note: docco for svn_fs_commit_txn() states that CONFLICT_PATH will
+     be allocated in the txn's pool. But it lies. Regardless, we want
+     it placed into RESULT_POOL.  */
+
+  if (!err)
+    err = svn_fs_commit_txn(&inner_conflict_path,
+                            revision,
+                            eb->txn,
+                            scratch_pool);
+  if (SVN_IS_VALID_REVNUM(*revision))
+    {
+      if (err)
+        {
+          /* Case 3. ERR is a post-commit (cleanup) error.  */
+
+          /* Pass responsibility via POST_COMMIT_ERR.  */
+          *post_commit_err = err;
+          err = SVN_NO_ERROR;
+        }
+      /* else: Case 1.  */
+    }
+  else
+    {
+      SVN_ERR_ASSERT(err != NULL);
+      if (err->apr_err == SVN_ERR_FS_CONFLICT)
+        {
+          /* Case 2.  */
+
+          /* Copy this into the correct pool (see note above).  */
+          *conflict_path = apr_pstrdup(result_pool, inner_conflict_path);
+
+          /* Return sucess. The caller should inspect CONFLICT_PATH to
+             determine this particular case.  */
+          svn_error_clear(err);
+          err = SVN_NO_ERROR;
+        }
+      /* else: Case 4.  */
+
+      /* Abort the TXN. Nobody wants to use it.  */
+      /* ### should we examine the error and attempt svn_fs_purge_txn() ?  */
+      err = svn_error_compose_create(
+        err,
+        svn_fs_abort_txn(eb->txn, scratch_pool));
+    }
+
+  /* For safety, clear the now-useless txn.  */
+  eb->txn = NULL;
+
+  return svn_error_trace(err);
+}

Modified: subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c Thu Apr 26 20:37:17 2012
@@ -645,6 +645,7 @@ svn_error_t *
 svn_fs_commit_txn(const char **conflict_p, svn_revnum_t *new_rev,
                   svn_fs_txn_t *txn, apr_pool_t *pool)
 {
+  svn_error_t *err;
 #ifdef PACK_AFTER_EVERY_COMMIT
   svn_fs_root_t *txn_root;
   svn_fs_t *fs;
@@ -656,11 +657,25 @@ svn_fs_commit_txn(const char **conflict_
   fs_path = svn_fs_path(fs, pool);
 #endif
 
-  SVN_ERR(txn->vtable->commit(conflict_p, new_rev, txn, pool));
+  err = txn->vtable->commit(conflict_p, new_rev, txn, pool);
+
+#ifdef SVN_DEBUG
+  /* Check postconditions. */
+  if (conflict_p)
+    {
+      SVN_ERR_ASSERT_E(! (SVN_IS_VALID_REVNUM(*new_rev) && *conflict_p != NULL),
+                       err);
+      SVN_ERR_ASSERT_E((*conflict_p != NULL)
+                       == (err && err->apr_err == SVN_ERR_FS_CONFLICT),
+                       err);
+    }
+#endif
+
+  SVN_ERR(err);
 
 #ifdef PACK_AFTER_EVERY_COMMIT
   {
-    svn_error_t *err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
+    err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
     if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
       /* Pre-1.6 filesystem. */
       svn_error_clear(err);
@@ -1218,7 +1233,9 @@ svn_fs_get_file_delta_stream(svn_txdelta
 svn_error_t *
 svn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool)
 {
-  return svn_error_trace(fs->vtable->get_uuid(fs, uuid, pool));
+  /* If you change this, consider changing svn_fs__identifier(). */
+  *uuid = apr_pstrdup(pool, fs->uuid);
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *

Modified: subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.h Thu Apr 26 20:37:17 2012
@@ -172,7 +172,7 @@ typedef struct fs_vtable_t
                                   const svn_string_t *const *old_value_p,
                                   const svn_string_t *value,
                                   apr_pool_t *pool);
-  svn_error_t *(*get_uuid)(svn_fs_t *fs, const char **uuid, apr_pool_t *pool);
+  /* There is no get_uuid(); see svn_fs_t.uuid docstring. */
   svn_error_t *(*set_uuid)(svn_fs_t *fs, const char *uuid, apr_pool_t *pool);
   svn_error_t *(*revision_root)(svn_fs_root_t **root_p, svn_fs_t *fs,
                                 svn_revnum_t rev, apr_pool_t *pool);
@@ -391,6 +391,9 @@ struct svn_fs_t
   /* FSAP-specific vtable and private data */
   fs_vtable_t *vtable;
   void *fsap_data;
+
+  /* UUID, stored by open(), create(), and set_uuid(). */
+  const char *uuid;
 };
 
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.c Thu Apr 26 20:37:17 2012
@@ -473,15 +473,6 @@ bdb_write_config(svn_fs_t *fs)
 
 
 
-static svn_error_t *
-base_serialized_init(svn_fs_t *fs, apr_pool_t *common_pool, apr_pool_t *pool)
-{
-  /* Nothing to do here. */
-  return SVN_NO_ERROR;
-}
-
-
-
 /* Creating a new filesystem */
 
 static fs_vtable_t fs_vtable = {
@@ -489,7 +480,6 @@ static fs_vtable_t fs_vtable = {
   svn_fs_base__revision_prop,
   svn_fs_base__revision_proplist,
   svn_fs_base__change_rev_prop,
-  svn_fs_base__get_uuid,
   svn_fs_base__set_uuid,
   svn_fs_base__revision_root,
   svn_fs_base__begin_txn,
@@ -656,6 +646,15 @@ open_databases(svn_fs_t *fs,
 }
 
 
+/* Called by functions that initialize an svn_fs_t struct, after that 
+   initialization is done, to populate svn_fs_t->uuid. */
+static svn_error_t *
+populate_opened_fs(svn_fs_t *fs, apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_fs_base__populate_uuid(fs, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 base_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
             apr_pool_t *common_pool)
@@ -691,7 +690,9 @@ base_create(svn_fs_t *fs, const char *pa
   if (svn_err) goto error;
 
   ((base_fs_data_t *) fs->fsap_data)->format = format;
-  return base_serialized_init(fs, common_pool, pool);
+
+  SVN_ERR(populate_opened_fs(fs, pool));
+  return SVN_NO_ERROR;;
 
 error:
   svn_error_clear(cleanup_fs(fs));
@@ -775,7 +776,8 @@ base_open(svn_fs_t *fs, const char *path
       if (svn_err) goto error;
     }
 
-  return base_serialized_init(fs, common_pool, pool);
+  SVN_ERR(populate_opened_fs(fs, pool));
+  return SVN_NO_ERROR;
 
  error:
   svn_error_clear(cleanup_fs(fs));

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.h?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_base/fs.h Thu Apr 26 20:37:17 2012
@@ -108,9 +108,6 @@ typedef struct base_fs_data_t
      transaction trail alive. */
   svn_boolean_t in_txn_trail;
 
-  /* The filesystem UUID (or NULL if not-yet-known; see svn_fs_get_uuid). */
-  const char *uuid;
-
   /* The format number of this FS. */
   int format;
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_base/tree.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_base/tree.c Thu Apr 26 20:37:17 2012
@@ -3192,17 +3192,7 @@ fs_same_p(svn_boolean_t *same_p,
           svn_fs_t *fs2,
           apr_pool_t *pool)
 {
-  const char *uuid1;
-  const char *uuid2;
-
-  /* Random thought: if fetching UUIDs to compare filesystems is too
-     expensive, one solution would be to cache the UUID in each fs
-     object (copying the UUID into fs->pool, of course). */
-
-  SVN_ERR(fs1->vtable->get_uuid(fs1, &uuid1, pool));
-  SVN_ERR(fs2->vtable->get_uuid(fs2, &uuid2, pool));
-
-  *same_p = ! strcmp(uuid1, uuid2);
+  *same_p = ! strcmp(fs1->uuid, fs2->uuid);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.c Thu Apr 26 20:37:17 2012
@@ -48,39 +48,27 @@ txn_body_get_uuid(void *baton, trail_t *
 
 
 svn_error_t *
-svn_fs_base__get_uuid(svn_fs_t *fs,
-                      const char **uuid,
-                      apr_pool_t *pool)
+svn_fs_base__populate_uuid(svn_fs_t *fs,
+                           apr_pool_t *scratch_pool)
 {
-  base_fs_data_t *bfd = fs->fsap_data;
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
-  /* Check for a cached UUID first.  Failing that, we hit the
-     database. */
-  if (bfd->uuid)
-    {
-      *uuid = apr_pstrdup(pool, bfd->uuid);
-    }
-  else
+  /* We hit the database. */
     {
+      const char *uuid;
       struct get_uuid_args args;
-      apr_pool_t *scratch_pool = svn_pool_create(pool);
 
       args.idx = 1;
-      args.uuid = uuid;
+      args.uuid = &uuid;
       SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_get_uuid, &args,
                                      FALSE, scratch_pool));
 
-      if (*uuid)
+      if (uuid)
         {
-          *uuid = apr_pstrdup(pool, *uuid);
-
           /* Toss what we find into the cache. */
-          bfd->uuid = apr_pstrdup(fs->pool, *uuid);
+          fs->uuid = apr_pstrdup(fs->pool, uuid);
         }
-
-      svn_pool_destroy(scratch_pool);
     }
 
   return SVN_NO_ERROR;
@@ -109,7 +97,6 @@ svn_fs_base__set_uuid(svn_fs_t *fs,
                       apr_pool_t *pool)
 {
   struct set_uuid_args args;
-  base_fs_data_t *bfd = fs->fsap_data;
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
@@ -122,7 +109,7 @@ svn_fs_base__set_uuid(svn_fs_t *fs,
 
   /* Toss our value into the cache. */
   if (uuid)
-    bfd->uuid = apr_pstrdup(fs->pool, uuid);
+    fs->uuid = apr_pstrdup(fs->pool, uuid);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.h?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_base/uuid.h Thu Apr 26 20:37:17 2012
@@ -29,12 +29,15 @@ extern "C" {
 
 
 
+/* Set FS->UUID to the the value read from the database, allocated
+   in FS->POOL.  Use SCRATCH_POOL for temporary allocations. */
+svn_error_t *svn_fs_base__populate_uuid(svn_fs_t *fs,
+                                        apr_pool_t *scratch_pool);
+
+
 /* These functions implement some of the calls in the FS loader
    library's fs vtable. */
 
-svn_error_t *svn_fs_base__get_uuid(svn_fs_t *fs, const char **uuid,
-                                   apr_pool_t *pool);
-
 svn_error_t *svn_fs_base__set_uuid(svn_fs_t *fs, const char *uuid,
                                    apr_pool_t *pool);
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/caching.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/caching.c Thu Apr 26 20:37:17 2012
@@ -252,7 +252,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   const char *prefix = apr_pstrcat(pool,
-                                   "fsfs:", ffd->uuid,
+                                   "fsfs:", fs->uuid,
                                    "/", fs->path, ":",
                                    (char *)NULL);
   svn_memcache_t *memcache;
@@ -495,7 +495,7 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
      to start a new transaction later that receives the same id.
      Therefore, throw in a uuid as well - just to be sure. */
   const char *prefix = apr_pstrcat(pool,
-                                   "fsfs:", ffd->uuid,
+                                   "fsfs:", fs->uuid,
                                    "/", fs->path,
                                    ":", txn_id,
                                    ":", svn_uuid_generate(pool), ":",

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.c Thu Apr 26 20:37:17 2012
@@ -73,7 +73,7 @@ fs_serialized_init(svn_fs_t *fs, apr_poo
      know of a better way of associating such data with the
      repository. */
 
-  key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX, ffd->uuid,
+  key = apr_pstrcat(pool, SVN_FSFS_SHARED_USERDATA_PREFIX, fs->uuid,
                     (char *) NULL);
   status = apr_pool_userdata_get(&val, key, common_pool);
   if (status)
@@ -130,7 +130,6 @@ static fs_vtable_t fs_vtable = {
   svn_fs_fs__revision_prop,
   svn_fs_fs__revision_proplist,
   svn_fs_fs__change_rev_prop,
-  svn_fs_fs__get_uuid,
   svn_fs_fs__set_uuid,
   svn_fs_fs__revision_root,
   svn_fs_fs__begin_txn,

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs.h Thu Apr 26 20:37:17 2012
@@ -218,9 +218,6 @@ typedef struct fs_fs_data_t
      layouts) or zero (for linear layouts). */
   int max_files_per_dir;
 
-  /* The uuid of this FS. */
-  const char *uuid;
-
   /* The revision that was youngest, last time we checked. */
   svn_revnum_t youngest_rev_cache;
 

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.c Thu Apr 26 20:37:17 2012
@@ -1307,7 +1307,7 @@ svn_fs_fs__open(svn_fs_t *fs, const char
 
   limit = sizeof(buf);
   SVN_ERR(svn_io_read_length_line(uuid_file, buf, &limit, pool));
-  ffd->uuid = apr_pstrdup(fs->pool, buf);
+  fs->uuid = apr_pstrdup(fs->pool, buf);
 
   SVN_ERR(svn_io_file_close(uuid_file, pool));
 
@@ -7500,17 +7500,6 @@ svn_fs_fs__recover(svn_fs_t *fs,
 }
 
 svn_error_t *
-svn_fs_fs__get_uuid(svn_fs_t *fs,
-                    const char **uuid_p,
-                    apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  *uuid_p = apr_pstrdup(pool, ffd->uuid);
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
 svn_fs_fs__set_uuid(svn_fs_t *fs,
                     const char *uuid,
                     apr_pool_t *pool)
@@ -7519,7 +7508,6 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
   apr_size_t my_uuid_len;
   const char *tmp_path;
   const char *uuid_path = path_uuid(fs, pool);
-  fs_fs_data_t *ffd = fs->fsap_data;
 
   if (! uuid)
     uuid = svn_uuid_generate(pool);
@@ -7540,7 +7528,7 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
 
   /* Remove the newline we added, and stash the UUID. */
   my_uuid[my_uuid_len - 1] = '\0';
-  ffd->uuid = my_uuid;
+  fs->uuid = my_uuid;
 
   return SVN_NO_ERROR;
 }
@@ -8709,7 +8697,7 @@ hotcopy_incremental_check_preconditions(
 
   /* Make sure the UUID of source and destination match up.
    * We don't want to copy over a different repository. */
-  if (strcmp(src_ffd->uuid, dst_ffd->uuid) != 0)
+  if (strcmp(src_fs->uuid, dst_fs->uuid) != 0)
     return svn_error_create(SVN_ERR_RA_UUID_MISMATCH, NULL,
                             _("The UUID of the hotcopy source does "
                               "not match the UUID of the hotcopy "
@@ -9155,7 +9143,7 @@ hotcopy_create_empty_dest(svn_fs_t *src_
 
   /* Create lock file and UUID. */
   SVN_ERR(svn_io_file_create(path_lock(dst_fs, pool), "", pool));
-  SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_ffd->uuid, pool));
+  SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_fs->uuid, pool));
 
   /* Create the min unpacked rev file. */
   if (dst_ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/fs_fs.h Thu Apr 26 20:37:17 2012
@@ -355,12 +355,6 @@ svn_error_t *svn_fs_fs__create(svn_fs_t 
                                const char *path,
                                apr_pool_t *pool);
 
-/* Store the uuid of the repository FS in *UUID.  Allocate space in
-   POOL. */
-svn_error_t *svn_fs_fs__get_uuid(svn_fs_t *fs,
-                                 const char **uuid,
-                                 apr_pool_t *pool);
-
 /* Set the uuid of repository FS to UUID, if UUID is not NULL;
    otherwise, set the uuid of FS to a newly generated UUID.  Perform
    temporary allocations in POOL. */

Modified: subversion/branches/ev2-export/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs_fs/tree.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs_fs/tree.c Thu Apr 26 20:37:17 2012
@@ -1925,17 +1925,7 @@ fs_same_p(svn_boolean_t *same_p,
           svn_fs_t *fs2,
           apr_pool_t *pool)
 {
-  const char *uuid1;
-  const char *uuid2;
-
-  /* Random thought: if fetching UUIDs to compare filesystems is too
-     expensive, one solution would be to cache the UUID in each fs
-     object (copying the UUID into fs->pool, of course). */
-
-  SVN_ERR(fs1->vtable->get_uuid(fs1, &uuid1, pool));
-  SVN_ERR(fs2->vtable->get_uuid(fs2, &uuid2, pool));
-
-  *same_p = ! strcmp(uuid1, uuid2);
+  *same_p = ! strcmp(fs1->uuid, fs2->uuid);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_local/ra_plugin.c Thu Apr 26 20:37:17 2012
@@ -76,8 +76,6 @@ get_username(svn_ra_session_t *session,
              apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  svn_auth_iterstate_t *iterstate;
-  svn_fs_access_t *access_ctx;
 
   /* If we've already found the username don't ask for it again. */
   if (! sess->username)
@@ -88,6 +86,8 @@ get_username(svn_ra_session_t *session,
         {
           void *creds;
           svn_auth_cred_username_t *username_creds;
+          svn_auth_iterstate_t *iterstate;
+
           SVN_ERR(svn_auth_first_credentials(&creds, &iterstate,
                                              SVN_AUTH_CRED_USERNAME,
                                              sess->uuid, /* realmstring */
@@ -118,6 +118,8 @@ get_username(svn_ra_session_t *session,
   */
   if (*sess->username)
     {
+      svn_fs_access_t *access_ctx;
+
       SVN_ERR(svn_fs_create_access(&access_ctx, sess->username,
                                    session->pool));
       SVN_ERR(svn_fs_set_access(sess->fs, access_ctx));
@@ -367,11 +369,12 @@ struct deltify_etc_baton
 {
   svn_fs_t *fs;                     /* the fs to deltify in */
   svn_repos_t *repos;               /* repos for unlocking */
-  const char *fs_path;              /* fs-path part of split session URL */
+  const char *fspath_base;          /* fs-path part of split session URL */
+
   apr_hash_t *lock_tokens;          /* tokens to unlock, if any */
-  apr_pool_t *pool;                 /* pool for scratch work */
-  svn_commit_callback2_t callback;  /* the original callback */
-  void *callback_baton;             /* the original callback's baton */
+
+  svn_commit_callback2_t commit_cb; /* the original callback */
+  void *commit_baton;               /* the original callback's baton */
 };
 
 /* This implements 'svn_commit_callback_t'.  Its invokes the original
@@ -380,60 +383,107 @@ struct deltify_etc_baton
    BATON is 'struct deltify_etc_baton *'. */
 static svn_error_t *
 deltify_etc(const svn_commit_info_t *commit_info,
-            void *baton, apr_pool_t *pool)
+            void *baton,
+            apr_pool_t *scratch_pool)
 {
-  struct deltify_etc_baton *db = baton;
+  struct deltify_etc_baton *deb = baton;
   svn_error_t *err1 = SVN_NO_ERROR;
   svn_error_t *err2;
-  apr_hash_index_t *hi;
-  apr_pool_t *iterpool;
 
   /* Invoke the original callback first, in case someone's waiting to
      know the revision number so they can go off and annotate an
      issue or something. */
-  if (db->callback)
-    err1 = db->callback(commit_info, db->callback_baton, pool);
+  if (deb->commit_cb)
+    err1 = deb->commit_cb(commit_info, deb->commit_baton, scratch_pool);
 
   /* Maybe unlock the paths. */
-  if (db->lock_tokens)
+  if (deb->lock_tokens)
     {
-      iterpool = svn_pool_create(db->pool);
-      for (hi = apr_hash_first(db->pool, db->lock_tokens); hi;
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      apr_hash_index_t *hi;
+
+      for (hi = apr_hash_first(scratch_pool, deb->lock_tokens); hi;
            hi = apr_hash_next(hi))
         {
-          const void *rel_path;
-          void *val;
-          const char *abs_path, *token;
+          const void *relpath = svn__apr_hash_index_key(hi);
+          const char *token = svn__apr_hash_index_val(hi);
+          const char *fspath;
 
           svn_pool_clear(iterpool);
-          apr_hash_this(hi, &rel_path, NULL, &val);
-          token = val;
-          abs_path = svn_fspath__join(db->fs_path, rel_path, iterpool);
+
+          fspath = svn_fspath__join(deb->fspath_base, relpath, iterpool);
+
           /* We may get errors here if the lock was broken or stolen
              after the commit succeeded.  This is fine and should be
              ignored. */
-          svn_error_clear(svn_repos_fs_unlock(db->repos, abs_path, token,
+          svn_error_clear(svn_repos_fs_unlock(deb->repos, fspath, token,
                                               FALSE, iterpool));
         }
+
       svn_pool_destroy(iterpool);
     }
 
   /* But, deltification shouldn't be stopped just because someone's
      random callback failed, so proceed unconditionally on to
      deltification. */
-  err2 = svn_fs_deltify_revision(db->fs, commit_info->revision, db->pool);
+  err2 = svn_fs_deltify_revision(deb->fs, commit_info->revision, scratch_pool);
+
+  return svn_error_compose_create(err1, err2);
+}
+
 
-  /* It's more interesting if the original callback failed, so let
-     that one dominate. */
-  if (err1)
+/* If LOCK_TOKENS is not NULL, then copy all tokens into the access context
+   of FS. The tokens' paths will be prepended with FSPATH_BASE.
+
+   ACCESS_POOL must match (or exceed) the lifetime of the access context
+   that was associated with FS. Typically, this is the session pool.
+
+   Temporary allocations are made in SCRATCH_POOL.  */
+static svn_error_t *
+apply_lock_tokens(svn_fs_t *fs,
+                  const char *fspath_base,
+                  apr_hash_t *lock_tokens,
+                  apr_pool_t *access_pool,
+                  apr_pool_t *scratch_pool)
+{
+  if (lock_tokens)
     {
-      svn_error_clear(err2);
-      return err1;
+      svn_fs_access_t *access_ctx;
+
+      SVN_ERR(svn_fs_get_access(&access_ctx, fs));
+
+      /* If there is no access context, the filesystem will scream if a
+         lock is needed.  */
+      if (access_ctx)
+        {
+          apr_hash_index_t *hi;
+
+          /* Note: we have no use for an iterpool here since the data
+             within the loop is copied into ACCESS_POOL.  */
+
+          for (hi = apr_hash_first(scratch_pool, lock_tokens); hi;
+               hi = apr_hash_next(hi))
+            {
+              const void *relpath = svn__apr_hash_index_key(hi);
+              const char *token = svn__apr_hash_index_val(hi);
+              const char *fspath;
+
+              /* The path needs to live as long as ACCESS_CTX.  */
+              fspath = svn_fspath__join(fspath_base, relpath, access_pool);
+
+              /* The token must live as long as ACCESS_CTX.  */
+              token = apr_pstrdup(access_pool, token);
+
+              SVN_ERR(svn_fs_access_add_lock_token2(access_ctx, fspath,
+                                                    token));
+            }
+        }
     }
 
-  return err2;
+  return SVN_NO_ERROR;
 }
 
+
 /*----------------------------------------------------------------*/
 
 /*** The RA vtable routines ***/
@@ -679,47 +729,24 @@ svn_ra_local__get_commit_editor(svn_ra_s
                                 apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  struct deltify_etc_baton *db = apr_palloc(pool, sizeof(*db));
-  apr_hash_index_t *hi;
-  svn_fs_access_t *fs_access;
+  struct deltify_etc_baton *deb = apr_palloc(pool, sizeof(*deb));
 
-  db->fs = sess->fs;
-  db->repos = sess->repos;
-  db->fs_path = sess->fs_path->data;
+  /* Prepare the baton for deltify_etc()  */
+  deb->fs = sess->fs;
+  deb->repos = sess->repos;
+  deb->fspath_base = sess->fs_path->data;
   if (! keep_locks)
-    db->lock_tokens = lock_tokens;
+    deb->lock_tokens = lock_tokens;
   else
-    db->lock_tokens = NULL;
-  db->pool = pool;
-  db->callback = callback;
-  db->callback_baton = callback_baton;
+    deb->lock_tokens = NULL;
+  deb->commit_cb = callback;
+  deb->commit_baton = callback_baton;
 
   SVN_ERR(get_username(session, pool));
 
   /* If there are lock tokens to add, do so. */
-  if (lock_tokens)
-    {
-      SVN_ERR(svn_fs_get_access(&fs_access, sess->fs));
-
-      /* If there is no access context, the filesystem will scream if a
-         lock is needed. */
-      if (fs_access)
-        {
-          for (hi = apr_hash_first(pool, lock_tokens); hi;
-               hi = apr_hash_next(hi))
-            {
-              void *val;
-              const char *abs_path, *token;
-              const void *key;
-
-              apr_hash_this(hi, &key, NULL, &val);
-              abs_path = svn_fspath__join(sess->fs_path->data, key, pool);
-              token = val;
-              SVN_ERR(svn_fs_access_add_lock_token2(fs_access,
-                                                    abs_path, token));
-            }
-        }
-    }
+  SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
+                            session->pool, pool));
 
   /* Copy the revprops table so we can add the username. */
   revprop_table = apr_hash_copy(pool, revprop_table);
@@ -730,7 +757,7 @@ svn_ra_local__get_commit_editor(svn_ra_s
   return svn_repos_get_commit_editor5
          (editor, edit_baton, sess->repos, NULL,
           svn_path_uri_decode(sess->repos_url, pool), sess->fs_path->data,
-          revprop_table, deltify_etc, db, NULL, NULL, pool);
+          revprop_table, deltify_etc, deb, NULL, NULL, pool);
 }
 
 
@@ -1514,6 +1541,62 @@ svn_ra_local__register_editor_shim_callb
   return SVN_NO_ERROR;
 }
 
+
+static svn_error_t *
+svn_ra_local__get_commit_ev2(svn_editor_t **editor,
+                             svn_ra_session_t *session,
+                             apr_hash_t *revprops,
+                             svn_commit_callback2_t commit_cb,
+                             void *commit_baton,
+                             apr_hash_t *lock_tokens,
+                             svn_boolean_t keep_locks,
+                             svn_ra__provide_base_cb_t provide_base_cb,
+                             svn_ra__provide_props_cb_t provide_props_cb,
+                             svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+                             void *cb_baton,
+                             svn_cancel_func_t cancel_func,
+                             void *cancel_baton,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  svn_ra_local__session_baton_t *sess = session->priv;
+  struct deltify_etc_baton *deb = apr_palloc(result_pool, sizeof(*deb));
+
+  /* NOTE: the RA callbacks are ignored. We pass everything directly to
+     the REPOS editor.  */
+
+  /* Prepare the baton for deltify_etc()  */
+  deb->fs = sess->fs;
+  deb->repos = sess->repos;
+  deb->fspath_base = sess->fs_path->data;
+  if (! keep_locks)
+    deb->lock_tokens = lock_tokens;
+  else
+    deb->lock_tokens = NULL;
+  deb->commit_cb = commit_cb;
+  deb->commit_baton = commit_baton;
+
+  /* Ensure there is a username (and an FS access context) associated with
+     the session and its FS handle.  */
+  SVN_ERR(get_username(session, scratch_pool));
+
+  /* If there are lock tokens to add, do so.  */
+  SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
+                            session->pool, scratch_pool));
+
+  /* Copy the REVPROPS and insert the author/username.  */
+  revprops = apr_hash_copy(scratch_pool, revprops);
+  apr_hash_set(revprops, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING,
+               svn_string_create(sess->username, scratch_pool));
+
+  return svn_error_trace(svn_repos__get_commit_ev2(
+                           editor, sess->repos, NULL /* authz */,
+                           NULL /* authz_repos_name */, NULL /* authz_user */,
+                           revprops,
+                           deltify_etc, deb, cancel_func, cancel_baton,
+                           result_pool, scratch_pool));
+}
+
 /*----------------------------------------------------------------*/
 
 static const svn_version_t *
@@ -1561,7 +1644,8 @@ static const svn_ra__vtable_t ra_local_v
   svn_ra_local__has_capability,
   svn_ra_local__replay_range,
   svn_ra_local__get_deleted_rev,
-  svn_ra_local__register_editor_shim_callbacks
+  svn_ra_local__register_editor_shim_callbacks,
+  svn_ra_local__get_commit_ev2
 };
 
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_neon/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_neon/commit.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_neon/commit.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_neon/commit.c Thu Apr 26 20:37:17 2012
@@ -737,6 +737,7 @@ static svn_error_t * commit_open_root(vo
          transaction (and, optionally, a corresponding activity). */
       svn_ra_neon__request_t *req;
       const char *header_val;
+      svn_error_t *err;
 
       SVN_ERR(svn_ra_neon__request_create(&req, cc->ras, "POST",
                                           cc->ras->me_resource, dir_pool));
@@ -749,33 +750,39 @@ static svn_error_t * commit_open_root(vo
                             svn_uuid_generate(dir_pool));
 #endif
 
-      SVN_ERR(svn_ra_neon__request_dispatch(NULL, req, NULL, "( create-txn )",
-                                            201, 0, dir_pool));
-
-      /* Check the response headers for either the virtual transaction
-         details, or the real transaction details.  We need to have
-         one or the other of those!  */
-      if ((header_val = ne_get_response_header(req->ne_req,
-                                               SVN_DAV_VTXN_NAME_HEADER)))
-        {
-          cc->txn_url = svn_path_url_add_component2(cc->ras->vtxn_stub,
-                                                    header_val, cc->pool);
-          cc->txn_root_url
-            = svn_path_url_add_component2(cc->ras->vtxn_root_stub,
-                                          header_val, cc->pool);
-        }
-      else if ((header_val = ne_get_response_header(req->ne_req,
-                                                    SVN_DAV_TXN_NAME_HEADER)))
-        {
-          cc->txn_url = svn_path_url_add_component2(cc->ras->txn_stub,
-                                                    header_val, cc->pool);
-          cc->txn_root_url = svn_path_url_add_component2(cc->ras->txn_root_stub,
-                                                         header_val, cc->pool);
+      err = svn_ra_neon__request_dispatch(NULL, req, NULL, "( create-txn )",
+                                          201, 0, dir_pool);
+      if (!err)
+        {
+          /* Check the response headers for either the virtual transaction
+             details, or the real transaction details.  We need to have
+             one or the other of those!  */
+          if ((header_val = ne_get_response_header(req->ne_req,
+                                                   SVN_DAV_VTXN_NAME_HEADER)))
+            {
+              cc->txn_url = svn_path_url_add_component2(cc->ras->vtxn_stub,
+                                                        header_val, cc->pool);
+              cc->txn_root_url
+                = svn_path_url_add_component2(cc->ras->vtxn_root_stub,
+                                              header_val, cc->pool);
+            }
+          else if ((header_val
+                    = ne_get_response_header(req->ne_req,
+                                             SVN_DAV_TXN_NAME_HEADER)))
+            {
+              cc->txn_url = svn_path_url_add_component2(cc->ras->txn_stub,
+                                                        header_val, cc->pool);
+              cc->txn_root_url
+                = svn_path_url_add_component2(cc->ras->txn_root_stub,
+                                              header_val, cc->pool);
+            }
+          else
+            err = svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+                                    _("POST request did not return transaction "
+                                      "information"));
         }
-      else
-        return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
-                                 _("POST request did not return transaction "
-                                   "information"));
+      svn_ra_neon__request_destroy(req);
+      SVN_ERR(err);
 
       root->rsrc = NULL;
       root->txn_root_url = svn_path_url_add_component2(cc->txn_root_url,

Modified: subversion/branches/ev2-export/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_repos/commit.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_repos/commit.c Thu Apr 26 20:37:17 2012
@@ -136,6 +136,17 @@ struct ev2_baton
   /* The repository we are editing.  */
   svn_repos_t *repos;
 
+  /* The authz baton for checks; NULL to skip authz.  */
+  svn_authz_t *authz;
+
+  /* The repository name and user for performing authz checks.  */
+  const char *authz_repos_name;
+  const char *authz_user;
+
+  /* Callback to provide info about the committed revision.  */
+  svn_commit_callback2_t commit_cb;
+  void *commit_baton;
+
   /* The FS txn editor  */
   svn_editor_t *inner;
 
@@ -158,6 +169,40 @@ out_of_date(const char *path, svn_node_k
 }
 
 
+static svn_error_t *
+invoke_commit_cb(svn_commit_callback2_t commit_cb,
+                 void *commit_baton,
+                 svn_fs_t *fs,
+                 svn_revnum_t revision,
+                 const char *post_commit_errstr,
+                 apr_pool_t *scratch_pool)
+{
+  /* FS interface returns non-const values.  */
+  /* const */ svn_string_t *date;
+  /* const */ svn_string_t *author;
+  svn_commit_info_t *commit_info;
+
+  if (commit_cb == NULL)
+    return SVN_NO_ERROR;
+
+  SVN_ERR(svn_fs_revision_prop(&date, fs, revision, SVN_PROP_REVISION_DATE,
+                               scratch_pool));
+  SVN_ERR(svn_fs_revision_prop(&author, fs, revision,
+                               SVN_PROP_REVISION_AUTHOR,
+                               scratch_pool));
+
+  commit_info = svn_create_commit_info(scratch_pool);
+
+  /* fill up the svn_commit_info structure */
+  commit_info->revision = revision;
+  commit_info->date = date ? date->data : NULL;
+  commit_info->author = author ? author->data : NULL;
+  commit_info->post_commit_err = post_commit_errstr;
+
+  return svn_error_trace(commit_cb(commit_info, commit_baton, scratch_pool));
+}
+
+
 
 /* If EDITOR_BATON contains a valid authz callback, verify that the
    REQUIRED access to PATH in ROOT is authorized.  Return an error
@@ -646,7 +691,8 @@ svn_repos__post_commit_error_str(svn_err
   else
     hook_err2 = hook_err1;
 
-  /* This implementation counts on svn_repos_fs_commit_txn() returning
+  /* This implementation counts on svn_repos_fs_commit_txn() and
+     libsvn_repos/commit.c:complete_cb() returning
      svn_fs_commit_txn() as the parent error with a child
      SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED error.  If the parent error
      is SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED then there was no error
@@ -718,7 +764,6 @@ close_edit(void *edit_baton,
              display it as a warning) and clear the error. */
           post_commit_err = svn_repos__post_commit_error_str(err, pool);
           svn_error_clear(err);
-          err = SVN_NO_ERROR;
         }
     }
   else
@@ -745,41 +790,19 @@ close_edit(void *edit_baton,
                                          svn_fs_abort_txn(eb->txn, pool)));
     }
 
-  /* Pass new revision information to the caller's callback. */
-  {
-    svn_string_t *date, *author;
-    svn_commit_info_t *commit_info;
-
-    /* Even if there was a post-commit hook failure, it's more serious
-       if one of the calls here fails, so we explicitly check for errors
-       here, while saving the possible post-commit error for later. */
-
-    err = svn_fs_revision_prop(&date, svn_repos_fs(eb->repos),
-                                new_revision, SVN_PROP_REVISION_DATE,
-                                pool);
-    if (! err)
-      {
-        err = svn_fs_revision_prop(&author, svn_repos_fs(eb->repos),
-                                   new_revision, SVN_PROP_REVISION_AUTHOR,
-                                   pool);
-      }
-
-    if ((! err) && eb->commit_callback)
-      {
-        commit_info = svn_create_commit_info(pool);
-
-        /* fill up the svn_commit_info structure */
-        commit_info->revision = new_revision;
-        commit_info->date = date ? date->data : NULL;
-        commit_info->author = author ? author->data : NULL;
-        commit_info->post_commit_err = post_commit_err;
-        err = (*eb->commit_callback)(commit_info,
-                                     eb->commit_callback_baton,
-                                     pool);
-      }
-  }
+  /* At this point, the post-commit error has been converted to a string.
+     That information will be passed to a callback, if provided. If the
+     callback invocation fails in some way, that failure is returned here.
+     IOW, the post-commit error information is low priority compared to
+     other gunk here.  */
 
-  return svn_error_trace(err);
+  /* Pass new revision information to the caller's callback. */
+  return svn_error_trace(invoke_commit_cb(eb->commit_callback,
+                                          eb->commit_callback_baton,
+                                          eb->repos->fs,
+                                          new_revision,
+                                          post_commit_err,
+                                          pool));
 }
 
 
@@ -973,41 +996,366 @@ svn_repos_get_commit_editor5(const svn_d
 }
 
 
+#if 0
+static svn_error_t *
+ev2_check_authz(const struct ev2_baton *eb,
+                const char *relpath,
+                svn_repos_authz_access_t required,
+                apr_pool_t *scratch_pool)
+{
+  const char *fspath;
+  svn_boolean_t allowed;
+
+  if (eb->authz == NULL)
+    return SVN_NO_ERROR;
+
+  if (relpath)
+    fspath = apr_pstrcat(scratch_pool, "/", relpath, NULL);
+  else
+    fspath = NULL;
+
+  SVN_ERR(svn_repos_authz_check_access(eb->authz, eb->authz_repos_name, fspath,
+                                       eb->authz_user, required,
+                                       &allowed, scratch_pool));
+  if (!allowed)
+    return svn_error_create(required & svn_authz_write
+                            ? SVN_ERR_AUTHZ_UNWRITABLE
+                            : SVN_ERR_AUTHZ_UNREADABLE,
+                            NULL, "Access denied");
+
+  return SVN_NO_ERROR;
+}
+#endif
+
+
+/* This implements svn_editor_cb_add_directory_t */
+static svn_error_t *
+add_directory_cb(void *baton,
+                 const char *relpath,
+                 const apr_array_header_t *children,
+                 apr_hash_t *props,
+                 svn_revnum_t replaces_rev,
+                 apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_directory(eb->inner, relpath, children, props,
+                                   replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_file_t */
+static svn_error_t *
+add_file_cb(void *baton,
+            const char *relpath,
+            const svn_checksum_t *checksum,
+            svn_stream_t *contents,
+            apr_hash_t *props,
+            svn_revnum_t replaces_rev,
+            apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_file(eb->inner, relpath, checksum, contents, props,
+                              replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_symlink_t */
+static svn_error_t *
+add_symlink_cb(void *baton,
+               const char *relpath,
+               const char *target,
+               apr_hash_t *props,
+               svn_revnum_t replaces_rev,
+               apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_symlink(eb->inner, relpath, target, props,
+                                 replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_add_absent_t */
+static svn_error_t *
+add_absent_cb(void *baton,
+              const char *relpath,
+              svn_kind_t kind,
+              svn_revnum_t replaces_rev,
+              apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_add_absent(eb->inner, relpath, kind, replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_directory_t */
+static svn_error_t *
+alter_directory_cb(void *baton,
+                   const char *relpath,
+                   svn_revnum_t revision,
+                   apr_hash_t *props,
+                   apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_alter_directory(eb->inner, relpath, revision, props));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_file_t */
+static svn_error_t *
+alter_file_cb(void *baton,
+              const char *relpath,
+              svn_revnum_t revision,
+              apr_hash_t *props,
+              const svn_checksum_t *checksum,
+              svn_stream_t *contents,
+              apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_alter_file(eb->inner, relpath, revision, props,
+                                checksum, contents));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_alter_symlink_t */
+static svn_error_t *
+alter_symlink_cb(void *baton,
+                 const char *relpath,
+                 svn_revnum_t revision,
+                 apr_hash_t *props,
+                 const char *target,
+                 apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_alter_symlink(eb->inner, relpath, revision, props,
+                                   target));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_delete_t */
+static svn_error_t *
+delete_cb(void *baton,
+          const char *relpath,
+          svn_revnum_t revision,
+          apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_delete(eb->inner, relpath, revision));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_copy_t */
+static svn_error_t *
+copy_cb(void *baton,
+        const char *src_relpath,
+        svn_revnum_t src_revision,
+        const char *dst_relpath,
+        svn_revnum_t replaces_rev,
+        apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_copy(eb->inner, src_relpath, src_revision, dst_relpath,
+                          replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_move_t */
+static svn_error_t *
+move_cb(void *baton,
+        const char *src_relpath,
+        svn_revnum_t src_revision,
+        const char *dst_relpath,
+        svn_revnum_t replaces_rev,
+        apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_move(eb->inner, src_relpath, src_revision, dst_relpath,
+                          replaces_rev));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_rotate_t */
+static svn_error_t *
+rotate_cb(void *baton,
+          const apr_array_header_t *relpaths,
+          const apr_array_header_t *revisions,
+          apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_rotate(eb->inner, relpaths, revisions));
+  return SVN_NO_ERROR;
+}
+
+
+/* This implements svn_editor_cb_complete_t */
+static svn_error_t *
+complete_cb(void *baton,
+            apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+  svn_revnum_t revision;
+  svn_error_t *post_commit_err;
+  const char *conflict_path;
+  svn_error_t *err;
+  const char *post_commit_errstr;
+
+  /* The transaction has been fully edited. Let the pre-commit hook
+     have a look at the thing.  */
+  SVN_ERR(svn_repos__hooks_pre_commit(eb->repos, eb->txn_name, scratch_pool));
+
+  /* Hook is done. Let's do the actual commit.  */
+  SVN_ERR(svn_fs_editor_commit(&revision, &post_commit_err, &conflict_path,
+                               eb->inner, scratch_pool, scratch_pool));
+
+  /* Did a conflict occur during the commit process?  */
+  if (conflict_path != NULL)
+    return svn_error_createf(SVN_ERR_FS_CONFLICT, NULL,
+                             _("Conflict at '%s'"), conflict_path);
+
+  /* Since did not receive an error during the commit process, and no
+     conflict was specified... we committed a revision. Run the hooks.
+     Other errors may have occurred within the FS (specified by the
+     POST_COMMIT_ERR localvar), but we need to run the hooks.  */
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
+  err = svn_repos__hooks_post_commit(eb->repos, revision, eb->txn_name,
+                                     scratch_pool);
+  if (err)
+    err = svn_error_create(SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
+                           _("Commit succeeded, but post-commit hook failed"));
+
+  /* Combine the FS errors with the hook errors, and stringify.  */
+  err = svn_error_compose_create(post_commit_err, err);
+  if (err)
+    {
+      post_commit_errstr = svn_repos__post_commit_error_str(err, scratch_pool);
+      svn_error_clear(err);
+    }
+  else
+    {
+      post_commit_errstr = NULL;
+    }
+
+  return svn_error_trace(invoke_commit_cb(eb->commit_cb, eb->commit_baton,
+                                          eb->repos->fs, revision,
+                                          post_commit_errstr,
+                                          scratch_pool));
+}
+
+
+/* This implements svn_editor_cb_abort_t */
+static svn_error_t *
+abort_cb(void *baton,
+         apr_pool_t *scratch_pool)
+{
+  struct ev2_baton *eb = baton;
+
+  SVN_ERR(svn_editor_abort(eb->inner));
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+apply_revprops(svn_fs_t *fs,
+               const char *txn_name,
+               apr_hash_t *revprops,
+               apr_pool_t *scratch_pool)
+{
+  svn_fs_txn_t *txn;
+  const apr_array_header_t *revprops_array;
+
+  /* The FS editor has a TXN inside it, but we can't access it. Open another
+     based on the TXN_NAME.  */
+  SVN_ERR(svn_fs_open_txn(&txn, fs, txn_name, scratch_pool));
+
+  /* Validate and apply the revision properties.  */
+  revprops_array = svn_prop_hash_to_array(revprops, scratch_pool);
+  SVN_ERR(svn_repos_fs_change_txn_props(txn, revprops_array, scratch_pool));
+
+  /* ### do we need to force the txn to close, or is it enough to wait
+     ### for the pool to be cleared?  */
+  return SVN_NO_ERROR;
+}
+
+
 svn_error_t *
 svn_repos__get_commit_ev2(svn_editor_t **editor,
                           svn_repos_t *repos,
-                          svn_revnum_t revision,
-                          apr_hash_t *revprop_table,
+                          svn_authz_t *authz,
+                          const char *authz_repos_name,
+                          const char *authz_user,
+                          apr_hash_t *revprops,
+                          svn_commit_callback2_t commit_cb,
+                          void *commit_baton,
                           svn_cancel_func_t cancel_func,
                           void *cancel_baton,
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
 {
   static const svn_editor_cb_many_t editor_cbs = {
-    NULL /* add_directory_cb */,
-    NULL /* add_file_cb */,
-    NULL /* add_symlink_cb */,
-    NULL /* add_absent_cb */,
-    NULL /* alter_directory_cb */,
-    NULL /* alter_file_cb */,
-    NULL /* alter_symlink_cb */,
-    NULL /* delete_cb */,
-    NULL /* copy_cb */,
-    NULL /* move_cb */,
-    NULL /* rotate_cb */,
-    NULL /* complete_cb */,
-    NULL /* abort_cb */
+    add_directory_cb,
+    add_file_cb,
+    add_symlink_cb,
+    add_absent_cb,
+    alter_directory_cb,
+    alter_file_cb,
+    alter_symlink_cb,
+    delete_cb,
+    copy_cb,
+    move_cb,
+    rotate_cb,
+    complete_cb,
+    abort_cb
   };
-  struct ev2_baton *eb = apr_palloc(result_pool, sizeof(*eb));
+  struct ev2_baton *eb;
+  const svn_string_t *author;
+
+  /* Can the user modify the repository at all?  */
+  /* ### check against AUTHZ.  */
 
+  /* Okay... some access is allowed. Let's run the start-commit hook.  */
+  author = apr_hash_get(revprops, SVN_PROP_REVISION_AUTHOR,
+                        APR_HASH_KEY_STRING);
+  SVN_ERR(svn_repos__hooks_start_commit(repos, author ? author->data : NULL,
+                                        repos->client_capabilities,
+                                        scratch_pool));
+
+  eb = apr_palloc(result_pool, sizeof(*eb));
   eb->repos = repos;
+  eb->authz = authz;
+  eb->authz_repos_name = authz_repos_name;
+  eb->authz_user = authz_user;
+  eb->commit_cb = commit_cb;
+  eb->commit_baton = commit_baton;
 
   SVN_ERR(svn_fs_editor_create(&eb->inner, &eb->txn_name,
-                               repos->fs, revision,
-                               SVN_FS_TXN_CHECK_LOCKS,
+                               repos->fs, SVN_FS_TXN_CHECK_LOCKS,
                                cancel_func, cancel_baton,
                                result_pool, scratch_pool));
 
+  /* The TXN has been created. Go ahead and apply all revision properties.  */
+  SVN_ERR(apply_revprops(repos->fs, eb->txn_name, revprops, scratch_pool));
+
+  /* Wrap the FS editor within our editor.  */
   SVN_ERR(svn_editor_create(editor, eb, cancel_func, cancel_baton,
                             result_pool, scratch_pool));
   SVN_ERR(svn_editor_setcb_many(*editor, &editor_cbs, scratch_pool));

Modified: subversion/branches/ev2-export/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_repos/hooks.c?rev=1331076&r1=1331075&r2=1331076&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_repos/hooks.c Thu Apr 26 20:37:17 2012
@@ -30,6 +30,7 @@
 #include "svn_error.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
+#include "svn_pools.h"
 #include "svn_repos.h"
 #include "svn_utf.h"
 #include "repos.h"
@@ -212,7 +213,8 @@ run_hook_cmd(svn_string_t **result,
   apr_file_t *null_handle;
   apr_status_t apr_err;
   svn_error_t *err;
-  apr_proc_t cmd_proc;
+  apr_proc_t cmd_proc = {0};
+  apr_pool_t *cmd_pool;
 
   if (result)
     {
@@ -228,42 +230,39 @@ run_hook_cmd(svn_string_t **result,
             (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
     }
 
+  /* Tie resources allocated for the command to a special pool which we can
+   * destroy in order to clean up the stderr pipe opened for the process. */
+  cmd_pool = svn_pool_create(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)
-    {
-      /* CMD_PROC is not safe to use. Bail. */
-      return svn_error_createf
-        (SVN_ERR_REPOS_HOOK_FAILURE, err, _("Failed to start '%s' hook"), cmd);
-    }
+                          null_handle, TRUE, NULL, cmd_pool);
+  if (!err)
+    err = check_hook_result(name, cmd, &cmd_proc, cmd_proc.err, pool);
   else
     {
-      err = check_hook_result(name, cmd, &cmd_proc, cmd_proc.err, pool);
+      /* The command could not be started for some reason. */
+      err = svn_error_createf(SVN_ERR_REPOS_BAD_ARGS, err,
+                              _("Failed to start '%s' hook"), cmd);
     }
 
   /* Hooks are fallible, and so hook failure is "expected" to occur at
      times.  When such a failure happens we still want to close the pipe
      and null file */
-  apr_err = apr_file_close(cmd_proc.err);
-  if (!err && apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Error closing read end of stderr pipe"));
-
-  if (result)
+  if (!err && result)
     {
       svn_stringbuf_t *native_stdout;
-      SVN_ERR(svn_stringbuf_from_aprfile(&native_stdout, cmd_proc.out, pool));
-      apr_err = apr_file_close(cmd_proc.out);
-      if (!err && apr_err)
-        return svn_error_wrap_apr
-          (apr_err, _("Error closing read end of stderr pipe"));
-
-      *result = svn_stringbuf__morph_into_string(native_stdout);
+      err = svn_stringbuf_from_aprfile(&native_stdout, cmd_proc.out, pool);
+      if (!err)
+        *result = svn_stringbuf__morph_into_string(native_stdout);
     }
-  else
+
+  /* Close resources allocated by svn_io_start_cmd3(), such as the pipe. */
+  svn_pool_destroy(cmd_pool);
+
+  /* Close the null handle. */
+  if (null_handle)
     {
       apr_err = apr_file_close(null_handle);
       if (!err && apr_err)



Mime
View raw message