You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/09/15 21:32:38 UTC

svn commit: r997472 [12/41] - in /subversion/branches/py-tests-as-modules: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/server-side/ notes/ notes/tree-conflicts/ notes/wc-ng/ subversion/bindings/javahl/native/ subversi...

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/prop_commands.c Wed Sep 15 19:32:26 2010
@@ -97,7 +97,7 @@ struct propset_walk_baton
   void *notify_baton;
 };
 
-/* An node-walk callback for svn_client_propset3.
+/* An node-walk callback for svn_client_propset4.
  *
  * For LOCAL_ABSPATH, set the property named wb->PROPNAME to the value
  * wb->PROPVAL, where "wb" is the WALK_BATON of type "struct
@@ -118,7 +118,8 @@ propset_walk_cb(const char *local_abspat
 
   err = svn_wc_prop_set4(wb->wc_ctx, local_abspath, wb->propname, wb->propval,
                          wb->force, wb->notify_func, wb->notify_baton, pool);
-  if (err && err->apr_err == SVN_ERR_ILLEGAL_TARGET)
+  if (err && (err->apr_err == SVN_ERR_ILLEGAL_TARGET
+              || err->apr_err == SVN_ERR_WC_INVALID_SCHEDULE))
     {
       svn_error_clear(err);
       err = SVN_NO_ERROR;
@@ -189,13 +190,14 @@ do_url_propset(const char *propname,
 }
 
 static svn_error_t *
-propset_on_url(svn_commit_info_t **commit_info_p,
-               const char *propname,
+propset_on_url(const char *propname,
                const svn_string_t *propval,
                const char *target,
                svn_boolean_t skip_checks,
                svn_revnum_t base_revision_for_url,
                const apr_hash_t *revprop_table,
+               svn_commit_callback2_t commit_callback,
+               void *commit_baton,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
 {
@@ -204,7 +206,7 @@ propset_on_url(svn_commit_info_t **commi
   svn_node_kind_t node_kind;
   const char *message;
   const svn_delta_editor_t *editor;
-  void *commit_baton, *edit_baton;
+  void *edit_baton;
   apr_hash_t *commit_revprops;
   svn_error_t *err;
 
@@ -215,7 +217,7 @@ propset_on_url(svn_commit_info_t **commi
 
   /* Open an RA session for the URL. Note that we don't have a local
      directory, nor a place to put temp files. */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, target,
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, target,
                                                NULL, NULL, FALSE, TRUE,
                                                ctx, pool));
 
@@ -268,10 +270,9 @@ propset_on_url(svn_commit_info_t **commi
                                            message, ctx, pool));
 
   /* Fetch RA commit editor. */
-  SVN_ERR(svn_client__commit_get_baton(&commit_baton, commit_info_p, pool));
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
                                     commit_revprops,
-                                    svn_client__commit_callback,
+                                    commit_callback,
                                     commit_baton,
                                     NULL, TRUE, /* No lock tokens */
                                     pool));
@@ -290,10 +291,56 @@ propset_on_url(svn_commit_info_t **commi
   return editor->close_edit(edit_baton, pool);
 }
 
