subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject svn commit: r1239513 [1/2] - in /subversion/branches/reintegrate-keep-alive: ./ subversion/bindings/swig/python/libsvn_swig_py/ subversion/bindings/swig/python/tests/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/...
Date Thu, 02 Feb 2012 10:03:56 GMT
Author: julianfoad
Date: Thu Feb  2 10:03:55 2012
New Revision: 1239513

URL: http://svn.apache.org/viewvc?rev=1239513&view=rev
Log:
On the 'reintegrate-keep-alive' branch: Catch up to trunk@1239494.

Added:
    subversion/branches/reintegrate-keep-alive/tools/dev/gdb-py/
      - copied from r1239494, subversion/trunk/tools/dev/gdb-py/
    subversion/branches/reintegrate-keep-alive/tools/dev/merge-graph.py
      - copied unchanged from r1239494, subversion/trunk/tools/dev/merge-graph.py
Modified:
    subversion/branches/reintegrate-keep-alive/   (props changed)
    subversion/branches/reintegrate-keep-alive/CHANGES
    subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
    subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/tests/mergeinfo.py
    subversion/branches/reintegrate-keep-alive/subversion/include/private/svn_repos_private.h
    subversion/branches/reintegrate-keep-alive/subversion/include/svn_editor.h
    subversion/branches/reintegrate-keep-alive/subversion/include/svn_utf.h
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_client/commit_util.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/compat.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_neon/session.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_serf/property.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_serf/util.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_svn/cyrus_auth.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_repos/commit.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_repos/load-fs-vtable.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_subr/cmdline.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_subr/deprecated.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_subr/ssl_server_trust_providers.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_subr/utf.c
    subversion/branches/reintegrate-keep-alive/subversion/libsvn_wc/update_editor.c
    subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/liveprops.c
    subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/mod_dav_svn.c
    subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/reports/update.c
    subversion/branches/reintegrate-keep-alive/subversion/svnrdump/dump_editor.c
    subversion/branches/reintegrate-keep-alive/subversion/svnrdump/svnrdump.c
    subversion/branches/reintegrate-keep-alive/subversion/svnrdump/svnrdump.h
    subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/commit_tests.py
    subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/externals_tests.py
    subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/merge_tests.py
    subversion/branches/reintegrate-keep-alive/subversion/tests/cmdline/svntest/factory.py
    subversion/branches/reintegrate-keep-alive/tools/client-side/svnmucc/svnmucc.c
    subversion/branches/reintegrate-keep-alive/tools/dev/gdb-py/svndbg/   (props changed)
    subversion/branches/reintegrate-keep-alive/tools/dist/backport.pl

Propchange: subversion/branches/reintegrate-keep-alive/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Thu Feb  2 10:03:55 2012
@@ -57,3 +57,4 @@
 /subversion/branches/tree-conflicts:868291-873154
 /subversion/branches/tree-conflicts-notify:873926-874008
 /subversion/branches/uris-as-urls:1060426-1064427
+/subversion/trunk:1234907-1239494

