You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by jc...@apache.org on 2010/12/29 01:10:29 UTC

svn commit: r1053489 [2/7] - in /subversion/branches/diff-optimizations-bytes: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ contrib/client-side/svn_load_dirs/ notes/ subversion/bindings/javahl/native/ subversion/bindings/swig/ subv...

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra/util.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra/util.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra/util.c Wed Dec 29 00:10:25 2010
@@ -25,8 +25,10 @@
 
 /*** Includes. ***/
 #include <apr_pools.h>
+#include <apr_network_io.h>
 
 #include "svn_types.h"
+#include "svn_pools.h"
 #include "svn_error.h"
 #include "svn_error_codes.h"
 #include "svn_dirent_uri.h"
@@ -70,3 +72,171 @@ svn_ra__assert_mergeinfo_capable_server(
     }
   return SVN_NO_ERROR;
 }
+
+/* Does ERR mean "the current value of the revprop isn't equal to
+   the *OLD_VALUE_P you gave me"?
+ */
+static svn_boolean_t is_atomicity_error(svn_error_t *err)
+{
+  return svn_error_find_cause(err, SVN_ERR_FS_PROP_BASEVALUE_MISMATCH) != NULL;
+}
+
+svn_error_t *
+svn_ra__release_operational_lock(svn_ra_session_t *session,
+                                 const char *lock_revprop_name,
+                                 const svn_string_t *mylocktoken,
+                                 apr_pool_t *scratch_pool)
+{
+  svn_string_t *reposlocktoken;
+  svn_boolean_t be_atomic;
+
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                scratch_pool));
+  SVN_ERR(svn_ra_rev_prop(session, 0, lock_revprop_name,
+                          &reposlocktoken, scratch_pool));
+  if (reposlocktoken && svn_string_compare(reposlocktoken, mylocktoken))
+    {
+      svn_error_t *err;
+      
+      err = svn_ra_change_rev_prop2(session, 0, lock_revprop_name, 
+                                    be_atomic ? &mylocktoken : NULL, NULL,
+                                    scratch_pool);
+      if (is_atomicity_error(err))
+        return svn_error_createf(err->apr_err, err,
+                                 _("Lock was stolen by '%s'; unable to "
+                                   "remove it"), reposlocktoken->data);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra__get_operational_lock(const svn_string_t **lock_string_p,
+                             const svn_string_t **stolen_lock_p,
+                             svn_ra_session_t *session,
+                             const char *lock_revprop_name,
+                             svn_boolean_t steal_lock,
+                             int num_retries,
+                             svn_ra__lock_retry_func_t retry_func,
+                             void *retry_baton,
+                             svn_cancel_func_t cancel_func,
+                             void *cancel_baton,
+                             apr_pool_t *pool)
+{
+  char hostname_str[APRMAXHOSTLEN + 1] = { 0 };
+  svn_string_t *mylocktoken, *reposlocktoken;
+  apr_status_t apr_err;
+  svn_boolean_t be_atomic;
+  apr_pool_t *subpool;
+  int i;
+
+  *lock_string_p = NULL;
+  if (stolen_lock_p)
+    *stolen_lock_p = NULL;
+
+  SVN_ERR(svn_ra_has_capability(session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS, pool));
+
+  /* We build a lock token from the local hostname and a UUID.  */
+  apr_err = apr_gethostname(hostname_str, sizeof(hostname_str), pool);
+  if (apr_err)
+    return svn_error_wrap_apr(apr_err,
+                              _("Unable to determine local hostname"));
+  mylocktoken = svn_string_createf(pool, "%s:%s", hostname_str,
+                                   svn_uuid_generate(pool));
+
+  /* Ye Olde Retry Loope */
+  subpool = svn_pool_create(pool);
+
+  for (i = 0; i < num_retries; ++i)
+    {
+      svn_error_t *err;
+      const svn_string_t *unset = NULL;
+
+      svn_pool_clear(subpool);
+
+      /* Check for cancellation.  If we're cancelled, don't leave a
+         stray lock behind!  */
+      if (cancel_func)
+        {
+          err = cancel_func(cancel_baton);
+          if (err && err->apr_err == SVN_ERR_CANCELLED)
+            return svn_error_compose_create(
+                       svn_ra__release_operational_lock(session,
+                                                        lock_revprop_name,
+                                                        mylocktoken,
+                                                        subpool),
+                       err);
+          SVN_ERR(err);
+        }
+
+      /* Ask the repository for the value of the LOCK_REVPROP_NAME. */
+      SVN_ERR(svn_ra_rev_prop(session, 0, lock_revprop_name,
+                              &reposlocktoken, subpool));
+
+      /* Did we get a value from the repository?  We'll check to see
+         if it matches our token.  If so, we call it success.  If not
+         and we're told to steal locks, we remember the existing lock
+         token and fall through to the locking code; othewise, we
+         sleep and retry. */
+      if (reposlocktoken)
+        {
+          if (svn_string_compare(reposlocktoken, mylocktoken))
+            {
+              *lock_string_p = mylocktoken;
+              return SVN_NO_ERROR;
+            }
+          else if (! steal_lock)
+            {
+              if (retry_func)
+                SVN_ERR(retry_func(retry_baton, reposlocktoken, subpool));
+              apr_sleep(apr_time_from_sec(1));
+              continue;
+            }
+          else
+            {
+              if (stolen_lock_p)
+                *stolen_lock_p = svn_string_dup(reposlocktoken, pool);
+              unset = reposlocktoken;
+            }
+        }
+
+      /* No lock value in the repository, or we plan to steal it?
+         Well, if we've got a spare iteration, we'll try to set the
+         lock.  (We use the spare iteration to verify that we still
+         have the lock after setting it.) */
+      if (i < num_retries - 1)
+        {
+          /* Except in the very last iteration, try to set the lock. */
+          err = svn_ra_change_rev_prop2(session, 0, lock_revprop_name,
+                                        be_atomic ? &unset : NULL,
+                                        mylocktoken, subpool);
+
+          if (be_atomic && err && is_atomicity_error(err))
+            {
+              /* Someone else has the lock.  No problem, we'll loop again. */
+              svn_error_clear(err);
+            }
+          else if (be_atomic && err == SVN_NO_ERROR)
+            {
+              /* Yay!  We have the lock!  However, for compatibility
+                 with concurrent processes that don't support
+                 atomicity, loop anyway to double-check that they
+                 haven't overwritten our lock.
+              */
+              continue;
+            }
+          else
+            {
+              /* We have a genuine error, or aren't atomic and need
+                 to loop.  */
+              SVN_ERR(err);
+            }
+        }
+    }
+
+  return svn_error_createf(APR_EINVAL, NULL,
+                           _("Couldn't get lock on destination repos "
+                             "after %d attempts"), i);
+}

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_local/ra_plugin.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_local/ra_plugin.c Wed Dec 29 00:10:25 2010
@@ -416,7 +416,7 @@ svn_ra_local__get_schemes(apr_pool_t *po
 
 /* Do nothing.
  *
- * Why is this acceptable?  As of now, FS warnings are used for only
+ * Why is this acceptable?  FS warnings used to be used for only
  * two things: failures to close BDB repositories and failures to
  * interact with memcached in FSFS (new in 1.6).  In 1.5 and earlier,
  * we did not call svn_fs_set_warning_func in ra_local, which means
@@ -433,6 +433,9 @@ static void
 ignore_warnings(void *baton,
                 svn_error_t *err)
 {
+#ifdef SVN_DEBUG
+  SVN_DBG(("Ignoring FS warning %d\n", err ? err->apr_err : 0));
+#endif
   return;
 }
 

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/ra_serf.h?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/ra_serf.h Wed Dec 29 00:10:25 2010
@@ -883,10 +883,12 @@ svn_ra_serf__define_ns(svn_ra_serf__ns_t
  * Look up @a name in the @a ns_list list for previously declared namespace
  * definitions.
  *
- * @return @a svn_ra_serf__dav_props_t tuple representing the expanded name.
+ * Return (in @a *returned_prop_name) @a svn_ra_serf__dav_props_t tuple
+ * representing the expanded name.
  */
-svn_ra_serf__dav_props_t
-svn_ra_serf__expand_ns(svn_ra_serf__ns_t *ns_list,
+void
+svn_ra_serf__expand_ns(svn_ra_serf__dav_props_t *returned_prop_name,
+                       svn_ra_serf__ns_t *ns_list,
                        const char *name);
 
 /*

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/util.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/util.c Wed Dec 29 00:10:25 2010
@@ -1171,7 +1171,7 @@ start_xml(void *userData, const char *ra
 
   svn_ra_serf__define_ns(&parser->state->ns_list, attrs, parser->state->pool);
 
-  name = svn_ra_serf__expand_ns(parser->state->ns_list, raw_name);
+  svn_ra_serf__expand_ns(&name, parser->state->ns_list, raw_name);
 
   parser->error = parser->start(parser, parser->user_data, name, attrs);
 }
@@ -1185,7 +1185,7 @@ end_xml(void *userData, const char *raw_
   if (parser->error)
     return;
 
-  name = svn_ra_serf__expand_ns(parser->state->ns_list, raw_name);
+  svn_ra_serf__expand_ns(&name, parser->state->ns_list, raw_name);
 
   parser->error = parser->end(parser, parser->user_data, name);
 }

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/xml.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/xml.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/xml.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_ra_serf/xml.c Wed Dec 29 00:10:25 2010
@@ -86,8 +86,9 @@ svn_ra_serf__define_ns(svn_ra_serf__ns_t
  * Look up NAME in the NS_LIST list for previously declared namespace
  * definitions and return a DAV_PROPS_T-tuple that has values.
  */
-svn_ra_serf__dav_props_t
-svn_ra_serf__expand_ns(svn_ra_serf__ns_t *ns_list,
+void
+svn_ra_serf__expand_ns(svn_ra_serf__dav_props_t *returned_prop_name,
+                       svn_ra_serf__ns_t *ns_list,
                        const char *name)
 {
   const char *colon;
@@ -120,7 +121,8 @@ svn_ra_serf__expand_ns(svn_ra_serf__ns_t
       prop_name.name = name;
     }
 
-  return prop_name;
+  *returned_prop_name = prop_name;
+  return;
 }
 
 void

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/commit.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/commit.c Wed Dec 29 00:10:25 2010
@@ -38,6 +38,7 @@
 #include "svn_props.h"
 #include "repos.h"
 #include "svn_private_config.h"
+#include "private/svn_repos_private.h"
 
 
 
@@ -644,7 +645,68 @@ change_dir_prop(void *dir_baton,
                                        name, value, pool);
 }
 
+const char *
+svn_repos__post_commit_error_str(svn_error_t *err,
+                                 apr_pool_t *pool)
+{
+  svn_error_t *hook_err1, *hook_err2;
+  const char *msg;
+
+  if (! err)
+    return _("(no error)");
+
+  err = svn_error_purge_tracing(err);
+
+  /* hook_err1 is the SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED wrapped
+     error from the post-commit script, if any, and hook_err2 should
+     be the original error, but be defensive and handle a case where
+     SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED doesn't wrap an error. */
+  hook_err1 = svn_error_find_cause(err, SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED);
+  if (hook_err1 && hook_err1->child)
+    hook_err2 = hook_err1->child;
+  else
+    hook_err2 = hook_err1;
+
+  /* This implementation counts on svn_repos_fs_commit_txn() returning
+     svn_fs_commit_txn() as the parent error with a child
+     SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED error.  If the parent error
+     is SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED then there was no error
+     in svn_fs_commit_txn().
+
+     The post-commit hook error message is already self describing, so
+     it can be dropped into an error message without any additional
+     text. */
+  if (hook_err1)
+    {
+      if (err == hook_err1)
+        {
+          if (hook_err2->message)
+            msg = apr_pstrdup(pool, hook_err2->message);
+          else
+            msg = _("post-commit hook failed with no error message");
+        }
+      else
+        {
+          msg = hook_err2->message
+                  ? hook_err2->message
+                  : _("post-commit hook failed with no error message.");
+          msg = apr_psprintf(
+                  pool,
+                  _("post commit FS processing had error '%s' and %s"),
+                  err->message ? err->message : _("(no error message)"),
+                  msg);
+        }
+    }
+  else
+    {
+      msg = apr_psprintf(pool,
+                         _("post-commit FS processing had error '%s'."),
+                         hook_err2->message ? hook_err2->message
+                                            : _("(no error message)"));
+    }
 
+  return msg;
+}
 
 static svn_error_t *
 close_edit(void *edit_baton,
@@ -654,7 +716,7 @@ close_edit(void *edit_baton,
   svn_revnum_t new_revision = SVN_INVALID_REVNUM;
   svn_error_t *err;
   const char *conflict;
-  char *post_commit_err = NULL;
+  const char *post_commit_err = NULL;
 
   /* If no transaction has been created (ie. if open_root wasn't
      called before close_edit), abort the operation here with an
@@ -667,51 +729,40 @@ close_edit(void *edit_baton,
   err = svn_repos_fs_commit_txn(&conflict, eb->repos,
                                 &new_revision, eb->txn, pool);
 
-  if (err)
+  if (SVN_IS_VALID_REVNUM(new_revision))
     {
-      if (err->apr_err == SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED)
+      if (err)
         {
           /* If the error was in post-commit, then the commit itself
              succeeded.  In which case, save the post-commit warning
              (to be reported back to the client, who will probably
              display it as a warning) and clear the error. */
-          if (err->child && err->child->message)
-            {
-              svn_error_t *warning_err = err->child;
-#ifdef SVN_ERR__TRACING
-              /* Skip over any trace records.  */
-              while (warning_err->message != NULL
-                     && strcmp(warning_err->message, SVN_ERR__TRACED) == 0)
-                warning_err = warning_err->child;
-#endif
-              post_commit_err = apr_pstrdup(pool, warning_err->message);
-            }
-
+          post_commit_err = svn_repos__post_commit_error_str(err, pool);
           svn_error_clear(err);
           err = SVN_NO_ERROR;
         }
-      else  /* Got a real error -- one that stopped the commit */
-        {
-          /* ### todo: we should check whether it really was a conflict,
-             and return the conflict info if so? */
+    }
+  else
+    {
+      /* ### todo: we should check whether it really was a conflict,
+         and return the conflict info if so? */
 
-          /* If the commit failed, it's *probably* due to a conflict --
-             that is, the txn being out-of-date.  The filesystem gives us
-             the ability to continue diddling the transaction and try
-             again; but let's face it: that's not how the cvs or svn works
-             from a user interface standpoint.  Thus we don't make use of
-             this fs feature (for now, at least.)
-
-             So, in a nutshell: svn commits are an all-or-nothing deal.
-             Each commit creates a new fs txn which either succeeds or is
-             aborted completely.  No second chances;  the user simply
-             needs to update and commit again  :)
-
-             We ignore the possible error result from svn_fs_abort_txn();
-             it's more important to return the original error. */
-          svn_error_clear(svn_fs_abort_txn(eb->txn, pool));
-          return svn_error_return(err);
-        }
+      /* If the commit failed, it's *probably* due to a conflict --
+         that is, the txn being out-of-date.  The filesystem gives us
+         the ability to continue diddling the transaction and try
+         again; but let's face it: that's not how the cvs or svn works
+         from a user interface standpoint.  Thus we don't make use of
+         this fs feature (for now, at least.)
+
+         So, in a nutshell: svn commits are an all-or-nothing deal.
+         Each commit creates a new fs txn which either succeeds or is
+         aborted completely.  No second chances;  the user simply
+         needs to update and commit again  :)
+
+         We ignore the possible error result from svn_fs_abort_txn();
+         it's more important to return the original error. */
+      svn_error_clear(svn_fs_abort_txn(eb->txn, pool));
+      return svn_error_return(err);
     }
 
   /* Pass new revision information to the caller's callback. */
@@ -743,8 +794,8 @@ close_edit(void *edit_baton,
         commit_info->author = author ? author->data : NULL;
         commit_info->post_commit_err = post_commit_err;
         err = (*eb->commit_callback)(commit_info,
-                                      eb->commit_callback_baton,
-                                      pool);
+                                     eb->commit_callback_baton,
+                                     pool);
       }
   }
 

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/deprecated.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/deprecated.c Wed Dec 29 00:10:25 2010
@@ -718,7 +718,7 @@ svn_repos_load_fs2(svn_repos_t *repos,
                    apr_pool_t *pool)
 {
   return svn_repos_load_fs3(repos, dumpstream, uuid_action, parent_dir,
-                            use_pre_commit_hook, use_post_commit_hook,
+                            use_pre_commit_hook, use_post_commit_hook, FALSE,
                             feedback_stream ? repos_notify_handler : NULL,
                             feedback_stream, cancel_func, cancel_baton, pool);
 }
@@ -804,7 +804,7 @@ svn_repos_get_fs_build_parser2(const svn
                                apr_pool_t *pool)
 {
   return svn_repos_get_fs_build_parser3(parser, parse_baton, repos, use_history,
-                                        uuid_action, parent_dir,
+                                        FALSE, uuid_action, parent_dir,
                                         outstream ? repos_notify_handler : NULL,
                                         outstream, pool);
 }

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/fs-wrap.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/fs-wrap.c Wed Dec 29 00:10:25 2010
@@ -33,6 +33,7 @@
 #include "svn_time.h"
 #include "repos.h"
 #include "svn_private_config.h"
+#include "private/svn_repos_private.h"
 #include "private/svn_utf_private.h"
 
 
@@ -45,25 +46,29 @@ svn_repos_fs_commit_txn(const char **con
                         svn_fs_txn_t *txn,
                         apr_pool_t *pool)
 {
-  svn_error_t *err;
+  svn_error_t *err, *err2;
   const char *txn_name;
 
+  *new_rev = SVN_INVALID_REVNUM;
+
   /* Run pre-commit hooks. */
   SVN_ERR(svn_fs_txn_name(&txn_name, txn, pool));
   SVN_ERR(svn_repos__hooks_pre_commit(repos, txn_name, pool));
 
   /* Commit. */
-  SVN_ERR(svn_fs_commit_txn(conflict_p, new_rev, txn, pool));
+  err = svn_fs_commit_txn(conflict_p, new_rev, txn, pool);
+  if (! SVN_IS_VALID_REVNUM(*new_rev))
+    return err;
 
-  /* Run post-commit hooks.   Notice that we're wrapping the error
-     with a -specific- errorcode, so that our caller knows not to try
-     and abort the transaction. */
-  if ((err = svn_repos__hooks_post_commit(repos, *new_rev, pool)))
-    return svn_error_create
-      (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err,
-       _("Commit succeeded, but post-commit hook failed"));
+  /* Run post-commit hooks. */
+  if ((err2 = svn_repos__hooks_post_commit(repos, *new_rev, pool)))
+    {
+      err2 = svn_error_create
+               (SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED, err2,
+                _("Commit succeeded, but post-commit hook failed"));
+    }
 
-  return SVN_NO_ERROR;
+  return svn_error_compose_create(err, err2);
 }
 
 
@@ -152,15 +157,10 @@ svn_repos_fs_begin_txn_for_update(svn_fs
 
 /*** Property wrappers ***/
 
-/* Validate that property NAME is valid for use in a Subversion
-   repository; return SVN_ERR_REPOS_BAD_ARGS if it isn't.  For some "svn:"
-   properties, also validate the value, and return SVN_ERR_BAD_PROPERTY_VALUE
-   if it is not valid.
-
-   Use POOL for temporary allocations.
- */
-static svn_error_t *
-validate_prop(const char *name, const svn_string_t *value, apr_pool_t *pool)
+svn_error_t *
+svn_repos__validate_prop(const char *name,
+                         const svn_string_t *value,
+                         apr_pool_t *pool)
 {
   svn_prop_kind_t kind = svn_property_kind(NULL, name);
 
@@ -223,7 +223,7 @@ svn_repos_fs_change_node_prop(svn_fs_roo
                               apr_pool_t *pool)
 {
   /* Validate the property, then call the wrapped function. */
-  SVN_ERR(validate_prop(name, value, pool));
+  SVN_ERR(svn_repos__validate_prop(name, value, pool));
   return svn_fs_change_node_prop(root, path, name, value, pool);
 }
 
@@ -238,7 +238,7 @@ svn_repos_fs_change_txn_props(svn_fs_txn
   for (i = 0; i < txnprops->nelts; i++)
     {
       svn_prop_t *prop = &APR_ARRAY_IDX(txnprops, i, svn_prop_t);
-      SVN_ERR(validate_prop(prop->name, prop->value, pool));
+      SVN_ERR(svn_repos__validate_prop(prop->name, prop->value, pool));
     }
 
   return svn_fs_change_txn_props(txn, txnprops, pool);
@@ -286,7 +286,7 @@ svn_repos_fs_change_rev_prop4(svn_repos_
       const svn_string_t *old_value;
       char action;
 
-      SVN_ERR(validate_prop(name, new_value, pool));
+      SVN_ERR(svn_repos__validate_prop(name, new_value, pool));
 
       /* Fetch OLD_VALUE for svn_fs_change_rev_prop2(). */
       if (old_value_p)

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/hooks.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/hooks.c Wed Dec 29 00:10:25 2010
@@ -177,56 +177,14 @@ run_hook_cmd(svn_string_t **result,
              apr_file_t *stdin_handle,
              apr_pool_t *pool)
 {
-  apr_file_t *read_errhandle, *write_errhandle, *null_handle;
-  apr_file_t *read_outhandle, *write_outhandle;
+  apr_file_t *null_handle;
   apr_status_t apr_err;
   svn_error_t *err;
   apr_proc_t cmd_proc;
 
-  /* Create a pipe to access stderr of the child. */
-  apr_err = apr_file_pipe_create(&read_errhandle, &write_errhandle, pool);
-  if (apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Can't create pipe for hook '%s'"), cmd);
-
-  /* Pipes are inherited by default, but we don't want that, since
-     APR will duplicate the write end of the pipe for the child process.
-     Not closing the read end is harmless, but if the write end is inherited,
-     it will be inherited by grandchildren as well.  This causes problems
-     if a hook script puts long-running jobs in the background.  Even if
-     they redirect stderr to something else, the write end of our pipe will
-     still be open, causing us to block. */
-  apr_err = apr_file_inherit_unset(read_errhandle);
-  if (apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Can't make pipe read handle non-inherited for hook '%s'"),
-       cmd);
-
-  apr_err = apr_file_inherit_unset(write_errhandle);
-  if (apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Can't make pipe write handle non-inherited for hook '%s'"),
-       cmd);
-
   if (result)
     {
-      /* Create a pipe to access stdout of the child. */
-      apr_err = apr_file_pipe_create(&read_outhandle, &write_outhandle, pool);
-      if (apr_err)
-        return svn_error_wrap_apr
-          (apr_err, _("Can't create pipe for hook '%s'"), cmd);
-
-      apr_err = apr_file_inherit_unset(read_outhandle);
-      if (apr_err)
-        return svn_error_wrap_apr
-          (apr_err,
-           _("Can't make pipe read handle non-inherited for hook '%s'"), cmd);
-
-      apr_err = apr_file_inherit_unset(write_outhandle);
-      if (apr_err)
-        return svn_error_wrap_apr
-          (apr_err,
-           _("Can't make pipe write handle non-inherited for hook '%s'"), cmd);
+      null_handle = NULL;
     }
   else
     {
@@ -238,26 +196,9 @@ run_hook_cmd(svn_string_t **result,
             (apr_err, _("Can't create null stdout for hook '%s'"), cmd);
     }
 
-  err = svn_io_start_cmd(&cmd_proc, ".", cmd, args, FALSE,
-                         stdin_handle, result ? write_outhandle : null_handle,
-                         write_errhandle, pool);
-
-  /* This seems to be done automatically if we pass the third parameter of
-     apr_procattr_child_in/out_set(), but svn_io_run_cmd()'s interface does
-     not support those parameters. We need to close the write end of the
-     pipe so we don't hang on the read end later, if we need to read it. */
-  apr_err = apr_file_close(write_errhandle);
-  if (!err && apr_err)
-    return svn_error_wrap_apr
-      (apr_err, _("Error closing write end of stderr pipe"));
-
-  if (result)
-    {
-      apr_err = apr_file_close(write_outhandle);
-      if (!err && apr_err)
-        return svn_error_wrap_apr
-          (apr_err, _("Error closing write end of stderr pipe"));
-    }
+  err = svn_io_start_cmd2(&cmd_proc, ".", cmd, args, FALSE,
+                          FALSE, stdin_handle, result != NULL, null_handle,
+                          TRUE, NULL, pool);
 
   if (err)
     {
@@ -266,13 +207,13 @@ run_hook_cmd(svn_string_t **result,
     }
   else
     {
-      err = check_hook_result(name, cmd, &cmd_proc, read_errhandle, pool);
+      err = check_hook_result(name, cmd, &cmd_proc, cmd_proc.err, pool);
     }
 
   /* Hooks are fallible, and so hook failure is "expected" to occur at
      times.  When such a failure happens we still want to close the pipe
      and null file */
-  apr_err = apr_file_close(read_errhandle);
+  apr_err = apr_file_close(cmd_proc.err);
   if (!err && apr_err)
     return svn_error_wrap_apr
       (apr_err, _("Error closing read end of stderr pipe"));
@@ -280,8 +221,8 @@ run_hook_cmd(svn_string_t **result,
   if (result)
     {
       svn_stringbuf_t *native_stdout;
-      SVN_ERR(svn_stringbuf_from_aprfile(&native_stdout, read_outhandle, pool));
-      apr_err = apr_file_close(read_outhandle);
+      SVN_ERR(svn_stringbuf_from_aprfile(&native_stdout, cmd_proc.out, pool));
+      apr_err = apr_file_close(cmd_proc.out);
       if (!err && apr_err)
         return svn_error_wrap_apr
           (apr_err, _("Error closing read end of stderr pipe"));

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/load-fs-vtable.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_repos/load-fs-vtable.c Wed Dec 29 00:10:25 2010
@@ -52,6 +52,7 @@ struct parse_baton
   svn_fs_t *fs;
 
   svn_boolean_t use_history;
+  svn_boolean_t validate_props;
   svn_boolean_t use_pre_commit_hook;
   svn_boolean_t use_post_commit_hook;
   enum svn_repos_load_uuid uuid_action;
@@ -111,6 +112,44 @@ struct node_baton
 
 /*----------------------------------------------------------------------*/
 
+
+/* Change revision property NAME to VALUE for REVISION in REPOS.  If
+   VALIDATE_PROPS is set, use functions which perform validation of
+   the property value.  Otherwise, bypass those checks. */
+static svn_error_t *
+change_rev_prop(svn_repos_t *repos,
+                svn_revnum_t revision,
+                const char *name,
+                const svn_string_t *value,
+                svn_boolean_t validate_props,
+                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);
+}
+
+/* Change property NAME to VALUE for PATH in TXN_ROOT.  If
+   VALIDATE_PROPS is set, use functions which perform validation of
+   the property value.  Otherwise, bypass those checks. */
+static svn_error_t *
+change_node_prop(svn_fs_root_t *txn_root,
+                 const char *path,
+                 const char *name,
+                 const svn_string_t *value,
+                 svn_boolean_t validate_props,
+                 apr_pool_t *pool)
+{
+  if (validate_props)
+    return svn_repos_fs_change_node_prop(txn_root, path, name, value, pool);
+  else
+    return svn_fs_change_node_prop(txn_root, path, name, value, pool);
+}
+
 /* Prepend the mergeinfo source paths in MERGEINFO_ORIG with PARENT_DIR, and
    return it in *MERGEINFO_VAL. */
 static svn_error_t *
@@ -582,8 +621,7 @@ new_node_record(void **node_baton,
   *node_baton = nb;
   return SVN_NO_ERROR;
 }
-
-
+               
 static svn_error_t *
 set_revision_property(void *baton,
                       const char *name,
@@ -593,7 +631,10 @@ set_revision_property(void *baton,
 
   if (rb->rev > 0)
     {
-      SVN_ERR(svn_fs_change_txn_prop(rb->txn, name, value, rb->pool));
+      if (rb->pb->validate_props)
+        SVN_ERR(svn_repos_fs_change_txn_prop(rb->txn, name, value, rb->pool));
+      else
+        SVN_ERR(svn_fs_change_txn_prop(rb->txn, name, value, rb->pool));
 
       /* Remember any datestamp that passes through!  (See comment in
          close_revision() below.) */
@@ -610,8 +651,8 @@ set_revision_property(void *baton,
       SVN_ERR(svn_fs_youngest_rev(&youngest_rev, pb->fs, rb->pool));
 
       if (youngest_rev == 0)
-        SVN_ERR(svn_fs_change_rev_prop2(pb->fs, 0, name, NULL, value,
-                                        rb->pool));
+        SVN_ERR(change_rev_prop(pb->repos, 0, name, value,
+                                pb->validate_props, rb->pool));
     }
 
   return SVN_NO_ERROR;
@@ -676,8 +717,8 @@ set_node_property(void *baton,
         }
     }
 
-  return svn_fs_change_node_prop(rb->txn_root, nb->path,
-                                 name, value, nb->pool);
+  return change_node_prop(rb->txn_root, nb->path, name, value,
+                          pb->validate_props, nb->pool);
 }
 
 
@@ -688,8 +729,8 @@ delete_node_property(void *baton,
   struct node_baton *nb = baton;
   struct revision_baton *rb = nb->rb;
 
-  return svn_fs_change_node_prop(rb->txn_root, nb->path,
-                                 name, NULL, nb->pool);
+  return change_node_prop(rb->txn_root, nb->path, name, NULL,
+                          rb->pb->validate_props, nb->pool);
 }
 
 
@@ -709,10 +750,8 @@ remove_node_props(void *baton)
       const void *key;
 
       apr_hash_this(hi, &key, NULL, NULL);
-
-      SVN_ERR(svn_fs_change_node_prop(rb->txn_root, nb->path,
-                                      (const char *) key, NULL,
-                                      nb->pool));
+      SVN_ERR(change_node_prop(rb->txn_root, nb->path, key, NULL,
+                               rb->pb->validate_props, nb->pool));
     }
 
   return SVN_NO_ERROR;
@@ -801,7 +840,18 @@ close_revision(void *baton)
     }
 
   /* Commit. */
-  if ((err = svn_fs_commit_txn(&conflict_msg, new_rev, rb->txn, rb->pool)))
+  err = svn_fs_commit_txn(&conflict_msg, new_rev, rb->txn, rb->pool);
+  if (SVN_IS_VALID_REVNUM(*new_rev))
+    {
+      if (err)
+        {
+          /* ### Log any error, but better yet is to rev
+             ### close_revision()'s API to allow both new_rev and err
+             ### to be returned, see #3768. */
+          svn_error_clear(err);
+        }
+    }
+  else
     {
       svn_error_clear(svn_fs_abort_txn(rb->txn, rb->pool));
       if (conflict_msg)
@@ -858,9 +908,8 @@ close_revision(void *baton)
      Note that if rb->datestamp is NULL, that's fine -- if the dump
      data doesn't carry a datestamp, we want to preserve that fact in
      the load. */
-  SVN_ERR(svn_fs_change_rev_prop(pb->fs, *new_rev,
-                                 SVN_PROP_REVISION_DATE, rb->datestamp,
-                                 rb->pool));
+  SVN_ERR(change_rev_prop(pb->repos, *new_rev, SVN_PROP_REVISION_DATE,
+                          rb->datestamp, pb->validate_props, rb->pool));
 
   if (pb->notify_func)
     {
@@ -886,6 +935,7 @@ svn_repos_get_fs_build_parser3(const svn
                                void **parse_baton,
                                svn_repos_t *repos,
                                svn_boolean_t use_history,
+                               svn_boolean_t validate_props,
                                enum svn_repos_load_uuid uuid_action,
                                const char *parent_dir,
                                svn_repos_notify_func_t notify_func,
@@ -910,6 +960,7 @@ svn_repos_get_fs_build_parser3(const svn
   pb->repos = repos;
   pb->fs = svn_repos_fs(repos);
   pb->use_history = use_history;
+  pb->validate_props = validate_props;
   pb->notify_func = notify_func;
   pb->notify_baton = notify_baton;
   pb->notify = svn_repos_notify_create(svn_repos_notify_load_txn_start, pool);
@@ -934,6 +985,7 @@ svn_repos_load_fs3(svn_repos_t *repos,
                    const char *parent_dir,
                    svn_boolean_t use_pre_commit_hook,
                    svn_boolean_t use_post_commit_hook,
+                   svn_boolean_t validate_props,
                    svn_repos_notify_func_t notify_func,
                    void *notify_baton,
                    svn_cancel_func_t cancel_func,
@@ -949,6 +1001,7 @@ svn_repos_load_fs3(svn_repos_t *repos,
   SVN_ERR(svn_repos_get_fs_build_parser3(&parser, &parse_baton,
                                          repos,
                                          TRUE, /* look for copyfrom revs */
+                                         validate_props,
                                          uuid_action,
                                          parent_dir,
                                          notify_func,

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/deprecated.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/deprecated.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/deprecated.c Wed Dec 29 00:10:25 2010
@@ -250,6 +250,16 @@ svn_subst_stream_translated_to_normal_fo
 }
 
 svn_error_t *
+svn_subst_translate_string(svn_string_t **new_value,
+                           const svn_string_t *value,
+                           const char *encoding,
+                           apr_pool_t *pool)
+{
+  return svn_subst_translate_string2(new_value, NULL, NULL, value,
+                                     encoding, pool, pool);
+}
+
+svn_error_t *
 svn_subst_stream_detranslated(svn_stream_t **stream_p,
                               const char *src,
                               svn_subst_eol_style_t eol_style,
@@ -754,6 +764,22 @@ svn_io_get_dirents(apr_hash_t **dirents,
   return svn_io_get_dirents2(dirents, path, pool);
 }
 
+svn_error_t *
+svn_io_start_cmd(apr_proc_t *cmd_proc,
+                 const char *path,
+                 const char *cmd,
+                 const char *const *args,
+                 svn_boolean_t inherit,
+                 apr_file_t *infile,
+                 apr_file_t *outfile,
+                 apr_file_t *errfile,
+                 apr_pool_t *pool)
+{
+  return svn_io_start_cmd2(cmd_proc, path, cmd, args, inherit, FALSE,
+                           infile, FALSE, outfile, FALSE, errfile, pool);
+}
+
+
 struct walk_func_filter_baton_t
 {
   svn_io_walk_func_t walk_func;

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/dirent_uri.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/dirent_uri.c Wed Dec 29 00:10:25 2010
@@ -2144,6 +2144,7 @@ svn_uri_condense_targets(const char **pc
   /* Early exit when there's only one uri to work on. */
   if (targets->nelts == 1)
     {
+      *pcommon = apr_pstrdup(result_pool, *pcommon);
       if (pcondensed_targets)
         *pcondensed_targets = apr_array_make(result_pool, 0,
                                              sizeof(const char *));

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/error.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/error.c Wed Dec 29 00:10:25 2010
@@ -34,34 +34,46 @@
 #include "svn_utf.h"
 
 #ifdef SVN_DEBUG
+/* XXX FIXME: These should be protected by a thread mutex.
+   svn_error__locate and make_error_internal should cooperate
+   in locking and unlocking it. */
+
+/* XXX TODO: Define mutex here #if APR_HAS_THREADS */
+static const char * volatile error_file = NULL;
+static long volatile error_line = -1;
+
 /* file_line for the non-debug case. */
 static const char SVN_FILE_LINE_UNDEFINED[] = "svn:<undefined>";
 #endif /* SVN_DEBUG */
 
 #include "svn_private_config.h"
+#include "private/svn_error_private.h"
 
 
-/*** Helpers for creating errors ***/
+/*
+ * Undefine the helpers for creating errors.
+ *
+ * *NOTE*: Any use of these functions in any other function may need
+ * to call svn_error__locate() because the macro that would otherwise
+ * do this is being undefined and the filename and line number will
+ * not be properly set in the static error_file and error_line
+ * variables.
+ */
 #undef svn_error_create
 #undef svn_error_createf
 #undef svn_error_quick_wrap
 #undef svn_error_wrap_apr
 
-
-/* XXX FIXME: These should be protected by a thread mutex.
-   svn_error__locate and make_error_internal should cooperate
-   in locking and unlocking it. */
-
-/* XXX TODO: Define mutex here #if APR_HAS_THREADS */
-static const char * volatile error_file = NULL;
-static long volatile error_line = -1;
-
+/* Note: This function was historically in the public API, so we need
+ * to define it even when !SVN_DEBUG. */
 void
 svn_error__locate(const char *file, long line)
 {
+#if defined(SVN_DEBUG)
   /* XXX TODO: Lock mutex here */
   error_file = file;
   error_line = line;
+#endif
 }
 
 
@@ -103,11 +115,11 @@ make_error_internal(apr_status_t apr_err
   new_error->apr_err = apr_err;
   new_error->child   = child;
   new_error->pool    = pool;
+#if defined(SVN_DEBUG)
   new_error->file    = error_file;
   new_error->line    = error_line;
   /* XXX TODO: Unlock mutex here */
 
-#if defined(SVN_DEBUG)
   if (! child)
       apr_pool_cleanup_register(pool, new_error,
                                 err_abort,
@@ -269,16 +281,16 @@ svn_error_root_cause(svn_error_t *err)
   return err;
 }
 
-svn_boolean_t
-svn_error_has_cause(svn_error_t *err, apr_status_t apr_err)
+svn_error_t *
+svn_error_find_cause(svn_error_t *err, apr_status_t apr_err)
 {
   svn_error_t *child;
 
   for (child = err; child; child = child->child)
     if (child->apr_err == apr_err)
-      return TRUE;
+      return child;
 
-  return FALSE;
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -331,8 +343,8 @@ svn_error_clear(svn_error_t *err)
     }
 }
 
-/* Is ERR a tracing-only error chain link?  */
-static svn_boolean_t is_tracing_link(svn_error_t *err)
+svn_boolean_t
+svn_error__is_tracing_link(svn_error_t *err)
 {
 #ifdef SVN_ERR__TRACING
   /* ### A strcmp()?  Really?  I think it's the best we can do unless
@@ -349,39 +361,46 @@ svn_error_t *
 svn_error_purge_tracing(svn_error_t *err)
 {
 #ifdef SVN_ERR__TRACING
-  svn_error_t *tmp_err = err;
   svn_error_t *new_err = NULL, *new_err_leaf = NULL;
 
   if (! err)
     return SVN_NO_ERROR;
 
-  while (tmp_err)
+  do
     {
+      svn_error_t *tmp_err;
+
       /* Skip over any trace-only links. */
-      while (tmp_err && is_tracing_link(tmp_err))
-        tmp_err = tmp_err->child;
+      while (err && svn_error__is_tracing_link(err))
+        err = err->child;
+
+      /* The link must be a real link in the error chain, otherwise an
+         error chain with trace only links would map into SVN_NO_ERROR. */
+      SVN_ERR_ASSERT(err);
+
+      /* Copy the current error except for its child error pointer
+         into the new error.  Share any message and source filename
+         strings from the error. */
+      tmp_err = apr_palloc(err->pool, sizeof(*tmp_err));
+      *tmp_err = *err;
+      tmp_err->child = NULL;
 
       /* Add a new link to the new chain (creating the chain if necessary). */
       if (! new_err)
         {
           new_err = tmp_err;
-          new_err_leaf = new_err;
+          new_err_leaf = tmp_err;
         }
       else
         {
           new_err_leaf->child = tmp_err;
-          new_err_leaf = new_err_leaf->child;
+          new_err_leaf = tmp_err;
         }
 
       /* Advance to the next link in the original chain. */
-      tmp_err = tmp_err->child;
-    }
+      err = err->child;
+    } while (err);
 
-  /* If we get here, there had better be a real link in this error chain. */
-  SVN_ERR_ASSERT(new_err_leaf);
-
-  /* Tie off the chain, and return its head. */
-  new_err_leaf->child = NULL;
   return new_err;
 #else  /* SVN_ERR__TRACING */
   return err;
@@ -420,7 +439,7 @@ print_error(svn_error_t *err, FILE *stre
 #endif /* SVN_DEBUG */
 
   /* "traced call" */
-  if (is_tracing_link(err))
+  if (svn_error__is_tracing_link(err))
     {
       /* Skip it.  We already printed the file-line coordinates. */
     }
@@ -550,7 +569,7 @@ const char *
 svn_err_best_message(svn_error_t *err, char *buf, apr_size_t bufsize)
 {
   /* Skip over any trace records.  */
-  while (is_tracing_link(err))
+  while (svn_error__is_tracing_link(err))
     err = err->child;
   if (err->message)
     return err->message;
@@ -593,6 +612,11 @@ svn_error_raise_on_malfunction(svn_boole
   if (!can_return)
     abort(); /* Nothing else we can do as a library */
 
+  /* The filename and line number of the error source needs to be set
+     here because svn_error_createf() is not the macro defined in
+     svn_error.h but the real function. */
+  svn_error__locate(file, line);
+
   if (expr)
     return svn_error_createf(SVN_ERR_ASSERTION_FAIL, NULL,
                              _("In file '%s' line %d: assertion failed (%s)"),

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/io.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/io.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/io.c Wed Dec 29 00:10:25 2010
@@ -756,7 +756,7 @@ svn_io_copy_file(const char *src,
 #endif
 
   SVN_ERR(svn_io_file_open(&from_file, src, APR_READ | APR_BINARY,
-                         APR_OS_DEFAULT, pool));
+                           APR_OS_DEFAULT, pool));
 
   /* For atomicity, we copy to a tmp file and then rename the tmp
      file over the real destination. */
@@ -2188,15 +2188,18 @@ handle_child_process_error(apr_pool_t *p
 
 
 svn_error_t *
-svn_io_start_cmd(apr_proc_t *cmd_proc,
-                 const char *path,
-                 const char *cmd,
-                 const char *const *args,
-                 svn_boolean_t inherit,
-                 apr_file_t *infile,
-                 apr_file_t *outfile,
-                 apr_file_t *errfile,
-                 apr_pool_t *pool)
+svn_io_start_cmd2(apr_proc_t *cmd_proc,
+                  const char *path,
+                  const char *cmd,
+                  const char *const *args,
+                  svn_boolean_t inherit,
+                  svn_boolean_t infile_pipe,
+                  apr_file_t *infile,
+                  svn_boolean_t outfile_pipe,
+                  apr_file_t *outfile,
+                  svn_boolean_t errfile_pipe,
+                  apr_file_t *errfile,
+                  apr_pool_t *pool)
 {
   apr_status_t apr_err;
   apr_procattr_t *cmdproc_attr;
@@ -2204,6 +2207,10 @@ svn_io_start_cmd(apr_proc_t *cmd_proc,
   const char **args_native;
   const char *cmd_apr;
 
+  SVN_ERR_ASSERT(!((infile != NULL) && infile_pipe));
+  SVN_ERR_ASSERT(!((outfile != NULL) && outfile_pipe));
+  SVN_ERR_ASSERT(!((errfile != NULL) && errfile_pipe));
+
   /* Create the process attributes. */
   apr_err = apr_procattr_create(&cmdproc_attr, pool);
   if (apr_err)
@@ -2212,7 +2219,7 @@ svn_io_start_cmd(apr_proc_t *cmd_proc,
 
   /* Make sure we invoke cmd directly, not through a shell. */
   apr_err = apr_procattr_cmdtype_set(cmdproc_attr,
-                                     inherit?APR_PROGRAM_PATH:APR_PROGRAM);
+                                     inherit ? APR_PROGRAM_PATH : APR_PROGRAM);
   if (apr_err)
     return svn_error_wrap_apr(apr_err, _("Can't set process '%s' cmdtype"),
                               cmd);
@@ -2256,6 +2263,13 @@ svn_io_start_cmd(apr_proc_t *cmd_proc,
           (apr_err, _("Can't set process '%s' child errfile"), cmd);
     }
 
+  /* Forward request for pipes to APR. */
+  if (infile_pipe || outfile_pipe || errfile_pipe)
+    apr_procattr_io_set(cmdproc_attr,
+                        infile_pipe ? APR_FULL_BLOCK : APR_NO_PIPE,
+                        outfile_pipe ? APR_FULL_BLOCK : APR_NO_PIPE,
+                        errfile_pipe ? APR_FULL_BLOCK : APR_NO_PIPE);
+
   /* Have the child print any problems executing its program to errfile. */
   apr_err = apr_pool_userdata_set(errfile, ERRFILE_KEY, NULL, pool);
   if (apr_err)
@@ -2347,8 +2361,9 @@ svn_io_run_cmd(const char *path,
 {
   apr_proc_t cmd_proc;
 
-  SVN_ERR(svn_io_start_cmd(&cmd_proc, path, cmd, args, inherit,
-                           infile, outfile, errfile, pool));
+  SVN_ERR(svn_io_start_cmd2(&cmd_proc, path, cmd, args, inherit,
+                            FALSE, infile, FALSE, outfile, FALSE, errfile,
+                            pool));
 
   return svn_io_wait_for_cmd(&cmd_proc, cmd, exitcode, exitwhy, pool);
 }

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/prompt.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/prompt.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/prompt.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/prompt.c Wed Dec 29 00:10:25 2010
@@ -418,12 +418,14 @@ plaintext_prompt_helper(svn_boolean_t *m
           else
             return err;
         }
-      if (apr_strnatcasecmp(answer, _("yes")) == 0)
+      if (apr_strnatcasecmp(answer, _("yes")) == 0 ||
+          apr_strnatcasecmp(answer, _("y")) == 0)
         {
           *may_save_plaintext = TRUE;
           answered = TRUE;
         }
-      else if (apr_strnatcasecmp(answer, _("no")) == 0)
+      else if (apr_strnatcasecmp(answer, _("no")) == 0 ||
+               apr_strnatcasecmp(answer, _("n")) == 0)
         {
           *may_save_plaintext = FALSE;
           answered = TRUE;

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/subst.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/subst.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/subst.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_subr/subst.c Wed Dec 29 00:10:25 2010
@@ -606,11 +606,34 @@ translate_keyword(char *buf,
   return FALSE;
 }
 
+/* A boolean expression that evaluates to true if the first STR_LEN characters
+   of the string STR are one of the end-of-line strings LF, CR, or CRLF;
+   to false otherwise.  */
+#define STRING_IS_EOL(str, str_len) \
+  (((str_len) == 2 &&  (str)[0] == '\r' && (str)[1] == '\n') || \
+   ((str_len) == 1 && ((str)[0] == '\n' || (str)[0] == '\r')))
+
+/* A boolean expression that evaluates to true if the end-of-line string EOL1,
+   having length EOL1_LEN, and the end-of-line string EOL2, having length
+   EOL2_LEN, are different, assuming that EOL1 and EOL2 are both from the
+   set {"\n", "\r", "\r\n"};  to false otherwise.
+
+   Given that EOL1 and EOL2 are either "\n", "\r", or "\r\n", then if
+   EOL1_LEN is not the same as EOL2_LEN, then EOL1 and EOL2 are of course
+   different. If EOL1_LEN and EOL2_LEN are both 2 then EOL1 and EOL2 are both
+   "\r\n" and *EOL1 == *EOL2. Otherwise, EOL1_LEN and EOL2_LEN are both 1.
+   We need only check the one character for equality to determine whether
+   EOL1 and EOL2 are different in that case. */
+#define DIFFERENT_EOL_STRINGS(eol1, eol1_len, eol2, eol2_len) \
+  (((eol1_len) != (eol2_len)) || (*(eol1) != *(eol2)))
+
 
 /* Translate the newline string NEWLINE_BUF (of length NEWLINE_LEN) to
    the newline string EOL_STR (of length EOL_STR_LEN), writing the
    result (which is always EOL_STR) to the stream DST.
 
+   This function assumes that NEWLINE_BUF is either "\n", "\r", or "\r\n".
+
    Also check for consistency of the source newline strings across
    multiple calls, using SRC_FORMAT (length *SRC_FORMAT_LEN) as a cache
    of the first newline found.  If the current newline is not the same
@@ -620,6 +643,11 @@ translate_keyword(char *buf,
    newline in the file, and copy it to {SRC_FORMAT, *SRC_FORMAT_LEN} to
    use for later consistency checks.
 
+   If TRANSLATED_EOL is not NULL, then set *TRANSLATED_EOL to TRUE if the
+   newline string that was written (EOL_STR) is not the same as the newline
+   string that was translated (NEWLINE_BUF), otherwise leave *TRANSLATED_EOL
+   untouched.
+
    Note: all parameters are required even if REPAIR is TRUE.
    ### We could require that REPAIR must not change across a sequence of
        calls, and could then optimize by not using SRC_FORMAT at all if
@@ -633,17 +661,19 @@ translate_newline(const char *eol_str,
                   const char *newline_buf,
                   apr_size_t newline_len,
                   svn_stream_t *dst,
+                  svn_boolean_t *translated_eol,
                   svn_boolean_t repair)
 {
+  SVN_ERR_ASSERT(STRING_IS_EOL(newline_buf, newline_len));
+
   /* If we've seen a newline before, compare it with our cache to
      check for consistency, else cache it for future comparisons. */
   if (*src_format_len)
     {
       /* Comparing with cache.  If we are inconsistent and
          we are NOT repairing the file, generate an error! */
-      if ((! repair) &&
-          ((*src_format_len != newline_len) ||
-           (strncmp(src_format, newline_buf, newline_len))))
+      if ((! repair) && DIFFERENT_EOL_STRINGS(src_format, *src_format_len,
+                                              newline_buf, newline_len))
         return svn_error_create(SVN_ERR_IO_INCONSISTENT_EOL, NULL, NULL);
     }
   else
@@ -653,8 +683,18 @@ translate_newline(const char *eol_str,
       strncpy(src_format, newline_buf, newline_len);
       *src_format_len = newline_len;
     }
+
   /* Write the desired newline */
-  return translate_write(dst, eol_str, eol_str_len);
+  SVN_ERR(translate_write(dst, eol_str, eol_str_len));
+
+  /* Report whether we translated it.  Note: Not using DIFFERENT_EOL_STRINGS()
+   * because EOL_STR may not be a valid EOL sequence. */
+  if (translated_eol != NULL &&
+      (eol_str_len != newline_len ||
+       memcmp(eol_str, newline_buf, eol_str_len) != 0))
+    *translated_eol = TRUE;
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -765,10 +805,12 @@ svn_subst_keywords_differ2(apr_hash_t *a
   return FALSE;
 }
 
+
 /* Baton for translate_chunk() to store its state in. */
 struct translation_baton
 {
   const char *eol_str;
+  svn_boolean_t *translated_eol;
   svn_boolean_t repair;
   apr_hash_t *keywords;
   svn_boolean_t expand;
@@ -813,6 +855,7 @@ struct translation_baton
  */
 static struct translation_baton *
 create_translation_baton(const char *eol_str,
+                         svn_boolean_t *translated_eol,
                          svn_boolean_t repair,
                          apr_hash_t *keywords,
                          svn_boolean_t expand,
@@ -826,6 +869,7 @@ create_translation_baton(const char *eol
 
   b->eol_str = eol_str;
   b->eol_str_len = eol_str ? strlen(eol_str) : 0;
+  b->translated_eol = translated_eol;
   b->repair = repair;
   b->keywords = keywords;
   b->expand = expand;
@@ -888,6 +932,9 @@ eol_unchanged(struct translation_baton *
  * To finish a series of chunk translations, flush all buffers by calling
  * this routine with a NULL value for BUF.
  *
+ * If B->translated_eol is not NULL, then set *B->translated_eol to TRUE if
+ * an end-of-line sequence was changed, otherwise leave it untouched.
+ *
  * Use POOL for temporary allocations.
  */
 static svn_error_t *
@@ -924,7 +971,8 @@ translate_chunk(svn_stream_t *dst,
               SVN_ERR(translate_newline(b->eol_str, b->eol_str_len,
                                         b->src_format,
                                         &b->src_format_len, b->newline_buf,
-                                        b->newline_off, dst, b->repair));
+                                        b->newline_off, dst, b->translated_eol,
+                                        b->repair));
 
               b->newline_off = 0;
             }
@@ -1070,7 +1118,8 @@ translate_chunk(svn_stream_t *dst,
                                             b->src_format,
                                             &b->src_format_len,
                                             b->newline_buf,
-                                            b->newline_off, dst, b->repair));
+                                            b->newline_off, dst,
+                                            b->translated_eol, b->repair));
 
                   b->newline_off = 0;
                   break;
@@ -1086,7 +1135,7 @@ translate_chunk(svn_stream_t *dst,
           SVN_ERR(translate_newline(b->eol_str, b->eol_str_len,
                                     b->src_format, &b->src_format_len,
                                     b->newline_buf, b->newline_off,
-                                    dst, b->repair));
+                                    dst, b->translated_eol, b->repair));
           b->newline_off = 0;
         }
 
@@ -1349,14 +1398,20 @@ svn_subst_read_specialfile(svn_stream_t 
   return SVN_NO_ERROR;
 }
 
-
-svn_stream_t *
-svn_subst_stream_translated(svn_stream_t *stream,
-                            const char *eol_str,
-                            svn_boolean_t repair,
-                            apr_hash_t *keywords,
-                            svn_boolean_t expand,
-                            apr_pool_t *result_pool)
+/* Same as svn_subst_stream_translated(), except for the following.
+ *
+ * If TRANSLATED_EOL is not NULL, then reading and/or writing to the stream
+ * will set *TRANSLATED_EOL to TRUE if an end-of-line sequence was changed,
+ * otherwise leave it untouched.
+ */
+static svn_stream_t *
+stream_translated(svn_stream_t *stream,
+                  const char *eol_str,
+                  svn_boolean_t *translated_eol,
+                  svn_boolean_t repair,
+                  apr_hash_t *keywords,
+                  svn_boolean_t expand,
+                  apr_pool_t *result_pool)
 {
   struct translated_stream_baton *baton
     = apr_palloc(result_pool, sizeof(*baton));
@@ -1398,9 +1453,11 @@ svn_subst_stream_translated(svn_stream_t
   /* Setup the baton fields */
   baton->stream = stream;
   baton->in_baton
-    = create_translation_baton(eol_str, repair, keywords, expand, result_pool);
+    = create_translation_baton(eol_str, translated_eol, repair, keywords,
+                               expand, result_pool);
   baton->out_baton
-    = create_translation_baton(eol_str, repair, keywords, expand, result_pool);
+    = create_translation_baton(eol_str, translated_eol, repair, keywords,
+                               expand, result_pool);
   baton->written = FALSE;
   baton->readbuf = svn_stringbuf_create("", result_pool);
   baton->readbuf_off = 0;
@@ -1417,15 +1474,32 @@ svn_subst_stream_translated(svn_stream_t
   return s;
 }
 
+svn_stream_t *
+svn_subst_stream_translated(svn_stream_t *stream,
+                            const char *eol_str,
+                            svn_boolean_t repair,
+                            apr_hash_t *keywords,
+                            svn_boolean_t expand,
+                            apr_pool_t *result_pool)
+{
+  return stream_translated(stream, eol_str, NULL, repair, keywords, expand,
+                           result_pool);
+}
 
-svn_error_t *
-svn_subst_translate_cstring2(const char *src,
-                             const char **dst,
-                             const char *eol_str,
-                             svn_boolean_t repair,
-                             apr_hash_t *keywords,
-                             svn_boolean_t expand,
-                             apr_pool_t *pool)
+/* Same as svn_subst_translate_cstring2(), except for the following.
+ *
+ * If TRANSLATED_EOL is not NULL, then set *TRANSLATED_EOL to TRUE if an
+ * end-of-line sequence was changed, or to FALSE otherwise.
+ */
+static svn_error_t *
+translate_cstring(const char **dst,
+                  svn_boolean_t *translated_eol,
+                  const char *src,
+                  const char *eol_str,
+                  svn_boolean_t repair,
+                  apr_hash_t *keywords,
+                  svn_boolean_t expand,
+                  apr_pool_t *pool)
 {
   svn_stringbuf_t *dst_stringbuf;
   svn_stream_t *dst_stream;
@@ -1442,9 +1516,12 @@ svn_subst_translate_cstring2(const char 
   dst_stringbuf = svn_stringbuf_create("", pool);
   dst_stream = svn_stream_from_stringbuf(dst_stringbuf, pool);
 
+  if (translated_eol)
+    *translated_eol = FALSE;
+
   /* Another wrapper to translate the content. */
-  dst_stream = svn_subst_stream_translated(dst_stream, eol_str, repair,
-                                           keywords, expand, pool);
+  dst_stream = stream_translated(dst_stream, eol_str, translated_eol, repair,
+                                 keywords, expand, pool);
 
   /* Jam the text into the destination stream (to translate it). */
   SVN_ERR(svn_stream_write(dst_stream, src, &len));
@@ -1456,6 +1533,19 @@ svn_subst_translate_cstring2(const char 
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_subst_translate_cstring2(const char *src,
+                             const char **dst,
+                             const char *eol_str,
+                             svn_boolean_t repair,
+                             apr_hash_t *keywords,
+                             svn_boolean_t expand,
+                             apr_pool_t *pool)
+{
+  return translate_cstring(dst, NULL, src, eol_str, repair, keywords, expand,
+                            pool);
+}
+
 /* Given a special file at SRC, generate a textual representation of
    it in a normal file at DST.  Perform all allocations in POOL. */
 /* ### this should be folded into svn_subst_copy_and_translate3 */
@@ -1768,14 +1858,16 @@ svn_subst_stream_from_specialfile(svn_st
 
 /*** String translation */
 svn_error_t *
-svn_subst_translate_string(svn_string_t **new_value,
-                           const svn_string_t *value,
-                           const char *encoding,
-                           apr_pool_t *pool)
+svn_subst_translate_string2(svn_string_t **new_value,
+                            svn_boolean_t *translated_to_utf8,
+                            svn_boolean_t *translated_line_endings,
+                            const svn_string_t *value,
+                            const char *encoding,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
 {
   const char *val_utf8;
   const char *val_utf8_lf;
-  apr_pool_t *scratch_pool = svn_pool_create(pool);
 
   if (value == NULL)
     {
@@ -1793,16 +1885,19 @@ svn_subst_translate_string(svn_string_t 
       SVN_ERR(svn_utf_cstring_to_utf8(&val_utf8, value->data, scratch_pool));
     }
 
-  SVN_ERR(svn_subst_translate_cstring2(val_utf8,
-                                       &val_utf8_lf,
-                                       "\n",  /* translate to LF */
-                                       FALSE, /* no repair */
-                                       NULL,  /* no keywords */
-                                       FALSE, /* no expansion */
-                                       scratch_pool));
+  if (translated_to_utf8)
+    *translated_to_utf8 = (strcmp(value->data, val_utf8) != 0);
+
+  SVN_ERR(translate_cstring(&val_utf8_lf,
+                            translated_line_endings,
+                            val_utf8,
+                            "\n",  /* translate to LF */
+                            FALSE, /* no repair */
+                            NULL,  /* no keywords */
+                            FALSE, /* no expansion */
+                            scratch_pool));
 
-  *new_value = svn_string_create(val_utf8_lf, pool);
-  svn_pool_destroy(scratch_pool);
+  *new_value = svn_string_create(val_utf8_lf, result_pool);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.c Wed Dec 29 00:10:25 2010
@@ -1578,6 +1578,7 @@ write_entry(struct write_baton **entry_n
             apr_int64_t wc_id,
             apr_int64_t repos_id,
             const svn_wc_entry_t *entry,
+            const svn_wc__text_base_info_t *text_base_info,
             const char *local_relpath,
             const char *entry_abspath,
             const svn_wc_entry_t *this_dir,
@@ -1748,12 +1749,8 @@ write_entry(struct write_baton **entry_n
                 svn_path_uri_decode(relative_url, result_pool);
             }
           working_node->copyfrom_revnum = entry->copyfrom_rev;
-#ifdef SVN_WC__OP_DEPTH
           working_node->op_depth
             = svn_wc__db_op_depth_for_upgrade(local_relpath);
-#else
-          working_node->op_depth = 2; /* ### temporary op_depth */
-#endif
         }
       else if (parent_node->work && parent_node->work->copyfrom_repos_path)
         {
@@ -1855,14 +1852,43 @@ write_entry(struct write_baton **entry_n
             }
         }
 
-      /* If there is a WORKING node file then we don't have the
-         revert-base checksum for this file.  It will get updated
-         later when we transfer the pristine texts. */
-      if (entry->kind == svn_node_dir || working_node)
+      if (entry->kind == svn_node_dir)
         base_node->checksum = NULL;
       else
-        SVN_ERR(svn_checksum_parse_hex(&base_node->checksum, svn_checksum_md5,
-                                       entry->checksum, result_pool));
+        {
+          if (text_base_info && text_base_info->revert_base.sha1_checksum)
+            base_node->checksum = text_base_info->revert_base.sha1_checksum;
+          else if (text_base_info && text_base_info->normal_base.sha1_checksum)
+            base_node->checksum = text_base_info->normal_base.sha1_checksum;
+          else
+            base_node->checksum = NULL;
+
+          /* The base MD5 checksum is available in the entry, unless there
+           * is a copied WORKING node.  If possible, verify that the entry
+           * checksum matches the base file that we found. */
+#ifdef SVN_DEBUG
+          if (! (working_node && entry->copied))
+            {
+              svn_checksum_t *entry_md5_checksum, *found_md5_checksum;
+              SVN_ERR(svn_checksum_parse_hex(&entry_md5_checksum, svn_checksum_md5,
+                                             entry->checksum, scratch_pool));
+              if (text_base_info && text_base_info->revert_base.md5_checksum)
+                found_md5_checksum = text_base_info->revert_base.md5_checksum;
+              else if (text_base_info && text_base_info->normal_base.md5_checksum)
+                found_md5_checksum = text_base_info->normal_base.md5_checksum;
+              else
+                found_md5_checksum = NULL;
+              if (entry_md5_checksum && found_md5_checksum)
+                SVN_ERR_ASSERT(svn_checksum_match(entry_md5_checksum,
+                                                  found_md5_checksum));
+              else
+                {
+                  /* ### Not sure what conditions this should cover. */
+                  /* SVN_ERR_ASSERT(entry->deleted || ...); */
+                }
+            }
+#endif
+        }
 
       if (this_dir->repos)
         {
@@ -1946,7 +1972,6 @@ write_entry(struct write_baton **entry_n
         }
     }
 
-#ifdef SVN_WC__OP_DEPTH
   if (below_working_node)
     {
       below_working_node->wc_id = wc_id;
@@ -1965,10 +1990,9 @@ write_entry(struct write_baton **entry_n
       below_working_node->moved_here = FALSE;
       below_working_node->moved_to = FALSE;
 
-      /* We have a problem, the revert_base information isn't
-         available in the entry structure.  The checksum will get
-         updated later when we transfer the pristines. */
-      below_working_node->checksum = NULL;
+      /* The revert_base checksum isn't available in the entry structure,
+         so the caller provides it. */
+      below_working_node->checksum = text_base_info->revert_base.sha1_checksum;
       below_working_node->translated_size = 0;
       below_working_node->changed_rev = SVN_INVALID_REVNUM;
       below_working_node->changed_date = 0;
@@ -1978,7 +2002,6 @@ write_entry(struct write_baton **entry_n
       below_working_node->properties = NULL;
       SVN_ERR(insert_working_node(sdb, below_working_node, scratch_pool));
     }
-#endif
 
   /* Insert the working node. */
   if (working_node)
@@ -2001,9 +2024,24 @@ write_entry(struct write_baton **entry_n
       if (entry->kind == svn_node_dir)
         working_node->checksum = NULL;
       else
-        SVN_ERR(svn_checksum_parse_hex(&working_node->checksum,
-                                       svn_checksum_md5,
-                                       entry->checksum, result_pool));
+        {
+          working_node->checksum = text_base_info->normal_base.sha1_checksum;
+
+          /* If an MD5 checksum is present in the entry, we can verify that
+           * it matches the MD5 of the base file we found earlier. */
+#ifdef SVN_DEBUG
+          if (entry->checksum)
+          {
+            svn_checksum_t *md5_checksum;
+            SVN_ERR(svn_checksum_parse_hex(&md5_checksum, svn_checksum_md5,
+                                           entry->checksum, result_pool));
+            SVN_ERR_ASSERT(
+              md5_checksum && text_base_info->normal_base.md5_checksum);
+            SVN_ERR_ASSERT(svn_checksum_match(
+              md5_checksum, text_base_info->normal_base.md5_checksum));
+          }
+#endif
+        }
 
       /* All subdirs start of incomplete, and stop being incomplete
          when the entries file in the subdir is upgraded. */
@@ -2067,15 +2105,8 @@ write_entry(struct write_baton **entry_n
 
       if (!entry->copied)
         {
-          if (parent_node->work)
-            working_node->op_depth = parent_node->work->op_depth;
-          else
-#ifdef SVN_WC__OP_DEPTH
-            working_node->op_depth
-              = svn_wc__db_op_depth_for_upgrade(local_relpath);
-#else
-            working_node->op_depth = 2; /* ### temporary op_depth */
-#endif
+          working_node->op_depth
+            = svn_wc__db_op_depth_for_upgrade(local_relpath);
         }
 
       SVN_ERR(insert_working_node(sdb, working_node, scratch_pool));
@@ -2111,6 +2142,7 @@ struct entries_write_baton
   const char *dir_abspath;
   const char *new_root_abspath;
   apr_hash_t *entries;
+  apr_hash_t *text_bases_info;
   struct write_baton *parent_node;
   struct write_baton *dir_node;
   apr_pool_t *result_pool;
@@ -2152,7 +2184,7 @@ entries_write_new_cb(void *baton,
 
   /* Write out "this dir" */
   SVN_ERR(write_entry(&ewb->dir_node, ewb->parent_node, db, sdb,
-                      ewb->wc_id, ewb->repos_id, this_dir, dir_relpath,
+                      ewb->wc_id, ewb->repos_id, this_dir, NULL, dir_relpath,
                       svn_dirent_join(new_root_abspath, dir_relpath,
                                       scratch_pool),
                       this_dir, FALSE, ewb->result_pool, iterpool));
@@ -2163,6 +2195,8 @@ entries_write_new_cb(void *baton,
       const char *name = svn__apr_hash_index_key(hi);
       const svn_wc_entry_t *this_entry = svn__apr_hash_index_val(hi);
       const char *child_abspath, *child_relpath;
+      svn_wc__text_base_info_t *text_base_info
+        = apr_hash_get(ewb->text_bases_info, name, APR_HASH_KEY_STRING);
 
       svn_pool_clear(iterpool);
 
@@ -2176,7 +2210,7 @@ entries_write_new_cb(void *baton,
       child_relpath = svn_dirent_skip_ancestor(old_root_abspath, child_abspath);
       SVN_ERR(write_entry(NULL, ewb->dir_node, db, sdb,
                           ewb->wc_id, ewb->repos_id,
-                          this_entry, child_relpath,
+                          this_entry, text_base_info, child_relpath,
                           svn_dirent_join(new_root_abspath, child_relpath,
                                           scratch_pool),
                           this_dir, TRUE, iterpool, iterpool));
@@ -2197,6 +2231,7 @@ svn_wc__write_upgraded_entries(void **di
                                const char *dir_abspath,
                                const char *new_root_abspath,
                                apr_hash_t *entries,
+                               apr_hash_t *text_bases_info,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool)
 {
@@ -2208,6 +2243,7 @@ svn_wc__write_upgraded_entries(void **di
   ewb.dir_abspath = dir_abspath;
   ewb.new_root_abspath = new_root_abspath;
   ewb.entries = entries;
+  ewb.text_bases_info = text_bases_info;
   ewb.parent_node = parent_baton;
   ewb.result_pool = result_pool;
 

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.h
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.h?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.h (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/entries.h Wed Dec 29 00:10:25 2010
@@ -80,17 +80,30 @@ svn_error_t *
 svn_wc__entry_is_hidden(svn_boolean_t *hidden, const svn_wc_entry_t *entry);
 
 
-/* For internal use by entries.c to read/write old-format working copies. */
-svn_error_t *
-svn_wc__read_entries_old(apr_hash_t **entries,
-                         const char *dir_abspath,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool);
+/* The checksums of one pre-1.7 text-base file.  If the text-base file
+ * exists, both checksums are filled in, otherwise both fields are NULL. */
+typedef struct svn_wc__text_base_file_info_t
+{
+  svn_checksum_t *sha1_checksum;
+  svn_checksum_t *md5_checksum;
+} svn_wc__text_base_file_info_t;
+
+/* The text-base checksums of the normal base and/or the revert-base of one
+ * pre-1.7 versioned text file. */
+typedef struct svn_wc__text_base_info_t
+{
+  svn_wc__text_base_file_info_t normal_base;
+  svn_wc__text_base_file_info_t revert_base;
+} svn_wc__text_base_info_t;
 
 /* For internal use by upgrade.c to write entries in the wc-ng format.
    Return in DIR_BATON the baton to be passed as PARENT_BATON when
    upgrading child directories. Pass a NULL PARENT_BATON when upgrading
-   the root directory. */
+   the root directory.
+
+   TEXT_BASES_INFO is a hash of information about all the text bases found
+   in this directory's admin area, keyed on (const char *) name of the
+   versioned file, with (svn_wc__text_base_info_t *) values. */
 svn_error_t *
 svn_wc__write_upgraded_entries(void **dir_baton,
                                void *parent_baton,
@@ -101,6 +114,7 @@ svn_wc__write_upgraded_entries(void **di
                                const char *dir_abspath,
                                const char *new_root_abspath,
                                apr_hash_t *entries,
+                               apr_hash_t *text_bases_info,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/lock.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/lock.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/lock.c Wed Dec 29 00:10:25 2010
@@ -543,18 +543,8 @@ open_single(svn_wc_adm_access_t **adm_ac
 
   /* The format version must match exactly. Note that wc_db will perform
      an auto-upgrade if allowed. If it does *not*, then it has decided a
-     manual upgrade is required.
-
-     Note: if it decided on a manual upgrade, then we "should" never even
-     reach this code. An error should have been raised earlier.  */
-  if (wc_format != SVN_WC__VERSION)
-    {
-      return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL,
-                               _("Working copy format of '%s' is too old (%d); "
-                                 "please run 'svn upgrade'"),
-                               svn_dirent_local_style(path, scratch_pool),
-                               wc_format);
-    }
+     manual upgrade is required and it should have raised an error.  */
+  SVN_ERR_ASSERT(wc_format == SVN_WC__VERSION);
 
   /* Need to create a new lock */
   SVN_ERR(adm_access_alloc(&lock, path, db, db_provided, write_lock,

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/node.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/node.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/node.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/node.c Wed Dec 29 00:10:25 2010
@@ -165,6 +165,55 @@ svn_wc__node_get_repos_info(const char *
   return SVN_NO_ERROR;
 }
 
+/* Convert DB_KIND into the appropriate NODE_KIND value.
+ * If SHOW_HIDDEN is TRUE, report the node kind as found in the DB
+ * even if DB_STATUS indicates that the node is hidden.
+ * Else, return svn_kind_none for such nodes.
+ *
+ * ### This is a bit ugly. We should consider promoting svn_wc__db_kind_t
+ * ### to the de-facto node kind type instead of converting between them
+ * ### in non-backwards compat code.
+ * ### See also comments at the definition of svn_wc__db_kind_t. */
+static svn_error_t *
+convert_db_kind_to_node_kind(svn_node_kind_t *node_kind,
+                             svn_wc__db_kind_t db_kind,
+                             svn_wc__db_status_t db_status,
+                             svn_boolean_t show_hidden)
+{
+  switch (db_kind)
+    {
+      case svn_wc__db_kind_file:
+        *node_kind = svn_node_file;
+        break;
+      case svn_wc__db_kind_dir:
+        *node_kind = svn_node_dir;
+        break;
+      case svn_wc__db_kind_symlink:
+        *node_kind = svn_node_file;
+        break;
+      case svn_wc__db_kind_unknown:
+        *node_kind = svn_node_unknown;
+        break;
+      default:
+        SVN_ERR_MALFUNCTION();
+    }
+
+  /* Make sure hidden nodes return svn_node_none. */
+  if (! show_hidden)
+    switch (db_status)
+      {
+        case svn_wc__db_status_not_present:
+        case svn_wc__db_status_absent:
+        case svn_wc__db_status_excluded:
+          *node_kind = svn_node_none;
+
+        default:
+          break;
+      }
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc_read_kind(svn_node_kind_t *kind,
                  svn_wc_context_t *wc_ctx,
@@ -192,36 +241,7 @@ svn_wc_read_kind(svn_node_kind_t *kind,
   else
     SVN_ERR(err);
 
-  switch (db_kind)
-    {
-      case svn_wc__db_kind_file:
-        *kind = svn_node_file;
-        break;
-      case svn_wc__db_kind_dir:
-        *kind = svn_node_dir;
-        break;
-      case svn_wc__db_kind_symlink:
-        *kind = svn_node_file;
-        break;
-      case svn_wc__db_kind_unknown:
-        *kind = svn_node_unknown;
-        break;
-      default:
-        SVN_ERR_MALFUNCTION();
-    }
-
-  /* Make sure hidden nodes return svn_node_none. */
-  if (! show_hidden)
-    switch (db_status)
-      {
-        case svn_wc__db_status_not_present:
-        case svn_wc__db_status_absent:
-        case svn_wc__db_status_excluded:
-          *kind = svn_node_none;
-
-        default:
-          break;
-      }
+  SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, db_status, show_hidden));
 
   return SVN_NO_ERROR;
 }
@@ -648,22 +668,28 @@ walker_helper(svn_wc__db_t *db,
               void *cancel_baton,
               apr_pool_t *scratch_pool)
 {
-  const apr_array_header_t *rel_children;
+  apr_hash_t *rel_children_info;
+  apr_hash_index_t *hi;
   apr_pool_t *iterpool;
-  int i;
 
   if (depth == svn_depth_empty)
     return SVN_NO_ERROR;
 
-  SVN_ERR(svn_wc__db_read_children(&rel_children, db, dir_abspath,
-                                   scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__db_read_children_walker_info(&rel_children_info, db,
+                                               dir_abspath, scratch_pool,
+                                               scratch_pool));
+
 
   iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < rel_children->nelts; i++)
+  for (hi = apr_hash_first(scratch_pool, rel_children_info);
+       hi;
+       hi = apr_hash_next(hi))
     {
+      const char *child_name = svn__apr_hash_index_key(hi);
+      struct svn_wc__db_walker_info_t *wi = svn__apr_hash_index_val(hi);
+      svn_wc__db_kind_t child_kind = wi->kind;
+      svn_wc__db_status_t child_status = wi->status;
       const char *child_abspath;
-      svn_wc__db_kind_t child_kind;
-      svn_wc__db_status_t child_status;
 
       svn_pool_clear(iterpool);
 
@@ -671,17 +697,7 @@ walker_helper(svn_wc__db_t *db,
       if (cancel_func)
         SVN_ERR(cancel_func(cancel_baton));
 
-      child_abspath = svn_dirent_join(dir_abspath,
-                                      APR_ARRAY_IDX(rel_children, i,
-                                                    const char *),
-                                      iterpool);
-
-      SVN_ERR(svn_wc__db_read_info(&child_status, &child_kind, NULL, NULL,
-                                   NULL, NULL, NULL, NULL, NULL, NULL,
-                                   NULL, NULL, NULL, NULL, NULL, NULL,
-                                   NULL, NULL, NULL, NULL, NULL,
-                                   NULL, NULL, NULL,
-                                   db, child_abspath, iterpool, iterpool));
+      child_abspath = svn_dirent_join(dir_abspath, child_name, iterpool);
 
       if (!show_hidden)
         switch (child_status)
@@ -699,9 +715,14 @@ walker_helper(svn_wc__db_t *db,
       if (child_kind == svn_wc__db_kind_file
             || depth >= svn_depth_immediates)
         {
-          /* ### Maybe we should pass kind to the callback?.
-             ### almost every callee starts by asking for this */
-          SVN_ERR(walk_callback(child_abspath, walk_baton, iterpool));
+          svn_node_kind_t kind;
+
+          SVN_ERR(convert_db_kind_to_node_kind(&kind, child_kind,
+                                               child_status, show_hidden));
+          /* ### We might want to pass child_status as well because at least
+           * ### one callee is asking for it.
+           * ### But is it OK to use an svn_wc__db type in this API? */
+          SVN_ERR(walk_callback(child_abspath, kind, walk_baton, iterpool));
         }
 
       /* Recurse into this directory, if appropriate. */
@@ -737,28 +758,30 @@ svn_wc__internal_walk_children(svn_wc__d
                                void *cancel_baton,
                                apr_pool_t *scratch_pool)
 {
-  svn_wc__db_kind_t kind;
+  svn_wc__db_kind_t db_kind;
+  svn_node_kind_t kind;
   svn_wc__db_status_t status;
 
   SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
                  && walk_depth <= svn_depth_infinity);
 
   /* Check if the node exists before the first callback */
-  SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
+  SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
                                NULL, NULL, NULL, NULL, NULL, NULL,
                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                NULL, NULL, NULL, NULL, NULL,
                                db, local_abspath, scratch_pool, scratch_pool));
 
-  SVN_ERR(walk_callback(local_abspath, walk_baton, scratch_pool));
+  SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
+  SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
 
-  if (kind == svn_wc__db_kind_file
+  if (db_kind == svn_wc__db_kind_file
       || status == svn_wc__db_status_not_present
       || status == svn_wc__db_status_excluded
       || status == svn_wc__db_status_absent)
     return SVN_NO_ERROR;
 
-  if (kind == svn_wc__db_kind_dir)
+  if (db_kind == svn_wc__db_kind_dir)
     {
       return svn_error_return(
         walker_helper(db, local_abspath, show_hidden, walk_callback, walk_baton,
@@ -1317,6 +1340,19 @@ svn_wc__internal_node_get_schedule(svn_w
               if (base_status != svn_wc__db_status_not_present)
                 *schedule = svn_wc_schedule_replace;
             }
+          else
+            {
+              svn_boolean_t below_work;
+
+              SVN_ERR(svn_wc__db_temp_below_work(&below_work,
+                                                 db, local_abspath,
+                                                 scratch_pool));
+              /* Unlike base nodes above, not-present is considered a
+                 replace since working not-present represents a delete
+                 to be committed */
+              if (below_work)
+                *schedule = svn_wc_schedule_replace;
+            }
 
           if (status == svn_wc__db_status_added)
             break; /* Local addition */

Modified: subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/revision_status.c
URL: http://svn.apache.org/viewvc/subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/revision_status.c?rev=1053489&r1=1053488&r2=1053489&view=diff
==============================================================================
--- subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/revision_status.c (original)
+++ subversion/branches/diff-optimizations-bytes/subversion/libsvn_wc/revision_status.c Wed Dec 29 00:10:25 2010
@@ -52,6 +52,7 @@ struct walk_baton
  * Temporary allocations are made in SCRATCH_POOL. */
 static svn_error_t *
 analyze_status(const char *local_abspath,
+               svn_node_kind_t kind,
                void *baton,
                apr_pool_t *scratch_pool)
 {