+/* Baton for set_props_cb */
+struct set_props_baton
+{
+  svn_client_ctx_t *ctx;
+  const char *local_abspath;
+  svn_depth_t depth;
+  svn_node_kind_t kind;
+  const char *propname;
+  const svn_string_t *propval;
+  svn_boolean_t skip_checks;
+  apr_hash_t *changelist_hash;
+};
+
+/* Working copy lock callback for svn_client_propset4 */
+static svn_error_t *
+set_props_cb(void *baton,
+             apr_pool_t *result_pool,
+             apr_pool_t *scratch_pool)
+{
+  struct set_props_baton *bt = baton;
+
+  if (bt->depth >= svn_depth_files && bt->kind == svn_node_dir)
+    {
+      struct propset_walk_baton wb;
+
+      wb.wc_ctx = bt->ctx->wc_ctx;
+      wb.propname = bt->propname;
+      wb.propval = bt->propval;
+      wb.force = bt->skip_checks;
+      wb.changelist_hash = bt->changelist_hash;
+      wb.notify_func = bt->ctx->notify_func2;
+      wb.notify_baton = bt->ctx->notify_baton2;
+      SVN_ERR(svn_wc__node_walk_children(bt->ctx->wc_ctx, bt->local_abspath,
+                                         FALSE, propset_walk_cb, &wb,
+                                         bt->depth, bt->ctx->cancel_func,
+                                         bt->ctx->cancel_baton, scratch_pool));
+    }
+  else if (svn_wc__changelist_match(bt->ctx->wc_ctx, bt->local_abspath,
+                                    bt->changelist_hash, scratch_pool))
+    {
+      SVN_ERR(svn_wc_prop_set4(bt->ctx->wc_ctx, bt->local_abspath,
+                               bt->propname, bt->propval, bt->skip_checks,
+                               bt->ctx->notify_func2, bt->ctx->notify_baton2,
+                               scratch_pool));
+    }
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
-svn_client_propset3(svn_commit_info_t **commit_info_p,
-                    const char *propname,
+svn_client_propset4(const char *propname,
                     const svn_string_t *propval,
                     const char *target,
                     svn_depth_t depth,
@@ -301,6 +348,8 @@ svn_client_propset3(svn_commit_info_t **
                     svn_revnum_t base_revision_for_url,
                     const apr_array_header_t *changelists,
                     const apr_hash_t *revprop_table,
+                    svn_commit_callback2_t commit_callback,
+                    void *commit_baton,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *pool)
 {
@@ -351,9 +400,9 @@ svn_client_propset3(svn_commit_info_t **
                                  _("Setting property '%s' on non-local target "
                                    "'%s' is not supported"), propname, target);
 
-      return propset_on_url(commit_info_p, propname, propval, target,
-                            skip_checks, base_revision_for_url, revprop_table,
-                            ctx, pool);
+      return propset_on_url(propname, propval, target, skip_checks,
+                            base_revision_for_url, revprop_table,
+                            commit_callback, commit_baton, ctx, pool);
     }
   else
     {
@@ -361,6 +410,7 @@ svn_client_propset3(svn_commit_info_t **
       apr_hash_t *changelist_hash = NULL;
       const char *target_abspath;
       svn_error_t *err;
+      struct set_props_baton baton;
 
       SVN_ERR(svn_dirent_get_absolute(&target_abspath, target, pool));
 
@@ -383,29 +433,18 @@ svn_client_propset3(svn_commit_info_t **
       else
         SVN_ERR(err);
 
-      if (depth >= svn_depth_files && kind == svn_node_dir)
-        {
-          struct propset_walk_baton wb;
-
-          wb.wc_ctx = ctx->wc_ctx;
-          wb.propname = propname;
-          wb.propval = propval;
-          wb.force = skip_checks;
-          wb.changelist_hash = changelist_hash;
-          wb.notify_func = ctx->notify_func2;
-          wb.notify_baton = ctx->notify_baton2;
-          SVN_ERR(svn_wc__node_walk_children(ctx->wc_ctx, target_abspath,
-                                             FALSE, propset_walk_cb, &wb,
-                                             depth, ctx->cancel_func,
-                                             ctx->cancel_baton, pool));
-        }
-      else if (svn_wc__changelist_match(ctx->wc_ctx, target_abspath,
-                                        changelist_hash, pool))
-        {
-          SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, target_abspath, propname,
-                                   propval, skip_checks, ctx->notify_func2,
-                                   ctx->notify_baton2, pool));
-        }
+      baton.ctx = ctx;
+      baton.local_abspath = target_abspath;
+      baton.depth = depth;
+      baton.kind = kind;
+      baton.propname = propname;
+      baton.propval = propval;
+      baton.skip_checks = skip_checks;
+      baton.changelist_hash = changelist_hash;
+
+      SVN_ERR(svn_wc__call_with_write_lock(set_props_cb, &baton,
+                                           ctx->wc_ctx, target_abspath, FALSE,
+                                           pool, pool));
 
       return SVN_NO_ERROR;
     }
@@ -438,7 +477,7 @@ svn_client_revprop_set2(const char *prop
 
   /* Open an RA session for the URL. Note that we don't have a local
      directory, nor a place to put temp files. */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, URL, NULL,
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, URL, NULL,
                                                NULL, FALSE, TRUE, ctx, pool));
 
   /* Resolve the revision into something real, and return that to the
@@ -930,7 +969,7 @@ svn_client_revprop_get(const char *propn
 
   /* Open an RA session for the URL. Note that we don't have a local
      directory, nor a place to put temp files. */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, URL, NULL,
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, URL, NULL,
                                                NULL, FALSE, TRUE, ctx, pool));
 
   /* Resolve the revision into something real, and return that to the
@@ -1274,7 +1313,7 @@ svn_client_revprop_list(apr_hash_t **pro
 
   /* Open an RA session for the URL. Note that we don't have a local
      directory, nor a place to put temp files. */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, URL, NULL,
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, URL, NULL,
                                                NULL, FALSE, TRUE, ctx, pool));
 
   /* Resolve the revision into something real, and return that to the

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/ra.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/ra.c Wed Sep 15 19:32:26 2010
@@ -280,8 +280,12 @@ get_client_string(void *baton,
   return SVN_NO_ERROR;
 }
 
+
+#define SVN_CLIENT__MAX_REDIRECT_ATTEMPTS 3 /* ### TODO:  Make configurable. */
+
 svn_error_t *
 svn_client__open_ra_session_internal(svn_ra_session_t **ra_session,
+                                     const char **corrected_url,
                                      const char *base_url,
                                      const char *base_dir_abspath,
                                      const apr_array_header_t *commit_items,
@@ -332,9 +336,63 @@ svn_client__open_ra_session_internal(svn
         SVN_ERR(err);
     }
 
-  return svn_error_return(svn_ra_open3(ra_session, base_url, uuid, cbtable, cb,
-                                       ctx->config, pool));
-}
+  /* If the caller allows for auto-following redirections, and the
+     RA->open() call above reveals a CORRECTED_URL, try the new URL.
+     We'll do this in a loop up to some maximum number follow-and-retry
+     attempts.  */
+  if (corrected_url)
+    {
+      apr_hash_t *attempted = apr_hash_make(pool);
+      int attempts_left = SVN_CLIENT__MAX_REDIRECT_ATTEMPTS;
+
+      *corrected_url = NULL;
+      while (attempts_left--)
+        {
+          const char *corrected = NULL;
+
+          /* Try to open the RA session.  If this is our last attempt,
+             don't accept corrected URLs from the RA provider. */
+          SVN_ERR(svn_ra_open4(ra_session,
+                               attempts_left == 0 ? NULL : &corrected,
+                               base_url, uuid, cbtable, cb, ctx->config, pool));
+
+          /* No error and no corrected URL?  We're done here. */
+          if (! corrected)
+            break;
+
+          /* Notify the user that a redirect is being followed. */
+          if (ctx->notify_func2 != NULL)
+            {
+              svn_wc_notify_t *notify = 
+                svn_wc_create_notify_url(corrected, 
+                                         svn_wc_notify_url_redirect, pool);
+              (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+            }
+
+          /* Our caller will want to know what our final corrected URL was. */
+          *corrected_url = corrected;
+
+          /* Make sure we've not attempted this URL before. */
+          if (apr_hash_get(attempted, corrected, APR_HASH_KEY_STRING))
+            return svn_error_createf(SVN_ERR_CLIENT_CYCLE_DETECTED, NULL,
+                                     _("Redirect cycle detected for URL '%s'"),
+                                     corrected);
+
+          /* Remember this CORRECTED_URL so we don't wind up in a loop. */
+          apr_hash_set(attempted, corrected, APR_HASH_KEY_STRING, (void *)1);
+          base_url = corrected;
+        }
+    }
+  else
+    {
+      SVN_ERR(svn_ra_open4(ra_session, NULL, base_url,
+                           uuid, cbtable, cb, ctx->config, pool));
+    }
+
+  return SVN_NO_ERROR;
+ }
+#undef SVN_CLIENT__MAX_REDIRECT_ATTEMPTS
+
 
 svn_error_t *
 svn_client_open_ra_session(svn_ra_session_t **session,
@@ -342,9 +400,10 @@ svn_client_open_ra_session(svn_ra_sessio
                            svn_client_ctx_t *ctx,
                            apr_pool_t *pool)
 {
-  return svn_error_return(svn_client__open_ra_session_internal(session, url,
-                                              NULL, NULL,
-                                              FALSE, TRUE, ctx, pool));
+  return svn_error_return(
+             svn_client__open_ra_session_internal(session, NULL, url,
+                                                  NULL, NULL, FALSE, TRUE,
+                                                  ctx, pool));
 }
 
 
@@ -358,7 +417,7 @@ svn_client_uuid_from_url(const char **uu
   apr_pool_t *subpool = svn_pool_create(pool);
 
   /* use subpool to create a temporary RA session */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, url,
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url,
                                                NULL, /* no base dir */
                                                NULL, FALSE, TRUE,
                                                ctx, subpool));
