You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2011/10/11 21:52:46 UTC

svn commit: r1182053 [10/30] - in /subversion/branches/svn_mutex: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/ contrib/hook-scripts/enforcer/ contrib/server-side/ notes/ notes/merge-t...

Modified: subversion/branches/svn_mutex/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_client/repos_diff.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_client/repos_diff.c Tue Oct 11 19:52:34 2011
@@ -51,14 +51,6 @@
 
 /* Overall crawler editor baton.  */
 struct edit_baton {
-  /* TARGET is a working-copy directory which corresponds to the base
-     URL open in RA_SESSION below. */
-  const char *target;
-
-  /* A working copy context for TARGET, NULL if this is purely a
-     repository operation. */
-  svn_wc_context_t *wc_ctx;
-
   /* The passed depth */
   svn_depth_t depth;
 
@@ -67,9 +59,6 @@ struct edit_baton {
   const svn_wc_diff_callbacks4_t *diff_callbacks;
   void *diff_cmd_baton;
 
-  /* DRY_RUN is TRUE if this is a dry-run diff, false otherwise. */
-  svn_boolean_t dry_run;
-
   /* RA_SESSION is the open session for making requests to the RA layer */
   svn_ra_session_t *ra_session;
 
@@ -101,6 +90,9 @@ struct edit_baton {
      FALSE otherwise. */
   svn_boolean_t walk_deleted_repos_dirs;
 
+  /* Whether to report text deltas */
+  svn_boolean_t text_deltas;
+
   /* A callback used to see if the client wishes to cancel the running
      operation. */
   svn_cancel_func_t cancel_func;
@@ -140,9 +132,6 @@ struct dir_baton {
   /* The path of the directory within the repository */
   const char *path;
 
-  /* The path of the directory in the wc, relative to cwd */
-  const char *wcpath;
-
   /* The baton for the parent directory, or null if this is the root of the
      hierarchy to be compared. */
   struct dir_baton *dir_baton;
@@ -179,9 +168,6 @@ struct file_baton {
   /* The path of the file within the repository */
   const char *path;
 
-  /* The path of the file in the wc, relative to cwd */
-  const char *wcpath;
-
   /* The path and APR file handle to the temporary file that contains the
      first repository version.  Also, the pristine-property list of
      this file. */
@@ -242,7 +228,6 @@ make_dir_baton(const char *path,
   dir_baton->skip_children = FALSE;
   dir_baton->pool = dir_pool;
   dir_baton->path = apr_pstrdup(dir_pool, path);
-  dir_baton->wcpath = svn_dirent_join(edit_baton->target, path, dir_pool);
   dir_baton->propchanges  = apr_array_make(pool, 1, sizeof(svn_prop_t));
 
   return dir_baton;
@@ -268,7 +253,6 @@ make_file_baton(const char *path,
   file_baton->skip = FALSE;
   file_baton->pool = file_pool;
   file_baton->path = apr_pstrdup(file_pool, path);
-  file_baton->wcpath = svn_dirent_join(edit_baton->target, path, file_pool);
   file_baton->propchanges  = apr_array_make(pool, 1, sizeof(svn_prop_t));
   file_baton->base_revision = edit_baton->revision;
 
@@ -318,11 +302,19 @@ get_file_mime_types(const char **mimetyp
 }
 
 
-/* Get revision REVISION of the file described by B from the repository.
- * Set B->path_start_revision to the path of a new temporary file containing
- * the file's text.  Set B->pristine_props to a new hash containing the
- * file's properties.  Install a pool cleanup handler on B->pool to delete
- * the file.
+/* Get revision B->base_revision of the file described by B from the
+ * repository, through B->edit_baton->ra_session.
+ *
+ * Unless PROPS_ONLY is true:
+ *   Set B->path_start_revision to the path of a new temporary file containing
+ *   the file's text.
+ *   Set B->start_md5_checksum to that file's MD-5 checksum.
+ *   Install a pool cleanup handler on B->pool to delete the file.
+ *
+ * Always:
+ *   Set B->pristine_props to a new hash containing the file's properties.
+ *
+ * Allocate all results in B->pool.
  */
 static svn_error_t *
 get_file_from_ra(struct file_baton *b,
@@ -334,11 +326,11 @@ get_file_from_ra(struct file_baton *b,
       svn_stream_t *fstream;
 
       SVN_ERR(svn_stream_open_unique(&fstream, &(b->path_start_revision), NULL,
-                                     svn_io_file_del_on_pool_cleanup, b->pool,
-                                     b->pool));
+                                     svn_io_file_del_on_pool_cleanup,
+                                     b->pool, scratch_pool));
 
       fstream = svn_stream_checksummed2(fstream, NULL, &b->start_md5_checksum,
-                                        svn_checksum_md5, TRUE, b->pool);
+                                        svn_checksum_md5, TRUE, scratch_pool);
 
       /* Retrieve the file and its properties */
       SVN_ERR(svn_ra_get_file(b->edit_baton->ra_session,
@@ -362,7 +354,11 @@ get_file_from_ra(struct file_baton *b,
   return SVN_NO_ERROR;
 }
 
-/* Issue #3657 'dav update report handler in skelta mode can cause
+/* Remove every no-op property change from CHANGES: that is, remove every
+   entry in which the target value is the same as the value of the
+   corresponding property in PRISTINE_PROPS.
+
+     Issue #3657 'dav update report handler in skelta mode can cause
      spurious conflicts'.  When communicating with the repository via ra_serf
      and ra_neon, the change_dir_prop and change_file_prop svn_delta_editor_t
      callbacks are called (obviously) when a directory or file property has
@@ -389,8 +385,6 @@ get_file_from_ra(struct file_baton *b,
 
      See http://subversion.tigris.org/issues/show_bug.cgi?id=3657#desc9 and
      http://svn.haxx.se/dev/archive-2010-08/0351.shtml for more details.
-
-     This function filters these property changes from the change hash
  */
 static void
 remove_non_prop_changes(apr_hash_t *pristine_props,
@@ -456,7 +450,7 @@ get_empty_file(struct edit_baton *eb,
   return SVN_NO_ERROR;
 }
 
-/* An editor function. The root of the comparison hierarchy */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 set_target_revision(void *edit_baton,
                     svn_revnum_t target_revision,
@@ -468,7 +462,7 @@ set_target_revision(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function. The root of the comparison hierarchy */
+/* An svn_delta_editor_t function. The root of the comparison hierarchy */
 static svn_error_t *
 open_root(void *edit_baton,
           svn_revnum_t base_revision,
@@ -478,9 +472,6 @@ open_root(void *edit_baton,
   struct edit_baton *eb = edit_baton;
   struct dir_baton *b = make_dir_baton("", NULL, eb, FALSE, pool);
 
-  /* Override the wcpath in our baton. */
-  b->wcpath = apr_pstrdup(pool, eb->target);
-
   SVN_ERR(get_dirprops_from_ra(b, base_revision));
 
   *root_baton = b;
@@ -488,7 +479,7 @@ open_root(void *edit_baton,
 }
 
 /* Recursively walk tree rooted at DIR (at REVISION) in the repository,
- * reporting all files as deleted.  Part of a workaround for issue 2333.
+ * reporting all children as deleted.  Part of a workaround for issue 2333.
  *
  * DIR is a repository path relative to the URL in RA_SESSION.  REVISION
  * must be a valid revision number, not SVN_INVALID_REVNUM.  EB is the
@@ -540,14 +531,17 @@ diff_deleted_dir(const char *dir,
 
           /* Compare a file being deleted against an empty file */
           b = make_file_baton(path, FALSE, eb, iterpool);
-          SVN_ERR(get_file_from_ra(b, FALSE, iterpool));
+          if (eb->text_deltas)
+            SVN_ERR(get_file_from_ra(b, FALSE, iterpool));
+          else
+            SVN_ERR(get_empty_file(eb, &b->path_start_revision));
 
           SVN_ERR(get_empty_file(b->edit_baton, &(b->path_end_revision)));
 
           get_file_mime_types(&mimetype1, &mimetype2, b);
 
           SVN_ERR(eb->diff_callbacks->file_deleted(
-                                NULL, NULL, b->wcpath,
+                                NULL, NULL, b->path,
                                 b->path_start_revision,
                                 b->path_end_revision,
                                 mimetype1, mimetype2,
@@ -557,20 +551,25 @@ diff_deleted_dir(const char *dir,
         }
 
       if (dirent->kind == svn_node_dir)
-        SVN_ERR(diff_deleted_dir(path,
-                                 revision,
-                                 ra_session,
-                                 eb,
-                                 cancel_func,
-                                 cancel_baton,
-                                 iterpool));
+        {
+          SVN_ERR(eb->diff_callbacks->dir_deleted(
+                                NULL, NULL, path,
+                                eb->diff_cmd_baton, iterpool));
+          SVN_ERR(diff_deleted_dir(path,
+                                   revision,
+                                   ra_session,
+                                   eb,
+                                   cancel_func,
+                                   cancel_baton,
+                                   iterpool));
+        }
     }
 
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 delete_entry(const char *path,
              svn_revnum_t base_revision,
@@ -605,13 +604,17 @@ delete_entry(const char *path,
 
         /* Compare a file being deleted against an empty file */
         b = make_file_baton(path, FALSE, eb, scratch_pool);
-        SVN_ERR(get_file_from_ra(b, FALSE, scratch_pool));
+        if (eb->text_deltas)
+          SVN_ERR(get_file_from_ra(b, FALSE, scratch_pool));
+        else
+          SVN_ERR(get_empty_file(eb, &b->path_start_revision));
+
         SVN_ERR(get_empty_file(b->edit_baton, &(b->path_end_revision)));
 
         get_file_mime_types(&mimetype1, &mimetype2, b);
 
         SVN_ERR(eb->diff_callbacks->file_deleted(
-                     &state, &tree_conflicted, b->wcpath,
+                     &state, &tree_conflicted, b->path,
                      b->path_start_revision,
                      b->path_end_revision,
                      mimetype1, mimetype2,
@@ -625,7 +628,7 @@ delete_entry(const char *path,
       {
         SVN_ERR(eb->diff_callbacks->dir_deleted(
                      &state, &tree_conflicted,
-                     svn_dirent_join(eb->target, path, pool),
+                     path,
                      eb->diff_cmd_baton, scratch_pool));
 
         if (eb->walk_deleted_repos_dirs)
@@ -656,9 +659,9 @@ delete_entry(const char *path,
 
   if (eb->notify_func)
     {
-      const char* deleted_path;
+      const char *deleted_path = apr_pstrdup(eb->pool, path);
       deleted_path_notify_t *dpn = apr_pcalloc(eb->pool, sizeof(*dpn));
-      deleted_path = svn_dirent_join(eb->target, path, eb->pool);
+
       dpn->kind = kind;
       dpn->action = tree_conflicted ? svn_wc_notify_tree_conflict : action;
       dpn->state = state;
@@ -671,7 +674,7 @@ delete_entry(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 add_directory(const char *path,
               void *parent_baton,
@@ -702,7 +705,7 @@ add_directory(const char *path,
 
   SVN_ERR(eb->diff_callbacks->dir_added(
                 &state, &b->tree_conflicted,
-                &b->skip, &b->skip_children, b->wcpath,
+                &b->skip, &b->skip_children, b->path,
                 eb->target_revision, copyfrom_path, copyfrom_revision,
                 eb->diff_cmd_baton, pool));
 
@@ -721,12 +724,12 @@ add_directory(const char *path,
 
       /* Find out if a pending delete notification for this path is
        * still around. */
-      dpn = apr_hash_get(eb->deleted_paths, b->wcpath, APR_HASH_KEY_STRING);
+      dpn = apr_hash_get(eb->deleted_paths, b->path, APR_HASH_KEY_STRING);
       if (dpn)
         {
           /* If any was found, we will handle the pending 'deleted path
            * notification' (DPN) here. Remove it from the list. */
-          apr_hash_set(eb->deleted_paths, b->wcpath,
+          apr_hash_set(eb->deleted_paths, b->path,
                        APR_HASH_KEY_STRING, NULL);
 
           /* the pending delete might be on a different node kind. */
@@ -752,7 +755,7 @@ add_directory(const char *path,
       else
         action = svn_wc_notify_update_add;
 
-      notify = svn_wc_create_notify(b->wcpath, action, pool);
+      notify = svn_wc_create_notify(b->path, action, pool);
       notify->kind = kind;
       notify->content_state = notify->prop_state = state;
       (*eb->notify_func)(eb->notify_baton, notify, pool);
@@ -761,7 +764,7 @@ add_directory(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 open_directory(const char *path,
                void *parent_baton,
@@ -788,14 +791,14 @@ open_directory(const char *path,
 
   SVN_ERR(eb->diff_callbacks->dir_opened(
                 &b->tree_conflicted, &b->skip,
-                &b->skip_children, b->wcpath, base_revision,
+                &b->skip_children, b->path, base_revision,
                 b->edit_baton->diff_cmd_baton, pool));
 
   return SVN_NO_ERROR;
 }
 
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 add_file(const char *path,
          void *parent_baton,
@@ -825,7 +828,7 @@ add_file(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 open_file(const char *path,
           void *parent_baton,
@@ -851,7 +854,7 @@ open_file(const char *path,
 
   SVN_ERR(eb->diff_callbacks->file_opened(
                    &b->tree_conflicted, &b->skip,
-                   b->wcpath, base_revision, eb->diff_cmd_baton, pool));
+                   b->path, base_revision, eb->diff_cmd_baton, pool));
 
   return SVN_NO_ERROR;
 }
@@ -875,7 +878,7 @@ window_handler(svn_txdelta_window_t *win
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 apply_textdelta(void *file_baton,
                 const char *base_md5_digest,
@@ -896,9 +899,22 @@ apply_textdelta(void *file_baton,
       return SVN_NO_ERROR;
     }
 
+  /* If we're not sending file text, then ignore any that we receive. */
+  if (! b->edit_baton->text_deltas)
+    {
+      /* Supply valid paths to indicate there is a text change. */
+      SVN_ERR(get_empty_file(b->edit_baton, &b->path_start_revision));
+      SVN_ERR(get_empty_file(b->edit_baton, &b->path_end_revision));
+
+      *handler = svn_delta_noop_window_handler;
+      *handler_baton = NULL;
+
+      return SVN_NO_ERROR;
+    }
+
   /* We need the expected pristine file, so go get it */
   if (!b->added)
-    SVN_ERR(get_file_from_ra(b, FALSE, b->pool));
+    SVN_ERR(get_file_from_ra(b, FALSE, scratch_pool));
   else
     SVN_ERR(get_empty_file(b->edit_baton, &(b->path_start_revision)));
 
@@ -942,7 +958,7 @@ apply_textdelta(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  When the file is closed we have a temporary
+/* An svn_delta_editor_t function.  When the file is closed we have a temporary
  * file containing a pristine version of the repository file. This can
  * be compared against the working copy.
  *
@@ -972,7 +988,7 @@ close_file(void *file_baton,
 
   scratch_pool = b->pool;
 
-  if (expected_md5_digest)
+  if (expected_md5_digest && eb->text_deltas)
     {
       svn_checksum_t *expected_md5_checksum;
 
@@ -1009,7 +1025,7 @@ close_file(void *file_baton,
       if (b->added)
         SVN_ERR(eb->diff_callbacks->file_added(
                  &content_state, &prop_state, &b->tree_conflicted,
-                 b->wcpath,
+                 b->path,
                  b->path_end_revision ? b->path_start_revision : NULL,
                  b->path_end_revision,
                  0,
@@ -1022,7 +1038,7 @@ close_file(void *file_baton,
       else
         SVN_ERR(eb->diff_callbacks->file_changed(
                  &content_state, &prop_state,
-                 &b->tree_conflicted, b->wcpath,
+                 &b->tree_conflicted, b->path,
                  b->path_end_revision ? b->path_start_revision : NULL,
                  b->path_end_revision,
                  b->edit_baton->revision,
@@ -1043,12 +1059,12 @@ close_file(void *file_baton,
 
       /* Find out if a pending delete notification for this path is
        * still around. */
-      dpn = apr_hash_get(eb->deleted_paths, b->wcpath, APR_HASH_KEY_STRING);
+      dpn = apr_hash_get(eb->deleted_paths, b->path, APR_HASH_KEY_STRING);
       if (dpn)
         {
           /* If any was found, we will handle the pending 'deleted path
            * notification' (DPN) here. Remove it from the list. */
-          apr_hash_set(eb->deleted_paths, b->wcpath,
+          apr_hash_set(eb->deleted_paths, b->path,
                        APR_HASH_KEY_STRING, NULL);
 
           /* the pending delete might be on a different node kind. */
@@ -1077,7 +1093,7 @@ close_file(void *file_baton,
       else
         action = svn_wc_notify_update_update;
 
-      notify = svn_wc_create_notify(b->wcpath, action, scratch_pool);
+      notify = svn_wc_create_notify(b->path, action, scratch_pool);
       notify->kind = kind;
       notify->content_state = content_state;
       notify->prop_state = prop_state;
@@ -1089,7 +1105,13 @@ close_file(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* Report any accumulated prop changes via the 'dir_props_changed' callback,
+ * and then call the 'dir_closed' callback.  Notify about any deleted paths
+ * within this directory that have not already been notified, and then about
+ * this directory itself (unless it was added, in which case the notification
+ * was done at that time).
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 close_directory(void *dir_baton,
                 apr_pool_t *pool)
@@ -1113,15 +1135,13 @@ close_directory(void *dir_baton,
   if (!b->added && b->propchanges->nelts > 0)
     remove_non_prop_changes(b->pristine_props, b->propchanges);
 
-  /* Don't do the props_changed stuff if this is a dry_run and we don't
-     have an access baton, since in that case the directory will already
-     have been recognised as added, in which case they cannot conflict. */
+  /* Report any prop changes. */
   if (b->propchanges->nelts > 0)
     {
       svn_boolean_t tree_conflicted = FALSE;
       SVN_ERR(eb->diff_callbacks->dir_props_changed(
                &prop_state, &tree_conflicted,
-               b->wcpath, b->added,
+               b->path, b->added,
                b->propchanges, b->pristine_props,
                b->edit_baton->diff_cmd_baton, scratch_pool));
       if (tree_conflicted)
@@ -1136,12 +1156,12 @@ close_directory(void *dir_baton,
     }
 
   SVN_ERR(eb->diff_callbacks->dir_closed(NULL, NULL, NULL,
-                                         b->wcpath, b->added,
+                                         b->path, b->added,
                                          b->edit_baton->diff_cmd_baton,
                                          scratch_pool));
 
-  /* Don't notify added directories as they triggered notification
-     in add_directory. */
+  /* Notify about any deleted paths within this directory that have not
+   * already been notified. */
   if (!skipped && !b->added && eb->notify_func)
     {
       apr_hash_index_t *hi;
@@ -1163,6 +1183,8 @@ close_directory(void *dir_baton,
         }
     }
 
+  /* Notify about this directory itself (unless it was added, in which
+   * case the notification was done at that time). */
   if (!b->added && eb->notify_func)
     {
       svn_wc_notify_t *notify;
@@ -1175,7 +1197,7 @@ close_directory(void *dir_baton,
       else
         action = svn_wc_notify_update_update;
 
-      notify = svn_wc_create_notify(b->wcpath, action, pool);
+      notify = svn_wc_create_notify(b->path, action, pool);
       notify->kind = svn_node_dir;
 
       /* In case of a tree conflict during merge, the diff callback
@@ -1194,7 +1216,9 @@ close_directory(void *dir_baton,
 }
 
 
-/* An editor function.  */
+/* Record a prop change, which we will report later in close_file().
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 change_file_prop(void *file_baton,
                  const char *name,
@@ -1215,7 +1239,9 @@ change_file_prop(void *file_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* Make a note of this prop change, to be reported when the dir is closed.
+ *
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 change_dir_prop(void *dir_baton,
                 const char *name,
@@ -1237,7 +1263,7 @@ change_dir_prop(void *dir_baton,
 }
 
 
-/* An editor function.  */
+/* An svn_delta_editor_t function.  */
 static svn_error_t *
 close_edit(void *edit_baton,
            apr_pool_t *pool)
@@ -1249,7 +1275,8 @@ close_edit(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-/* An editor function.  */
+/* Notify that the node at PATH is 'missing'.
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 absent_directory(const char *path,
                  void *parent_baton,
@@ -1263,11 +1290,8 @@ absent_directory(const char *path,
   if (eb->notify_func)
     {
       svn_wc_notify_t *notify
-        = svn_wc_create_notify(svn_dirent_join(pb->wcpath,
-                                               svn_relpath_basename(path,
-                                                                    NULL),
-                                               pool),
-                               svn_wc_notify_skip, pool);
+        = svn_wc_create_notify(path, svn_wc_notify_skip, pool);
+
       notify->kind = svn_node_dir;
       notify->content_state = notify->prop_state
         = svn_wc_notify_state_missing;
@@ -1278,7 +1302,8 @@ absent_directory(const char *path,
 }
 
 
-/* An editor function.  */
+/* Notify that the node at PATH is 'missing'.
+ * An svn_delta_editor_t function.  */
 static svn_error_t *
 absent_file(const char *path,
             void *parent_baton,
@@ -1292,11 +1317,8 @@ absent_file(const char *path,
   if (eb->notify_func)
     {
       svn_wc_notify_t *notify
-        = svn_wc_create_notify(svn_dirent_join(pb->wcpath,
-                                               svn_relpath_basename(path,
-                                                                    pool),
-                                               pool),
-                               svn_wc_notify_skip, pool);
+        = svn_wc_create_notify(path, svn_wc_notify_skip, pool);
+
       notify->kind = svn_node_file;
       notify->content_state = notify->prop_state
         = svn_wc_notify_state_missing;
@@ -1310,36 +1332,27 @@ absent_file(const char *path,
 svn_error_t *
 svn_client__get_diff_editor(const svn_delta_editor_t **editor,
                             void **edit_baton,
-                            svn_wc_context_t *wc_ctx,
-                            const char *target,
                             svn_depth_t depth,
                             svn_ra_session_t *ra_session,
                             svn_revnum_t revision,
                             svn_boolean_t walk_deleted_dirs,
-                            svn_boolean_t dry_run,
+                            svn_boolean_t text_deltas,
                             const svn_wc_diff_callbacks4_t *diff_callbacks,
                             void *diff_cmd_baton,
                             svn_cancel_func_t cancel_func,
                             void *cancel_baton,
                             svn_wc_notify_func2_t notify_func,
                             void *notify_baton,
-                            apr_pool_t *result_pool,
-                            apr_pool_t *scratch_pool)
+                            apr_pool_t *result_pool)
 {
   apr_pool_t *editor_pool = svn_pool_create(result_pool);
   svn_delta_editor_t *tree_editor = svn_delta_default_editor(editor_pool);
   struct edit_baton *eb = apr_pcalloc(editor_pool, sizeof(*eb));
-  const char *target_abspath;
-
-  SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, editor_pool));
 
   eb->pool = editor_pool;
-  eb->target = target;
-  eb->wc_ctx = wc_ctx;
   eb->depth = depth;
   eb->diff_callbacks = diff_callbacks;
   eb->diff_cmd_baton = diff_cmd_baton;
-  eb->dry_run = dry_run;
   eb->ra_session = ra_session;
 
   eb->revision = revision;
@@ -1349,6 +1362,7 @@ svn_client__get_diff_editor(const svn_de
   eb->notify_func = notify_func;
   eb->notify_baton = notify_baton;
   eb->walk_deleted_repos_dirs = walk_deleted_dirs;
+  eb->text_deltas = text_deltas;
   eb->cancel_func = cancel_func;
   eb->cancel_baton = cancel_baton;
 
@@ -1368,11 +1382,14 @@ svn_client__get_diff_editor(const svn_de
   tree_editor->absent_directory = absent_directory;
   tree_editor->absent_file = absent_file;
 
-  return svn_delta_get_cancellation_editor(cancel_func,
-                                           cancel_baton,
-                                           tree_editor,
-                                           eb,
-                                           editor,
-                                           edit_baton,
-                                           eb->pool);
+  SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
+                                            tree_editor, eb,
+                                            editor, edit_baton,
+                                            eb->pool));
+
+  SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
+                                   NULL, NULL, NULL, NULL,
+                                   result_pool, result_pool));
+
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/svn_mutex/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_client/status.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_client/status.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_client/status.c Tue Oct 11 19:52:34 2011
@@ -85,12 +85,23 @@ tweak_status(void *baton,
   /* If the status item has an entry, but doesn't belong to one of the
      changelists our caller is interested in, we filter out this status
      transmission.  */
-  if (sb->changelist_hash
-      && (! status->changelist
-          || ! apr_hash_get(sb->changelist_hash, status->changelist,
-                            APR_HASH_KEY_STRING)))
+  /* ### duplicated in ../libsvn_wc/diff_local.c */
+  if (sb->changelist_hash)
     {
-      return SVN_NO_ERROR;
+      if (status->changelist)
+        {
+          /* Skip unless the caller requested this changelist. */
+          if (! apr_hash_get(sb->changelist_hash, status->changelist,
+                             APR_HASH_KEY_STRING))
+            return SVN_NO_ERROR;
+        }
+      else
+        {
+          /* Skip unless the caller requested changelist-lacking items. */
+          if (! apr_hash_get(sb->changelist_hash, "",
+                             APR_HASH_KEY_STRING))
+            return SVN_NO_ERROR;
+        }
     }
 
   /* If we know that the target was deleted in HEAD of the repository,
@@ -282,13 +293,12 @@ svn_client_status5(svn_revnum_t *result_
 
   SVN_ERR(svn_dirent_get_absolute(&target_abspath, path, pool));
   {
-    svn_node_kind_t kind, disk_kind;
+    svn_node_kind_t kind;
 
-    SVN_ERR(svn_io_check_path(target_abspath, &disk_kind, pool));
     SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, target_abspath, FALSE, pool));
 
-    /* Dir must be an existing directory or the status editor fails */
-    if (kind == svn_node_dir && disk_kind == svn_node_dir)
+    /* Dir must be a working copy directory or the status editor fails */
+    if (kind == svn_node_dir)
       {
         dir_abspath = target_abspath;
         target_basename = "";
@@ -313,15 +323,6 @@ svn_client_status5(svn_revnum_t *result_
                                          _("'%s' is not a working copy"),
                                          svn_dirent_local_style(path, pool));
               }
-
-            /* Check for issue #1617 and stat_tests.py 14
-               "status on '..' where '..' is not versioned". */
-            if (strcmp(path, "..") == 0)
-              {
-                return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
-                                         _("'%s' is not a working copy"),
-                                         svn_dirent_local_style(path, pool));
-              }
           }
       }
   }
@@ -377,7 +378,8 @@ svn_client_status5(svn_revnum_t *result_
                                     &edit_revision, ctx->wc_ctx,
                                     dir_abspath, target_basename,
                                     depth, get_all,
-                                    no_ignore, server_supports_depth,
+                                    no_ignore, depth_as_sticky,
+                                    server_supports_depth,
                                     ignores, tweak_status, &sb,
                                     ctx->cancel_func, ctx->cancel_baton,
                                     pool, pool));
@@ -394,7 +396,7 @@ svn_client_status5(svn_revnum_t *result_
           svn_boolean_t added;
 
           /* Our status target does not exist in HEAD.  If we've got
-             it localled added, that's okay.  But if it was previously
+             it locally added, that's okay.  But if it was previously
              versioned, then it must have since been deleted from the
              repository.  (Note that "locally replaced" doesn't count
              as "added" in this case.)  */
@@ -456,10 +458,11 @@ svn_client_status5(svn_revnum_t *result_
              working copy and HEAD. */
           SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx,
                                           target_abspath,
-                                          &lock_fetch_reporter, &rb, FALSE,
-                                          depth, TRUE,
+                                          &lock_fetch_reporter, &rb,
+                                          FALSE /* restore_files */,
+                                          depth, (! depth_as_sticky),
                                           (! server_supports_depth),
-                                          FALSE,
+                                          FALSE /* use_commit_times */,
                                           ctx->cancel_func, ctx->cancel_baton,
                                           NULL, NULL, pool));
         }
@@ -542,6 +545,9 @@ svn_client_status_dup(const svn_client_s
   if (status->repos_root_url)
     st->repos_root_url = apr_pstrdup(result_pool, status->repos_root_url);
 
+  if (status->repos_uuid)
+    st->repos_uuid = apr_pstrdup(result_pool, status->repos_uuid);
+
   if (status->repos_relpath)
     st->repos_relpath = apr_pstrdup(result_pool, status->repos_relpath);
 
@@ -568,6 +574,13 @@ svn_client_status_dup(const svn_client_s
                                                              result_pool);
     }
 
+  if (status->moved_from_abspath)
+    st->moved_from_abspath =
+      apr_pstrdup(result_pool, status->moved_from_abspath);
+
+  if (status->moved_to_abspath)
+    st->moved_to_abspath = apr_pstrdup(result_pool, status->moved_to_abspath);
+
   return st;
 }
 
@@ -603,30 +616,16 @@ svn_client__create_status(svn_client_sta
   (*cst)->changed_author = status->changed_author;
 
   (*cst)->repos_root_url = status->repos_root_url;
+  (*cst)->repos_uuid = status->repos_uuid;
   (*cst)->repos_relpath = status->repos_relpath;
 
   (*cst)->switched = status->switched;
-  (*cst)->file_external = FALSE;
-
-  if (/* Old style file-externals */
-      (status->versioned
-       && status->switched
-       && status->kind == svn_node_file))
-    {
-      svn_node_kind_t external_kind;
-
-      SVN_ERR(svn_wc__read_external_info(&external_kind, NULL, NULL, NULL,
-                                         NULL, wc_ctx,
-                                         local_abspath /* wri_abspath */,
-                                         local_abspath, TRUE,
-                                         scratch_pool, scratch_pool));
 
-      if (external_kind == svn_node_file)
-        {
-          (*cst)->file_external = TRUE;
-          (*cst)->switched = FALSE;
-          (*cst)->node_status = (*cst)->text_status;
-        }
+  (*cst)->file_external = status->file_external;
+  if (status->file_external)
+    {
+      (*cst)->switched = FALSE;
+      (*cst)->node_status = (*cst)->text_status;
     }
 
   (*cst)->lock = status->lock;
@@ -671,6 +670,9 @@ svn_client__create_status(svn_client_sta
         (*cst)->node_status = svn_wc_status_conflicted;
     }
 
+  (*cst)->moved_from_abspath = status->moved_from_abspath;
+  (*cst)->moved_to_abspath = status->moved_to_abspath;
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/svn_mutex/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_client/update.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_client/update.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_client/update.c Tue Oct 11 19:52:34 2011
@@ -83,8 +83,7 @@ svn_client__dirent_fetcher(void *baton,
     *dirents = NULL;
 
   if (old_url)
-    SVN_ERR(svn_client__ensure_ra_session_url(&old_url, dfb->ra_session,
-                                              old_url, scratch_pool));
+    SVN_ERR(svn_ra_reparent(dfb->ra_session, old_url, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -169,7 +168,7 @@ is_empty_wc(svn_boolean_t *clean_checkou
    This is typically either the same as LOCAL_ABSPATH, or the
    immediate parent of LOCAL_ABSPATH.
 
-   If NOTIFY_SUMMARY is set (and there's a notification hander in
+   If NOTIFY_SUMMARY is set (and there's a notification handler in
    CTX), transmit the final update summary upon successful
    completion of the update.
 */
@@ -255,7 +254,7 @@ update_internal(svn_revnum_t *result_rev
 
           nt = svn_wc_create_notify(local_abspath,
                                     tree_conflicted
-                                      ? svn_wc_notify_skip
+                                      ? svn_wc_notify_skip_conflicted
                                       : svn_wc_notify_update_skip_working_only,
                                     pool);
 

Modified: subversion/branches/svn_mutex/subversion/libsvn_client/url.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_client/url.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_client/url.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_client/url.c Tue Oct 11 19:52:34 2011
@@ -73,6 +73,6 @@ svn_client_root_url_from_path(const char
     SVN_ERR(svn_dirent_get_absolute(&path_or_url, path_or_url, pool));
 
   return svn_error_trace(
-           svn_client__get_repos_root(url, path_or_url,
+           svn_client__get_repos_root(url, NULL, path_or_url,
                                       ctx, pool, pool));
 }

Modified: subversion/branches/svn_mutex/subversion/libsvn_client/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_client/util.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_client/util.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_client/util.c Tue Oct 11 19:52:34 2011
@@ -25,7 +25,6 @@
 #include <apr_strings.h>
 
 #include "svn_pools.h"
-#include "svn_string.h"
 #include "svn_error.h"
 #include "svn_types.h"
 #include "svn_opt.h"
@@ -42,25 +41,6 @@
 
 #include "svn_private_config.h"
 
-/* Duplicate a HASH containing (char * -> svn_string_t *) key/value
-   pairs using POOL. */
-static apr_hash_t *
-string_hash_dup(apr_hash_t *hash, apr_pool_t *pool)
-{
-  apr_hash_index_t *hi;
-  apr_hash_t *new_hash = apr_hash_make(pool);
-
-  for (hi = apr_hash_first(pool, hash); hi; hi = apr_hash_next(hi))
-    {
-      const char *key = apr_pstrdup(pool, svn__apr_hash_index_key(hi));
-      apr_ssize_t klen = svn__apr_hash_index_klen(hi);
-      svn_string_t *val = svn_string_dup(svn__apr_hash_index_val(hi), pool);
-
-      apr_hash_set(new_hash, key, klen, val);
-    }
-  return new_hash;
-}
-
 svn_client_commit_item3_t *
 svn_client_commit_item3_create(apr_pool_t *pool)
 {
@@ -95,21 +75,6 @@ svn_client_commit_item3_dup(const svn_cl
   return new_item;
 }
 
-svn_client_proplist_item_t *
-svn_client_proplist_item_dup(const svn_client_proplist_item_t *item,
-                             apr_pool_t * pool)
-{
-  svn_client_proplist_item_t *new_item = apr_pcalloc(pool, sizeof(*new_item));
-
-  if (item->node_name)
-    new_item->node_name = svn_stringbuf_dup(item->node_name, pool);
-
-  if (item->prop_hash)
-    new_item->prop_hash = string_hash_dup(item->prop_hash, pool);
-
-  return new_item;
-}
-
 svn_error_t *
 svn_client__path_relative_to_root(const char **rel_path,
                                   svn_wc_context_t *wc_ctx,
@@ -180,6 +145,7 @@ svn_client__path_relative_to_root(const 
 
 svn_error_t *
 svn_client__get_repos_root(const char **repos_root,
+                           const char **repos_uuid,
                            const char *abspath_or_url,
                            svn_client_ctx_t *ctx,
                            apr_pool_t *result_pool,
@@ -190,7 +156,7 @@ svn_client__get_repos_root(const char **
   /* If PATH_OR_URL is a local path we can fetch the repos root locally. */
   if (!svn_path_is_url(abspath_or_url))
     {
-      SVN_ERR(svn_wc__node_get_repos_info(repos_root, NULL,
+      SVN_ERR(svn_wc__node_get_repos_info(repos_root, repos_uuid,
                                           ctx->wc_ctx, abspath_or_url,
                                           result_pool, scratch_pool));
 
@@ -203,7 +169,10 @@ svn_client__get_repos_root(const char **
                                                NULL, NULL, FALSE, TRUE,
                                                ctx, scratch_pool));
 
-  SVN_ERR(svn_ra_get_repos_root2(ra_session, repos_root, result_pool));
+  if (repos_root)
+    SVN_ERR(svn_ra_get_repos_root2(ra_session, repos_root, result_pool));
+  if (repos_uuid)
+    SVN_ERR(svn_ra_get_uuid2(ra_session, repos_uuid, result_pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/svn_mutex/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_delta/compat.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_delta/compat.c Tue Oct 11 19:52:34 2011
@@ -21,11 +21,14 @@
  * ====================================================================
  */
 
-#include <apr_pools.h>
-
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_delta.h"
+#include "svn_sorts.h"
+#include "svn_dirent_uri.h"
+#include "svn_path.h"
+#include "svn_props.h"
+#include "svn_pools.h"
 
 
 struct file_rev_handler_wrapper_baton {
@@ -76,3 +79,887 @@ svn_compat_wrap_file_rev_handler(svn_fil
   *handler2_baton = fwb;
   *handler2 = file_rev_handler_wrapper;
 }
+
+
+/* The following code maps the calls to a traditional delta editor to an
+ * Editorv2 editor.  It does this by keeping track of a lot of state, and
+ * then communicating that state to Ev2 upon closure of the file or dir (or
+ * edit).  Note that Ev2 calls add_symlink() and set_target() are not present
+ * in the delta editor paradigm, so we never call them.
+ *
+ * The general idea here is that we have to see *all* the actions on a node's
+ * parent before we can process that node, which means we need to buffer a
+ * large amount of information in the dir batons, and then process it in the
+ * close_directory() handler. */
+
+struct ev2_edit_baton
+{
+  svn_editor_t *editor;
+  apr_hash_t *paths;
+  svn_revnum_t target_revision;
+  apr_pool_t *edit_pool;
+  svn_delta_fetch_props_func_t fetch_props_func;
+  void *fetch_props_baton;
+};
+
+struct ev2_dir_baton
+{
+  struct ev2_edit_baton *eb;
+  const char *path;
+};
+
+struct ev2_file_baton
+{
+  struct ev2_edit_baton *eb;
+  const char *path;
+};
+
+enum action
+{
+  ACTION_ADD,
+  ACTION_DELETE,
+  ACTION_SET_PROP
+};
+
+struct path_action
+{
+  enum action action;
+  void *args;
+};
+
+struct prop_args
+{
+  const char *name;
+  const svn_string_t *value;
+};
+
+static svn_error_t *
+add_action(struct ev2_edit_baton *eb,
+           const char *path,
+           enum action action,
+           void *args)
+{
+  struct path_action *p_action;
+  apr_array_header_t *action_list = apr_hash_get(eb->paths, path,
+                                                 APR_HASH_KEY_STRING);
+
+  p_action = apr_palloc(eb->edit_pool, sizeof(*p_action));
+  p_action->action = action;
+  p_action->args = args;
+
+  if (action_list == NULL)
+    {
+      action_list = apr_array_make(eb->edit_pool, 1,
+                                   sizeof(struct path_action *));
+      apr_hash_set(eb->paths, apr_pstrdup(eb->edit_pool, path),
+                   APR_HASH_KEY_STRING, action_list);
+    }
+
+  APR_ARRAY_PUSH(action_list, struct path_action *) = p_action;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+process_actions(void *edit_baton,
+                const char *path,
+                apr_array_header_t *actions,
+                apr_pool_t *scratch_pool)
+{
+  struct ev2_edit_baton *eb = edit_baton;
+  apr_hash_t *props = NULL;
+  int i;
+
+  /* Go through all of our actions, populating various datastructures
+   * dependent on them. */
+  for (i = 0; i < actions->nelts; i++)
+    {
+      const struct path_action *action = APR_ARRAY_IDX(actions, i,
+                                                       struct path_action *);
+
+      switch (action->action)
+        {
+          case ACTION_SET_PROP:
+            {
+              const struct prop_args *p_args = action->args;
+
+              if (!props)
+                {
+                  /* Fetch the original props. We can then apply each of
+                     the modifications to it.  */
+                  SVN_ERR(eb->fetch_props_func(&props,
+                                               eb->fetch_props_baton,
+                                               path,
+                                               scratch_pool, scratch_pool));
+                }
+
+              /* Note that p_args->value may be NULL.  */
+              apr_hash_set(props, p_args->name, APR_HASH_KEY_STRING,
+                           p_args->value);
+              break;
+            }
+
+          case ACTION_DELETE:
+            {
+              svn_revnum_t *revnum = action->args;
+
+              /* If we get a delete, we'd better not have gotten any
+                 other actions for this path later, so we can go ahead
+                 and call our handler. */
+              SVN_ERR(svn_editor_delete(eb->editor, path, *revnum));
+              break;
+            }
+
+          case ACTION_ADD:
+            {
+              /* ### do something  */
+              break;
+            }
+
+          default:
+            SVN_ERR_MALFUNCTION();
+        }
+    }
+
+  /* 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 (props)
+    {
+      /* We fetched and modified the props in some way. Apply 'em now that
+         we have the new set.  */
+      SVN_ERR(svn_editor_set_props(eb->editor, path, eb->target_revision,
+                                   props, TRUE));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_set_target_revision(void *edit_baton,
+                        svn_revnum_t target_revision,
+                        apr_pool_t *scratch_pool)
+{
+  struct ev2_edit_baton *eb = edit_baton;
+
+  eb->target_revision = target_revision;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_open_root(void *edit_baton,
+              svn_revnum_t base_revision,
+              apr_pool_t *result_pool,
+              void **root_baton)
+{
+  struct ev2_dir_baton *db = apr_palloc(result_pool, sizeof(*db));
+  struct ev2_edit_baton *eb = edit_baton;
+
+  db->eb = eb;
+  db->path = "";
+
+  *root_baton = db;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_delete_entry(const char *path,
+                 svn_revnum_t revision,
+                 void *parent_baton,
+                 apr_pool_t *scratch_pool)
+{
+  struct ev2_dir_baton *pb = parent_baton;
+  svn_revnum_t *revnum = apr_palloc(pb->eb->edit_pool, sizeof(*revnum));
+
+  *revnum = revision;
+  SVN_ERR(add_action(pb->eb, path, ACTION_DELETE, revnum));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_add_directory(const char *path,
+                  void *parent_baton,
+                  const char *copyfrom_path,
+                  svn_revnum_t copyfrom_revision,
+                  apr_pool_t *result_pool,
+                  void **child_baton)
+{
+  struct ev2_dir_baton *pb = parent_baton;
+  struct ev2_dir_baton *cb = apr_palloc(result_pool, sizeof(*cb));
+  svn_node_kind_t *kind;
+
+  kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+  *kind = svn_node_dir;
+  SVN_ERR(add_action(pb->eb, path, ACTION_ADD, kind));
+
+  cb->eb = pb->eb;
+  cb->path = apr_pstrdup(result_pool, path);
+  *child_baton = cb;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_open_directory(const char *path,
+                   void *parent_baton,
+                   svn_revnum_t base_revision,
+                   apr_pool_t *result_pool,
+                   void **child_baton)
+{
+  struct ev2_dir_baton *pb = parent_baton;
+  struct ev2_dir_baton *db = apr_palloc(result_pool, sizeof(*db));
+
+  db->eb = pb->eb;
+  db->path = apr_pstrdup(result_pool, path);
+
+  *child_baton = db;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_change_dir_prop(void *dir_baton,
+                    const char *name,
+                    const svn_string_t *value,
+                    apr_pool_t *scratch_pool)
+{
+  struct ev2_dir_baton *db = dir_baton;
+  struct prop_args *p_args = apr_palloc(db->eb->edit_pool, sizeof(*p_args));
+
+  p_args->name = apr_pstrdup(db->eb->edit_pool, name);
+  p_args->value = value ? svn_string_dup(value, db->eb->edit_pool) : NULL;
+
+  SVN_ERR(add_action(db->eb, db->path, ACTION_SET_PROP, p_args));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_close_directory(void *dir_baton,
+                    apr_pool_t *scratch_pool)
+{
+  struct ev2_dir_baton *db = dir_baton;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_absent_directory(const char *path,
+                     void *parent_baton,
+                     apr_pool_t *scratch_pool)
+{
+  struct ev2_dir_baton *pb = parent_baton;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_add_file(const char *path,
+             void *parent_baton,
+             const char *copyfrom_path,
+             svn_revnum_t copyfrom_revision,
+             apr_pool_t *result_pool,
+             void **file_baton)
+{
+  struct ev2_file_baton *fb = apr_palloc(result_pool, sizeof(*fb));
+  struct ev2_dir_baton *pb = parent_baton;
+  svn_node_kind_t *kind;
+
+  fb->eb = pb->eb;
+  fb->path = apr_pstrdup(result_pool, path);
+  *file_baton = fb;
+
+  kind = apr_palloc(pb->eb->edit_pool, sizeof(*kind));
+  *kind = svn_node_file;
+  SVN_ERR(add_action(pb->eb, path, ACTION_ADD, kind));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_open_file(const char *path,
+              void *parent_baton,
+              svn_revnum_t base_revision,
+              apr_pool_t *result_pool,
+              void **file_baton)
+{
+  struct ev2_file_baton *fb = apr_palloc(result_pool, sizeof(*fb));
+  struct ev2_dir_baton *pb = parent_baton;
+
+  fb->eb = pb->eb;
+  fb->path = apr_pstrdup(result_pool, path);
+
+  *file_baton = fb;
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+ev2_apply_textdelta(void *file_baton,
+                    const char *base_checksum,
+                    apr_pool_t *result_pool,
+                    svn_txdelta_window_handler_t *handler,
+                    void **handler_baton)
+{
+  struct ev2_file_baton *fb = file_baton;
+
+  *handler_baton = NULL;
+  *handler = svn_delta_noop_window_handler;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_change_file_prop(void *file_baton,
+                     const char *name,
+                     const svn_string_t *value,
+                     apr_pool_t *scratch_pool)
+{
+  struct ev2_file_baton *fb = file_baton;
+  struct prop_args *p_args = apr_palloc(fb->eb->edit_pool, sizeof(*p_args));
+
+  p_args->name = apr_pstrdup(fb->eb->edit_pool, name);
+  p_args->value = value ? svn_string_dup(value, fb->eb->edit_pool) : NULL;
+
+  SVN_ERR(add_action(fb->eb, fb->path, ACTION_SET_PROP, p_args));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_close_file(void *file_baton,
+               const char *text_checksum,
+               apr_pool_t *scratch_pool)
+{
+  struct ev2_file_baton *fb = file_baton;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_absent_file(const char *path,
+                void *parent_baton,
+                apr_pool_t *scratch_pool)
+{
+  struct ev2_dir_baton *pb = parent_baton;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ev2_close_edit(void *edit_baton,
+               apr_pool_t *scratch_pool)
+{
+  struct ev2_edit_baton *eb = edit_baton;
+  apr_array_header_t *sorted_hash;
+  apr_pool_t *iterpool;
+  int i;
+
+  /* Sort the paths touched by this edit.
+   * Ev2 doesn't really have any particular need for depth-first-ness, but
+   * we want to ensure all parent directories are handled before children in
+   * the case of adds (which does introduce an element of depth-first-ness). */
+  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
+                               scratch_pool);
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < sorted_hash->nelts; i++)
+    {
+      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
+      apr_array_header_t *actions = item->value;
+      const char *path = item->key;
+
+      svn_pool_clear(iterpool);
+      SVN_ERR(process_actions(edit_baton, path, actions, iterpool));
+    }
+  svn_pool_destroy(iterpool);
+
+  return svn_error_trace(svn_editor_complete(eb->editor));
+}
+
+static svn_error_t *
+ev2_abort_edit(void *edit_baton,
+               apr_pool_t *scratch_pool)
+{
+  struct ev2_edit_baton *eb = edit_baton;
+
+  return svn_error_trace(svn_editor_abort(eb->editor));
+}
+
+svn_error_t *
+svn_delta_from_editor(const svn_delta_editor_t **deditor,
+                      void **dedit_baton,
+                      svn_editor_t *editor,
+                      svn_delta_fetch_props_func_t fetch_props_func,
+                      void *fetch_props_baton,
+                      apr_pool_t *pool)
+{
+  /* Static 'cause we don't want it to be on the stack. */
+  static svn_delta_editor_t delta_editor = {
+      ev2_set_target_revision,
+      ev2_open_root,
+      ev2_delete_entry,
+      ev2_add_directory,
+      ev2_open_directory,
+      ev2_change_dir_prop,
+      ev2_close_directory,
+      ev2_absent_directory,
+      ev2_add_file,
+      ev2_open_file,
+      ev2_apply_textdelta,
+      ev2_change_file_prop,
+      ev2_close_file,
+      ev2_absent_file,
+      ev2_close_edit,
+      ev2_abort_edit
+    };
+  struct ev2_edit_baton *eb = apr_palloc(pool, sizeof(*eb));
+
+  eb->editor = editor;
+  eb->paths = apr_hash_make(pool);
+  eb->target_revision = SVN_INVALID_REVNUM;
+  eb->edit_pool = pool;
+  eb->fetch_props_func = fetch_props_func;
+  eb->fetch_props_baton = fetch_props_baton;
+
+  *dedit_baton = eb;
+  *deditor = &delta_editor;
+
+  return SVN_NO_ERROR;
+}
+
+
+
+
+
+typedef enum action_code_t {
+  ACTION_MV,
+  ACTION_MKDIR,
+  ACTION_CP,
+  ACTION_PROPSET,
+  ACTION_PUT,
+  ACTION_RM
+} action_code_t;
+
+struct operation {
+  enum {
+    OP_OPEN,
+    OP_DELETE,
+    OP_ADD,
+    OP_REPLACE,
+    OP_PROPSET           /* only for files for which no other operation is
+                            occuring; directories are OP_OPEN with non-empty
+                            props */
+  } operation;
+  svn_node_kind_t kind;  /* to copy, mkdir, put or set revprops */
+  svn_revnum_t rev;      /* to copy, valid for add and replace */
+  const char *url;       /* to copy, valid for add and replace */
+  const char *src_file;  /* for put, the source file for contents */
+  apr_hash_t *children;  /* const char *path -> struct operation * */
+  apr_hash_t *props;     /* const char *prop_name ->
+                            const svn_string_t *prop_value */
+  void *baton;           /* as returned by the commit editor */
+};
+
+struct editor_baton
+{
+  const svn_delta_editor_t *deditor;
+  void *dedit_baton;
+
+  svn_delta_fetch_kind_func_t fetch_kind_func;
+  void *fetch_kind_baton;
+
+  struct operation root;
+
+  apr_hash_t *paths;
+  apr_pool_t *edit_pool;
+};
+
+/* Find the operation associated with PATH, which is a single-path
+   component representing a child of the path represented by
+   OPERATION.  If no such child operation exists, create a new one of
+   type OP_OPEN. */
+static struct operation *
+get_operation(const char *path,
+              struct operation *operation,
+              apr_pool_t *result_pool)
+{
+  struct operation *child = apr_hash_get(operation->children, path,
+                                         APR_HASH_KEY_STRING);
+  if (! child)
+    {
+      child = apr_pcalloc(result_pool, sizeof(*child));
+      child->children = apr_hash_make(result_pool);
+      child->operation = OP_OPEN;
+      child->rev = SVN_INVALID_REVNUM;
+      child->kind = svn_node_dir;
+      child->props = NULL;
+      apr_hash_set(operation->children, apr_pstrdup(result_pool, path),
+                   APR_HASH_KEY_STRING, child);
+    }
+  return child;
+}
+
+/* Add PATH to the operations tree rooted at OPERATION, creating any
+   intermediate nodes that are required.  Here's what's expected for
+   each action type:
+
+      ACTION          URL    REV      SRC-FILE  PROPNAME
+      ------------    -----  -------  --------  --------
+      ACTION_MKDIR    NULL   invalid  NULL      NULL
+      ACTION_CP       valid  valid    NULL      NULL
+      ACTION_PUT      NULL   invalid  valid     NULL
+      ACTION_RM       NULL   invalid  NULL      NULL
+      ACTION_PROPSET  valid  invalid  NULL      valid
+
+   Node type information is obtained for any copy source (to determine
+   whether to create a file or directory) and for any deleted path (to
+   ensure it exists since svn_delta_editor_t->delete_entry doesn't
+   return an error on non-existent nodes). */
+static svn_error_t *
+build(struct editor_baton *eb,
+      action_code_t action,
+      const char *relpath,
+      const char *url,
+      svn_revnum_t rev,
+      apr_hash_t *props,
+      const char *src_file,
+      svn_revnum_t head,
+      apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *path_bits = svn_path_decompose(relpath, scratch_pool);
+  const char *path_so_far = "";
+  struct operation *operation = &eb->root;
+  int i;
+
+  /* We should only see PROPS when action is ACTION_PROPSET. */
+  SVN_ERR_ASSERT((props && action == ACTION_PROPSET)
+                || (!props && action != ACTION_PROPSET) );
+
+  /* Look for any previous operations we've recognized for PATH.  If
+     any of PATH's ancestors have not yet been traversed, we'll be
+     creating OP_OPEN operations for them as we walk down PATH's path
+     components. */
+  for (i = 0; i < path_bits->nelts; ++i)
+    {
+      const char *path_bit = APR_ARRAY_IDX(path_bits, i, const char *);
+      path_so_far = svn_relpath_join(path_so_far, path_bit, scratch_pool);
+      operation = get_operation(path_so_far, operation, eb->edit_pool);
+    }
+
+  /* Handle property changes. */
+  if (props)
+    {
+      SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
+                                  relpath, scratch_pool));
+
+      /* If we're not adding this thing ourselves, check for existence.  */
+      if (! ((operation->operation == OP_ADD) ||
+             (operation->operation == OP_REPLACE)))
+        {
+          if ((operation->kind == svn_node_file)
+                   && (operation->operation == OP_OPEN))
+            operation->operation = OP_PROPSET;
+        }
+      operation->props = svn_prop_hash_dup(props, eb->edit_pool);
+      if (!operation->rev)
+        operation->rev = rev;
+      return SVN_NO_ERROR;
+    }
+
+  if (action == ACTION_RM)
+    operation->operation = OP_DELETE;
+
+  /* Handle copy operations (which can be adds or replacements). */
+  else if (action == ACTION_CP)
+    {
+      operation->operation =
+        operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
+
+      SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
+                                  relpath, scratch_pool));
+      operation->url = url;
+      operation->rev = rev;
+    }
+  /* Handle mkdir operations (which can be adds or replacements). */
+  else if (action == ACTION_MKDIR)
+    {
+      operation->operation =
+        operation->operation == OP_DELETE ? OP_REPLACE : OP_ADD;
+      operation->kind = svn_node_dir;
+    }
+  /* Handle put operations (which can be adds, replacements, or opens). */
+  else if (action == ACTION_PUT)
+    {
+      if (operation->operation == OP_DELETE)
+        {
+          operation->operation = OP_REPLACE;
+        }
+      else
+        {
+          SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
+                                      relpath, scratch_pool));
+          if (operation->kind == svn_node_file)
+            operation->operation = OP_OPEN;
+          else if (operation->kind == svn_node_none)
+            operation->operation = OP_ADD;
+          else
+            return svn_error_createf(SVN_ERR_BAD_URL, NULL,
+                                     "'%s' is not a file", relpath);
+        }
+      operation->kind = svn_node_file;
+      operation->src_file = src_file;
+    }
+  else
+    {
+      /* We shouldn't get here. */
+      SVN_ERR_MALFUNCTION();
+    }
+
+  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)
+{
+  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)
+{
+  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)
+{
+  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_node_kind_t kind,
+              svn_revnum_t replaces_rev,
+              apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
+
+/* This implements svn_editor_cb_set_props_t */
+static svn_error_t *
+set_props_cb(void *baton,
+             const char *relpath,
+             svn_revnum_t revision,
+             apr_hash_t *props,
+             svn_boolean_t complete,
+             apr_pool_t *scratch_pool)
+{
+  struct editor_baton *eb = baton;
+
+  SVN_ERR(build(eb, ACTION_PROPSET, relpath, NULL, SVN_INVALID_REVNUM,
+                props, NULL, SVN_INVALID_REVNUM, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* This implements svn_editor_cb_set_text_t */
+static svn_error_t *
+set_text_cb(void *baton,
+            const char *relpath,
+            svn_revnum_t revision,
+            const svn_checksum_t *checksum,
+            svn_stream_t *contents,
+            apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
+
+/* This implements svn_editor_cb_set_target_t */
+static svn_error_t *
+set_target_cb(void *baton,
+              const char *relpath,
+              svn_revnum_t revision,
+              const char *target,
+              apr_pool_t *scratch_pool)
+{
+  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)
+{
+  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)
+{
+  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)
+{
+  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 editor_baton *eb = baton;
+  apr_array_header_t *sorted_hash;
+  int i;
+
+  /* Sort the paths touched by this edit.
+   * Ev2 doesn't really have any particular need for depth-first-ness, but
+   * we want to ensure all parent directories are handled before children in
+   * the case of adds (which does introduce an element of depth-first-ness). */
+  sorted_hash = svn_sort__hash(eb->paths, svn_sort_compare_items_as_paths,
+                               scratch_pool);
+
+  for (i = 0; i < sorted_hash->nelts; i++)
+    {
+      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i, svn_sort__item_t);
+      const char *path = item->key;
+
+      /* ### We should actually do something here, but for now... */
+    }
+
+  return svn_error_trace(eb->deditor->close_edit(eb->dedit_baton,
+                                                 scratch_pool));
+}
+
+/* This implements svn_editor_cb_abort_t */
+static svn_error_t *
+abort_cb(void *baton,
+         apr_pool_t *scratch_pool)
+{
+  struct editor_baton *eb = baton;
+  return svn_error_trace(eb->deditor->abort_edit(eb->dedit_baton,
+                                                 scratch_pool));
+}
+
+svn_error_t *
+svn_editor_from_delta(svn_editor_t **editor_p,
+                      const svn_delta_editor_t *deditor,
+                      void *dedit_baton,
+                      svn_cancel_func_t cancel_func,
+                      void *cancel_baton,
+                      svn_delta_fetch_kind_func_t fetch_kind_func,
+                      void *fetch_kind_baton,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  svn_editor_t *editor;
+  static const svn_editor_cb_many_t editor_cbs = {
+      add_directory_cb,
+      add_file_cb,
+      add_symlink_cb,
+      add_absent_cb,
+      set_props_cb,
+      set_text_cb,
+      set_target_cb,
+      delete_cb,
+      copy_cb,
+      move_cb,
+      complete_cb,
+      abort_cb
+    };
+  struct editor_baton *eb = apr_palloc(result_pool, sizeof(*eb));
+
+  eb->deditor = deditor;
+  eb->dedit_baton = dedit_baton;
+  eb->edit_pool = result_pool;
+  eb->paths = apr_hash_make(result_pool);
+
+  eb->fetch_kind_func = fetch_kind_func;
+  eb->fetch_kind_baton = fetch_kind_baton;
+
+  eb->root.children = apr_hash_make(result_pool);
+  eb->root.kind = svn_node_dir;
+  eb->root.operation = OP_OPEN;
+  eb->root.props = NULL;
+  eb->root.rev = SVN_INVALID_REVNUM;
+
+  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));
+
+  *editor_p = editor;
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Uncomment below to add editor shims throughout Subversion.  In it's
+ * current state, that will likely break The World. */
+/* #define ENABLE_EDITOR_SHIMS*/
+
+svn_error_t *
+svn_editor__insert_shims(const svn_delta_editor_t **deditor_out,
+                         void **dedit_baton_out,
+                         const svn_delta_editor_t *deditor_in,
+                         void *dedit_baton_in,
+                         svn_delta_fetch_props_func_t fetch_props_func,
+                         void *fetch_props_baton,
+                         svn_delta_fetch_kind_func_t fetch_kind_func,
+                         void *fetch_kind_baton,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
+{
+#ifndef ENABLE_EDITOR_SHIMS
+  /* Shims disabled, just copy the editor and baton directly. */
+  *deditor_out = deditor_in;
+  *dedit_baton_out = dedit_baton_in;
+#else
+  /* Use our shim APIs to create an intermediate svn_editor_t, and then
+     wrap that again back into a svn_delta_editor_t.  This introduces
+     a lot of overhead. */
+  svn_editor_t *editor;
+
+  SVN_ERR(svn_editor_from_delta(&editor, deditor_in, dedit_baton_in,
+                                NULL, NULL, fetch_kind_func, fetch_kind_baton,
+                                result_pool, scratch_pool));
+  SVN_ERR(svn_delta_from_editor(deditor_out, dedit_baton_out, editor,
+                                fetch_props_func, fetch_props_baton,
+                                result_pool));
+
+#endif
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/svn_mutex/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_delta/editor.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_delta/editor.c Tue Oct 11 19:52:34 2011
@@ -26,8 +26,17 @@
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_pools.h"
+#include "svn_editor.h"
+#include "svn_dirent_uri.h"
 
-#include "private/svn_editor.h"
+#ifdef SVN_DEBUG
+/* This enables runtime checks of the editor API constraints.  This may
+   introduce additional memory and runtime overhead, and should not be used
+   in production builds.
+   
+   ### Remove before release? */
+#define ENABLE_ORDERING_CHECK
+#endif
 
 
 struct svn_editor_t
@@ -44,6 +53,15 @@ struct svn_editor_t
 
   /* This pool is used as the scratch_pool for all callbacks.  */
   apr_pool_t *scratch_pool;
+
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_t *pending_incomplete_children;
+  apr_hash_t *completed_nodes;
+  apr_hash_t *needs_text_or_target;
+  svn_boolean_t finished;
+
+  apr_pool_t *result_pool;
+#endif
 };
 
 
@@ -61,6 +79,13 @@ svn_editor_create(svn_editor_t **editor,
   (*editor)->cancel_func = cancel_func;
   (*editor)->cancel_baton = cancel_baton;
   (*editor)->scratch_pool = svn_pool_create(result_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  (*editor)->pending_incomplete_children = apr_hash_make(result_pool);
+  (*editor)->completed_nodes = apr_hash_make(result_pool);
+  (*editor)->needs_text_or_target = apr_hash_make(result_pool);
+  (*editor)->finished = FALSE;
+  (*editor)->result_pool = result_pool;
+#endif
 
   return SVN_NO_ERROR;
 }
@@ -222,6 +247,11 @@ svn_editor_add_directory(svn_editor_t *e
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_add_directory != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -229,6 +259,25 @@ svn_editor_add_directory(svn_editor_t *e
   err = editor->funcs.cb_add_directory(editor->baton, relpath, children,
                                        props, replaces_rev,
                                        editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+  apr_hash_set(editor->pending_incomplete_children, relpath,
+               APR_HASH_KEY_STRING, NULL);
+  {
+    int i;
+    for (i = 0; i < children->nelts; i++)
+      {
+        const char *child_basename = APR_ARRAY_IDX(children, i, const char *);
+        const char *child = svn_relpath_join(relpath, child_basename,
+                                             editor->result_pool);
+
+        apr_hash_set(editor->pending_incomplete_children, child,
+                     APR_HASH_KEY_STRING, (void *)0xdeadbeef);
+      }
+  }
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -237,18 +286,33 @@ svn_editor_add_directory(svn_editor_t *e
 svn_error_t *
 svn_editor_add_file(svn_editor_t *editor,
                     const char *relpath,
+                    const svn_checksum_t *checksum,
+                    svn_stream_t *contents,
                     apr_hash_t *props,
                     svn_revnum_t replaces_rev)
 {
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_add_file != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  err = editor->funcs.cb_add_file(editor->baton, relpath, props,
+  err = editor->funcs.cb_add_file(editor->baton, relpath,
+                                  checksum, contents, props,
                                   replaces_rev, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+  apr_hash_set(editor->pending_incomplete_children, relpath,
+               APR_HASH_KEY_STRING, NULL);
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -264,12 +328,24 @@ svn_editor_add_symlink(svn_editor_t *edi
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_add_symlink != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
   err = editor->funcs.cb_add_symlink(editor->baton, relpath, target, props,
                                      replaces_rev, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+  apr_hash_set(editor->pending_incomplete_children, relpath,
+               APR_HASH_KEY_STRING, NULL);
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -284,12 +360,24 @@ svn_editor_add_absent(svn_editor_t *edit
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_add_absent != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
   err = editor->funcs.cb_add_absent(editor->baton, relpath, kind,
                                     replaces_rev, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+  apr_hash_set(editor->pending_incomplete_children, relpath,
+               APR_HASH_KEY_STRING, NULL);
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -305,12 +393,33 @@ svn_editor_set_props(svn_editor_t *edito
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_set_props != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
   err = editor->funcs.cb_set_props(editor->baton, relpath, revision, props,
                                    complete, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  /* ### Some of the ordering here depends upon the kind of RELPATH, but
+   * ### we have no way of determining what that is. */
+  if (complete)
+    {
+      apr_hash_set(editor->completed_nodes,
+                   apr_pstrdup(editor->result_pool, relpath),
+                   APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+    }
+  else
+    {
+      apr_hash_set(editor->needs_text_or_target,
+                   apr_pstrdup(editor->result_pool, relpath),
+                   APR_HASH_KEY_STRING, (void *) 0xba5eba11);
+    }
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -326,12 +435,24 @@ svn_editor_set_text(svn_editor_t *editor
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_set_text != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
   err = editor->funcs.cb_set_text(editor->baton, relpath, revision,
                                   checksum, contents, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_set(editor->needs_text_or_target, relpath, APR_HASH_KEY_STRING,
+               NULL);
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -346,12 +467,24 @@ svn_editor_set_target(svn_editor_t *edit
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_set_target != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
   err = editor->funcs.cb_set_target(editor->baton, relpath, revision,
                                     target, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_set(editor->needs_text_or_target, relpath, APR_HASH_KEY_STRING,
+               NULL);
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -365,12 +498,22 @@ svn_editor_delete(svn_editor_t *editor,
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_delete != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
   err = editor->funcs.cb_delete(editor->baton, relpath, revision,
                                 editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -386,6 +529,11 @@ svn_editor_copy(svn_editor_t *editor,
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_copy != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, dst_relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -408,6 +556,13 @@ svn_editor_move(svn_editor_t *editor,
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_move != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, src_relpath,
+                               APR_HASH_KEY_STRING));
+  SVN_ERR_ASSERT(!apr_hash_get(editor->completed_nodes, dst_relpath,
+                               APR_HASH_KEY_STRING));
+#endif
 
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
@@ -415,6 +570,22 @@ svn_editor_move(svn_editor_t *editor,
   err = editor->funcs.cb_move(editor->baton, src_relpath, src_revision,
                               dst_relpath, replaces_rev,
                               editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  /* ### after moving a node away, a new one can be created. how does
+     ### affect the "replaces_rev" concept elsewhere?  */
+#if 0
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, src_relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+#endif
+
+  /* ### hmm. post-move, it should be possible to change props/contents.  */
+#if 0
+  apr_hash_set(editor->completed_nodes,
+               apr_pstrdup(editor->result_pool, dst_relpath),
+               APR_HASH_KEY_STRING, (void *) 0x5ca1ab1e);
+#endif
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -426,8 +597,16 @@ svn_editor_complete(svn_editor_t *editor
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_complete != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  SVN_ERR_ASSERT(apr_hash_count(editor->pending_incomplete_children) == 0);
+  SVN_ERR_ASSERT(apr_hash_count(editor->needs_text_or_target) == 0);
+#endif
 
   err = editor->funcs.cb_complete(editor->baton, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  editor->finished = TRUE;
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -439,8 +618,14 @@ svn_editor_abort(svn_editor_t *editor)
   svn_error_t *err;
 
   SVN_ERR_ASSERT(editor->funcs.cb_abort != NULL);
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+#endif
 
   err = editor->funcs.cb_abort(editor->baton, editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  editor->finished = TRUE;
+#endif
   svn_pool_clear(editor->scratch_pool);
   return err;
 }

Modified: subversion/branches/svn_mutex/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_delta/svndiff.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_delta/svndiff.c Tue Oct 11 19:52:34 2011
@@ -149,7 +149,7 @@ zlib_encode(const char *data,
      ZLIB will produce an output no shorter than the input.  Hence,
      the DATA would directly appended to OUT, so we can do that directly
      without calling ZLIB before. */
-  if (   (len < MIN_COMPRESS_SIZE) 
+  if (   (len < MIN_COMPRESS_SIZE)
       || (compression_level == SVN_DELTA_COMPRESSION_LEVEL_NONE))
     {
       svn_stringbuf_appendbytes(out, data, len);

Modified: subversion/branches/svn_mutex/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_diff/diff_file.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_diff/diff_file.c Tue Oct 11 19:52:34 2011
@@ -1636,7 +1636,7 @@ output_unified_diff_modified(void *baton
 
       if (output_baton->show_c_function)
         {
-          int p;
+          apr_size_t p;
           const char *invalid_character;
 
           /* Save the extra context for later use.
@@ -1920,7 +1920,7 @@ flush_context_saver(context_saver_t *cs,
   int i;
   for (i = 0; i < SVN_DIFF__UNIFIED_CONTEXT_SIZE; i++)
     {
-      int slot = (i + cs->next_slot) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+      apr_size_t slot = (i + cs->next_slot) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
       if (cs->data[slot])
         {
           apr_size_t len = cs->len[slot];

Modified: subversion/branches/svn_mutex/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_diff/diff_memory.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_diff/diff_memory.c Tue Oct 11 19:52:34 2011
@@ -710,7 +710,7 @@ flush_context_saver(context_saver_t *cs,
   int i;
   for (i = 0; i < SVN_DIFF__UNIFIED_CONTEXT_SIZE; i++)
     {
-      int slot = (i + cs->next_slot) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
+      apr_size_t slot = (i + cs->next_slot) % SVN_DIFF__UNIFIED_CONTEXT_SIZE;
       if (cs->data[slot])
         {
           apr_size_t len = cs->len[slot];

Modified: subversion/branches/svn_mutex/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_diff/parse-diff.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_diff/parse-diff.c Tue Oct 11 19:52:34 2011
@@ -22,6 +22,7 @@
  */
 
 #include <stdlib.h>
+#include <stddef.h>
 #include <string.h>
 
 #include "svn_types.h"
@@ -965,8 +966,8 @@ git_start(enum parse_state *new_state, c
 
   while (TRUE)
     {
-      int len_old;
-      int len_new;
+      ptrdiff_t len_old;
+      ptrdiff_t len_new;
 
       new_path_marker = strstr(new_path_start, " b/");
 

Modified: subversion/branches/svn_mutex/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn_mutex/subversion/libsvn_fs/fs-loader.c?rev=1182053&r1=1182052&r2=1182053&view=diff
==============================================================================
--- subversion/branches/svn_mutex/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/svn_mutex/subversion/libsvn_fs/fs-loader.c Tue Oct 11 19:52:34 2011
@@ -29,6 +29,7 @@
 #include <apr_thread_mutex.h>
 #include <apr_uuid.h>
 
+#include "svn_ctype.h"
 #include "svn_types.h"
 #include "svn_dso.h"
 #include "svn_version.h"
@@ -389,6 +390,31 @@ svn_fs_upgrade(const char *path, apr_poo
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_verify(const char *path,
+              svn_cancel_func_t cancel_func,
+              void *cancel_baton,
+              apr_pool_t *pool) 
+{
+  svn_error_t *err;
+  svn_error_t *err2;
+  fs_library_vtable_t *vtable;
+  svn_fs_t *fs;
+
+  SVN_ERR(fs_library_vtable(&vtable, path, pool));
+  fs = fs_new(NULL, pool);
+  SVN_ERR(acquire_fs_mutex());
+  err = vtable->verify_fs(fs, path, cancel_func, cancel_baton,
+                          pool, common_pool);
+  err2 = release_fs_mutex();
+  if (err)
+    {
+      svn_error_clear(err2);
+      return svn_error_trace(err);
+    }
+  return svn_error_trace(err2);
+}
+
 const char *
 svn_fs_path(svn_fs_t *fs, apr_pool_t *pool)
 {
@@ -872,22 +898,6 @@ svn_fs_closest_copy(svn_fs_root_t **root
 }
 
 svn_error_t *
-svn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog,
-                      svn_fs_root_t *root,
-                      const apr_array_header_t *paths,
-                      svn_mergeinfo_inheritance_t inherit,
-                      svn_boolean_t validate_inherited_mergeinfo,
-                      svn_boolean_t include_descendants,
-                      apr_pool_t *pool)
-{
-  return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths,
-                                                     inherit,
-                                                     validate_inherited_mergeinfo,
-                                                     include_descendants,
-                                                     pool));
-}
-
-svn_error_t *
 svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
                      svn_fs_root_t *root,
                      const apr_array_header_t *paths,
@@ -895,24 +905,10 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catal
                      svn_boolean_t include_descendants,
                      apr_pool_t *pool)
 {
-  return svn_error_trace(svn_fs_get_mergeinfo2(catalog, root, paths,
-                                               inherit,
-                                               FALSE,
-                                               include_descendants,
-                                               pool));
-}
-
-svn_error_t *
-svn_fs_validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
-                          svn_fs_t *fs,
-                          svn_mergeinfo_t mergeinfo,
-                          apr_pool_t *result_pool,
-                          apr_pool_t *scratch_pool)
-{
-  return svn_error_trace(fs->vtable->validate_mergeinfo(validated_mergeinfo,
-                                                        fs, mergeinfo,
-                                                        result_pool,
-                                                        scratch_pool));
+  return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths,
+                                                     inherit,
+                                                     include_descendants,
+                                                     pool));
 }
 
 svn_error_t *
@@ -1180,6 +1176,31 @@ svn_fs_lock(svn_lock_t **lock, svn_fs_t 
            _("Lock comment contains illegal characters"));
     }
 
+  /* Enforce that the token be an XML-safe URI. */
+  if (token)
+    {
+      const char *c;
+
+      if (strncmp(token, "opaquelocktoken:", 16))
+        return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
+                                 _("Lock token URI '%s' has bad scheme; "
+                                   "expected '%s'"),
+                                 token, "opaquelocktoken");
+
+      for (c = token; *c; c++)
+        if (! svn_ctype_isascii(*c))
+          return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
+                                   _("Lock token '%s' is not ASCII "
+                                     "at byte %u"),
+                                   token, (unsigned)(c - token));
+
+      /* strlen(token) == c - token. */
+      if (! svn_xml_is_xml_safe(token, c - token))
+        return svn_error_createf(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL,
+                                 _("Lock token URI '%s' is not XML-safe"),
+                                 token);
+    }
+
   if (expiration_date < 0)
         return svn_error_create
           (SVN_ERR_INCORRECT_PARAMS, NULL,