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 2012/02/02 14:37:32 UTC

svn commit: r1239613 [2/3] - in /subversion/branches/moves-scan-log: ./ notes/ subversion/bindings/javahl/ subversion/bindings/javahl/native/ subversion/bindings/swig/python/libsvn_swig_py/ subversion/bindings/swig/python/tests/ subversion/include/ sub...

Modified: subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_client/merge.c Thu Feb  2 13:37:30 2012
@@ -9842,6 +9842,85 @@ find_unsynced_ranges(const char *source_
 }
 
 
+/* Find the youngest revision that has been merged from target to source.
+ *
+ * If any location in TARGET_HISTORY_AS_MERGEINFO is mentioned in
+ * SOURCE_MERGEINFO, then we know that at least one merge was done from the
+ * target to the source.  In that case, set *YOUNGEST_MERGED_REV to the
+ * youngest revision of that intersection (unless *YOUNGEST_MERGED_REV is
+ * already younger than that).  Otherwise, leave *YOUNGEST_MERGED_REV alone.
+ */
+static svn_error_t *
+find_youngest_merged_rev(svn_revnum_t *youngest_merged_rev,
+                         svn_mergeinfo_t target_history_as_mergeinfo,
+                         svn_mergeinfo_t source_mergeinfo,
+                         apr_pool_t *scratch_pool)
+{
+  svn_mergeinfo_t explicit_source_target_history_intersection;
+
+  SVN_ERR(svn_mergeinfo_intersect2(
+            &explicit_source_target_history_intersection,
+            source_mergeinfo, target_history_as_mergeinfo, TRUE,
+            scratch_pool, scratch_pool));
+  if (apr_hash_count(explicit_source_target_history_intersection))
+    {
+      svn_revnum_t old_rev, young_rev;
+
+      /* Keep track of the youngest revision merged from target to source. */
+      SVN_ERR(svn_mergeinfo__get_range_endpoints(
+                &young_rev, &old_rev,
+                explicit_source_target_history_intersection, scratch_pool));
+      if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
+          || (young_rev > *youngest_merged_rev))
+        *youngest_merged_rev = young_rev;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Set *FILTERED_MERGEINFO_P to the parts of TARGET_HISTORY_AS_MERGEINFO
+ * that are not present in the source branch.
+ *
+ * SOURCE_MERGEINFO is the explicit or inherited mergeinfo of the source
+ * branch SOURCE_URL@SOURCE_REV.  Extend SOURCE_MERGEINFO, modifying it in
+ * place, to include the natural history (implicit mergeinfo) of
+ * SOURCE_URL@SOURCE_REV.  ### But make these additions in SCRATCH_POOL.
+ */
+static svn_error_t *
+find_unmerged_mergeinfo_subroutine(svn_mergeinfo_t *filtered_mergeinfo_p,
+                                   svn_mergeinfo_t target_history_as_mergeinfo,
+                                   svn_mergeinfo_t source_mergeinfo,
+                                   const char *source_url,
+                                   svn_revnum_t source_rev,
+                                   svn_ra_session_t *source_ra_session,
+                                   svn_client_ctx_t *ctx,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool)
+{
+  svn_mergeinfo_t source_history_as_mergeinfo;
+
+  /* Get the source path's natural history and merge it into source
+     path's explicit or inherited mergeinfo. */
+  SVN_ERR(svn_client__get_history_as_mergeinfo(
+            &source_history_as_mergeinfo, NULL /* has_rev_zero_history */,
+            source_url, source_rev, source_rev, SVN_INVALID_REVNUM,
+            source_ra_session, ctx, scratch_pool));
+  SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo,
+                               source_history_as_mergeinfo,
+                               scratch_pool, scratch_pool));
+
+  /* Now source_mergeinfo represents everything we know about
+     source_path's history.  Now we need to know what part, if any, of the
+     corresponding target's history is *not* part of source_path's total
+     history; because it is neither shared history nor was it ever merged
+     from the target to the source. */
+  SVN_ERR(svn_mergeinfo_remove2(filtered_mergeinfo_p,
+                                source_mergeinfo,
+                                target_history_as_mergeinfo, TRUE,
+                                result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 /* Helper for calculate_left_hand_side() which produces a mergeinfo catalog
    describing what parts of of the reintegrate target have not previously been
    merged to the reintegrate source.
@@ -9884,8 +9963,7 @@ find_unsynced_ranges(const char *source_
    TARGET_HISTORY_HASH.
 
    If no part of TARGET_HISTORY_HASH is found in SOURCE_CATALOG set
-   *NEVER_SYNCHED to TRUE and set *YOUNGEST_MERGED_REV to SVN_INVALID_REVNUM.
-   Otherwise set *NEVER_SYNCHED to FALSE, *YOUNGEST_MERGED_REV to the youngest
+   *YOUNGEST_MERGED_REV to SVN_INVALID_REVNUM; otherwise set it to the youngest
    revision previously merged from the target to the source, and filter
    *UNMERGED_TO_SOURCE_CATALOG so that it contains no ranges greater than
    *YOUNGEST_MERGED_REV.
@@ -9894,7 +9972,6 @@ find_unsynced_ranges(const char *source_
    SCRATCH_POOL is used for all temporary allocations.  */
 static svn_error_t *
 find_unmerged_mergeinfo(svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
-                        svn_boolean_t *never_synched,
                         svn_revnum_t *youngest_merged_rev,
                         svn_revnum_t yc_ancestor_rev,
                         svn_mergeinfo_catalog_t source_catalog,
@@ -9914,9 +9991,7 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
   apr_hash_index_t *hi;
   svn_mergeinfo_catalog_t new_catalog = apr_hash_make(result_pool);
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  svn_revnum_t old_rev, young_rev;
 
-  *never_synched = TRUE;
   *youngest_merged_rev = SVN_INVALID_REVNUM;
 
   SVN_ERR(svn_ra_get_session_url(target_ra_session, &target_session_url,
@@ -9932,12 +10007,11 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
     {
       const char *target_path = svn__apr_hash_index_key(hi);
       svn_mergeinfo_t target_history_as_mergeinfo = svn__apr_hash_index_val(hi);
-      svn_mergeinfo_t source_history_as_mergeinfo;
       const char *path_rel_to_session
         = svn_relpath_skip_ancestor(target_repos_rel_path, target_path);
       const char *source_path;
       const char *source_url;
-      svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo, common_mergeinfo;
+      svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo;
 
       svn_pool_clear(iterpool);
 
@@ -9966,31 +10040,13 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
                                       APR_HASH_KEY_STRING);
       if (source_mergeinfo)
         {
-          svn_mergeinfo_t explicit_source_target_history_intersection;
-
           apr_hash_set(source_catalog, source_path, APR_HASH_KEY_STRING,
                        NULL);
-          /* If there is an intersection between the *explicit* mergeinfo on
-             this source path and the corresponding target's history then we
-             know that at least one merge was done from the target to the
-             source. */
-          SVN_ERR(svn_mergeinfo_intersect2(
-            &explicit_source_target_history_intersection,
-            source_mergeinfo, target_history_as_mergeinfo, TRUE,
-            iterpool, iterpool));
-          if (apr_hash_count(explicit_source_target_history_intersection))
-            {
-              *never_synched = FALSE;
-              /* Keep track of the youngest revision merged from the
-                 target to the source. */
-              SVN_ERR(svn_mergeinfo__get_range_endpoints(
-                &young_rev, &old_rev,
-                explicit_source_target_history_intersection,
-                iterpool));
-              if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
-                  || (young_rev > *youngest_merged_rev))
-                *youngest_merged_rev = young_rev;
-            }
+
+          SVN_ERR(find_youngest_merged_rev(youngest_merged_rev,
+                                           target_history_as_mergeinfo,
+                                           source_mergeinfo,
+                                           iterpool));
         }
       else
         {
@@ -10027,40 +10083,13 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
             source_mergeinfo = apr_hash_make(iterpool);
         }
 
-      /* Get the source path's natural history and convert it to mergeinfo.
-         Then merge that natural history into source path's explicit
-         or inherited mergeinfo. */
-      SVN_ERR(svn_client__get_history_as_mergeinfo(&source_history_as_mergeinfo,
-                                                   NULL /* has_rev_zero_history */,
-                                                   source_url,
-                                                   source_rev, source_rev,
-                                                   SVN_INVALID_REVNUM,
-                                                   source_ra_session,
-                                                   ctx, iterpool));
-      SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo,
-                                   source_history_as_mergeinfo, iterpool,
-                                   iterpool));
-
-      /* Now source_mergeinfo represents everything we know about
-         source_path's history.  Now we need to know what part, if any, of the
-         corresponding target's history is *not* part of source_path's total
-         history; because it is neither shared history nor was it ever merged
-         from the target to the source. */
-      SVN_ERR(svn_mergeinfo_intersect2(&common_mergeinfo,
-                                       source_mergeinfo,
-                                       target_history_as_mergeinfo, TRUE,
-                                       iterpool, iterpool));
-
-      /* Use scratch_pool rather than iterpool because filtered_mergeinfo is
-         going into new_catalog below and needs to last to the end of
+      /* Use scratch_pool rather than iterpool because filtered_mergeinfo
+         is going into new_catalog below and needs to last to the end of
          this function. */
-      SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo,
-                                    common_mergeinfo,
-                                    target_history_as_mergeinfo, TRUE,
-                                    scratch_pool, iterpool));
-
-      /* As with svn_mergeinfo_intersect above, we need to use scratch_pool
-         rather than iterpool. */
+      SVN_ERR(find_unmerged_mergeinfo_subroutine(
+                &filtered_mergeinfo, target_history_as_mergeinfo,
+                source_mergeinfo, source_url, source_rev,
+                source_ra_session, ctx, scratch_pool, iterpool));
       apr_hash_set(new_catalog,
                    apr_pstrdup(scratch_pool, source_path),
                    APR_HASH_KEY_STRING,
@@ -10081,9 +10110,9 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
         svn_relpath_skip_ancestor(source_repos_rel_path, source_path);
       const char *source_url;
       svn_mergeinfo_t source_mergeinfo = svn__apr_hash_index_val(hi);
-      svn_mergeinfo_t filtered_mergeinfo, common_mergeinfo;
+      svn_mergeinfo_t filtered_mergeinfo;
       const char *target_url;
-      svn_mergeinfo_t target_history_as_mergeinfo, source_history_as_mergeinfo;
+      svn_mergeinfo_t target_history_as_mergeinfo;
       svn_error_t *err;
 
       svn_pool_clear(iterpool);
@@ -10116,56 +10145,19 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
         }
       else
         {
-          svn_mergeinfo_t explicit_source_target_history_intersection;
-
-          /* If there is an intersection between the *explicit* mergeinfo
-             on this source path and the corresponding target's history
-             then we know that at least one merge was done from the target
-             to the source. */
-          SVN_ERR(svn_mergeinfo_intersect2(
-            &explicit_source_target_history_intersection,
-            source_mergeinfo, target_history_as_mergeinfo, TRUE,
-            iterpool, iterpool));
-
-          if (apr_hash_count(explicit_source_target_history_intersection))
-            {
-              *never_synched = FALSE;
-              /* Keep track of the youngest revision merged from the
-                 target to the source. */
-              SVN_ERR(svn_mergeinfo__get_range_endpoints(
-                &young_rev, &old_rev,
-                explicit_source_target_history_intersection, iterpool));
-              if (!SVN_IS_VALID_REVNUM(*youngest_merged_rev)
-                  || (young_rev > *youngest_merged_rev))
-                *youngest_merged_rev = young_rev;
-            }
-
-          /* Get the source path's natural history and convert it to
-             mergeinfo.  Then merge that natural history into source
-             path's explicit or inherited mergeinfo. */
-          SVN_ERR(svn_client__get_history_as_mergeinfo(
-            &source_history_as_mergeinfo,
-            NULL /* has_rev_zero_history */,
-            source_url,
-            target_rev,
-            target_rev,
-            SVN_INVALID_REVNUM,
-            source_ra_session,
-            ctx, iterpool));
-          SVN_ERR(svn_mergeinfo_merge2(source_mergeinfo,
-                                       source_history_as_mergeinfo,
-                                       iterpool, iterpool));
-          SVN_ERR(svn_mergeinfo_intersect2(&common_mergeinfo,
-                                           source_mergeinfo,
+          SVN_ERR(find_youngest_merged_rev(youngest_merged_rev,
                                            target_history_as_mergeinfo,
-                                           TRUE, iterpool, iterpool));
-          /* Use subpool rather than iterpool because filtered_mergeinfo
-             is  going into new_catalog below and needs to last to the
-             end of this function. */
-          SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo,
-                                        common_mergeinfo,
-                                        target_history_as_mergeinfo,
-                                        TRUE, scratch_pool, iterpool));
+                                           source_mergeinfo,
+                                           iterpool));
+
+          /* Use scratch_pool rather than iterpool because filtered_mergeinfo
+             is going into new_catalog below and needs to last to the end of
+             this function. */
+          /* ### Why looking at SOURCE_url at TARGET_rev? */
+          SVN_ERR(find_unmerged_mergeinfo_subroutine(
+                    &filtered_mergeinfo, target_history_as_mergeinfo,
+                    source_mergeinfo, source_url, target_rev,
+                    source_ra_session, ctx, scratch_pool, iterpool));
           if (apr_hash_count(filtered_mergeinfo))
             apr_hash_set(new_catalog,
                          apr_pstrdup(scratch_pool, source_path),
@@ -10251,7 +10243,6 @@ calculate_left_hand_side(const char **ur
   apr_hash_index_t *hi;
   /* hash of paths mapped to arrays of svn_mergeinfo_t. */
   apr_hash_t *target_history_hash = apr_hash_make(scratch_pool);
-  svn_boolean_t never_synced;
   svn_revnum_t youngest_merged_rev;
   const char *yc_ancestor_url;
   svn_revnum_t yc_ancestor_rev;
@@ -10359,7 +10350,6 @@ calculate_left_hand_side(const char **ur
      mergeinfo that describes what has *not* previously been merged from
      TARGET_REPOS_REL_PATH@TARGET_REV to SOURCE_REPOS_REL_PATH@SOURCE_REV. */
   SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog,
-                                  &never_synced,
                                   &youngest_merged_rev,
                                   yc_ancestor_rev,
                                   mergeinfo_catalog,
@@ -10379,7 +10369,7 @@ calculate_left_hand_side(const char **ur
   *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(unmerged_catalog,
                                                           result_pool);
 
-  if (never_synced)
+  if (youngest_merged_rev == SVN_INVALID_REVNUM)
     {
       /* We never merged to the source.  Just return the branch point. */
       *url_left = apr_pstrdup(result_pool, yc_ancestor_url);

Modified: subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_delta/compat.c Thu Feb  2 13:37:30 2012
@@ -91,7 +91,18 @@ svn_compat_wrap_file_rev_handler(svn_fil
  * 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. */
+ * close_directory() handler.
+ *
+ * There are a few ways we alter the callback stream.  One is when unlocking
+ * paths.  To tell a client a path should be unlocked, the server sends a
+ * prop-del for the SVN_PROP_ENTRY_LOCK_TOKEN property.  This causes problems,
+ * since the client doesn't have this property in the first place, but the
+ * deletion has side effects (unlike deleting a non-existent regular property
+ * would).  To solve this, we introduce *another* function into the API, not
+ * a part of the Ev2 callbacks, but a companion which is used to register
+ * the unlock of a path.  See ev2_change_file_prop() for implemenation
+ * details.
+ */
 
 typedef svn_error_t *(*start_edit_func_t)(
     void *baton,
@@ -102,6 +113,11 @@ typedef svn_error_t *(*target_revision_f
     svn_revnum_t target_revision,
     apr_pool_t *scratch_pool);
 
+typedef svn_error_t *(*unlock_func_t)(
+    void *baton,
+    const char *path,
+    apr_pool_t *scratch_pool);
+
 /* svn_editor__See insert_shims() for more information. */
 struct extra_baton
 {
@@ -125,6 +141,9 @@ struct ev2_edit_baton
 
   svn_delta_fetch_base_func_t fetch_base_func;
   void *fetch_base_baton;
+
+  unlock_func_t do_unlock;
+  void *unlock_baton;
 };
 
 struct ev2_dir_baton
@@ -155,7 +174,8 @@ enum action_code_t
   ACTION_ADD,
   ACTION_DELETE,
   ACTION_ADD_ABSENT,
-  ACTION_SET_TEXT
+  ACTION_SET_TEXT,
+  ACTION_UNLOCK
 };
 
 struct path_action
@@ -261,10 +281,13 @@ process_actions(void *edit_baton,
                 {
                   /* 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, props_base_revision,
-                                               scratch_pool, scratch_pool));
+                  if (need_delete && need_add)
+                    props = apr_hash_make(scratch_pool);
+                  else
+                    SVN_ERR(eb->fetch_props_func(&props,
+                                                 eb->fetch_props_baton,
+                                                 path, props_base_revision,
+                                                 scratch_pool, scratch_pool));
                 }
 
               /* Note that p_args->value may be NULL.  */
@@ -334,6 +357,12 @@ process_actions(void *edit_baton,
               break;
             }
 
+          case ACTION_UNLOCK:
+            {
+              SVN_ERR(eb->do_unlock(eb->unlock_baton, path, scratch_pool));
+              break;
+            }
+
           default:
             SVN_ERR_MALFUNCTION();
         }
@@ -751,6 +780,15 @@ ev2_change_file_prop(void *file_baton,
   struct ev2_file_baton *fb = file_baton;
   struct prop_args *p_args = apr_palloc(fb->eb->edit_pool, sizeof(*p_args));
 
+  if (!strcmp(name, SVN_PROP_ENTRY_LOCK_TOKEN) && value == NULL)
+    {
+      /* 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));
+    }
+
+  /* We also pass through the deletion, since there may actually exist such
+     a property we want to get rid of.   In the worse case, this is a no-op. */
   p_args->name = apr_pstrdup(fb->eb->edit_pool, name);
   p_args->value = value ? svn_string_dup(value, fb->eb->edit_pool) : NULL;
   p_args->base_revision = fb->base_revision;
@@ -802,10 +840,32 @@ ev2_abort_edit(void *edit_baton,
   return svn_error_trace(svn_editor_abort(eb->editor));
 }
 
+/* Return a svn_delta_editor_t * in DEDITOR, with an accompanying baton in
+ * DEDITOR_BATON, which will be driven by EDITOR.  These will both be
+ * allocated in RESULT_POOL, which may become large and long-lived;
+ * SCRATCH_POOL is used for temporary allocations.
+ *
+ * The other parameters are as follows:
+ *  - UNLOCK_FUNC / UNLOCK_BATON: A callback / baton which will be called
+ *         when an unlocking action is received.
+ *  - FOUND_ABS_PATHS: A pointer to a boolean flag which will be set if
+ *         this shim determines that it is receiving absolute paths.
+ *  - FETCH_PROPS_FUNC / FETCH_PROPS_BATON: A callback / baton pair which
+ *         will be used by the shim handlers if they need to determine the
+ *         existing properties on a  path.
+ *  - FETCH_BASE_FUNC / FETCH_BASE_BATON: A callback / baton pair which will
+ *         be used by the shims handlers if they need to determine the base
+ *         text of a path.  It should only be invoked for files.
+ *  - EXB: An 'extra baton' which is used to communicate between the shims.
+ *         Its callbacks should be invoked at the appropriate time by this
+ *         shim.
+ */ 
 static svn_error_t *
 delta_from_editor(const svn_delta_editor_t **deditor,
                   void **dedit_baton,
                   svn_editor_t *editor,
+                  unlock_func_t unlock_func,
+                  void *unlock_baton,
                   svn_boolean_t *found_abs_paths,
                   svn_delta_fetch_props_func_t fetch_props_func,
                   void *fetch_props_baton,
@@ -848,6 +908,9 @@ delta_from_editor(const svn_delta_editor
   eb->fetch_base_func = fetch_base_func;
   eb->fetch_base_baton = fetch_base_baton;
 
+  eb->do_unlock = unlock_func;
+  eb->unlock_baton = unlock_baton;
+
   *dedit_baton = eb;
   *deditor = &delta_editor;
 
@@ -874,6 +937,7 @@ struct operation {
   svn_kind_t kind;  /* to copy, mkdir, put or set revprops */
   svn_revnum_t base_revision;       /* When committing, the base revision */
   svn_revnum_t copyfrom_revision;      /* to copy, valid for add and replace */
+  svn_checksum_t *new_checksum;   /* An MD5 hash of the new contents, if any */
   const char *copyfrom_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 * */
@@ -895,7 +959,6 @@ struct editor_baton
   void *fetch_props_baton;
 
   struct operation root;
-  svn_boolean_t root_opened;
   svn_boolean_t *make_abs_paths;
 
   apr_hash_t *paths;
@@ -929,6 +992,11 @@ get_operation(const char *path,
       apr_hash_set(operation->children, apr_pstrdup(result_pool, path),
                    APR_HASH_KEY_STRING, child);
     }
+
+  /* If an operation has a child, it must of necessity be a directory,
+     so ensure this fact. */
+  operation->kind = svn_kind_dir;
+
   return child;
 }
 
@@ -957,6 +1025,7 @@ build(struct editor_baton *eb,
       svn_revnum_t rev,
       apr_hash_t *props,
       const char *src_file,
+      svn_checksum_t *checksum,
       svn_revnum_t head,
       apr_pool_t *scratch_pool)
 {
@@ -986,14 +1055,23 @@ build(struct editor_baton *eb,
       apr_hash_t *current_props;
       apr_array_header_t *propdiffs;
 
-      if (kind == svn_kind_unknown)
-        SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
-                                    relpath, rev, scratch_pool));
-      else
-        operation->kind = kind;
+      /* Only fetch the kind if operating on something other than the root,
+         as we already know the kind on the root. */
+      if (operation->path)
+        {
+          if (kind == svn_kind_unknown)
+            SVN_ERR(eb->fetch_kind_func(&operation->kind, eb->fetch_kind_baton,
+                                        relpath, rev, scratch_pool));
+          else
+            operation->kind = kind;
+        }
 
-      SVN_ERR(eb->fetch_props_func(&current_props, eb->fetch_props_baton,
-                                   relpath, rev, scratch_pool, scratch_pool));
+      if (operation->operation == OP_REPLACE)
+        current_props = apr_hash_make(scratch_pool);
+      else
+        SVN_ERR(eb->fetch_props_func(&current_props, eb->fetch_props_baton,
+                                     relpath, rev, scratch_pool,
+                                     scratch_pool));
 
       SVN_ERR(svn_prop_diffs(&propdiffs, props, current_props, scratch_pool));
 
@@ -1006,7 +1084,9 @@ build(struct editor_baton *eb,
             APR_ARRAY_PUSH(operation->prop_dels, const char *) = 
                                         apr_pstrdup(eb->edit_pool, prop->name);
           else
-            apr_hash_set(operation->prop_mods, prop->name, APR_HASH_KEY_STRING,
+            apr_hash_set(operation->prop_mods,
+                         apr_pstrdup(eb->edit_pool, prop->name),
+                         APR_HASH_KEY_STRING,
                          svn_string_dup(prop->value, eb->edit_pool));
         }
 
@@ -1024,7 +1104,10 @@ build(struct editor_baton *eb,
     }
 
   if (action == ACTION_DELETE)
-    operation->operation = OP_DELETE;
+    {
+      operation->operation = OP_DELETE;
+      operation->base_revision = rev;
+    }
 
   else if (action == ACTION_ADD_ABSENT)
     operation->operation = OP_ADD_ABSENT;
@@ -1068,7 +1151,8 @@ build(struct editor_baton *eb,
                                      "'%s' is not a file", relpath);
         }
       operation->kind = svn_kind_file;
-      operation->src_file = src_file;
+      operation->src_file = apr_pstrdup(eb->edit_pool, src_file);
+      operation->new_checksum = svn_checksum_dup(checksum, eb->edit_pool);
     }
   else
     {
@@ -1079,19 +1163,6 @@ build(struct editor_baton *eb,
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-ensure_root_opened(struct editor_baton *eb)
-{
-  if (!eb->root_opened)
-    {
-      SVN_ERR(eb->deditor->open_root(eb->dedit_baton, eb->root.base_revision,
-                                     eb->edit_pool, &eb->root.baton));
-      eb->root_opened = TRUE;
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* This implements svn_editor_cb_add_directory_t */
 static svn_error_t *
 add_directory_cb(void *baton,
@@ -1103,25 +1174,23 @@ add_directory_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   if (SVN_IS_VALID_REVNUM(replaces_rev))
     {
       /* We need to add the delete action. */
 
       SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
                     NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
     }
 
   SVN_ERR(build(eb, ACTION_MKDIR, relpath, svn_kind_dir,
                 NULL, SVN_INVALID_REVNUM,
-                NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+                NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
 
   if (props && apr_hash_count(props) > 0)
     SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_dir,
                   NULL, SVN_INVALID_REVNUM, props,
-                  NULL, SVN_INVALID_REVNUM, scratch_pool));
+                  NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1139,8 +1208,14 @@ add_file_cb(void *baton,
   struct editor_baton *eb = baton;
   const char *tmp_filename;
   svn_stream_t *tmp_stream;
+  svn_checksum_t *md5_checksum;
 
-  SVN_ERR(ensure_root_opened(eb));
+  /* We may need to re-checksum these contents */
+  if (!(checksum && checksum->kind == svn_checksum_md5))
+    contents = svn_stream_checksummed2(contents, &md5_checksum, NULL,
+                                       svn_checksum_md5, TRUE, scratch_pool);
+  else
+    md5_checksum = (svn_checksum_t *)checksum;
 
   if (SVN_IS_VALID_REVNUM(replaces_rev))
     {
@@ -1148,24 +1223,24 @@ add_file_cb(void *baton,
 
       SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
                     NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
     }
 
   /* Spool the contents to a tempfile, and provide that to the driver. */
   SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_filename, NULL,
                                  svn_io_file_del_on_pool_cleanup,
                                  eb->edit_pool, scratch_pool));
-  SVN_ERR(svn_stream_copy3(svn_stream_disown(contents, scratch_pool),
-                           tmp_stream, NULL, NULL, scratch_pool));
+  SVN_ERR(svn_stream_copy3(contents, tmp_stream, NULL, NULL, scratch_pool));
 
   SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_none,
                 NULL, SVN_INVALID_REVNUM,
-                NULL, tmp_filename, SVN_INVALID_REVNUM, scratch_pool));
+                NULL, tmp_filename, md5_checksum, SVN_INVALID_REVNUM,
+                scratch_pool));
 
   if (props && apr_hash_count(props) > 0)
     SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_file,
                   NULL, SVN_INVALID_REVNUM, props,
-                  NULL, SVN_INVALID_REVNUM, scratch_pool));
+                  NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1181,15 +1256,13 @@ add_symlink_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   if (SVN_IS_VALID_REVNUM(replaces_rev))
     {
       /* We need to add the delete action. */
 
       SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
                     NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -1205,11 +1278,9 @@ add_absent_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   SVN_ERR(build(eb, ACTION_ADD_ABSENT, relpath, kind,
                 NULL, SVN_INVALID_REVNUM,
-                NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+                NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1225,11 +1296,9 @@ set_props_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   SVN_ERR(build(eb, ACTION_PROPSET, relpath, svn_kind_unknown,
                 NULL, SVN_INVALID_REVNUM,
-                props, NULL, revision, scratch_pool));
+                props, NULL, NULL, revision, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1246,19 +1315,24 @@ set_text_cb(void *baton,
   struct editor_baton *eb = baton;
   const char *tmp_filename;
   svn_stream_t *tmp_stream;
+  svn_checksum_t *md5_checksum;
 
-  SVN_ERR(ensure_root_opened(eb));
+  /* We may need to re-checksum these contents */
+  if (!(checksum && checksum->kind == svn_checksum_md5))
+    contents = svn_stream_checksummed2(contents, &md5_checksum, NULL,
+                                       svn_checksum_md5, TRUE, scratch_pool);
+  else
+    md5_checksum = (svn_checksum_t *)checksum;
 
   /* Spool the contents to a tempfile, and provide that to the driver. */
   SVN_ERR(svn_stream_open_unique(&tmp_stream, &tmp_filename, NULL,
                                  svn_io_file_del_on_pool_cleanup,
                                  eb->edit_pool, scratch_pool));
-  SVN_ERR(svn_stream_copy3(svn_stream_disown(contents, scratch_pool),
-                           tmp_stream, NULL, NULL, scratch_pool));
+  SVN_ERR(svn_stream_copy3(contents, tmp_stream, NULL, NULL, scratch_pool));
 
   SVN_ERR(build(eb, ACTION_PUT, relpath, svn_kind_file,
                 NULL, SVN_INVALID_REVNUM,
-                NULL, tmp_filename, revision, scratch_pool));
+                NULL, tmp_filename, md5_checksum, revision, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1273,8 +1347,6 @@ set_target_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   return SVN_NO_ERROR;
 }
 
@@ -1287,10 +1359,8 @@ delete_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   SVN_ERR(build(eb, ACTION_DELETE, relpath, svn_kind_unknown,
-                NULL, SVN_INVALID_REVNUM, NULL, NULL, SVN_INVALID_REVNUM,
+                NULL, revision, NULL, NULL, NULL, SVN_INVALID_REVNUM,
                 scratch_pool));
 
   return SVN_NO_ERROR;
@@ -1307,20 +1377,18 @@ copy_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   if (SVN_IS_VALID_REVNUM(replaces_rev))
     {
       /* We need to add the delete action. */
 
       SVN_ERR(build(eb, ACTION_DELETE, dst_relpath, svn_kind_unknown,
                     NULL, SVN_INVALID_REVNUM,
-                    NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
+                    NULL, NULL, NULL, SVN_INVALID_REVNUM, scratch_pool));
     }
 
   SVN_ERR(build(eb, ACTION_COPY, dst_relpath, svn_kind_unknown,
-                src_relpath, src_revision, NULL, NULL, SVN_INVALID_REVNUM,
-                scratch_pool));
+                src_relpath, src_revision, NULL, NULL, NULL,
+                SVN_INVALID_REVNUM, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1336,7 +1404,17 @@ move_cb(void *baton,
 {
   struct editor_baton *eb = baton;
 
-  SVN_ERR(ensure_root_opened(eb));
+  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 editor_baton *eb = baton;
 
   return SVN_NO_ERROR;
 }
@@ -1403,7 +1481,7 @@ drive_tree(struct operation *op,
   /* Deletes and replacements are simple -- just delete the thing. */
   if (op->operation == OP_DELETE || op->operation == OP_REPLACE)
     {
-      SVN_ERR(editor->delete_entry(path, SVN_INVALID_REVNUM,
+      SVN_ERR(editor->delete_entry(path, op->base_revision,
                                    parent_op->baton, scratch_pool));
     }
 
@@ -1411,8 +1489,7 @@ drive_tree(struct operation *op,
     {
       /* Open or create our baton. */
       if (op->operation == OP_OPEN || op->operation == OP_PROPSET)
-        SVN_ERR(editor->open_directory(path, parent_op->baton,
-                                       parent_op->base_revision,
+        SVN_ERR(editor->open_directory(path, parent_op->baton, op->base_revision,
                                        scratch_pool, &op->baton));
 
       else if (op->operation == OP_ADD || op->operation == OP_REPLACE)
@@ -1488,7 +1565,10 @@ drive_tree(struct operation *op,
           SVN_ERR(change_props(editor, file_baton, op, scratch_pool));
 
           /* Close the file. */
-          SVN_ERR(editor->close_file(file_baton, NULL, scratch_pool));
+          SVN_ERR(editor->close_file(file_baton,
+                                     svn_checksum_to_cstring(op->new_checksum,
+                                                             scratch_pool),
+                                     scratch_pool));
         }
 
     }
@@ -1540,8 +1620,6 @@ complete_cb(void *baton,
   struct editor_baton *eb = baton;
   svn_error_t *err;
 
-  SVN_ERR(ensure_root_opened(eb));
-
   /* Drive the tree we've created. */
   err = drive_root(&eb->root, eb->deditor, *eb->make_abs_paths, scratch_pool);
   if (!err)
@@ -1592,7 +1670,8 @@ start_edit_func(void *baton,
   struct editor_baton *eb = baton;
 
   eb->root.base_revision = base_revision;
-  SVN_ERR(ensure_root_opened(eb));
+  SVN_ERR(eb->deditor->open_root(eb->dedit_baton, eb->root.base_revision,
+                                 eb->edit_pool, &eb->root.baton));
 
   return SVN_NO_ERROR;
 }
@@ -1611,8 +1690,65 @@ target_revision_func(void *baton,
 }
 
 static svn_error_t *
+do_unlock(void *baton,
+          const char *path,
+          apr_pool_t *scratch_pool)
+{
+  struct editor_baton *eb = baton;
+  apr_array_header_t *path_bits = svn_path_decompose(path, scratch_pool);
+  const char *path_so_far = "";
+  struct operation *operation = &eb->root;
+  int i;
+
+  /* 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, SVN_INVALID_REVNUM,
+                                eb->edit_pool);
+    }
+
+  APR_ARRAY_PUSH(operation->prop_dels, const char *) =
+                                                SVN_PROP_ENTRY_LOCK_TOKEN;
+
+  return SVN_NO_ERROR;
+}
+
+/* Return an svn_editor_t * in EDITOR_P which will be driven by
+ * DEDITOR/DEDIT_BATON.  EDITOR_P is allocated in RESULT_POOL, which may
+ * become large and long-lived; SCRATCH_POOL is used for temporary
+ * allocations.
+ *
+ * The other parameters are as follows:
+ *  - EXB: An 'extra_baton' used for passing information between the coupled
+ *         shims.  This includes actions like 'start edit' and 'set target'.
+ *         As this shim receives these actions, it provides the extra baton
+ *         to its caller.
+ *  - UNLOCK_FUNC / UNLOCK_BATON: A callback / baton pair which a caller
+ *         can use to notify this shim that a path should be unlocked (in the
+ *         'svn lock' sense).  As this shim receives this action, it provides
+ *         this callback / baton to its caller.
+ *  - SEND_ABS_PATHS: A pointer which will be set prior to this edit (but
+ *         not necessarily at the invocation of editor_from_delta()),and
+ *         which indicates whether incoming paths should be expected to
+ *         be absolute or relative.
+ *  - CANCEL_FUNC / CANCEL_BATON: The usual; folded into the produced editor.
+ *  - FETCH_KIND_FUNC / FETCH_KIND_BATON: A callback / baton pair which will
+ *         be used by the shim handlers if they need to determine the kind of
+ *         a path.
+ *  - FETCH_PROPS_FUNC / FETCH_PROPS_BATON: A callback / baton pair which
+ *         will be used by the shim handlers if they need to determine the
+ *         existing properties on a path.
+ */
+static svn_error_t *
 editor_from_delta(svn_editor_t **editor_p,
                   struct extra_baton **exb,
+                  unlock_func_t *unlock_func,
+                  void **unlock_baton,
                   const svn_delta_editor_t *deditor,
                   void *dedit_baton,
                   svn_boolean_t *send_abs_paths,
@@ -1637,6 +1773,7 @@ editor_from_delta(svn_editor_t **editor_
       delete_cb,
       copy_cb,
       move_cb,
+      rotate_cb,
       complete_cb,
       abort_cb
     };
@@ -1662,7 +1799,6 @@ editor_from_delta(svn_editor_t **editor_
   eb->root.prop_dels = apr_array_make(result_pool, 1, sizeof(const char *));
   eb->root.copyfrom_revision = SVN_INVALID_REVNUM;
 
-  eb->root_opened = FALSE;
   eb->make_abs_paths = send_abs_paths;
 
   SVN_ERR(svn_editor_create(&editor, eb, cancel_func, cancel_baton,
@@ -1671,6 +1807,9 @@ editor_from_delta(svn_editor_t **editor_
 
   *editor_p = editor;
 
+  *unlock_func = do_unlock;
+  *unlock_baton = eb;
+
   extra_baton->start_edit = start_edit_func;
   extra_baton->target_revision = target_revision_func;
   extra_baton->baton = eb;
@@ -1723,7 +1862,11 @@ svn_editor__insert_shims(const svn_delta
   svn_boolean_t *found_abs_paths = apr_palloc(result_pool,
                                               sizeof(*found_abs_paths));
 
-  SVN_ERR(editor_from_delta(&editor, &exb, deditor_in, dedit_baton_in,
+  unlock_func_t unlock_func;
+  void *unlock_baton;
+
+  SVN_ERR(editor_from_delta(&editor, &exb, &unlock_func, &unlock_baton,
+                            deditor_in, dedit_baton_in,
                             found_abs_paths, NULL, NULL,
                             shim_callbacks->fetch_kind_func,
                             shim_callbacks->fetch_baton,
@@ -1731,6 +1874,7 @@ svn_editor__insert_shims(const svn_delta
                             shim_callbacks->fetch_baton,
                             result_pool, scratch_pool));
   SVN_ERR(delta_from_editor(deditor_out, dedit_baton_out, editor,
+                            unlock_func, unlock_baton,
                             found_abs_paths,
                             shim_callbacks->fetch_props_func,
                             shim_callbacks->fetch_baton,

Modified: subversion/branches/moves-scan-log/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_delta/editor.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_delta/editor.c Thu Feb  2 13:37:30 2012
@@ -192,6 +192,16 @@ svn_editor_setcb_move(svn_editor_t *edit
 
 
 svn_error_t *
+svn_editor_setcb_rotate(svn_editor_t *editor,
+                        svn_editor_cb_rotate_t callback,
+                        apr_pool_t *scratch_pool)
+{
+  editor->funcs.cb_rotate = callback;
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
 svn_editor_setcb_complete(svn_editor_t *editor,
                           svn_editor_cb_complete_t callback,
                           apr_pool_t *scratch_pool)
@@ -228,6 +238,7 @@ svn_editor_setcb_many(svn_editor_t *edit
   COPY_CALLBACK(cb_delete);
   COPY_CALLBACK(cb_copy);
   COPY_CALLBACK(cb_move);
+  COPY_CALLBACK(cb_rotate);
   COPY_CALLBACK(cb_complete);
   COPY_CALLBACK(cb_abort);
 
@@ -244,9 +255,8 @@ svn_editor_add_directory(svn_editor_t *e
                          apr_hash_t *props,
                          svn_revnum_t replaces_rev)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -256,9 +266,10 @@ svn_editor_add_directory(svn_editor_t *e
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  err = editor->funcs.cb_add_directory(editor->baton, relpath, children,
-                                       props, replaces_rev,
-                                       editor->scratch_pool);
+  if (editor->funcs.cb_add_directory)
+    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),
@@ -291,9 +302,8 @@ svn_editor_add_file(svn_editor_t *editor
                     apr_hash_t *props,
                     svn_revnum_t replaces_rev)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -303,9 +313,10 @@ svn_editor_add_file(svn_editor_t *editor
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  err = editor->funcs.cb_add_file(editor->baton, relpath,
-                                  checksum, contents, props,
-                                  replaces_rev, editor->scratch_pool);
+  if (editor->funcs.cb_add_file)
+    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),
@@ -325,9 +336,8 @@ svn_editor_add_symlink(svn_editor_t *edi
                        apr_hash_t *props,
                        svn_revnum_t replaces_rev)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -337,8 +347,9 @@ svn_editor_add_symlink(svn_editor_t *edi
   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);
+  if (editor->funcs.cb_add_symlink)
+    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),
@@ -357,9 +368,8 @@ svn_editor_add_absent(svn_editor_t *edit
                       svn_kind_t kind,
                       svn_revnum_t replaces_rev)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -369,8 +379,9 @@ svn_editor_add_absent(svn_editor_t *edit
   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);
+  if (editor->funcs.cb_add_absent)
+    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),
@@ -390,9 +401,8 @@ svn_editor_set_props(svn_editor_t *edito
                      apr_hash_t *props,
                      svn_boolean_t complete)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -402,8 +412,9 @@ svn_editor_set_props(svn_editor_t *edito
   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);
+  if (editor->funcs.cb_set_props)
+    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. */
@@ -432,9 +443,8 @@ svn_editor_set_text(svn_editor_t *editor
                     const svn_checksum_t *checksum,
                     svn_stream_t *contents)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -444,8 +454,9 @@ svn_editor_set_text(svn_editor_t *editor
   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);
+  if (editor->funcs.cb_set_text)
+    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);
@@ -464,9 +475,8 @@ svn_editor_set_target(svn_editor_t *edit
                       svn_revnum_t revision,
                       const char *target)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -476,8 +486,9 @@ svn_editor_set_target(svn_editor_t *edit
   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);
+  if (editor->funcs.cb_set_target)
+    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);
@@ -495,9 +506,8 @@ svn_editor_delete(svn_editor_t *editor,
                   const char *relpath,
                   svn_revnum_t revision)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -507,8 +517,9 @@ svn_editor_delete(svn_editor_t *editor,
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  err = editor->funcs.cb_delete(editor->baton, relpath, revision,
-                                editor->scratch_pool);
+  if (editor->funcs.cb_delete)
+    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),
@@ -526,9 +537,8 @@ svn_editor_copy(svn_editor_t *editor,
                 const char *dst_relpath,
                 svn_revnum_t replaces_rev)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -538,9 +548,10 @@ svn_editor_copy(svn_editor_t *editor,
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  err = editor->funcs.cb_copy(editor->baton, src_relpath, src_revision,
-                              dst_relpath, replaces_rev,
-                              editor->scratch_pool);
+  if (editor->funcs.cb_copy)
+    err = editor->funcs.cb_copy(editor->baton, src_relpath, src_revision,
+                                dst_relpath, replaces_rev,
+                                editor->scratch_pool);
   svn_pool_clear(editor->scratch_pool);
   return err;
 }
@@ -553,9 +564,8 @@ svn_editor_move(svn_editor_t *editor,
                 const char *dst_relpath,
                 svn_revnum_t replaces_rev)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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,
@@ -567,9 +577,10 @@ svn_editor_move(svn_editor_t *editor,
   if (editor->cancel_func)
     SVN_ERR(editor->cancel_func(editor->cancel_baton));
 
-  err = editor->funcs.cb_move(editor->baton, src_relpath, src_revision,
-                              dst_relpath, replaces_rev,
-                              editor->scratch_pool);
+  if (editor->funcs.cb_move)
+    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?  */
@@ -592,18 +603,44 @@ svn_editor_move(svn_editor_t *editor,
 
 
 svn_error_t *
+svn_editor_rotate(svn_editor_t *editor,
+                  const apr_array_header_t *relpaths,
+                  const apr_array_header_t *revisions)
+{
+  svn_error_t *err = SVN_NO_ERROR;
+
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  /* ### something more  */
+#endif
+
+  if (editor->cancel_func)
+    SVN_ERR(editor->cancel_func(editor->cancel_baton));
+
+  if (editor->funcs.cb_rotate)
+    err = editor->funcs.cb_rotate(editor->baton, relpaths, revisions,
+                                  editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  /* ### something more  */
+#endif
+  svn_pool_clear(editor->scratch_pool);
+  return err;
+}
+
+
+svn_error_t *
 svn_editor_complete(svn_editor_t *editor)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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);
+  if (editor->funcs.cb_complete)
+    err = editor->funcs.cb_complete(editor->baton, editor->scratch_pool);
 #ifdef ENABLE_ORDERING_CHECK
   if (!err)
     editor->finished = TRUE;
@@ -616,14 +653,14 @@ svn_editor_complete(svn_editor_t *editor
 svn_error_t *
 svn_editor_abort(svn_editor_t *editor)
 {
-  svn_error_t *err;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  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);
+  if (editor->funcs.cb_abort)
+    err = editor->funcs.cb_abort(editor->baton, editor->scratch_pool);
 #ifdef ENABLE_ORDERING_CHECK
   editor->finished = TRUE;
 #endif

Modified: subversion/branches/moves-scan-log/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_fs/fs-loader.h?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_fs/fs-loader.h Thu Feb  2 13:37:30 2012
@@ -25,7 +25,7 @@
 #ifndef LIBSVN_FS_FS_H
 #define LIBSVN_FS_FS_H
 
-#include "svn_version.h"
+#include "svn_types.h"
 #include "svn_fs.h"
 
 #ifdef __cplusplus

Modified: subversion/branches/moves-scan-log/subversion/libsvn_ra_neon/session.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_ra_neon/session.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_ra_neon/session.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_ra_neon/session.c Thu Feb  2 13:37:30 2012
@@ -985,12 +985,15 @@ svn_ra_neon__open(svn_ra_session_t *sess
 
       if (authorities != NULL)
         {
-          char *files, *file;
-          files = apr_pstrdup(pool, authorities);
+          int i;
+          apr_array_header_t *files = svn_cstring_split(authorities, ";", TRUE,
+                                                        pool);
 
-          while ((file = svn_cstring_tokenize(";", &files)) != NULL)
+          for (i = 0; i < files->nelts; ++i)
             {
               ne_ssl_certificate *ca_cert;
+              const char *file = APR_ARRAY_IDX(files, i, const char *);
+
               ca_cert = ne_ssl_cert_read(file);
               if (ca_cert == NULL)
                 {

Modified: subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/property.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/property.c Thu Feb  2 13:37:30 2012
@@ -988,32 +988,33 @@ svn_ra_serf__get_baseline_info(const cha
      revision (if needed) with an OPTIONS request.  */
   if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
     {
-      basecoll_url = apr_psprintf(pool, "%s/%ld",
-                                  session->rev_root_stub, revision);
+      svn_revnum_t actual_revision;
 
-      if (latest_revnum)
+      if (SVN_IS_VALID_REVNUM(revision))
         {
-          if (SVN_IS_VALID_REVNUM(revision))
-            {
-              *latest_revnum = revision;
-            }
-          else
-           {
-              svn_ra_serf__options_context_t *opt_ctx;
+          actual_revision = revision;
+        }
+      else
+        {
+          svn_ra_serf__options_context_t *opt_ctx;
 
-              SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, session, conn,
+          SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, session, conn,
                                                   session->session_url.path,
                                                   pool));
-              SVN_ERR(svn_ra_serf__context_run_wait(
+          SVN_ERR(svn_ra_serf__context_run_wait(
                 svn_ra_serf__get_options_done_ptr(opt_ctx), session, pool));
 
-             *latest_revnum = svn_ra_serf__options_get_youngest_rev(opt_ctx);
-             if (! SVN_IS_VALID_REVNUM(*latest_revnum))
-               return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
-                                       _("The OPTIONS response did not include "
-                                         "the youngest revision"));
-          }
+          actual_revision = svn_ra_serf__options_get_youngest_rev(opt_ctx);
+          if (! SVN_IS_VALID_REVNUM(actual_revision))
+            return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
+                                    _("The OPTIONS response did not include "
+                                      "the youngest revision"));
         }
+
+      basecoll_url = apr_psprintf(pool, "%s/%ld",
+                                  session->rev_root_stub, actual_revision);
+      if (latest_revnum)
+        *latest_revnum = actual_revision;
     }
 
   /* Otherwise, we fall back to the old VCC_URL PROPFIND hunt.  */
@@ -1021,7 +1022,7 @@ svn_ra_serf__get_baseline_info(const cha
     {
       SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, session, conn, pool));
 
-      if (revision != SVN_INVALID_REVNUM)
+      if (SVN_IS_VALID_REVNUM(revision))
         {
           /* First check baseline information cache. */
           SVN_ERR(svn_ra_serf__blncache_get_bc_url(&basecoll_url,

Modified: subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/ra_serf.h?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/ra_serf.h Thu Feb  2 13:37:30 2012
@@ -78,6 +78,7 @@ typedef struct svn_ra_serf__connection_t
 
   /* Are we using ssl */
   svn_boolean_t using_ssl;
+  int server_cert_failures; /* Collected cert failures in chain */
 
   /* Should we ask for compressed responses? */
   svn_boolean_t using_compression;

Modified: subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/serf.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/serf.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/serf.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/serf.c Thu Feb  2 13:37:30 2012
@@ -403,6 +403,7 @@ svn_ra_serf__open(svn_ra_session_t *sess
   serf_sess->conns[0]->last_status_code = -1;
 
   serf_sess->conns[0]->using_ssl = serf_sess->using_ssl;
+  serf_sess->conns[0]->server_cert_failures = 0;
   serf_sess->conns[0]->using_compression = serf_sess->using_compression;
   serf_sess->conns[0]->hostname = url.hostname;
   serf_sess->conns[0]->useragent = NULL;

Modified: subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/util.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_ra_serf/util.c Thu Feb  2 13:37:30 2012
@@ -271,6 +271,8 @@ ssl_server_cert(void *baton, int failure
   /* Implicitly approve any non-server certs. */
   if (serf_ssl_cert_depth(cert) > 0)
     {
+      if (failures)
+        conn->server_cert_failures |= ssl_convert_serf_failures(failures);
       return APR_SUCCESS;
     }
 
@@ -295,7 +297,8 @@ ssl_server_cert(void *baton, int failure
   cert_info.issuer_dname = convert_organisation_to_str(issuer, scratch_pool);
   cert_info.ascii_cert = serf_ssl_cert_export(cert, scratch_pool);
 
-  svn_failures = ssl_convert_serf_failures(failures);
+  svn_failures = (ssl_convert_serf_failures(failures)
+                  | conn->server_cert_failures);
 
   /* Try to find matching server name via subjectAltName first... */
   if (san) {
@@ -383,20 +386,23 @@ static svn_error_t *
 load_authorities(svn_ra_serf__connection_t *conn, const char *authorities,
                  apr_pool_t *pool)
 {
-  char *files, *file;
-  files = apr_pstrdup(pool, authorities);
+  apr_array_header_t *files = svn_cstring_split(authorities, ";",
+                                                TRUE /* chop_whitespace */,
+                                                pool);
+  int i;
 
-  while ((file = svn_cstring_tokenize(";", &files)) != NULL)
+  for (i = 0; i < files->nelts; ++i)
     {
+      const char *file = APR_ARRAY_IDX(files, i, const char *);
       serf_ssl_certificate_t *ca_cert;
       apr_status_t status = serf_ssl_load_cert_file(&ca_cert, file, pool);
+
       if (status == APR_SUCCESS)
         status = serf_ssl_trust_cert(conn->ssl_context, ca_cert);
 
       if (status != APR_SUCCESS)
         {
-          return svn_error_createf
-            (SVN_ERR_BAD_CONFIG_VALUE, NULL,
+          return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
              _("Invalid config: unable to load certificate file '%s'"),
              svn_dirent_local_style(file, pool));
         }

Modified: subversion/branches/moves-scan-log/subversion/libsvn_ra_svn/cyrus_auth.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_ra_svn/cyrus_auth.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_ra_svn/cyrus_auth.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_ra_svn/cyrus_auth.c Thu Feb  2 13:37:30 2012
@@ -186,12 +186,64 @@ svn_ra_svn__sasl_common_init(apr_pool_t 
   return SVN_NO_ERROR;
 }
 
+/* We are going to look at errno when we get SASL_FAIL but we don't
+   know for sure whether SASL always sets errno.  Clearing errno
+   before calling SASL functions helps in cases where SASL does
+   nothing to set errno. */
+#ifdef apr_set_os_error
+#define clear_sasl_errno() apr_set_os_error(APR_SUCCESS)
+#else
+#define clear_sasl_errno() (void)0
+#endif
+
+/* Sometimes SASL returns SASL_FAIL as RESULT and sets errno.
+ * SASL_FAIL translates to "generic error" which is quite unhelpful.
+ * Try to append a more informative error message based on errno so
+ * should be called before doing anything that may change errno. */
+static const char *
+get_sasl_errno_msg(int result, apr_pool_t *result_pool)
+{
+#ifdef apr_get_os_error
+  char buf[1024];
+
+  if (result == SASL_FAIL && apr_get_os_error() != 0)
+    return apr_psprintf(result_pool, ": %s",
+                        svn_strerror(apr_get_os_error(), buf, sizeof(buf)));
+#endif
+  return "";
+}
+
+/* Wrap an error message from SASL with a prefix that allows users
+ * to tell that the error message came from SASL.  Queries errno and
+ * so should be called before doing anything that may change errno. */
+static const char *
+get_sasl_error(sasl_conn_t *sasl_ctx, int result, apr_pool_t *result_pool)
+{
+  const char *sasl_errno_msg = get_sasl_errno_msg(result, result_pool);
+
+  return apr_psprintf(result_pool,
+                      _("SASL authentication error: %s%s"),
+                      sasl_errdetail(sasl_ctx), sasl_errno_msg);
+}
+
 static svn_error_t *sasl_init_cb(void *baton, apr_pool_t *pool)
 {
+  int result;
+
   SVN_ERR(svn_ra_svn__sasl_common_init(pool));
-  if (sasl_client_init(NULL) != SASL_OK)
-    return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                            _("Could not initialize the SASL library"));
+  clear_sasl_errno();
+  result = sasl_client_init(NULL);
+  if (result != SASL_OK)
+    {
+      const char *sasl_errno_msg = get_sasl_errno_msg(result, pool);
+
+      return svn_error_createf
+        (SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+         _("Could not initialized the SASL library: %s%s"),
+         sasl_errstring(result, NULL, NULL),
+         sasl_errno_msg);
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -338,31 +390,6 @@ get_password_cb(sasl_conn_t *conn, void 
   return SASL_FAIL;
 }
 
-/* Sometimes SASL returns SASL_FAIL as RESULT and sets errno.
- * SASL_FAIL translates to "generic error" which is quite unhelpful.
- * Try to append a more informative error message based on errno. */
-static const char *
-get_sasl_errno_msg(int result, apr_pool_t *result_pool)
-{
-  char buf[1024];
-
-  if (result == SASL_FAIL && apr_get_os_error() != 0)
-    return apr_psprintf(result_pool, ": %s",
-                        svn_strerror(apr_get_os_error(), buf, sizeof(buf)));
-  return "";
-}
-
-/* Wrap an error message from SASL with a prefix that allows users
- * to tell that the error message came from SASL. */
-static const char *
-get_sasl_error(sasl_conn_t *sasl_ctx, int result, apr_pool_t *result_pool)
-{
-  return apr_psprintf(result_pool,
-                      _("SASL authentication error: %s%s"),
-                      sasl_errdetail(sasl_ctx),
-                      get_sasl_errno_msg(result, result_pool));
-}
-
 /* Create a new SASL context. */
 static svn_error_t *new_sasl_ctx(sasl_conn_t **sasl_ctx,
                                  svn_boolean_t is_tunneled,
@@ -375,15 +402,20 @@ static svn_error_t *new_sasl_ctx(sasl_co
   sasl_security_properties_t secprops;
   int result;
 
+  clear_sasl_errno();
   result = sasl_client_new(SVN_RA_SVN_SASL_NAME,
                            hostname, local_addrport, remote_addrport,
                            callbacks, SASL_SUCCESS_DATA,
                            sasl_ctx);
   if (result != SASL_OK)
-    return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
-                             _("Could not create SASL context: %s%s"),
-                             sasl_errstring(result, NULL, NULL),
-                             get_sasl_errno_msg(result, pool));
+    {
+      const char *sasl_errno_msg = get_sasl_errno_msg(result, pool);
+
+      return svn_error_createf(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
+                               _("Could not create SASL context: %s%s"),
+                               sasl_errstring(result, NULL, NULL),
+                               sasl_errno_msg);
+    }
   svn_atomic_inc(&sasl_ctx_count);
   apr_pool_cleanup_register(pool, *sasl_ctx, sasl_dispose_cb,
                             apr_pool_cleanup_null);
@@ -394,6 +426,7 @@ static svn_error_t *new_sasl_ctx(sasl_co
          otherwise it will ignore EXTERNAL. The third parameter
          should be the username, but since SASL doesn't seem
          to use it on the client side, any non-empty string will do. */
+      clear_sasl_errno();
       result = sasl_setprop(*sasl_ctx,
                             SASL_AUTH_EXTERNAL, " ");
       if (result != SASL_OK)
@@ -426,6 +459,7 @@ static svn_error_t *try_auth(svn_ra_svn_
   do
     {
       again = FALSE;
+      clear_sasl_errno();
       result = sasl_client_start(sasl_ctx,
                                  mechstring,
                                  &client_interact,
@@ -496,6 +530,7 @@ static svn_error_t *try_auth(svn_ra_svn_
       if (strcmp(mech, "CRAM-MD5") != 0)
         in = svn_base64_decode_string(in, pool);
 
+      clear_sasl_errno();
       result = sasl_client_step(sasl_ctx,
                                 in->data,
                                 in->len,
@@ -584,6 +619,7 @@ static svn_error_t *sasl_read_cb(void *b
           *len = 0;
           return SVN_NO_ERROR;
         }
+      clear_sasl_errno();
       result = sasl_decode(sasl_baton->ctx, buffer, len2,
                            &sasl_baton->read_buf,
                            &sasl_baton->read_len);
@@ -625,6 +661,7 @@ sasl_write_cb(void *baton, const char *b
     {
       /* Make sure we don't write too much. */
       *len = (*len > sasl_baton->maxsize) ? sasl_baton->maxsize : *len;
+      clear_sasl_errno();
       result = sasl_encode(sasl_baton->ctx, buffer, *len,
                            &sasl_baton->write_buf,
                            &sasl_baton->write_len);
@@ -685,6 +722,7 @@ svn_error_t *svn_ra_svn__enable_sasl_enc
       int result;
 
       /* Get the strength of the security layer. */
+      clear_sasl_errno();
       result = sasl_getprop(sasl_ctx, SASL_SSF, (void*) &ssfp);
       if (result != SASL_OK)
         return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
@@ -704,6 +742,7 @@ svn_error_t *svn_ra_svn__enable_sasl_enc
           sasl_baton->scratch_pool = conn->pool;
 
           /* Find out the maximum input size for sasl_encode. */
+          clear_sasl_errno();
           result = sasl_getprop(sasl_ctx, SASL_MAXOUTBUF, &maxsize);
           if (result != SASL_OK)
             return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL,
@@ -714,6 +753,7 @@ svn_error_t *svn_ra_svn__enable_sasl_enc
              we need to decrypt it. */
           if (conn->read_end > conn->read_ptr)
             {
+              clear_sasl_errno();
               result = sasl_decode(sasl_ctx, conn->read_ptr,
                                    conn->read_end - conn->read_ptr,
                                    &sasl_baton->read_buf,

Modified: subversion/branches/moves-scan-log/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_repos/commit.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_repos/commit.c Thu Feb  2 13:37:30 2012
@@ -823,6 +823,7 @@ kind_fetch_func(svn_kind_t *kind,
 {
   struct edit_baton *eb = baton;
   svn_node_kind_t node_kind;
+  svn_fs_root_t *fs_root;
 
   if (!SVN_IS_VALID_REVNUM(base_revision))
     base_revision = svn_fs_txn_base_revision(eb->txn);
@@ -831,6 +832,7 @@ kind_fetch_func(svn_kind_t *kind,
     {
       /* This is a copyfrom URL. */
       path = svn_uri_skip_ancestor(eb->repos_url, path, scratch_pool);
+      path = svn_fspath__canonicalize(path, scratch_pool);
     }
   else
     {
@@ -840,7 +842,9 @@ kind_fetch_func(svn_kind_t *kind,
         path = svn_fspath__join(eb->base_path, path, scratch_pool);
     }
 
-  SVN_ERR(svn_fs_check_path(&node_kind, eb->txn_root, path, scratch_pool));
+  SVN_ERR(svn_fs_revision_root(&fs_root, eb->fs, base_revision, scratch_pool));
+
+  SVN_ERR(svn_fs_check_path(&node_kind, fs_root, path, scratch_pool));
   *kind = svn__kind_from_node_kind(node_kind, FALSE);
 
   return SVN_NO_ERROR;
@@ -868,6 +872,7 @@ fetch_base_func(const char **filename,
     {
       /* This is a copyfrom URL. */
       path = svn_uri_skip_ancestor(eb->repos_url, path, scratch_pool);
+      path = svn_fspath__canonicalize(path, scratch_pool);
     }
   else
     {

Modified: subversion/branches/moves-scan-log/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_repos/load-fs-vtable.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_repos/load-fs-vtable.c Thu Feb  2 13:37:30 2012
@@ -160,12 +160,12 @@ change_rev_prop(svn_repos_t *repos,
                 apr_pool_t *pool)
 {
   if (validate_props)
-    return svn_fs_change_rev_prop2(svn_repos_fs(repos), revision, name,
-                                   NULL, value, pool);
-  else
     return svn_repos_fs_change_rev_prop4(repos, revision, NULL, name,
                                          NULL, value, FALSE, FALSE,
                                          NULL, NULL, pool);
+  else
+    return svn_fs_change_rev_prop2(svn_repos_fs(repos), revision, name,
+                                   NULL, value, pool);
 }
 
 /* Change property NAME to VALUE for PATH in TXN_ROOT.  If

Modified: subversion/branches/moves-scan-log/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_subr/cmdline.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_subr/cmdline.c Thu Feb  2 13:37:30 2012
@@ -226,7 +226,7 @@ svn_cmdline_init(const char *progname, F
   /* Create a pool for use by the UTF-8 routines.  It will be cleaned
      up by APR at exit time. */
   pool = svn_pool_create(NULL);
-  svn_utf_initialize(pool);
+  svn_utf_initialize2(pool, FALSE);
 
   if ((err = svn_nls_init()))
     {

Modified: subversion/branches/moves-scan-log/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_subr/config_file.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_subr/config_file.c Thu Feb  2 13:37:30 2012
@@ -1050,7 +1050,7 @@ svn_config_ensure(const char *config_dir
         "### path separator.  A single backslash will be treated as an"      NL
         "### escape for the following character."                            NL
         ""                                                                   NL
-        "### Section for configuring miscelleneous Subversion options."      NL
+        "### Section for configuring miscellaneous Subversion options."      NL
         "[miscellany]"                                                       NL
         "### Set global-ignores to a set of whitespace-delimited globs"      NL
         "### which Subversion will ignore in its 'status' output, and"       NL

Modified: subversion/branches/moves-scan-log/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_subr/deprecated.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_subr/deprecated.c Thu Feb  2 13:37:30 2012
@@ -39,6 +39,7 @@
 #include "svn_pools.h"
 #include "svn_dso.h"
 #include "svn_mergeinfo.h"
+#include "svn_utf.h"
 #include "svn_xml.h"
 
 #include "opt.h"
@@ -1173,3 +1174,9 @@ svn_xml_make_header(svn_stringbuf_t **st
 {
   svn_xml_make_header2(str, NULL, pool);
 }
+
+void
+svn_utf_initialize(apr_pool_t *pool)
+{
+  svn_utf_initialize2(pool, FALSE);
+}

Modified: subversion/branches/moves-scan-log/subversion/libsvn_subr/spillbuf.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_subr/spillbuf.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_subr/spillbuf.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_subr/spillbuf.c Thu Feb  2 13:37:30 2012
@@ -552,3 +552,56 @@ svn_spillbuf__reader_write(svn_spillbuf_
   return svn_error_trace(svn_spillbuf__write(&reader->buf, data, len,
                                              scratch_pool));
 }
+
+
+struct spillbuf_baton
+{
+  svn_spillbuf_reader_t *reader;
+  apr_pool_t *scratch_pool;
+};
+
+
+static svn_error_t *
+read_handler_spillbuf(void *baton, char *buffer, apr_size_t *len)
+{
+  struct spillbuf_baton *sb = baton;
+
+  SVN_ERR(svn_spillbuf__reader_read(len, sb->reader, buffer, *len,
+                                    sb->scratch_pool));
+
+  svn_pool_clear(sb->scratch_pool);
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+write_handler_spillbuf(void *baton, const char *data, apr_size_t *len)
+{
+  struct spillbuf_baton *sb = baton;
+
+  SVN_ERR(svn_spillbuf__reader_write(sb->reader, data, *len, sb->scratch_pool));
+
+  svn_pool_clear(sb->scratch_pool);
+  return SVN_NO_ERROR;
+}
+
+
+svn_stream_t *
+svn_stream__from_spillbuf(apr_size_t blocksize,
+                          apr_size_t maxsize,
+                          apr_pool_t *result_pool)
+{
+  svn_stream_t *stream;
+  struct spillbuf_baton *sb = apr_pcalloc(result_pool, sizeof(*sb));
+
+  sb->reader = svn_spillbuf__reader_create(blocksize, maxsize, result_pool);
+  sb->scratch_pool = svn_pool_create(result_pool);
+
+  stream = svn_stream_create(sb, result_pool);
+
+  svn_stream_set_read(stream, read_handler_spillbuf);
+  svn_stream_set_write(stream, write_handler_spillbuf);
+
+
+  return stream;
+}

Modified: subversion/branches/moves-scan-log/subversion/libsvn_subr/ssl_server_trust_providers.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_subr/ssl_server_trust_providers.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_subr/ssl_server_trust_providers.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_subr/ssl_server_trust_providers.c Thu Feb  2 13:37:30 2012
@@ -208,11 +208,12 @@ ssl_server_trust_prompt_first_cred(void 
     apr_hash_get(parameters,
                  SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO,
                  APR_HASH_KEY_STRING);
+  svn_boolean_t may_save = (!no_auth_cache
+                            && !(*failures & SVN_AUTH_SSL_OTHER));
 
-  SVN_ERR(pb->prompt_func((svn_auth_cred_ssl_server_trust_t **)
-                          credentials_p, pb->prompt_baton, realmstring,
-                          *failures, cert_info, ! no_auth_cache &&
-                          ! (*failures & SVN_AUTH_SSL_OTHER), pool));
+  SVN_ERR(pb->prompt_func((svn_auth_cred_ssl_server_trust_t **)credentials_p,
+                          pb->prompt_baton, realmstring, *failures, cert_info,
+                          may_save, pool));
 
   *iter_baton = NULL;
   return SVN_NO_ERROR;

Modified: subversion/branches/moves-scan-log/subversion/libsvn_subr/stream.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_subr/stream.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_subr/stream.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_subr/stream.c Thu Feb  2 13:37:30 2012
@@ -45,6 +45,7 @@
 #include "private/svn_error_private.h"
 #include "private/svn_eol_private.h"
 #include "private/svn_io_private.h"
+#include "private/svn_subr_private.h"
 
 
 struct svn_stream_t {
@@ -1642,3 +1643,16 @@ svn_string_from_stream(svn_string_t **re
 
   return SVN_NO_ERROR;
 }
+
+
+/* These are somewhat arbirary, if we ever get good empirical data as to
+   actually valid values, feel free to update them. */
+#define BUFFER_BLOCK_SIZE 1024
+#define BUFFER_MAX_SIZE 100000
+
+svn_stream_t *
+svn_stream_buffered(apr_pool_t *result_pool)
+{
+  return svn_stream__from_spillbuf(BUFFER_BLOCK_SIZE, BUFFER_MAX_SIZE,
+                                   result_pool);
+}

Modified: subversion/branches/moves-scan-log/subversion/libsvn_subr/utf.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_subr/utf.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_subr/utf.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_subr/utf.c Thu Feb  2 13:37:30 2012
@@ -23,6 +23,7 @@
 
 
 
+#include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 
@@ -55,6 +56,7 @@ static const char *SVN_UTF_UTON_XLATE_HA
 static const char *SVN_APR_UTF8_CHARSET = "UTF-8";
 
 static svn_mutex__t *xlate_handle_mutex = NULL;
+static svn_boolean_t assume_native_charset_is_utf8 = FALSE;
 
 /* The xlate handle cache is a global hash table with linked lists of xlate
  * handles.  In multi-threaded environments, a thread "borrows" an xlate
@@ -118,7 +120,8 @@ xlate_handle_node_cleanup(void *arg)
 }
 
 void
-svn_utf_initialize(apr_pool_t *pool)
+svn_utf_initialize2(apr_pool_t *pool,
+                    svn_boolean_t assume_native_utf8)
 {
   if (!xlate_handle_hash)
     {
@@ -141,6 +144,9 @@ svn_utf_initialize(apr_pool_t *pool)
       apr_pool_cleanup_register(subpool, NULL, xlate_cleanup,
                                 apr_pool_cleanup_null);
     }
+
+    if (!assume_native_charset_is_utf8)
+      assume_native_charset_is_utf8 = assume_native_utf8;
 }
 
 /* Return a unique string key based on TOPAGE and FROMPAGE.  TOPAGE and
@@ -442,7 +448,9 @@ static svn_error_t *
 get_ntou_xlate_handle_node(xlate_handle_node_t **ret, apr_pool_t *pool)
 {
   return get_xlate_handle_node(ret, SVN_APR_UTF8_CHARSET,
-                               SVN_APR_LOCALE_CHARSET,
+                               assume_native_charset_is_utf8
+                                 ? SVN_APR_UTF8_CHARSET
+                                 : SVN_APR_LOCALE_CHARSET,
                                SVN_UTF_NTOU_XLATE_HANDLE, pool);
 }
 
@@ -455,7 +463,10 @@ get_ntou_xlate_handle_node(xlate_handle_
 static svn_error_t *
 get_uton_xlate_handle_node(xlate_handle_node_t **ret, apr_pool_t *pool)
 {
-  return get_xlate_handle_node(ret, SVN_APR_LOCALE_CHARSET,
+  return get_xlate_handle_node(ret,
+                               assume_native_charset_is_utf8
+                                 ? SVN_APR_UTF8_CHARSET
+                                 : SVN_APR_LOCALE_CHARSET,
                                SVN_APR_UTF8_CHARSET,
                                SVN_UTF_UTON_XLATE_HANDLE, pool);
 }

Modified: subversion/branches/moves-scan-log/subversion/libsvn_wc/diff_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_wc/diff_editor.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_wc/diff_editor.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_wc/diff_editor.c Thu Feb  2 13:37:30 2012
@@ -1937,7 +1937,7 @@ svn_wc_get_diff_editor6(const svn_delta_
   sfb = apr_palloc(result_pool, sizeof(*sfb));
   sfb->db = wc_ctx->db;
   sfb->base_abspath = eb->anchor_abspath;
-  sfb->fetch_base = FALSE;
+  sfb->fetch_base = TRUE;
 
   shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
   shim_callbacks->fetch_props_func = svn_wc__fetch_props_func;

Modified: subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_wc/status.c Thu Feb  2 13:37:30 2012
@@ -2610,7 +2610,11 @@ svn_wc__internal_walk_status(svn_wc__db_
   SVN_ERR(svn_io_stat_dirent(&dirent, local_abspath, TRUE,
                              scratch_pool, scratch_pool));
 
-  if (info && info->kind == svn_kind_dir)
+  if (info
+      && info->kind == svn_kind_dir
+      && info->status != svn_wc__db_status_not_present
+      && info->status != svn_wc__db_status_excluded
+      && info->status != svn_wc__db_status_server_excluded)
     {
       SVN_ERR(get_dir_status(&wb,
                              local_abspath,

Modified: subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c?rev=1239613&r1=1239612&r2=1239613&view=diff
==============================================================================
--- subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/moves-scan-log/subversion/libsvn_wc/update_editor.c Thu Feb  2 13:37:30 2012
@@ -5080,47 +5080,6 @@ close_edit(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-
-static svn_error_t *
-fetch_props_func(apr_hash_t **props,
-                 void *baton,
-                 const char *path,
-                 svn_revnum_t base_revision,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
-{
-  struct svn_wc__shim_fetch_baton_t *sfb = baton;
-  const char *local_abspath = svn_dirent_join(sfb->base_abspath, path,
-                                              scratch_pool);
-  svn_error_t *err;
-
-  if (sfb->fetch_base)
-    err = svn_wc__db_base_get_props(props, sfb->db, local_abspath, result_pool,
-                                    scratch_pool);
-  else
-    err = svn_wc__db_read_props(props, sfb->db, local_abspath,
-                                result_pool, scratch_pool);
-
-  /* If the path doesn't exist, just return an empty set of props. */
-  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-    {
-      svn_error_clear(err);
-      *props = apr_hash_make(result_pool);
-    }
-  else if (err)
-    return svn_error_trace(err);
-
-  /* Add a bogus LOCK_TOKEN if we don't already have one, so as to catch
-     any deletions thereto. */
-  if (!apr_hash_get(*props, SVN_PROP_ENTRY_LOCK_TOKEN, APR_HASH_KEY_STRING))
-    {
-      apr_hash_set(*props, SVN_PROP_ENTRY_LOCK_TOKEN, APR_HASH_KEY_STRING,
-                   svn_string_create("This is completely bogus", result_pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
 
 /*** Returning editors. ***/
 
@@ -5402,7 +5361,7 @@ make_editor(svn_revnum_t *target_revisio
   sfb->fetch_base = TRUE;
 
   shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
-  shim_callbacks->fetch_props_func = fetch_props_func;
+  shim_callbacks->fetch_props_func = svn_wc__fetch_props_func;
   shim_callbacks->fetch_base_func = svn_wc__fetch_base_func;
   shim_callbacks->fetch_baton = sfb;