@@ -416,7 +475,7 @@ svn_client__ra_session_from_path(svn_ra_
   svn_opt_revision_t dead_end_rev;
   svn_opt_revision_t *ignored_rev, *new_rev;
   svn_revnum_t rev;
-  const char *ignored_url;
+  const char *ignored_url, *corrected_url;
 
   SVN_ERR(svn_client_url_from_path2(&initial_url, path_or_url, ctx, pool,
                                     pool));
@@ -431,11 +490,17 @@ svn_client__ra_session_from_path(svn_ra_
                                     TRUE,
                                     pool));
 
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, initial_url,
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
+                                               initial_url,
                                                base_dir_abspath, NULL,
                                                base_dir_abspath != NULL,
                                                FALSE, ctx, pool));
 
+  /* If we got a CORRECTED_URL, we'll want to refer to that as the
+     URL-ized form of PATH_OR_URL from now on. */
+  if (corrected_url && svn_path_is_url(path_or_url))
+    path_or_url = corrected_url;
+
   dead_end_rev.kind = svn_opt_revision_unspecified;
 
   /* Run the history function to get the object's (possibly
@@ -588,7 +653,8 @@ svn_client__repos_locations(const char *
       SVN_ERR(svn_dirent_get_absolute(&local_abspath_or_url, path, subpool));
       SVN_ERR(svn_wc__node_get_url(&node_url, ctx->wc_ctx,
                                    local_abspath_or_url, pool, subpool));
-      SVN_ERR(svn_wc__node_get_copyfrom_info(&copyfrom_url, &copyfrom_rev,
+      SVN_ERR(svn_wc__node_get_copyfrom_info(NULL, NULL,
+                                             &copyfrom_url, &copyfrom_rev,
                                              NULL, ctx->wc_ctx,
                                              local_abspath_or_url,
                                              pool, subpool));
@@ -625,7 +691,7 @@ svn_client__repos_locations(const char *
 
   /* Open a RA session to this URL if we don't have one already. */
   if (! ra_session)