Modified: subversion/branches/reintegrate-keep-alive/CHANGES
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/CHANGES?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/CHANGES (original)
+++ subversion/branches/reintegrate-keep-alive/CHANGES Thu Feb  2 10:03:55 2012
@@ -16,6 +16,7 @@ http://svn.apache.org/repos/asf/subversi
     * reject some attempts to merge between unrelated branches (r1215273)
     * support GPG agent for password storage on UNIX-like platforms (r1150783)
     * new 'svnadmin lock' / 'svnadmin unlock' subcommands (issue #3942, #4092)
+    * new SVNUseUTF8 configuration option for mod_dav_svn (issue #2487)
 
   - Client-side bugfixes:
     *
@@ -37,6 +38,30 @@ http://svn.apache.org/repos/asf/subversi
     *
 
 
+Version 1.7.3
+(XX XXX 2012, from /branches/1.7.x)
+http://svn.apache.org/repos/asf/subversion/tags/1.7.3
+
+  User-visible changes:
+    * fix segfault on 'svn rm $ROOT_URL' (issue #4074)
+    * replace a couple of assertions in favor of errors (r1207858, -949)
+    * fix a server assert after being upgraded (r1210195)
+    * fix segfault on 'svn mkdir svn://localhost' (r1211483)
+    * make 'svnadmin recover' prune the rep cache (r1213331, et al)
+    * make svnmucc use values from --config-dir option
+    * update and clarify the merge help text (r1154121, et al)
+    * replace wc assertion with informative error (r1222521, -693)
+    * copy permissions correctly for FSFS dirs (r1229252)
+    * improve 'svn log --with-all-revprops' over ra-dav (issue #4082)
+    * fix segfault when remapping a file external (issue #4093)
+    * fix segfault caused by obstructing unversioned dir (r1229677)
+    * fix regression on first update of external dir with '-r' (issue #4053) 
+
+  Developer-visible changes:
+    * JavaHL: Add missing notify action, fixing an exception (r1221793)
+    * fix spurious test suite failure (r1220742, -50)
+
+
 Version 1.7.2
 (02 Dec 2011, from /branches/1.7.x)
 http://svn.apache.org/repos/asf/subversion/tags/1.7.2

Modified: subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c Thu Feb  2 10:03:55 2012
@@ -657,10 +657,22 @@ static PyObject *convert_rangelist(void 
   apr_array_header_t *array = value;
 
   list = PyList_New(0);
+  if (list == NULL)
+    return NULL;
+
   for (i = 0; i < array->nelts; i++)
     {
       svn_merge_range_t *range = APR_ARRAY_IDX(array, i, svn_merge_range_t *);
-      if (PyList_Append(list, convert_to_swigtype(range, ctx, py_pool)) == -1)
+      PyObject *obj;
+      int result;
+
+      obj = convert_to_swigtype(range, ctx, py_pool);
+      if (obj == NULL)
+        goto error;
+
+      result = PyList_Append(list, obj);
+      Py_DECREF(obj);
+      if (result == -1)
         goto error;
     }
   return list;

Modified: subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/tests/mergeinfo.py
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/tests/mergeinfo.py?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/tests/mergeinfo.py (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/bindings/swig/python/tests/mergeinfo.py Thu Feb  2 10:03:55 2012
@@ -18,7 +18,7 @@
 # under the License.
 #
 #
-import unittest, os
+import unittest, os, sys, gc
 from svn import core, repos, fs
 import utils
 
@@ -29,6 +29,15 @@ class RevRange:
     self.start = start
     self.end = end
 
+def get_svn_merge_range_t_objects():
+  """Returns a list 'svn_merge_range_t' objects being tracked by the
+     garbage collector, used for detecting memory leaks."""
+  return [
+    o for o in gc.get_objects()
+      if hasattr(o, '__class__') and
+        o.__class__.__name__ == 'svn_merge_range_t'
+  ]
+
 class SubversionMergeinfoTestCase(unittest.TestCase):
   """Test cases for mergeinfo"""
 
@@ -116,6 +125,53 @@ class SubversionMergeinfoTestCase(unitte
       }
     self.compare_mergeinfo_catalogs(mergeinfo, expected_mergeinfo)
 
+  def test_mergeinfo_leakage__incorrect_range_t_refcounts(self):
+    """Ensure that the ref counts on svn_merge_range_t objects returned by
+       svn_mergeinfo_parse() are correct."""
+    # When reference counting is working properly, each svn_merge_range_t in
+    # the returned mergeinfo will have a ref count of 1...
+    mergeinfo = core.svn_mergeinfo_parse(self.TEXT_MERGEINFO1)
+    for (path, rangelist) in mergeinfo.items():
+      # ....and now 2 (incref during iteration of rangelist)
+
+      for (i, r) in enumerate(rangelist):
+        # ....and now 3 (incref during iteration of each range object)
+
+        refcount = sys.getrefcount(r)
+        # ....and finally, 4 (getrefcount() also increfs)
+        expected = 4
+
+        # Note: if path and index are not '/trunk' and 0 respectively, then
+        # only some of the range objects are leaking, which is, as far as
+        # leaks go, even more impressive.
+        self.assertEquals(refcount, expected, (
+          "Memory leak!  Expected a ref count of %d for svn_merge_range_t "
+          "object, but got %d instead (path: %s, index: %d).  Probable "
+          "cause: incorrect Py_INCREF/Py_DECREF usage in libsvn_swig_py/"
+          "swigutil_py.c." % (expected, refcount, path, i)))
+
+    del mergeinfo
+    gc.collect()
+
+  def test_mergeinfo_leakage__lingering_range_t_objects_after_del(self):
+    """Ensure that there are no svn_merge_range_t objects being tracked by
+       the garbage collector after we explicitly `del` the results returned
+       by svn_mergeinfo_parse().  We call gc.collect() to force an explicit
+       garbage collection cycle after the `del`;
+       if our reference counts are correct, the allocated svn_merge_range_t
+       objects will be garbage collected and thus, not appear in the list of
+       objects returned by gc.get_objects()."""
+    mergeinfo = core.svn_mergeinfo_parse(self.TEXT_MERGEINFO1)
+    del mergeinfo
+    gc.collect()
+    lingering = get_svn_merge_range_t_objects()
+    self.assertEquals(lingering, list(), (
+      "Memory leak!  Found lingering svn_merge_range_t objects left over from "
+      "our call to svn_mergeinfo_parse(), even though we explicitly deleted "
+      "the returned mergeinfo object.  Probable cause: incorrect Py_INCREF/"
+      "Py_DECREF usage in libsvn_swig_py/swigutil_py.c.  Lingering objects:\n"
+      "%s" % lingering))
+
   def inspect_mergeinfo_dict(self, mergeinfo, merge_source, nbr_rev_ranges):
     rangelist = mergeinfo.get(merge_source)
     self.inspect_rangelist_tuple(rangelist, nbr_rev_ranges)

Modified: subversion/branches/reintegrate-keep-alive/subversion/include/private/svn_repos_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/include/private/svn_repos_private.h?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/include/private/svn_repos_private.h (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/include/private/svn_repos_private.h Thu Feb  2 10:03:55 2012
@@ -44,6 +44,14 @@ extern "C" {
  *
  * Use @a pool for temporary allocations.
  *
+ * @note This function is used to implement server-side validation.
+ * Consequently, if you make this function stricter in what it accepts, you
+ * (a) break svnsync'ing of existing repositories that contain now-invalid
+ * properties, (b) do not preclude such invalid values from entering the
+ * repository via tools that use the svn_fs_* API directly (possibly
+ * including svnadmin and svnlook).  This has happened before and there
+ * are known (documented, but unsupported) upgrade paths in some cases.
+ * 
  * @since New in 1.7.
  */
 svn_error_t *

Modified: subversion/branches/reintegrate-keep-alive/subversion/include/svn_editor.h
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/include/svn_editor.h?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/include/svn_editor.h (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/include/svn_editor.h Thu Feb  2 10:03:55 2012
@@ -182,6 +182,7 @@ extern "C" {
  *      svn_editor_setcb_delete() \n
  *      svn_editor_setcb_copy() \n
  *      svn_editor_setcb_move() \n
+ *      svn_editor_setcb_rotate() \n
  *      svn_editor_setcb_complete() \n
  *      svn_editor_setcb_abort()
  *
@@ -203,7 +204,8 @@ extern "C" {
  *      svn_editor_set_target() \n
  *      svn_editor_delete() \n
  *      svn_editor_copy() \n
- *      svn_editor_move()
+ *      svn_editor_move() \n
+ *      svn_editor_rotate()
  *    \n\n
  *    Just before each callback invocation is carried out, the @a cancel_func
  *    that was passed to svn_editor_create() is invoked to poll any
@@ -260,15 +262,17 @@ extern "C" {
  *   its children, if a directory) may be copied many times, and are
  *   otherwise subject to the Once Rule. The destination path of a copy
  *   or move may have set_* operations applied, but not add_* or delete.
- *   If the destination path of a copy or move is a directory, then its
- *   children are subject to the Once Rule. The source path of a move
- *   (and its child paths) may be referenced in add_*, or as the
- *   destination of a copy (where these new, copied nodes are subject to
- *   the Once Rule).
- *
- * - The ancestor of an added, copied-here, moved-here or modified node may
- *   not be deleted. The ancestor may not be moved (instead: perform the
- *   move, *then* the edits).
+ *   If the destination path of a copy, move, or rotate is a directory,
+ *   then its children are subject to the Once Rule. The source path of
+ *   a move (and its child paths) may be referenced in add_*, or as the
+ *   destination of a copy (where these new or copied nodes are subject
+ *   to the Once Rule). Paths listed in a rotation are both sources and
+ *   destinations, so they may not be referenced again in an add_* or a
+ *   deletion; these paths may have set_* operations applied.
+ *
+ * - The ancestor of an added, copied-here, moved-here, rotated, or
+ *   modified node may not be deleted. The ancestor may not be moved
+ *   (instead: perform the move, *then* the edits).
  *
  * - svn_editor_delete() must not be used to replace a path -- i.e.
  *   svn_editor_delete() must not be followed by an svn_editor_add_*() on
@@ -289,6 +293,10 @@ extern "C" {
  *   by a delete... that is fine. It is simply that svn_editor_move()
  *   should be used to describe a semantic move.
  *
+ * - Paths mentioned in svn_editor_rotate() may have their properties
+ *   and contents edited (via set_* calls) by a previous or later call,
+ *   but they may not be subject to a later move, rotate, or deletion.
+ *
  * - One of svn_editor_complete() or svn_editor_abort() must be called
  *   exactly once, which must be the final call the driver invokes.
  *   Invoking svn_editor_complete() must imply that the set of changes has
@@ -321,6 +329,19 @@ extern "C" {
  * for these items are invoked.
  * \n\n
  *
+ * <h3>Timing and State</h3>
+ * The calls made by the driver to alter the state in the receiver are
+ * based on the receiver's *current* state, which includes all prior changes
+ * made during the edit.
+ *
+ * Example: copy A to B; set-props on A; copy A to C. The props on C
+ * should reflect the updated properties of A.
+ *
+ * Example: mv A@N to B; mv C@M to A. The second move cannot be marked as
+ * a "replacing" move since it is not replacing A. The node at A was moved
+ * away. The second operation is simply moving C to the now-empty path
+ * known as A.
+ *
  * <h3>Paths</h3>
  * Each driver/receiver implementation of this editor interface must
  * establish the expected root path for the paths sent and received via the
@@ -505,6 +526,15 @@ typedef svn_error_t *(*svn_editor_cb_mov
   svn_revnum_t replaces_rev,
   apr_pool_t *scratch_pool);
 
+/** @see svn_editor_rotate(), svn_editor_t.
+ * @since New in 1.8.
+ */
+typedef svn_error_t *(*svn_editor_cb_rotate_t)(
+  void *baton,
+  const apr_array_header_t *relpaths,
+  const apr_array_header_t *revisions,
+  apr_pool_t *scratch_pool);
+
 /** @see svn_editor_complete(), svn_editor_t.
  * @since New in 1.8.
  */
@@ -655,6 +685,17 @@ svn_editor_setcb_move(svn_editor_t *edit
                       svn_editor_cb_move_t callback,
                       apr_pool_t *scratch_pool);
 
+/** Sets the #svn_editor_cb_rotate_t callback in @a editor
+ * to @a callback.
+ * @a scratch_pool is used for temporary allocations (if any).
+ * @see also svn_editor_setcb_many().
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_editor_setcb_rotate(svn_editor_t *editor,
+                        svn_editor_cb_rotate_t callback,
+                        apr_pool_t *scratch_pool);
+
 /** Sets the #svn_editor_cb_complete_t callback in @a editor
  * to @a callback.
  * @a scratch_pool is used for temporary allocations (if any).
@@ -695,6 +736,7 @@ typedef struct svn_editor_cb_many_t
   svn_editor_cb_delete_t cb_delete;
   svn_editor_cb_copy_t cb_copy;
   svn_editor_cb_move_t cb_move;
+  svn_editor_cb_rotate_t cb_rotate;
   svn_editor_cb_complete_t cb_complete;
   svn_editor_cb_abort_t cb_abort;
 
@@ -843,6 +885,7 @@ svn_editor_set_props(svn_editor_t *edito
  * with checksum @a checksum.
  * ### TODO @todo Does this send the *complete* content, always?
  * ### TODO @todo What is REVISION for?
+ * ### TODO @todo Who is responsible for closing the stream?
  *
  * For all restrictions on driving the editor, see #svn_editor_t.
  * @since New in 1.8.
@@ -929,6 +972,33 @@ svn_editor_move(svn_editor_t *editor,
                 const char *dst_relpath,
                 svn_revnum_t replaces_rev);
 
+/** Drive @a editor's #svn_editor_cb_rotate_t callback.
+ *
+ * Perform a rotation among multiple nodes in the target tree.
+ *
+ * The @relpaths and @revisions arrays (pair-wise) specify nodes in the
+ * tree which are located at a path and expected to be at a specific
+ * revision. These nodes are simultaneously moved in a rotation pattern.
+ * For example, the node at index 0 of @a relpaths and @a revisions will
+ * be moved to the relpath specified at index 1 of @a relpaths. The node
+ * at index 1 will be moved to the location at index 2. The node at index
+ * N-1 will be moved to the relpath specifed at index 0.
+ *
+ * The simplest form of this operation is to swap nodes A and B. One may
+ * think to move A to a temporary location T, then move B to A, then move
+ * T to B. However, this last move violations the Once Rule by moving T
+ * (which had already by edited by the move from A). In order to keep the
+ * restrictions against multiple moves of a single node, the rotation
+ * operation is needed for certain types of tree edits.
+ *
+ * For all restrictions on driving the editor, see #svn_editor_t.
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_editor_rotate(svn_editor_t *editor,
+                  const apr_array_header_t *relpaths,
+                  const apr_array_header_t *revisions);
+
 /** Drive @a editor's #svn_editor_cb_complete_t callback.
  *
  * Send word that the edit has been completed successfully.

Modified: subversion/branches/reintegrate-keep-alive/subversion/include/svn_utf.h
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/include/svn_utf.h?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/include/svn_utf.h (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/include/svn_utf.h Thu Feb  2 10:03:55 2012
@@ -49,12 +49,28 @@ extern "C" {
  * Initialize the UTF-8 encoding/decoding routines.
  * Allocate cached translation handles in a subpool of @a pool.
  *
+ * If @a assume_native_utf8 is TRUE, the native character set is
+ * assumed to be UTF-8, i.e. conversion is a no-op. This is useful
+ * in contexts where the native character set is ASCII but UTF-8
+ * should be used regardless (e.g. for mod_dav_svn which runs within
+ * httpd and always uses the "C" locale).
+ *
  * @note It is optional to call this function, but if it is used, no other
  * svn function may be in use in other threads during the call of this
  * function or when @a pool is cleared or destroyed.
  * Initializing the UTF-8 routines will improve performance.
  *
- * @since New in 1.1.
+ * @since New in 1.8.
+ */
+void
+svn_utf_initialize2(apr_pool_t *pool,
+                    svn_boolean_t assume_native_utf8);
+
+/**
+ * Like svn_utf_initialize but without the ability to force the
+ * native encoding to UTF-8.
+ *
+ * @deprecated Provided for backward compatibility with the 1.7 API.
  */
 void
 svn_utf_initialize(apr_pool_t *pool);

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_client/commit_util.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_client/commit_util.c?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_client/commit_util.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_client/commit_util.c Thu Feb  2 10:03:55 2012
@@ -416,6 +416,10 @@ bail_on_tree_conflicted_ancestor(svn_wc_
    by recursing deeper into a dir target. (This is used to skip all file
    externals that aren't explicit commit targets.)
 
+   DANGLERS is a hash table mapping const char* absolute paths of a parent
+   that must be committed to a const char * absolute path of a child that
+   needs them.
+
    If CANCEL_FUNC is non-null, call it with CANCEL_BATON to see
    if the user has cancelled the operation.
 
@@ -435,6 +439,7 @@ harvest_committables(svn_wc_context_t *w
                      svn_boolean_t skip_files,
                      svn_boolean_t skip_dirs,
                      svn_boolean_t is_explicit_target,
+                     apr_hash_t *danglers,
                      svn_client__check_url_kind_t check_url_func,
                      void *check_url_baton,
                      svn_cancel_func_t cancel_func,
@@ -814,6 +819,50 @@ harvest_committables(svn_wc_context_t *w
         }
     }
 
+  /* Make sure we check for dangling children on additions */
+  if (state_flags && is_added && is_explicit_target && danglers)
+    {
+      /* If a node is added, it's parent must exist in the repository at the
+         time of committing */
+
+      svn_boolean_t parent_added;
+      const char *parent_abspath = svn_dirent_dirname(local_abspath,
+                                                      scratch_pool);
+
+      SVN_ERR(svn_wc__node_is_added(&parent_added, wc_ctx, parent_abspath,
+                                    scratch_pool));
+
+      if (parent_added)
+        {
+          /* The op-root of the parent must be part of the commit */
+          const char *copy_root_abspath;
+          svn_boolean_t parent_is_copy;
+
+          /* Copies are always committed recursively as long as the
+           * copy root is in the commit target list.
+           * So for nodes copied along with a parent, the copy root path
+           * is the dangling parent. See issue #4059. */
+          SVN_ERR(svn_wc__node_get_origin(&parent_is_copy, NULL, NULL, NULL,
+                                          NULL, &copy_root_abspath,
+                                          wc_ctx, parent_abspath,
+                                          FALSE, scratch_pool, scratch_pool));
+
+          if (parent_is_copy)
+            parent_abspath = copy_root_abspath;
+
+          /* Copy the parent and target into pool; iterpool
+             lasts only for this loop iteration, and we check
+             danglers after the loop is over. */
+          if (!apr_hash_get(danglers, parent_abspath, APR_HASH_KEY_STRING))
+            {
+              apr_hash_set(danglers,
+                           apr_pstrdup(result_pool, parent_abspath),
+                           APR_HASH_KEY_STRING,
+                           apr_pstrdup(result_pool, local_abspath));
+            }
+        }
+    }
+
   if (db_kind != svn_node_dir || depth <= svn_depth_empty)
     return SVN_NO_ERROR;
 
@@ -863,6 +912,7 @@ harvest_committables(svn_wc_context_t *w
                                        (depth < svn_depth_files),
                                        (depth < svn_depth_immediates),
                                        FALSE, /* IS_EXPLICIT_TARGET */
+                                       danglers,
                                        check_url_func, check_url_baton,
                                        cancel_func, cancel_baton,
                                        notify_func, notify_baton,
@@ -1063,10 +1113,8 @@ svn_client__harvest_committables(svn_cli
   for (i = 0; i < targets->nelts; ++i)
     {
       const char *target_abspath;
-      svn_boolean_t is_added;
       svn_node_kind_t kind;
       const char *repos_root_url;
-      svn_error_t *err;
 
       svn_pool_clear(iterpool);
 
@@ -1103,51 +1151,6 @@ svn_client__harvest_committables(svn_cli
                                           target_abspath,
                                           result_pool, iterpool));
 
-      /* Handle an added/replaced node. */
-      SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath,
-                                    iterpool));
-      if (is_added)
-        {
-          /* This node is added. Is the parent also added? */
-          const char *parent_abspath = svn_dirent_dirname(target_abspath,
-                                                          iterpool);
-          err = svn_wc__node_is_added(&is_added, ctx->wc_ctx, parent_abspath,
-                                      iterpool);
-          if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-            return svn_error_createf(
-                SVN_ERR_WC_CORRUPT, err,
-                _("'%s' is scheduled for addition within unversioned parent"),
-                svn_dirent_local_style(target_abspath, iterpool));
-          SVN_ERR(err);
-
-          if (is_added)
-            {
-              svn_boolean_t is_copy;
-              const char *copy_root_abspath;
-
-              /* Copies are always committed recursively as long as the
-               * copy root is in the commit target list.
-               * So for nodes copied along with a parent, the copy root path
-               * is the dangling parent. See issue #4059. */
-              SVN_ERR(svn_wc__node_get_origin(&is_copy,
-                                              NULL, NULL, NULL, NULL,
-                                              &copy_root_abspath,
-                                              ctx->wc_ctx,
-                                              target_abspath,
-                                              FALSE, iterpool, iterpool));
-              if (is_copy && strcmp(copy_root_abspath, target_abspath) != 0)
-                parent_abspath = copy_root_abspath;
-
-              /* Copy the parent and target into pool; iterpool
-                 lasts only for this loop iteration, and we check
-                 danglers after the loop is over. */
-              apr_hash_set(danglers,
-                           apr_pstrdup(scratch_pool, parent_abspath),
-                           APR_HASH_KEY_STRING,
-                           apr_pstrdup(scratch_pool, target_abspath));
-            }
-        }
-
       /* Handle our TARGET. */
       /* Make sure this isn't inside a working copy subtree that is
        * marked as tree-conflicted. */
@@ -1164,6 +1167,7 @@ svn_client__harvest_committables(svn_cli
                                    depth, just_locked, changelist_hash,
                                    FALSE, FALSE,
                                    TRUE /* IS_EXPLICIT_TARGET */,
+                                   danglers,
                                    check_url_func, check_url_baton,
                                    ctx->cancel_func, ctx->cancel_baton,
                                    ctx->notify_func2, ctx->notify_baton2,
@@ -1258,6 +1262,7 @@ harvest_copy_committables(void *baton, v
                                NULL,
                                FALSE, FALSE, /* skip files, dirs */
                                TRUE, /* IS_EXPLICIT_TARGET (don't care) */
+                               NULL,
                                btn->check_url_func,
                                btn->check_url_baton,
                                btn->ctx->cancel_func,

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

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_delta/editor.c Thu Feb  2 10:03:55 2012
@@ -192,6 +192,16 @@ svn_editor_setcb_move(svn_editor_t *edit
 
 
 svn_error_t *
+svn_editor_setcb_rotate(svn_editor_t *editor,
+                        svn_editor_cb_rotate_t callback,
+                        apr_pool_t *scratch_pool)
+{
+  editor->funcs.cb_rotate = callback;
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
 svn_editor_setcb_complete(svn_editor_t *editor,
                           svn_editor_cb_complete_t callback,
                           apr_pool_t *scratch_pool)
@@ -228,6 +238,7 @@ svn_editor_setcb_many(svn_editor_t *edit
   COPY_CALLBACK(cb_delete);
   COPY_CALLBACK(cb_copy);
   COPY_CALLBACK(cb_move);
+  COPY_CALLBACK(cb_rotate);
   COPY_CALLBACK(cb_complete);
   COPY_CALLBACK(cb_abort);
 
@@ -592,6 +603,32 @@ svn_editor_move(svn_editor_t *editor,
 
 
 svn_error_t *
+svn_editor_rotate(svn_editor_t *editor,
+                  const apr_array_header_t *relpaths,
+                  const apr_array_header_t *revisions)
+{
+  svn_error_t *err = SVN_NO_ERROR;
+
+#ifdef ENABLE_ORDERING_CHECK
+  SVN_ERR_ASSERT(!editor->finished);
+  /* ### something more  */
+#endif
+
+  if (editor->cancel_func)
+    SVN_ERR(editor->cancel_func(editor->cancel_baton));
+
+  if (editor->funcs.cb_rotate)
+    err = editor->funcs.cb_rotate(editor->baton, relpaths, revisions,
+                                  editor->scratch_pool);
+#ifdef ENABLE_ORDERING_CHECK
+  /* ### something more  */
+#endif
+  svn_pool_clear(editor->scratch_pool);
+  return err;
+}
+
+
+svn_error_t *
 svn_editor_complete(svn_editor_t *editor)
 {
   svn_error_t *err = SVN_NO_ERROR;

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

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

Modified: subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_serf/util.c?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/libsvn_ra_serf/util.c Thu Feb  2 10:03:55 2012
@@ -386,20 +386,23 @@ static svn_error_t *
 load_authorities(svn_ra_serf__connection_t *conn, const char *authorities,
                  apr_pool_t *pool)
 {
-  char *files, *file;
-  files = apr_pstrdup(pool, authorities);
+  apr_array_header_t *files = svn_cstring_split(authorities, ";",
+                                                TRUE /* chop_whitespace */,
+                                                pool);
+  int i;
 
-  while ((file = svn_cstring_tokenize(";", &files)) != NULL)
+  for (i = 0; i < files->nelts; ++i)
     {
+      const char *file = APR_ARRAY_IDX(files, i, const char *);
       serf_ssl_certificate_t *ca_cert;
       apr_status_t status = serf_ssl_load_cert_file(&ca_cert, file, pool);
+
       if (status == APR_SUCCESS)
         status = serf_ssl_trust_cert(conn->ssl_context, ca_cert);
 
       if (status != APR_SUCCESS)
         {
-          return svn_error_createf
-            (SVN_ERR_BAD_CONFIG_VALUE, NULL,
+          return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
              _("Invalid config: unable to load certificate file '%s'"),
              svn_dirent_local_style(file, pool));
         }

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

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

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

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

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

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

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

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

Modified: subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/liveprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/liveprops.c?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/liveprops.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/liveprops.c Thu Feb  2 10:03:55 2012
@@ -25,6 +25,7 @@
 
 #include <httpd.h>
 #include <http_core.h>
+#include <http_log.h>
 #include <util_xml.h>
 #include <mod_dav.h>
 
@@ -377,7 +378,12 @@ insert_prop_internal(const dav_resource 
                                            scratch_pool);
             if (serr != NULL)
               {
-                /* ### what to do? */
+                ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err, 
+                              resource->info->r,
+                              "Can't get created-rev of '%s': "
+                              "%s",
+                              resource->info->repos_path,
+                              serr->message);
                 svn_error_clear(serr);
                 value = "###error###";
                 break;
@@ -395,7 +401,12 @@ insert_prop_internal(const dav_resource 
                                 scratch_pool);
         if (serr)
           {
-            /* ### what to do? */
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err, 
+                          resource->info->r,
+                          "Can't get author of r%ld: "
+                          "%s",
+                          committed_rev,
+                          serr->message);
             svn_error_clear(serr);
             value = "###error###";
             break;
@@ -538,7 +549,13 @@ insert_prop_internal(const dav_resource 
                                      scratch_pool);
           if (serr != NULL)
             {
-              /* ### what to do? */
+              ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err, 
+                            resource->info->r,
+                            "Can't get youngest revision in '%s': "
+                            "%s",
+                            svn_fs_path(resource->info->repos->fs,
+                                        scratch_pool),
+                            serr->message);
               svn_error_clear(serr);
               value = "###error###";
               break;
@@ -612,7 +629,12 @@ insert_prop_internal(const dav_resource 
                                          scratch_pool);
           if (serr != NULL)
             {
-              /* ### what to do? */
+              ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err, 
+                            resource->info->r,
+                            "Can't get created-rev of '%s': "
+                            "%s",
+                            resource->info->repos_path,
+                            serr->message);
               svn_error_clear(serr);
               value = "###error###";
               break;
@@ -651,7 +673,12 @@ insert_prop_internal(const dav_resource 
                                       scratch_pool);
           if (serr != NULL)
             {
-              /* ### what to do? */
+              ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err, 
+                            resource->info->r,
+                            "Can't get fetch or compute md5 checksum of '%s': "
+                            "%s",
+                            resource->info->repos_path,
+                            serr->message);
               svn_error_clear(serr);
               value = "###error###";
               break;
@@ -671,7 +698,12 @@ insert_prop_internal(const dav_resource 
       serr = svn_fs_get_uuid(resource->info->repos->fs, &value, scratch_pool);
       if (serr != NULL)
         {
-          /* ### what to do? */
+          ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err, 
+                        resource->info->r,
+                        "Can't fetch UUID of '%s': "
+                        "%s",
+                        svn_fs_path(resource->info->repos->fs, scratch_pool),
+                        serr->message);
           svn_error_clear(serr);
           value = "###error###";
           break;
@@ -691,7 +723,12 @@ insert_prop_internal(const dav_resource 
                                     resource->info->repos_path, scratch_pool);
         if (serr != NULL)
           {
-            /* ### what to do? */
+            ap_log_rerror(APLOG_MARK, APLOG_ERR, serr->apr_err, 
+                          resource->info->r,
+                          "Can't fetch proplist of '%s': "
+                          "%s",
+                          resource->info->repos_path,
+                          serr->message);
             svn_error_clear(serr);
             value = "###error###";
             break;

Modified: subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/mod_dav_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/mod_dav_svn.c?rev=1239513&r1=1239512&r2=1239513&view=diff
==============================================================================
--- subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/mod_dav_svn.c (original)
+++ subversion/branches/reintegrate-keep-alive/subversion/mod_dav_svn/mod_dav_svn.c Thu Feb  2 10:03:55 2012
@@ -22,6 +22,8 @@
  * ====================================================================
  */
 
+#include <stdlib.h>
+
 #include <apr_strings.h>
 
 #include <httpd.h>
@@ -55,6 +57,7 @@
 /* per-server configuration */
 typedef struct server_conf_t {
   const char *special_uri;
+  svn_boolean_t use_utf8;
 } server_conf_t;
 
 
@@ -111,6 +114,8 @@ static int
 init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
 {
   svn_error_t *serr;
+  server_conf_t *conf;
+
   ap_add_version_component(p, "SVN/" SVN_VER_NUMBER);
 
   serr = svn_fs_initialize(p);
@@ -123,7 +128,8 @@ init(apr_pool_t *p, apr_pool_t *plog, ap
     }
 
   /* This returns void, so we can't check for error. */
-  svn_utf_initialize(p);
+  conf = ap_get_module_config(s->module_config, &dav_svn_module);
+  svn_utf_initialize2(p, conf->use_utf8);
 
   return OK;
 }
@@ -510,6 +516,18 @@ SVNCompressionLevel_cmd(cmd_parms *cmd, 
   return NULL;
 }
 
+static const char *
+SVNUseUTF8_cmd(cmd_parms *cmd, void *config, int arg)
+{
+  server_conf_t *conf;
+
+  conf = ap_get_module_config(cmd->server->module_config,
+                              &dav_svn_module);
+  conf->use_utf8 = arg;
+
+  return NULL;
+}
+
 
 /** Accessor functions for the module's configuration state **/
 
@@ -1021,6 +1039,11 @@ static const command_rec cmds[] =
                 "content over the network (0 for no compression, 9 for "
                 "maximum, 5 is default)."),
 
+  /* per server */
+  AP_INIT_FLAG("SVNUseUTF8",
+               SVNUseUTF8_cmd, NULL,
+               RSRC_CONF,
+               "use UTF-8 as native character encoding (default is ASCII)."),
   { NULL }
 };
 



Mime
View raw message