-    SVN_ERR(svn_client__open_ra_session_internal(&ra_session, url, NULL,
+    SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url, NULL,
                                                  NULL, FALSE, TRUE,
                                                  ctx, subpool));
 

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/relocate.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/relocate.c Wed Sep 15 19:32:26 2010
@@ -66,6 +66,7 @@ validator_func(void *baton,
 {
   struct validator_baton_t *b = baton;
   struct url_uuid_t *url_uuid = NULL;
+  const char *disable_checks;
 
   apr_array_header_t *uuids = b->url_uuids;
   int i;
@@ -81,6 +82,16 @@ validator_func(void *baton,
         }
     }
 
+  disable_checks = getenv("SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_RELOCATE_VALIDATION");
+  if (disable_checks && (strcmp(disable_checks, "yes") == 0))
+    {
+      /* Lie about URL_UUID's components, claiming they match the
+         expectations of the validation code below.  */
+      url_uuid = apr_pcalloc(pool, sizeof(*url_uuid));
+      url_uuid->root = apr_pstrdup(pool, root_url);
+      url_uuid->uuid = apr_pstrdup(pool, uuid);
+    }
+
   /* We use an RA session in a subpool to get the UUID of the
      repository at the new URL so we can force the RA session to close
      by destroying the subpool. */
@@ -88,7 +99,7 @@ validator_func(void *baton,
     {
       apr_pool_t *sesspool = svn_pool_create(pool);
       svn_ra_session_t *ra_session;
-      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, url, NULL,
+      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, url, NULL,
                                                    NULL, FALSE, TRUE,
                                                    b->ctx, sesspool));
       url_uuid = &APR_ARRAY_PUSH(uuids, struct url_uuid_t);

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff.c Wed Sep 15 19:32:26 2010
@@ -89,6 +89,17 @@ struct edit_baton {
   svn_wc_notify_func2_t notify_func;
   void *notify_baton;
 
+  /* TRUE if the operation needs to walk deleted dirs on the "old" side.
+     FALSE otherwise. */
+  svn_boolean_t walk_deleted_repos_dirs;
+
+  /* A callback used to see if the client wishes to cancel the running
+     operation. */
+  svn_cancel_func_t cancel_func;
+
+  /* A baton to pass to the cancellation callback. */
+  void *cancel_baton;
+
   apr_pool_t *pool;
 };
 
@@ -230,11 +241,10 @@ make_dir_baton(const char *path,
 static struct file_baton *
 make_file_baton(const char *path,
                 svn_boolean_t added,
-                void *edit_baton,
+                struct edit_baton *edit_baton,
                 apr_pool_t *pool)
 {
   struct file_baton *file_baton = apr_pcalloc(pool, sizeof(*file_baton));
-  struct edit_baton *eb = edit_baton;
 
   file_baton->edit_baton = edit_baton;
   file_baton->added = added;
@@ -242,7 +252,7 @@ make_file_baton(const char *path,
   file_baton->skip = FALSE;
   file_baton->pool = pool;
   file_baton->path = apr_pstrdup(pool, path);
-  file_baton->wcpath = svn_dirent_join(eb->target, path, pool);
+  file_baton->wcpath = svn_dirent_join(edit_baton->target, path, pool);
   file_baton->propchanges  = apr_array_make(pool, 1, sizeof(svn_prop_t));
 
   return file_baton;
@@ -291,9 +301,11 @@ get_file_mime_types(const char **mimetyp
 }
 
 
-/* Get the repository version of a file. This makes an RA request to
- * retrieve the file contents. A pool cleanup handler is installed to
- * delete this file.
+/* 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.
  */
 static svn_error_t *
 get_file_from_ra(struct file_baton *b, svn_revnum_t revision)
@@ -443,6 +455,89 @@ open_root(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
+/* Recursively walk tree rooted at DIR (at REVISION) in the repository,
+ * reporting all files 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
+ * overall crawler editor baton.  If CANCEL_FUNC is not NULL, then it
+ * should refer to a cancellation function (along with CANCEL_BATON).
+ */
+/* ### TODO: Handle depth. */
+static svn_error_t *
+diff_deleted_dir(const char *dir,
+                 svn_revnum_t revision,
+                 svn_ra_session_t *ra_session,
+                 struct edit_baton *eb,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton,
+                 apr_pool_t *pool)
+{
+  apr_hash_t *dirents;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_hash_index_t *hi;
+
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  SVN_ERR(svn_ra_get_dir2(ra_session,
+                          &dirents,
+                          NULL, NULL,
+                          dir,
+                          revision,
+                          SVN_DIRENT_KIND,
+                          pool));
+  
+  for (hi = apr_hash_first(pool, dirents); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path;
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
+
+      svn_pool_clear(iterpool);
+
+      path = svn_relpath_join(dir, name, iterpool);
+
+      if (dirent->kind == svn_node_file)
+        {
+          struct file_baton *b;
+          const char *mimetype1, *mimetype2;
+
+          /* Compare a file being deleted against an empty file */
+          b = make_file_baton(path, FALSE, eb, iterpool);
+          SVN_ERR(get_file_from_ra(b, 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, NULL, b->wcpath,
+                                b->path_start_revision,
+                                b->path_end_revision,
+                                mimetype1, mimetype2,
+                                b->pristine_props,
+                                b->edit_baton->diff_cmd_baton,
+                                pool));
+        }
+ 
+      if (dirent->kind == svn_node_dir)
+        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.  */
 static svn_error_t *
 delete_entry(const char *path,
@@ -500,6 +595,20 @@ delete_entry(const char *path,
                     (local_dir_abspath, &state, &tree_conflicted,
                      svn_dirent_join(eb->target, path, pool),
                      eb->diff_cmd_baton, pool));
+ 
+            if (eb->walk_deleted_repos_dirs)
+              {
+                /* A workaround for issue 2333.  The "old" dir will be
+                skipped by the repository report.  Crawl it recursively,
+                diffing each file against the empty file. */
+                SVN_ERR(diff_deleted_dir(path,
+                                         eb->revision,
+                                         eb->ra_session,
+                                         eb,
+                                         eb->cancel_func,
+                                         eb->cancel_baton,
+                                         pool));
+              }
             break;
           }
         default:
@@ -1057,6 +1166,27 @@ change_file_prop(void *file_baton,
   if (b->skip)
     return SVN_NO_ERROR;
 
+  /* Issue #3657 'phantom svn:eol-style changes cause spurious merge text
+     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
+     changed between the start and end of the edit.  Less obvious however,
+     is that these callbacks may be made describing *all* of the properties
+     on FILE_BATON->PATH when using the DAV providers, not just the change(s).
+     (Specifically ra_neon does this for diff/merge and ra_serf does it
+     for diff/merge/update/switch).
+
+     Normally this is fairly harmless, but if it appears that the
+     svn:eol-style property has changed on a file, then we can get spurious
+     text conflicts (i.e. Issue #3657).  To prevent this, we populate
+     FILE_BATON->PRISTINE_PROPS only with actual property changes. */
+  if (value)
+    {
+      const char *current_prop = svn_prop_get_value(b->pristine_props, name);
+      if (current_prop && strcmp(current_prop, value->data) == 0)
+        return SVN_NO_ERROR;
+    }
+
   propchange = apr_array_push(b->propchanges);
   propchange->name = apr_pstrdup(b->pool, name);
   propchange->value = value ? svn_string_dup(value, b->pool) : NULL;
@@ -1192,6 +1322,9 @@ svn_client__get_diff_editor(const char *
   eb->pool = subpool;
   eb->notify_func = notify_func;
   eb->notify_baton = notify_baton;
+  eb->walk_deleted_repos_dirs = TRUE;
+  eb->cancel_func = cancel_func;
+  eb->cancel_baton = cancel_baton;
 
   tree_editor->set_target_revision = set_target_revision;
   tree_editor->open_root = open_root;

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff_summarize.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff_summarize.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff_summarize.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/repos_diff_summarize.c Wed Sep 15 19:32:26 2010
@@ -23,6 +23,7 @@
  */
 
 
+#include "svn_dirent_uri.h"
 #include "svn_props.h"
 #include "svn_pools.h"
 
@@ -45,6 +46,18 @@ struct edit_baton {
 
   /* The start revision for the comparison */
   svn_revnum_t revision;
+
+  /* TRUE if the operation needs to walk deleted dirs on the "old" side.
+     FALSE otherwise. */
+  svn_boolean_t walk_deleted_repos_dirs;
+
+  /* A callback used to see if the client wishes to cancel the running
+     operation. */
+  svn_cancel_func_t cancel_func;
+
+  /* A baton to pass to the cancellation callback. */
+  void *cancel_baton;
+
 };
 
 
@@ -97,7 +110,7 @@ create_item_baton(struct edit_baton *edi
 /* Make sure that this item baton contains a summarize struct.
  * If it doesn't before this call, allocate a new struct in the item's pool,
  * initializing the diff kind to normal.
- * All other fields are also initialized from IB to to NULL/invalid values. */
+ * All other fields are also initialized from IB or to NULL/invalid values. */
 static void
 ensure_summarize(struct item_baton *ib)
 {
@@ -129,6 +142,83 @@ open_root(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
+/* Recursively walk the tree rooted at DIR (at REVISION) in the
+ * repository, reporting all files as deleted.  Part of a workaround
+ * for issue 2333.
+ *
+ * DIR is a repository path relative to the URL in RA_SESSION.  REVISION
+ * may be NULL, in which case it defaults to HEAD.  EDIT_BATON is the
+ * overall crawler editor baton.  If CANCEL_FUNC is not NULL, then it
+ * should refer to a cancellation function (along with CANCEL_BATON).
+ */
+/* ### TODO: Handle depth. */
+static svn_error_t *
+diff_deleted_dir(const char *dir,
+                 svn_revnum_t revision,
+                 svn_ra_session_t *ra_session,
+                 void *edit_baton,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton,
+                 apr_pool_t *pool)
+{
+  struct edit_baton *eb = edit_baton;
+  apr_hash_t *dirents;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_hash_index_t *hi;
+
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
+
+  SVN_ERR(svn_ra_get_dir2(ra_session,
+                          &dirents,
+                          NULL, NULL,
+                          dir,
+                          revision,
+                          SVN_DIRENT_KIND,
+                          pool));
+  
+  for (hi = apr_hash_first(pool, dirents); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path;
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_dirent_t *dirent = svn__apr_hash_index_val(hi);
+      svn_node_kind_t kind;
+      svn_client_diff_summarize_t *sum;
+
+      svn_pool_clear(iterpool);
+
+      path = svn_relpath_join(dir, name, iterpool);
+
+      SVN_ERR(svn_ra_check_path(eb->ra_session,
+                                path,
+                                eb->revision,
+                                &kind,
+                                iterpool));
+
+      sum = apr_pcalloc(pool, sizeof(*sum));
+      sum->summarize_kind = svn_client_diff_summarize_kind_deleted;
+      sum->path = path;
+      sum->node_kind = kind;
+
+      SVN_ERR(eb->summarize_func(sum,
+                                 eb->summarize_func_baton,
+                                 iterpool));
+
+      if (dirent->kind == svn_node_dir)
+        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.  */
 static svn_error_t *
 delete_entry(const char *path,
@@ -153,7 +243,18 @@ delete_entry(const char *path,
   sum->path = path;
   sum->node_kind = kind;
 
-  return eb->summarize_func(sum, eb->summarize_func_baton, pool);
+  SVN_ERR(eb->summarize_func(sum, eb->summarize_func_baton, pool));
+
+  if (kind == svn_node_dir)
+        SVN_ERR(diff_deleted_dir(path,
+                                 eb->revision,
+                                 eb->ra_session,
+                                 eb,
+                                 eb->cancel_func,
+                                 eb->cancel_baton,
+                                 pool));
+
+  return SVN_NO_ERROR;
 }
 
 /* An editor function.  */
@@ -298,7 +399,9 @@ change_prop(void *entry_baton,
   if (svn_property_kind(NULL, name) == svn_prop_regular_kind)
     {
       ensure_summarize(ib);
-      ib->summarize->prop_changed = TRUE;
+
+      if (ib->summarize->summarize_kind != svn_client_diff_summarize_kind_added)
+        ib->summarize->prop_changed = TRUE;
     }
 
   return SVN_NO_ERROR;
@@ -309,7 +412,7 @@ svn_error_t *
 svn_client__get_diff_summarize_editor(const char *target,
                                       svn_client_diff_summarize_func_t
                                       summarize_func,
-                                      void *item_baton,
+                                      void *summarize_baton,
                                       svn_ra_session_t *ra_session,
                                       svn_revnum_t revision,
                                       svn_cancel_func_t cancel_func,
@@ -323,9 +426,12 @@ svn_client__get_diff_summarize_editor(co
 
   eb->target = target;
   eb->summarize_func = summarize_func;
-  eb->summarize_func_baton = item_baton;
+  eb->summarize_func_baton = summarize_baton;
   eb->ra_session = ra_session;
   eb->revision = revision;
+  eb->walk_deleted_repos_dirs = TRUE;
+  eb->cancel_func = cancel_func;
+  eb->cancel_baton = cancel_baton;
 
   tree_editor->open_root = open_root;
   tree_editor->delete_entry = delete_entry;

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/revert.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/revert.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/revert.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/revert.c Wed Sep 15 19:32:26 2010
@@ -151,7 +151,7 @@ svn_client_revert2(const apr_array_heade
       baton.changelists = changelists;
       baton.ctx = ctx;
       err = svn_wc__call_with_write_lock(revert, &baton, ctx->wc_ctx,
-                                         local_abspath, pool, pool);
+                                         local_abspath, TRUE, pool, pool);
       if (err)
         goto errorful;
     }

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/status.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/status.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/status.c Wed Sep 15 19:32:26 2010
@@ -121,6 +121,7 @@ typedef struct report_baton_t {
   /* The common ancestor URL of all paths included in the report. */
   char *ancestor;
   void *set_locks_baton;
+  svn_depth_t depth;
   svn_client_ctx_t *ctx;
   /* Pool to store locks in. */
   apr_pool_t *pool;
@@ -161,14 +162,17 @@ reporter_link_path(void *report_baton, c
   const char *ancestor;
   apr_size_t len;
 
-  ancestor = svn_dirent_get_longest_ancestor(url, rb->ancestor, pool);
+  ancestor = svn_uri_get_longest_ancestor(url, rb->ancestor, pool);
 
   /* If we got a shorter ancestor, truncate our current ancestor.
      Note that svn_dirent_get_longest_ancestor will allocate its return
      value even if it identical to one of its arguments. */
   len = strlen(ancestor);
   if (len < strlen(rb->ancestor))
-    rb->ancestor[len] = '\0';
+    {
+      rb->ancestor[len] = '\0';
+      rb->depth = svn_depth_infinity;
+    }
 
   return rb->wrapped_reporter->link_path(rb->wrapped_report_baton, path, url,
                                          revision, depth, start_empty,
@@ -188,14 +192,14 @@ reporter_finish_report(void *report_bato
 
   /* Open an RA session to our common ancestor and grab the locks under it.
    */
-  SVN_ERR(svn_client__open_ra_session_internal(&ras, rb->ancestor, NULL,
+  SVN_ERR(svn_client__open_ra_session_internal(&ras, NULL, rb->ancestor, NULL,
                                                NULL, FALSE, TRUE,
                                                rb->ctx, subpool));
 
   /* The locks need to live throughout the edit.  Note that if the
      server doesn't support lock discovery, we'll just not do locky
      stuff. */
-  err = svn_ra_get_locks(ras, &locks, "", rb->pool);
+  err = svn_ra_get_locks2(ras, &locks, "", rb->depth, rb->pool);
   if (err && ((err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
               || (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)))
     {
@@ -249,6 +253,7 @@ svn_client_status5(svn_revnum_t *result_
                    svn_boolean_t update,
                    svn_boolean_t no_ignore,
                    svn_boolean_t ignore_externals,
+                   svn_boolean_t depth_as_sticky,
                    const apr_array_header_t *changelists,
                    svn_client_status_func_t status_func,
                    void *status_baton,
@@ -390,7 +395,7 @@ svn_client_status5(svn_revnum_t *result_
                                     pool, pool));
 
       /* Open a repository session to the URL. */
-      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, URL,
+      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, URL,
                                                    dir_abspath,
                                                    NULL, FALSE, TRUE,
                                                    ctx, pool));
@@ -435,6 +440,7 @@ svn_client_status5(svn_revnum_t *result_
         {
           svn_revnum_t revnum;
           report_baton_t rb;
+          svn_depth_t status_depth;
 
           if (revision->kind == svn_opt_revision_head)
             {
@@ -452,11 +458,16 @@ svn_client_status5(svn_revnum_t *result_
                                                       pool));
             }
 
+          if (depth_as_sticky)
+            status_depth = depth;
+          else
+            status_depth = svn_depth_unknown; /* Use depth from WC */
+
           /* Do the deed.  Let the RA layer drive the status editor. */
           SVN_ERR(svn_ra_do_status2(ra_session, &rb.wrapped_reporter,
                                     &rb.wrapped_report_baton,
-                                    target_basename, revnum, depth, editor,
-                                    edit_baton, pool));
+                                    target_basename, revnum, status_depth,
+                                    editor, edit_baton, pool));
 
           /* Init the report baton. */
           rb.ancestor = apr_pstrdup(pool, URL); /* Edited later */
@@ -464,6 +475,11 @@ svn_client_status5(svn_revnum_t *result_
           rb.ctx = ctx;
           rb.pool = pool;
 
+          if (depth == svn_depth_unknown)
+            rb.depth = svn_depth_infinity;
+          else
+            rb.depth = depth;
+
           SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                         SVN_RA_CAPABILITY_DEPTH, pool));
 
@@ -605,8 +621,8 @@ create_client_status(svn_client_status_t
   (*cst)->switched = status->switched;
 
   if (status->kind == svn_node_dir)
-    SVN_ERR(svn_wc__temp_get_wclocked(&(*cst)->locked, wc_ctx, local_abspath,
-                                      scratch_pool));
+    SVN_ERR(svn_wc_locked2(NULL, &(*cst)->locked, wc_ctx, local_abspath,
+                           scratch_pool));
 
   (*cst)->copied = status->copied;
   (*cst)->revision = status->revision;

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/switch.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/switch.c Wed Sep 15 19:32:26 2010
@@ -294,8 +294,9 @@ svn_client__switch_internal(svn_revnum_t
 
   /* Rely on svn_wc__acquire_write_lock setting ANCHOR_ABSPATH even
      when it returns SVN_ERR_WC_LOCKED */
-  err = svn_wc__acquire_write_lock(&anchor_abspath, ctx->wc_ctx,
-                                   local_abspath, pool, pool);
+  err = svn_wc__acquire_write_lock(&anchor_abspath,
+                                   ctx->wc_ctx, local_abspath, TRUE,
+                                   pool, pool);
   if (err && err->apr_err != SVN_ERR_WC_LOCKED)
     return svn_error_return(err);
 

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/update.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/update.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/update.c Wed Sep 15 19:32:26 2010
@@ -70,7 +70,7 @@ file_fetcher(void *baton,
   struct ff_baton *ffb = (struct ff_baton *)baton;
   const char *dirpath, *base_name, *session_url, *old_session_url;
 
-  svn_relpath_split(path, &dirpath, &base_name, pool);
+  svn_relpath_split(&dirpath, &base_name, path, pool);
   session_url = svn_path_url_add_component2(ffb->repos_root, 
                                             dirpath, pool);
 
@@ -78,8 +78,9 @@ file_fetcher(void *baton,
     SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ffb->session,
                                               session_url, ffb->pool));
   else
-    SVN_ERR(svn_client__open_ra_session_internal(&(ffb->session), session_url,
-                                                 NULL, NULL, FALSE, TRUE,
+    SVN_ERR(svn_client__open_ra_session_internal(&(ffb->session), NULL,
+                                                 session_url, NULL, NULL,
+                                                 FALSE, TRUE,
                                                  ffb->ctx, ffb->pool));
 
   return svn_ra_get_file(ffb->session, base_name, revision, stream,
@@ -107,6 +108,7 @@ update_internal(svn_revnum_t *result_rev
   const svn_ra_reporter3_t *reporter;
   void *report_baton;
   const char *anchor_url;
+  const char *corrected_url;
   const char *target;
   const char *repos_root;
   svn_error_t *err;
@@ -156,9 +158,6 @@ update_internal(svn_revnum_t *result_rev
                                  pool));
 
           /* Target excluded, we are done now */
-          SVN_ERR(svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath,
-                                             pool));
-
           return SVN_NO_ERROR;
         }
 
@@ -191,9 +190,19 @@ update_internal(svn_revnum_t *result_rev
     : NULL;
 
   /* Open an RA session for the URL */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, anchor_url,
-                                               anchor_abspath, NULL, TRUE, TRUE,
-                                               ctx, pool));
+  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
+                                               anchor_url,
+                                               anchor_abspath, NULL, TRUE,
+                                               TRUE, ctx, pool));
+
+  /* If we got a corrected URL from the RA subsystem, we'll need to
+     relocate our working copy first. */
+  if (corrected_url)
+    {
+      SVN_ERR(svn_client_relocate(anchor_abspath, anchor_url, corrected_url,
+                                  TRUE, ctx, pool));
+      anchor_url = corrected_url;
+    }
 
   /* ### todo: shouldn't svn_client__get_revision_number be able
      to take a URL as easily as a local path?  */
@@ -282,8 +291,6 @@ update_internal(svn_revnum_t *result_rev
   if (sleep_here)
     svn_io_sleep_for_timestamps(local_abspath, pool);
 
-  SVN_ERR(svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool));
-
   /* Let everyone know we're finished here. */
   if (ctx->notify_func2)
     {
@@ -320,31 +327,30 @@ svn_client__update_internal(svn_revnum_t
                             apr_pool_t *pool)
 {
   const char *anchor_abspath;
-  svn_error_t *err1, *err2;
+  svn_error_t *err;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
   if (!innerupdate)
-    {
-      SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath, ctx->wc_ctx,
-                                         local_abspath, pool, pool));
-    }
+    SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
+                                       ctx->wc_ctx, local_abspath, TRUE,
+                                       pool, pool));
   else
-    {
-      SVN_ERR(svn_wc__acquire_write_lock(NULL, ctx->wc_ctx,
-                                         local_abspath, pool, pool));
-      anchor_abspath = local_abspath;
-    }
+    SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
+                                       ctx->wc_ctx, local_abspath, FALSE,
+                                       pool, pool));
 
-  err1 = update_internal(result_rev, local_abspath, anchor_abspath,
+  err = update_internal(result_rev, local_abspath, anchor_abspath,
                          revision, depth, depth_is_sticky,
                          ignore_externals, allow_unver_obstructions,
                          timestamp_sleep, send_copyfrom_args,
                          innerupdate, ctx, pool);
 
-  err2 = svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool);
+  err = svn_error_compose_create(
+            err,
+            svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool));
 
-  return svn_error_compose_create(err1, err2);
+  return svn_error_return(err);
 }
 
 

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_client/url.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_client/url.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_client/url.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_client/url.c Wed Sep 15 19:32:26 2010
@@ -116,9 +116,10 @@ svn_client__derive_location(const char *
     {
       if (ra_session == NULL)
         {
-          SVN_ERR(svn_client__open_ra_session_internal(&ra_session, *url, NULL,
-                                                       NULL, FALSE, TRUE, ctx,
-                                                       scratch_pool));
+          SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL,
+                                                       *url, NULL, NULL,
+                                                       FALSE, TRUE,
+                                                       ctx, scratch_pool));
         }
       SVN_ERR(svn_client__get_revision_number(peg_revnum, NULL, ctx->wc_ctx,
                                               NULL, ra_session, peg_revision,
@@ -146,7 +147,8 @@ svn_client__entry_location(const char **
       || peg_rev_kind == svn_opt_revision_head)
     return svn_error_create(SVN_ERR_CLIENT_BAD_REVISION, NULL, NULL);
 
-  SVN_ERR(svn_wc__node_get_copyfrom_info(&copyfrom_url, &copyfrom_rev,
+  SVN_ERR(svn_wc__node_get_copyfrom_info(NULL, NULL,
+                                         &copyfrom_url, &copyfrom_rev,
                                          NULL, wc_ctx, local_abspath,
                                          result_pool, scratch_pool));
 

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_delta/path_driver.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_delta/path_driver.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_delta/path_driver.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_delta/path_driver.c Wed Sep 15 19:32:26 2010
@@ -215,9 +215,9 @@ svn_delta_path_driver(const svn_delta_ed
       /*** Step C - Open any directories between the common ancestor
            and the parent of the current path. ***/
       if (*path == '/')
-        svn_uri_split(path, &pdir, &bname, iterpool);
+        svn_uri_split(&pdir, &bname, path, iterpool);
       else
-        svn_relpath_split(path, &pdir, &bname, iterpool);
+        svn_relpath_split(&pdir, &bname, path, iterpool);
       if (strlen(pdir) > common_len)
         {
           const char *piece = pdir + common_len + 1;

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_delta/svndiff.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_delta/svndiff.c Wed Sep 15 19:32:26 2010
@@ -31,10 +31,12 @@
 #include "svn_private_config.h"
 #include <zlib.h>
 
-/* This macro is taken from zlib, and was originally the function
-   compressBound.  It shouldn't ever change, but once every millenium,
-   it may be useful for someone to make sure. */
+/* The zlib compressBound function was not exported until 1.2.0. */
+#if ZLIB_VERNUM >= 0x1200
+#define svnCompressBound(LEN) compressBound(LEN)
+#else
 #define svnCompressBound(LEN) ((LEN) + ((LEN) >> 12) + ((LEN) >> 14) + 11)
+#endif
 
 /* For svndiff1, address/instruction/new data under this size will not
    be compressed using zlib as a secondary compressor.  */

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_delta/text_delta.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_delta/text_delta.c Wed Sep 15 19:32:26 2010
@@ -564,6 +564,73 @@ size_buffer(char **buf, apr_size_t *buf_
   return SVN_NO_ERROR;
 }
 
+/* Copy LEN bytes from SOURCE to TARGET, optimizing for the case where LEN
+ * is often very small.  Return a pointer to the first byte after the copied
+ * target range, unlike standard memcpy(), as a potential further
+ * optimization for the caller.
+ *
+ * memcpy() is hard to tune for a wide range of buffer lengths.  Therefore,
+ * it is often tuned for high throughput on large buffers and relatively
+ * low latency for mid-sized buffers (tens of bytes).  However, the overhead
+ * for very small buffers (<10 bytes) is still high.  Even passing the
+ * parameters, for instance, may take as long as copying 3 bytes.
+ *
+ * Because short copy sequences seem to be a common case, at least in
+ * "format 2" FSFS repositories, we copy them directly.  Larger buffer sizes
+ * aren't hurt measurably by the exta 'if' clause.  */
+static APR_INLINE char *
+fast_memcpy(char *target, const char *source, apr_size_t len)
+{
+  if (len > 7)
+    {
+      memcpy(target, source, len);
+      target += len;
+    }
+  else
+    {
+      /* memcpy is not exactly fast for small block sizes.
+       * Since they are common, let's run optimized code for them. */
+      const char *end = source + len;
+      for (; source != end; source++)
+        *(target++) = *source;
+    }
+
+  return target;
+}
+
+/* Copy LEN bytes from SOURCE to TARGET.  Unlike memmove() or memcpy(),
+ * create repeating patterns if the source and target ranges overlap.
+ * Return a pointer to the first byte after the copied target range.  */
+static APR_INLINE char *
+patterning_copy(char *target, const char *source, apr_size_t len)
+{
+  const char *end = source + len;
+
+  /* On the majority of machines (x86 / x64), unaligned access is much
+   * cheaper than repeated aligned access.  Therefore, use chunky copies on
+   * these machines when feasible.
+   * For those machines, GCC, ICC and MSC will define one of the following: */
+#if defined(_M_IX86) || defined(_M_X64) || defined(i386) || defined(__x86_64)
+
+  if (end + sizeof(apr_uint32_t) <= target)
+    {
+      /* Source and target are at least 4 bytes apart, so we can copy in
+       * 4-byte chunks.  */
+      for (; source + sizeof(apr_uint32_t) <= end;
+           source += sizeof(apr_uint32_t),
+           target += sizeof(apr_uint32_t))
+      *(apr_uint32_t *)(target) = *(apr_uint32_t *)(source);
+    }
+
+#endif
+
+  /* fall through to byte-wise copy (either for the below-chunk-size tail
+   * or the whole copy) */
+  for (; source != end; source++)
+    *(target++) = *source;
+
+  return target;
+}
 
 void
 svn_txdelta_apply_instructions(svn_txdelta_window_t *window,
@@ -571,7 +638,7 @@ svn_txdelta_apply_instructions(svn_txdel
                                apr_size_t *tlen)
 {
   const svn_txdelta_op_t *op;
-  apr_size_t i, j, tpos = 0;
+  apr_size_t tpos = 0;
 
   for (op = window->ops; op < window->ops + window->num_ops; op++)
     {
@@ -586,25 +653,26 @@ svn_txdelta_apply_instructions(svn_txdel
         case svn_txdelta_source:
           /* Copy from source area.  */
           assert(op->offset + op->length <= window->sview_len);
-          memcpy(tbuf + tpos, sbuf + op->offset, buf_len);
+          fast_memcpy(tbuf + tpos, sbuf + op->offset, buf_len);
           break;
 
         case svn_txdelta_target:
-          /* Copy from target area.  Don't use memcpy() since its
-             semantics aren't guaranteed for overlapping memory areas,
-             and target copies are allowed to overlap to generate
-             repeated data.  */
+          /* Copy from target area.  We can't use memcpy() or the like
+           * since we need a specific semantics for overlapping copies:
+           * they must result in repeating patterns.
+           * Note that most copies won't have overlapping source and
+           * target ranges (they are just a result of self-compressed
+           * data) but a small percentage will.  */
           assert(op->offset < tpos);
-          for (i = op->offset, j = tpos; i < op->offset + buf_len; i++)
-            tbuf[j++] = tbuf[i];
+          patterning_copy(tbuf + tpos, tbuf + op->offset, buf_len);
           break;
 
         case svn_txdelta_new:
           /* Copy from window new area.  */
           assert(op->offset + op->length <= window->new_data->len);
-          memcpy(tbuf + tpos,
-                 window->new_data->data + op->offset,
-                 buf_len);
+          fast_memcpy(tbuf + tpos,
+                      window->new_data->data + op->offset,
+                      buf_len);
           break;
 
         default:

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_file.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_file.c Wed Sep 15 19:32:26 2010
@@ -860,7 +860,7 @@ output_unified_line(svn_diff__file_outpu
             {
               if (type != svn_diff__file_output_unified_skip)
                 {
-                  svn_stringbuf_appendbytes(baton->hunk, curp, 1);
+                  svn_stringbuf_appendbyte(baton->hunk, *curp);
                 }
               /* We don't append the LF to extra_context, since it would
                * just be stripped anyway. */

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_memory.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_memory.c?rev=997472&r1=997471&r2=997472&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_memory.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_diff/diff_memory.c Wed Sep 15 19:32:26 2010
@@ -353,6 +353,10 @@ typedef struct unified_output_baton_t
   apr_off_t hunk_length[2]; /* 0 == original; 1 == modified */
   apr_off_t hunk_start[2];  /* 0 == original; 1 == modified */
 
+  /* The delimiters of the hunk header, '@@' for text hunks and '##' for
+   * property hunks. */
+  const char *hunk_delimiter;
+
   /* Pool for allocation of temporary memory in the callbacks
      Should be cleared on entry of each iteration of a callback */
   apr_pool_t *pool;
@@ -515,8 +519,13 @@ output_unified_diff_modified(void *baton
   targ_orig = (targ_orig < 0) ? 0 : targ_orig;
   targ_mod = modified_start;
 
+  /* If the changed ranges are far enough apart (no overlapping or
+   * connecting context), flush the current hunk. */
   if (btn->next_token + SVN_DIFF__UNIFIED_CONTEXT_SIZE < targ_orig)
-    SVN_ERR(output_unified_flush_hunk(btn, NULL));
+    SVN_ERR(output_unified_flush_hunk(btn, btn->hunk_delimiter));
+  /* Adjust offset if it's not the first hunk. */
+  else if (btn->hunk_length[0] != 0)
+    targ_orig = btn->next_token;
 
   if (btn->hunk_length[0] == 0
       && btn->hunk_length[1] == 0)
@@ -569,6 +578,7 @@ svn_diff_mem_string_output_unified2(svn_
       baton.pool = svn_pool_create(pool);
       baton.header_encoding = header_encoding;
       baton.hunk = svn_stringbuf_create("", pool);
+      baton.hunk_delimiter = hunk_delimiter;
 
       SVN_ERR(svn_utf_cstring_from_utf8_ex2
               (&(baton.prefix_str[unified_output_context]), " ",