You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by tr...@apache.org on 2018/12/15 19:23:40 UTC

svn commit: r1849003 - in /subversion/branches/swig-py3: ./ build/generator/ subversion/bindings/swig/include/ subversion/bindings/swig/python/libsvn_swig_py/ subversion/bindings/swig/python/tests/ subversion/include/ subversion/include/private/ subver...

Author: troycurtisjr
Date: Sat Dec 15 19:23:40 2018
New Revision: 1849003

URL: http://svn.apache.org/viewvc?rev=1849003&view=rev
Log:
On branch swig-py3: Catchup to trunk @r1849002.


Removed:
    subversion/branches/swig-py3/subversion/libsvn_client/copy_foreign.c
Modified:
    subversion/branches/swig-py3/   (props changed)
    subversion/branches/swig-py3/build/generator/gen_win.py
    subversion/branches/swig-py3/build/generator/gen_win_dependencies.py
    subversion/branches/swig-py3/subversion/bindings/swig/include/svn_types.swg
    subversion/branches/swig-py3/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
    subversion/branches/swig-py3/subversion/bindings/swig/python/tests/delta.py
    subversion/branches/swig-py3/subversion/bindings/swig/python/tests/repository.py
    subversion/branches/swig-py3/subversion/include/private/svn_client_private.h
    subversion/branches/swig-py3/subversion/include/svn_dirent_uri.h
    subversion/branches/swig-py3/subversion/include/svn_error_codes.h
    subversion/branches/swig-py3/subversion/libsvn_client/conflicts.c
    subversion/branches/swig-py3/subversion/libsvn_client/copy.c
    subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c
    subversion/branches/swig-py3/subversion/libsvn_repos/authz.h
    subversion/branches/swig-py3/subversion/libsvn_repos/authz_info.c
    subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c
    subversion/branches/swig-py3/subversion/libsvn_subr/config_file.c
    subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c
    subversion/branches/swig-py3/subversion/libsvn_subr/lz4/   (props changed)
    subversion/branches/swig-py3/subversion/libsvn_subr/win32_crashrpt.c
    subversion/branches/swig-py3/subversion/svnfsfs/   (props changed)
    subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py
    subversion/branches/swig-py3/subversion/tests/cmdline/externals_tests.py
    subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py
    subversion/branches/swig-py3/subversion/tests/libsvn_client/   (props changed)
    subversion/branches/swig-py3/subversion/tests/libsvn_client/client-test.c
    subversion/branches/swig-py3/subversion/tests/libsvn_ra/   (props changed)
    subversion/branches/swig-py3/subversion/tests/libsvn_subr/   (props changed)
    subversion/branches/swig-py3/tools/client-side/svnconflict/   (props changed)
    subversion/branches/swig-py3/tools/dev/svnmover/   (props changed)
    subversion/branches/swig-py3/tools/dev/wc-ng/   (props changed)

Propchange: subversion/branches/swig-py3/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Sat Dec 15 19:23:40 2018
@@ -101,4 +101,4 @@
 /subversion/branches/verify-at-commit:1462039-1462408
 /subversion/branches/verify-keep-going:1439280-1546110
 /subversion/branches/wc-collate-path:1402685-1480384
-/subversion/trunk:1813660-1847674
+/subversion/trunk:1813660-1849002

Modified: subversion/branches/swig-py3/build/generator/gen_win.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/build/generator/gen_win.py?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/build/generator/gen_win.py (original)
+++ subversion/branches/swig-py3/build/generator/gen_win.py Sat Dec 15 19:23:40 2018
@@ -743,6 +743,7 @@ class WinGeneratorBase(gen_win_dependenc
 
     if target.name.endswith('svn_subr'):
       fakedefines.append("SVN_USE_WIN32_CRASHHANDLER")
+      fakedefines.append('SVN_WIN32_CRASHREPORT_EMAIL="users@subversion.apache.org"')
 
     return fakedefines
 

Modified: subversion/branches/swig-py3/build/generator/gen_win_dependencies.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/build/generator/gen_win_dependencies.py?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/build/generator/gen_win_dependencies.py (original)
+++ subversion/branches/swig-py3/build/generator/gen_win_dependencies.py Sat Dec 15 19:23:40 2018
@@ -128,6 +128,8 @@ class GenDependenciesBase(gen_base.Gener
 
         # So optional, we don't even have any code to detect them on Windows
         'magic',
+        'macos-plist',
+        'macos-keychain',
   ]
 
   # When build.conf contains a 'when = SOMETHING' where SOMETHING is not in

Modified: subversion/branches/swig-py3/subversion/bindings/swig/include/svn_types.swg
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/bindings/swig/include/svn_types.swg?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/bindings/swig/include/svn_types.swg (original)
+++ subversion/branches/swig-py3/subversion/bindings/swig/include/svn_types.swg Sat Dec 15 19:23:40 2018
@@ -942,7 +942,15 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
 
 #ifdef SWIGPYTHON
 %typemap(in) svn_stream_t *WRAPPED_STREAM {
-    $1 = svn_swig_py_make_stream ($input, _global_pool);
+    if ($input == Py_None) {
+        $1 = NULL;
+    }
+    else {
+        $1 = svn_swig_py_make_stream ($input, _global_pool);
+        if ($1 == NULL) {
+            SWIG_fail;
+        }
+    }
 }
 #endif
 

Modified: subversion/branches/swig-py3/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (original)
+++ subversion/branches/swig-py3/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c Sat Dec 15 19:23:40 2018
@@ -2362,8 +2362,8 @@ static svn_error_t *parse_fn3_set_fullte
                                            void *node_baton)
 {
   item_baton *ib = node_baton;
-  PyObject *result;
-  svn_error_t *err;
+  PyObject *result = NULL;
+  svn_error_t *err = SVN_NO_ERROR;
 
   svn_swig_py_acquire_py_lock();
 
@@ -2385,14 +2385,17 @@ static svn_error_t *parse_fn3_set_fullte
       /* create a stream from the IO object. it will increment the
          reference on the 'result'. */
       *stream = svn_swig_py_make_stream(result, ib->pool);
+      if (*stream == NULL)
+        {
+          err = callback_exception_error();
+          goto finished;
+        }
     }
 
   /* if the handler returned an IO object, svn_swig_py_make_stream() has
      incremented its reference counter. If it was None, it is discarded. */
-  Py_DECREF(result);
-  err = SVN_NO_ERROR;
-
- finished:
+finished:
+  Py_XDECREF(result);
   svn_swig_py_release_py_lock();
   return err;
 }
@@ -2656,17 +2659,39 @@ svn_swig_py_stream_destroy(void *py_io)
 svn_stream_t *
 svn_swig_py_make_stream(PyObject *py_io, apr_pool_t *pool)
 {
-  svn_stream_t *stream;
+  PyObject *_stream = NULL;
+  void *result = NULL;
+  swig_type_info *typeinfo = svn_swig_TypeQuery("svn_stream_t *");
+
+  if (svn_swig_py_convert_ptr(py_io, &result, typeinfo) != 0) {
+      PyErr_Clear();
+      if (PyObject_HasAttrString(py_io, "_stream")) {
+        _stream = PyObject_GetAttrString(py_io, "_stream");
+        if (svn_swig_py_convert_ptr(_stream, &result, typeinfo) != 0) {
+          PyErr_Clear();
+        }
+      }
+  }
+  if (result == NULL) {
+    if (!PyObject_HasAttrString(py_io, "read")
+        && !PyObject_HasAttrString(py_io, "write")) {
+      PyErr_SetString(PyExc_TypeError,
+                      "expecting a svn_stream_t or file like object");
+      goto finished;
+    }
+    result = svn_stream_create(py_io, pool);
+    svn_stream_set_read2(result, read_handler_pyio, NULL);
+    svn_stream_set_write(result, write_handler_pyio);
+    svn_stream_set_close(result, close_handler_pyio);
+    apr_pool_cleanup_register(pool, py_io, svn_swig_py_stream_destroy,
+                              apr_pool_cleanup_null);
+    Py_INCREF(py_io);
+  }
 
-  stream = svn_stream_create(py_io, pool);
-  svn_stream_set_read2(stream, read_handler_pyio, NULL);
-  svn_stream_set_write(stream, write_handler_pyio);
-  svn_stream_set_close(stream, close_handler_pyio);
-  apr_pool_cleanup_register(pool, py_io, svn_swig_py_stream_destroy,
-                            apr_pool_cleanup_null);
-  Py_INCREF(py_io);
+finished:
+  Py_XDECREF(_stream);
 
-  return stream;
+  return result;
 }
 
 PyObject *

Modified: subversion/branches/swig-py3/subversion/bindings/swig/python/tests/delta.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/bindings/swig/python/tests/delta.py?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/bindings/swig/python/tests/delta.py (original)
+++ subversion/branches/swig-py3/subversion/bindings/swig/python/tests/delta.py Sat Dec 15 19:23:40 2018
@@ -19,6 +19,8 @@
 #
 #
 import unittest, setup_path
+import os
+import tempfile
 import svn.delta
 import svn.core
 from sys import version_info # For Python version check
@@ -42,6 +44,59 @@ class DeltaTestCase(unittest.TestCase):
        svn.delta.tx_apply(src_stream, target_stream, None)
     window_handler(None, baton)
 
+  def testTxWindowHandler_stream_IF(self):
+    """Test tx_invoke_window_handler, with svn.core.svn_stream_t object"""
+    pool = svn.core.Pool()
+    in_str = "hello world"
+    src_stream = svn.core.svn_stream_from_stringbuf(in_str)
+    content_str = "bye world"
+    content_stream = svn.core.svn_stream_from_stringbuf(content_str)
+    fd, fname = tempfile.mkstemp()
+    os.close(fd)
+    try:
+      target_stream = svn.core.svn_stream_from_aprfile2(fname, False)
+      window_handler, baton = \
+          svn.delta.tx_apply(src_stream, target_stream, None)
+      svn.delta.tx_send_stream(content_stream, window_handler, baton, pool)
+      fp = open(fname, 'rb')
+      out_str = fp.read()
+      fp.close()
+      self.assertEqual(content_str, out_str)
+    finally:
+      del pool
+      try:
+        os.remove(fname)
+      except OSError:
+        pass
+
+  def testTxWindowHandler_Stream_IF(self):
+    """Test tx_invoke_window_handler, with svn.core.Stream object"""
+    pool = svn.core.Pool()
+    in_str = "hello world"
+    src_stream = svn.core.Stream(
+                    svn.core.svn_stream_from_stringbuf(in_str))
+    content_str = "bye world"
+    content_stream = svn.core.Stream(
+                    svn.core.svn_stream_from_stringbuf(content_str))
+    fd, fname = tempfile.mkstemp()
+    os.close(fd)
+    try:
+      target_stream = svn.core.Stream(
+                    svn.core.svn_stream_from_aprfile2(fname, False))
+      window_handler, baton = \
+          svn.delta.tx_apply(src_stream, target_stream, None)
+      svn.delta.tx_send_stream(content_stream, window_handler, baton, None)
+      fp = open(fname, 'rb')
+      out_str = fp.read()
+      fp.close()
+      self.assertEqual(content_str, out_str)
+    finally:
+      del pool
+      try:
+        os.remove(fname)
+      except OSError:
+        pass
+
   def testTxdeltaWindowT(self):
     """Test the svn_txdelta_window_t wrapper."""
     a = BytesIO("abc\ndef\n".encode('UTF-8'))

Modified: subversion/branches/swig-py3/subversion/bindings/swig/python/tests/repository.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/bindings/swig/python/tests/repository.py?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/bindings/swig/python/tests/repository.py (original)
+++ subversion/branches/swig-py3/subversion/bindings/swig/python/tests/repository.py Sat Dec 15 19:23:40 2018
@@ -226,6 +226,21 @@ class SubversionRepositoryTestCase(unitt
     # the comparison list gets too long.
     self.assertEqual(dsp.ops[:len(expected_list)], expected_list)
 
+  def test_parse_fns3_invalid_set_fulltext(self):
+    class DumpStreamParserSubclass(DumpStreamParser):
+      def set_fulltext(self, node_baton):
+        DumpStreamParser.set_fulltext(self, node_baton)
+        return 42
+    stream = open(os.path.join(os.path.dirname(sys.argv[0]),
+                               "trac/versioncontrol/tests/svnrepos.dump"))
+    try:
+      dsp = DumpStreamParserSubclass()
+      ptr, baton = repos.make_parse_fns3(dsp)
+      self.assertRaises(TypeError, repos.parse_dumpstream3,
+                        stream, ptr, baton, False, None)
+    finally:
+      stream.close()
+
   def test_get_logs(self):
     """Test scope of get_logs callbacks"""
     logs = []

Modified: subversion/branches/swig-py3/subversion/include/private/svn_client_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/include/private/svn_client_private.h?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/include/private/svn_client_private.h (original)
+++ subversion/branches/swig-py3/subversion/include/private/svn_client_private.h Sat Dec 15 19:23:40 2018
@@ -281,28 +281,6 @@ svn_client__wc_node_get_origin(svn_clien
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
-/* Copy the file or directory at LOC to DST_ABSPATH,
- * copying node information and properties.
- *
- * If URL specifies a directory, create the copy using depth DEPTH.
- *
- * If MAKE_PARENTS is TRUE and DST_ABSPATH doesn't have an added parent
- * create missing parent directories
- *
- * The caller should be holding a WC write lock that allows DST_ABSPATH to
- * be created, such as on the parent of DST_ABSPATH.
- *
- * Use RA_SESSION to fetch the data. The session may point to a different
- * URL after returning.
- */
-svn_error_t *
-svn_client__copy_foreign(const svn_client__pathrev_t *loc,
-                         const char *dst_abspath,
-                         svn_depth_t depth,
-                         svn_ra_session_t *ra_session,
-                         svn_client_ctx_t *ctx,
-                         apr_pool_t *scratch_pool);
-
 /* Same as the public svn_client_mergeinfo_log2 API, except for the addition
  * of the TARGET_MERGEINFO_CATALOG and RESULT_POOL parameters.
  *
@@ -414,52 +392,53 @@ svn_client__get_diff_summarize_callbacks
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);
 
-/* Copy a directory tree from SRC_URL @ SRC_REV, to DST_ABSPATH in a WC.
+/* Copy a directory tree or a file (according to KIND) from SRC_URL @ SRC_REV,
+ * to DST_ABSPATH in a WC.
  *
  * The caller should be holding a WC write lock that allows DST_ABSPATH to
  * be created, such as on the parent of DST_ABSPATH.
  *
- * SAME_REPOSITORIES must be true if and only if the source of this copy
- * is from the same repository at the WC parent of DST_ABSPATH.
- * If SAME_REPOSITORIES, then fill in the 'copy-from' in the WC target.
- * If not SAME_REPOSITORIES, then remove any svn:mergeinfo property.
+ * If not same repositories, then remove any svn:mergeinfo property.
  *
  * Use RA_SESSION to fetch the data. The session may point to a different
  * URL after returning.
+ *
+ * This API does not process any externals definitions that may be present
+ * on copied directories.
  */
 svn_error_t *
-svn_client__repos_to_wc_copy_dir(svn_boolean_t *timestamp_sleep,
-                                 const char *src_url,
-                                 svn_revnum_t src_rev,
-                                 const char *dst_abspath,
-                                 svn_boolean_t ignore_externals,
-                                 svn_boolean_t same_repositories,
-                                 svn_ra_session_t *ra_session,
-                                 svn_client_ctx_t *ctx,
-                                 apr_pool_t *pool);
+svn_client__repos_to_wc_copy_internal(svn_boolean_t *timestamp_sleep,
+                             svn_node_kind_t kind,
+                             const char *src_url,
+                             svn_revnum_t src_rev,
+                             const char *dst_abspath,
+                             svn_ra_session_t *ra_session,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool);
 
-/* Copy a file from SRC_URL @ SRC_REV, to DST_ABSPATH in a WC.
+/* Copy a directory tree or a file (according to KIND) from SRC_URL @ SRC_REV,
+ * to DST_ABSPATH in a WC.
  *
  * The caller should be holding a WC write lock that allows DST_ABSPATH to
  * be created, such as on the parent of DST_ABSPATH.
  *
- * SAME_REPOSITORIES must be true if and only if the source of this copy
- * is from the same repository at the WC parent of DST_ABSPATH.
- * If SAME_REPOSITORIES, then fill in the 'copy-from' in the WC target.
- * If not SAME_REPOSITORIES, then remove any svn:mergeinfo property.
+ * If not same repositories, then remove any svn:mergeinfo property.
  *
  * Use RA_SESSION to fetch the data. The session may point to a different
  * URL after returning.
+ *
+ * This API does not process any externals definitions that may be present
+ * on copied directories.
  */
 svn_error_t *
-svn_client__repos_to_wc_copy_file(svn_boolean_t *timestamp_sleep,
-                                  const char *src_url,
-                                  svn_revnum_t src_rev,
-                                  const char *dst_abspath,
-                                  svn_boolean_t same_repositories,
-                                  svn_ra_session_t *ra_session,
-                                  svn_client_ctx_t *ctx,
-                                  apr_pool_t *scratch_pool);
+svn_client__repos_to_wc_copy_by_editor(svn_boolean_t *timestamp_sleep,
+                svn_node_kind_t kind,
+                const char *src_url,
+                svn_revnum_t src_rev,
+                const char *dst_abspath,
+                svn_ra_session_t *ra_session,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool);
 
 /** Return an editor for applying local modifications to a WC.
  *

Modified: subversion/branches/swig-py3/subversion/include/svn_dirent_uri.h
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/include/svn_dirent_uri.h?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/include/svn_dirent_uri.h (original)
+++ subversion/branches/swig-py3/subversion/include/svn_dirent_uri.h Sat Dec 15 19:23:40 2018
@@ -60,12 +60,15 @@
  * form, except:
  *
  *    - @c svn_dirent_canonicalize()
+ *    - @c svn_dirent_canonicalize_safe()
  *    - @c svn_dirent_is_canonical()
  *    - @c svn_dirent_internal_style()
  *    - @c svn_relpath_canonicalize()
+ *    - @c svn_relpath_canonicalize_safe()
  *    - @c svn_relpath_is_canonical()
  *    - @c svn_relpath__internal_style()
  *    - @c svn_uri_canonicalize()
+ *    - @c svn_uri_canonicalize_safe()
  *    - @c svn_uri_is_canonical()
  *
  * The Subversion codebase also recognizes some other classes of path:
@@ -144,17 +147,47 @@ extern "C" {
 #endif /* __cplusplus */
 
 
-/** Convert @a dirent from the local style to the canonical internal style.
+/**
+ * Convert @a dirent from the local style to the canonical internal style.
  * "Local style" means native path separators and "." for the empty path.
  *
  * Allocate the result in @a result_pool.
  *
+ * @warning This function may call @c abort() if the @a dirent parameter
+ *          is not a valid local-style path.
+ *          Use svn_dirent_internal_style_safe() for tainted input.
+ *
  * @since New in 1.6.
  */
 const char *
 svn_dirent_internal_style(const char *dirent,
                           apr_pool_t *result_pool);
 
+/**
+ * Convert @a dirent from the local style to the canonical internal style
+ * and return it in @a *internal_style_dirent. "Local style" means native
+ * path separators and "." for the empty path.
+ *
+ * Similar to svn_dirent_internal_style() (which see), but returns an error
+ * if the @a dirent can not be canonicalized or of the result does not pass
+ * the svn_dirent_is_canonical() test.
+ *
+ * If the function fails and @a non_canonical_result is not @c NULL, the
+ * result of the failed canonicalization attempt (which may be @c NULL)
+ * will be returned in @a *non_canonical_result.
+ *
+ * Allocates the results in @a result_pool. Uses @a scratch_pool for
+ * temporary allocations.
+ *
+ * @since New in 1.12.
+ */
+svn_error_t *
+svn_dirent_internal_style_safe(const char **internal_style_dirent,
+                               const char **non_canonical_result,
+                               const char *dirent,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool);
+
 /** Convert @a dirent from the internal style to the local style.
  * "Local style" means native path separators and "." for the empty path.
  * If the input is not canonical, the output may not be canonical.
@@ -453,7 +486,8 @@ svn_boolean_t
 svn_uri_is_root(const char *uri,
                 apr_size_t len);
 
-/** Return a new dirent like @a dirent, but transformed such that some types
+/**
+ * Return a new dirent like @a dirent, but transformed such that some types
  * of dirent specification redundancies are removed.
  *
  * This involves:
@@ -467,14 +501,43 @@ svn_uri_is_root(const char *uri,
  *
  * Allocate the result in @a result_pool.
  *
+ * @warning This function may call @c abort() if @a dirent can not be
+ *          canonicalized.
+ *          Use svn_dirent_canonicalize_safe() for tainted input.
+ *
  * @since New in 1.6.
  */
 const char *
 svn_dirent_canonicalize(const char *dirent,
                         apr_pool_t *result_pool);
 
+/**
+ * Return a new @a *canonical_dirent like @a dirent, but transformed such
+ * that some types of dirent specification redundancies are removed.
+ *
+ * Similar to svn_dirent_canonicalize() (which see), but returns an error
+ * if the @a dirent can not be canonicalized or of the result does not pass
+ * the svn_dirent_is_canonical() test.
+ *
+ * If the function fails and @a non_canonical_result is not @c NULL, the
+ * result of the failed canonicalization attempt (which may be @c NULL)
+ * will be returned in @a *non_canonical_result.
+ *
+ * Allocates the results in @a result_pool. Uses @a scratch_pool for
+ * temporary allocations.
+ *
+ * @since New in 1.12.
+ */
+svn_error_t *
+svn_dirent_canonicalize_safe(const char **canonical_dirent,
+                             const char **non_canonical_result,
+                             const char *dirent,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
+
 
-/** Return a new relpath like @a relpath, but transformed such that some types
+/**
+ * Return a new relpath like @a relpath, but transformed such that some types
  * of relpath specification redundancies are removed.
  *
  * This involves:
@@ -486,14 +549,44 @@ svn_dirent_canonicalize(const char *dire
  *
  * Allocate the result in @a result_pool.
  *
+ * @warning This function may call @c abort() if @a relpath can not be
+ *          canonicalized.
+ *          Use svn_relpath_canonicalize_safe() for tainted input.
+ *
  * @since New in 1.7.
  */
 const char *
 svn_relpath_canonicalize(const char *relpath,
                          apr_pool_t *result_pool);
 
+/**
+ * Return a new @a *canonical_relpath like @a relpath, but transformed such
+ * that some types of relpath specification redundancies are removed.
+ *
+ * Similar to svn_relpath_canonicalize() (which see), but returns an error
+ * if the @a relpath can not be canonicalized or of the result does not
+ * pass the svn_relpath_is_canonical() test.
+ *
+ * If the function fails and @a non_canonical_result is not @c NULL, the
+ * result of the failed canonicalization attempt (which may be @c NULL)
+ * will be returned in @a *non_canonical_result.
+ *
+ * Allocates the results in @a result_pool. Uses @a scratch_pool for
+ * temporary allocations.
+ *
+ * @since New in 1.12.
+ */
+
+svn_error_t *
+svn_relpath_canonicalize_safe(const char **canonical_relpath,
+                              const char **non_canonical_result,
+                              const char *relpath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool);
 
-/** Return a new uri like @a uri, but transformed such that some types
+
+/**
+ * Return a new uri like @a uri, but transformed such that some types
  * of uri specification redundancies are removed.
  *
  * This involves:
@@ -510,12 +603,41 @@ svn_relpath_canonicalize(const char *rel
  *
  * Allocate the result in @a result_pool.
  *
- * @since New in 1.7.
+ * @warning This function may call @c abort() if @a uri can not be
+ *          canonicalized.
+ *          Use svn_uri_canonicalize_safe() for tainted input.
+ *
+  * @since New in 1.7.
  */
 const char *
 svn_uri_canonicalize(const char *uri,
                      apr_pool_t *result_pool);
 
+/**
+ *  Return a new @a *canonical_uri like @a uri, but transformed such that
+ * some types of uri specification redundancies are removed.
+ *
+ * Similar to svn_uri_canonicalize() (which see), but returns an error if
+ * the @a uri can not be canonicalized or of the result does not pass the
+ * svn_uri_is_canonical() test.
+ *
+ * If the function fails and @a non_canonical_result is not @c NULL, the
+ * result of the failed canonicalization attempt (which may be @c NULL)
+ * will be returned in @a *non_canonical_result.
+ *
+ * Allocates the results in @a result_pool. Uses @a scratch_pool for
+ * temporary allocations.
+ *
+ * @since New in 1.12.
+ */
+svn_error_t *
+svn_uri_canonicalize_safe(const char **canonical_uri,
+                          const char **non_canonical_result,
+                          const char *uri,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
+
+
 /** Return @c TRUE iff @a dirent is canonical.
  *
  * Use @a scratch_pool for temporary allocations.

Modified: subversion/branches/swig-py3/subversion/include/svn_error_codes.h
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/include/svn_error_codes.h?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/include/svn_error_codes.h (original)
+++ subversion/branches/swig-py3/subversion/include/svn_error_codes.h Sat Dec 15 19:23:40 2018
@@ -1482,6 +1482,11 @@ SVN_ERROR_START
              SVN_ERR_MISC_CATEGORY_START + 46,
              "LZ4 decompression failed")
 
+  /** @since New in 1.12.  */
+  SVN_ERRDEF(SVN_ERR_CANONICALIZATION_FAILED,
+             SVN_ERR_MISC_CATEGORY_START + 47,
+             "Could not canonicalize path or URI")
+
   /* command-line client errors */
 
   SVN_ERRDEF(SVN_ERR_CL_ARG_PARSING_ERROR,

Modified: subversion/branches/swig-py3/subversion/libsvn_client/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_client/conflicts.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_client/conflicts.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_client/conflicts.c Sat Dec 15 19:23:40 2018
@@ -8041,13 +8041,11 @@ merge_incoming_added_dir_replace(svn_cli
   if (err)
     goto unlock_wc;
 
-  err = svn_client__repos_to_wc_copy_dir(&timestamp_sleep,
-                                         url,
-                                         incoming_new_pegrev,
-                                         local_abspath,
-                                         TRUE, /* we want to ignore externals */
-                                         TRUE /*same_repositories*/,
-                                         ra_session, ctx, scratch_pool);
+  err = svn_client__repos_to_wc_copy_by_editor(&timestamp_sleep,
+                                               svn_node_dir,
+                                               url, incoming_new_pegrev,
+                                               local_abspath,
+                                               ra_session, ctx, scratch_pool);
   if (err)
     goto unlock_wc;
 

Modified: subversion/branches/swig-py3/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_client/copy.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_client/copy.c Sat Dec 15 19:23:40 2018
@@ -1099,6 +1099,9 @@ verify_wc_dsts(const apr_array_header_t
   return SVN_NO_ERROR;
 }
 
+/* Verify that the WC sources in COPY_PAIRS exist, and set pair->src_kind
+   for each.
+ */
 static svn_error_t *
 verify_wc_srcs(const apr_array_header_t *copy_pairs,
                svn_client_ctx_t *ctx,
@@ -2350,12 +2353,72 @@ notification_adjust_func(void *baton,
     nb->inner_func(nb->inner_baton, inner_notify, pool);
 }
 
-svn_error_t *
+/** Copy a directory tree from a remote repository.
+ *
+ * Copy from RA_SESSION:LOCATION to WC_CTX:DST_ABSPATH.
+ *
+ * Create the directory DST_ABSPATH, if not present. Its parent should be
+ * already under version control in the WC and in a suitable state for
+ * scheduling the addition of a child.
+ *
+ * Ignore any incoming non-regular properties (entry-props, DAV/WC-props).
+ * Remove any incoming 'svn:mergeinfo' properties.
+ */
+static svn_error_t *
+copy_foreign_dir(svn_ra_session_t *ra_session,
+                 const svn_client__pathrev_t *location,
+                 const char *dst_abspath,
+                 svn_wc_notify_func2_t notify_func,
+                 void *notify_baton,
+                 svn_cancel_func_t cancel_func,
+                 void *cancel_baton,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *scratch_pool)
+{
+  const svn_delta_editor_t *editor;
+  void *eb;
+  const svn_delta_editor_t *wrapped_editor;
+  void *wrapped_baton;
+  const svn_ra_reporter3_t *reporter;
+  void *reporter_baton;
+
+  /* Get a WC editor. It does not need an RA session because we will not
+     be sending it any 'copy from' requests, only 'add' requests. */
+  SVN_ERR(svn_client__wc_editor_internal(&editor, &eb,
+                                         dst_abspath,
+                                         TRUE /*root_dir_add*/,
+                                         TRUE /*ignore_mergeinfo_changes*/,
+                                         notify_func, notify_baton,
+                                         NULL /*ra_session*/,
+                                         ctx, scratch_pool));
+
+  SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
+                                            editor, eb,
+                                            &wrapped_editor, &wrapped_baton,
+                                            scratch_pool));
+
+  SVN_ERR(svn_ra_do_update3(ra_session, &reporter, &reporter_baton,
+                            location->rev, "", svn_depth_infinity,
+                            FALSE, FALSE, wrapped_editor, wrapped_baton,
+                            scratch_pool, scratch_pool));
+
+  SVN_ERR(reporter->set_path(reporter_baton, "", location->rev,
+                             svn_depth_infinity /* irrelevant */,
+                             TRUE /*start_empty*/,
+                             NULL, scratch_pool));
+
+  SVN_ERR(reporter->finish_report(reporter_baton, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Implementation of svn_client__repos_to_wc_copy() for a dir.
+ */
+static svn_error_t *
 svn_client__repos_to_wc_copy_dir(svn_boolean_t *timestamp_sleep,
                                  const char *src_url,
                                  svn_revnum_t src_revnum,
                                  const char *dst_abspath,
-                                 svn_boolean_t ignore_externals,
                                  svn_boolean_t same_repositories,
                                  svn_ra_session_t *ra_session,
                                  svn_client_ctx_t *ctx,
@@ -2374,11 +2437,12 @@ svn_client__repos_to_wc_copy_dir(svn_boo
       SVN_ERR(svn_client__pathrev_create_with_session(&location, ra_session,
                                                       src_revnum, src_url,
                                                       scratch_pool));
-      SVN_ERR(svn_client__copy_foreign(location,
-                                       dst_abspath,
-                                       svn_depth_infinity,
-                                       ra_session,
-                                       ctx, scratch_pool));
+      SVN_ERR(svn_ra_reparent(ra_session, src_url, scratch_pool));
+      SVN_ERR(copy_foreign_dir(ra_session, location,
+                               dst_abspath,
+                               ctx->notify_func2, ctx->notify_baton2,
+                               ctx->cancel_func, ctx->cancel_baton,
+                               ctx, scratch_pool));
 
       return SVN_NO_ERROR;
     }
@@ -2422,7 +2486,7 @@ svn_client__repos_to_wc_copy_dir(svn_boo
                                         &copy_src_revision,
                                         &copy_src_revision,
                                         svn_depth_infinity,
-                                        ignore_externals,
+                                        TRUE /*ignore_externals*/,
                                         FALSE, /* we don't allow obstructions */
                                         ra_session, ctx, scratch_pool);
 
@@ -2454,7 +2518,12 @@ svn_client__repos_to_wc_copy_dir(svn_boo
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
+/* Implementation of svn_client__repos_to_wc_copy() for a file.
+ *
+ * This has no 'ignore_externals' parameter because we don't support the
+ * 'svn:externals' property being set on a file.
+ */
+static svn_error_t *
 svn_client__repos_to_wc_copy_file(svn_boolean_t *timestamp_sleep,
                                   const char *src_url,
                                   svn_revnum_t src_rev,
@@ -2498,6 +2567,116 @@ svn_client__repos_to_wc_copy_file(svn_bo
   return SVN_NO_ERROR;
 }
 
+/* Are RA_SESSION and the versioned *parent* dir of WC_TARGET_ABSPATH in
+ * the same repository?
+ */
+static svn_error_t *
+is_same_repository(svn_boolean_t *same_repository,
+                   svn_ra_session_t *ra_session,
+                   const char *wc_target_abspath,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *scratch_pool)
+{
+  const char *src_uuid, *dst_uuid;
+
+  /* Get the repository UUIDs of copy source URL and WC parent path */
+  SVN_ERR(svn_ra_get_uuid2(ra_session, &src_uuid, scratch_pool));
+  SVN_ERR(svn_client_get_repos_root(NULL /*root_url*/, &dst_uuid,
+                                    svn_dirent_dirname(wc_target_abspath,
+                                                       scratch_pool),
+                                    ctx, scratch_pool, scratch_pool));
+  *same_repository = (strcmp(src_uuid, dst_uuid) == 0);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__repos_to_wc_copy_internal(svn_boolean_t *timestamp_sleep,
+                             svn_node_kind_t kind,
+                             const char *src_url,
+                             svn_revnum_t src_rev,
+                             const char *dst_abspath,
+                             svn_ra_session_t *ra_session,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool)
+{
+  svn_boolean_t timestamp_sleep_ignored;
+  svn_boolean_t same_repositories;
+
+  SVN_ERR(is_same_repository(&same_repositories,
+                             ra_session, dst_abspath, ctx, scratch_pool));
+
+  if (!timestamp_sleep)
+    timestamp_sleep = &timestamp_sleep_ignored;
+
+  if (kind == svn_node_dir)
+    {
+      SVN_ERR(svn_client__repos_to_wc_copy_dir(timestamp_sleep,
+                                               src_url, src_rev,
+                                               dst_abspath,
+                                               same_repositories,
+                                               ra_session,
+                                               ctx, scratch_pool));
+    }
+  else if (kind == svn_node_file)
+    {
+      SVN_ERR(svn_client__repos_to_wc_copy_file(timestamp_sleep,
+                                                src_url, src_rev,
+                                                dst_abspath,
+                                                same_repositories,
+                                                ra_session,
+                                                ctx, scratch_pool));
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__repos_to_wc_copy_by_editor(svn_boolean_t *timestamp_sleep,
+                svn_node_kind_t kind,
+                const char *src_url,
+                svn_revnum_t src_rev,
+                const char *dst_abspath,
+                svn_ra_session_t *ra_session,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool)
+{
+  const svn_delta_editor_t *editor;
+  void *eb;
+  const char *src_anchor = svn_uri_dirname(src_url, scratch_pool);
+  const char *dst_target = svn_dirent_basename(dst_abspath, scratch_pool);
+  void *rb, *db;
+
+  SVN_ERR(svn_ra_reparent(ra_session, src_anchor, scratch_pool));
+
+  SVN_ERR(svn_client__wc_editor(&editor, &eb,
+                                svn_dirent_dirname(dst_abspath, scratch_pool),
+                                ctx->notify_func2, ctx->notify_baton2,
+                                ra_session,
+                                ctx, scratch_pool));
+
+  SVN_ERR(editor->open_root(eb, SVN_INVALID_REVNUM, scratch_pool, &rb));
+  if (kind == svn_node_dir)
+    {
+      SVN_ERR(editor->add_directory(dst_target, rb,
+                                    src_url, src_rev,
+                                    scratch_pool,
+                                    &db));
+      SVN_ERR(editor->close_directory(db, scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(editor->add_file(dst_target, rb,
+                               src_url, src_rev,
+                               scratch_pool,
+                               &db));
+      SVN_ERR(editor->close_file(db, NULL, scratch_pool));
+    }
+  SVN_ERR(editor->close_edit(eb, scratch_pool));
+
+  if (timestamp_sleep)
+    *timestamp_sleep = TRUE;
+  return SVN_NO_ERROR;
+}
+
 /* Peform each individual copy operation for a repos -> wc copy.  A
    helper for repos_to_wc_copy().
 
@@ -2507,7 +2686,6 @@ svn_client__repos_to_wc_copy_file(svn_bo
 static svn_error_t *
 repos_to_wc_copy_single(svn_boolean_t *timestamp_sleep,
                         const svn_client__copy_pair_t *pair,
-                        svn_boolean_t same_repositories,
                         svn_boolean_t ignore_externals,
                         svn_boolean_t pin_externals,
                         const apr_hash_t *externals_to_pin,
@@ -2517,11 +2695,14 @@ repos_to_wc_copy_single(svn_boolean_t *t
 {
   apr_hash_t *src_mergeinfo;
   const char *dst_abspath = pair->dst_abspath_or_url;
+  svn_boolean_t same_repositories;
 
   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(pair->src_revnum));
   SVN_ERR_ASSERT(svn_path_is_url(pair->src_abspath_or_url));
   SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
 
+  SVN_ERR(is_same_repository(&same_repositories,
+                             ra_session, dst_abspath, ctx, pool));
   if (!same_repositories && ctx->notify_func2)
     {
       svn_wc_notify_t *notify;
@@ -2537,60 +2718,59 @@ repos_to_wc_copy_single(svn_boolean_t *t
         SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
     }
 
-  if (pair->src_kind == svn_node_dir)
-    {
-      /* Avoid a chicken-and-egg problem:
-       * If pinning externals we'll need to adjust externals
-       * properties before checking out any externals.
-       * But copy needs to happen before pinning because else there
-       * are no svn:externals properties to pin. */
-      if (pin_externals)
-        ignore_externals = TRUE;
+  SVN_ERR(svn_client__repos_to_wc_copy_by_editor(
+            timestamp_sleep,
+            pair->src_kind,
+            pair->src_abspath_or_url,
+            pair->src_revnum,
+            dst_abspath,
+            ra_session, ctx, pool));
 
-      SVN_ERR(svn_client__repos_to_wc_copy_dir(timestamp_sleep,
-                                               pair->src_abspath_or_url,
-                                               pair->src_revnum,
-                                               dst_abspath,
-                                               ignore_externals,
-                                               same_repositories,
-                                               ra_session, ctx, pool));
-
-      if (same_repositories && pin_externals)
+  /* Fetch externals, pinning them if requested */
+  if (!ignore_externals && pair->src_kind == svn_node_dir)
+    {
+      if (same_repositories)
         {
-          apr_hash_t *pinned_externals;
-          apr_hash_index_t *hi;
-          apr_pool_t *iterpool;
           const char *repos_root_url;
           apr_hash_t *new_externals;
           apr_hash_t *new_depths;
 
           SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool));
-          SVN_ERR(resolve_pinned_externals(&pinned_externals,
-                                           externals_to_pin, pair,
-                                           ra_session, repos_root_url,
-                                           ctx, pool, pool));
 
-          iterpool = svn_pool_create(pool);
-          for (hi = apr_hash_first(pool, pinned_externals);
-               hi;
-               hi = apr_hash_next(hi))
+          if (pin_externals)
             {
-              const char *dst_relpath = apr_hash_this_key(hi);
-              svn_string_t *externals_propval = apr_hash_this_val(hi);
-              const char *local_abspath;
-
-              svn_pool_clear(iterpool);
-
-              local_abspath = svn_dirent_join(pair->dst_abspath_or_url,
-                                              dst_relpath, iterpool);
-              /* ### use a work queue? */
-              SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, local_abspath,
-                                       SVN_PROP_EXTERNALS, externals_propval,
-                                       svn_depth_empty, TRUE /* skip_checks */,
-                                       NULL  /* changelist_filter */,
-                                       ctx->cancel_func, ctx->cancel_baton,
-                                       NULL, NULL, /* no extra notification */
-                                       iterpool));
+              apr_hash_t *pinned_externals;
+              apr_hash_index_t *hi;
+              apr_pool_t *iterpool;
+
+              SVN_ERR(resolve_pinned_externals(&pinned_externals,
+                                               externals_to_pin, pair,
+                                               ra_session, repos_root_url,
+                                               ctx, pool, pool));
+
+              iterpool = svn_pool_create(pool);
+              for (hi = apr_hash_first(pool, pinned_externals);
+                   hi;
+                   hi = apr_hash_next(hi))
+                {
+                  const char *dst_relpath = apr_hash_this_key(hi);
+                  svn_string_t *externals_propval = apr_hash_this_val(hi);
+                  const char *local_abspath;
+
+                  svn_pool_clear(iterpool);
+
+                  local_abspath = svn_dirent_join(pair->dst_abspath_or_url,
+                                                  dst_relpath, iterpool);
+                  /* ### use a work queue? */
+                  SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, local_abspath,
+                                           SVN_PROP_EXTERNALS, externals_propval,
+                                           svn_depth_empty, TRUE /* skip_checks */,
+                                           NULL  /* changelist_filter */,
+                                           ctx->cancel_func, ctx->cancel_baton,
+                                           NULL, NULL, /* no extra notification */
+                                           iterpool));
+                }
+              svn_pool_destroy(iterpool);
             }
 
           /* Now update all externals in the newly created copy. */
@@ -2599,33 +2779,20 @@ repos_to_wc_copy_single(svn_boolean_t *t
                                                        ctx->wc_ctx,
                                                        dst_abspath,
                                                        svn_depth_infinity,
-                                                       iterpool, iterpool));
+                                                       pool, pool));
           SVN_ERR(svn_client__handle_externals(new_externals,
                                                new_depths,
                                                repos_root_url, dst_abspath,
                                                svn_depth_infinity,
                                                timestamp_sleep,
                                                ra_session,
-                                               ctx, iterpool));
-          svn_pool_destroy(iterpool);
+                                               ctx, pool));
         }
-    } /* end directory case */
-
-  else if (pair->src_kind == svn_node_file)
-    {
-      SVN_ERR(svn_client__repos_to_wc_copy_file(timestamp_sleep,
-                                                pair->src_abspath_or_url,
-                                                pair->src_revnum,
-                                                dst_abspath,
-                                                same_repositories,
-                                                ra_session,
-                                                ctx, pool));
     }
 
   if (same_repositories)
     {
-      /* Record the implied mergeinfo (before the notification callback
-         is invoked for the root node). */
+      /* Record the implied mergeinfo. */
       SVN_ERR(svn_client__get_repos_mergeinfo(&src_mergeinfo, ra_session,
                                               pair->src_abspath_or_url,
                                               pair->src_revnum,
@@ -2635,6 +2802,7 @@ repos_to_wc_copy_single(svn_boolean_t *t
       SVN_ERR(extend_wc_mergeinfo(dst_abspath, src_mergeinfo, ctx, pool));
 
       /* ### Maybe the notification should mention this mergeinfo change. */
+      /* ### Maybe we should do this during rather than after the copy. */
     }
 
   return SVN_NO_ERROR;
@@ -2652,32 +2820,8 @@ repos_to_wc_copy_locked(svn_boolean_t *t
                         apr_pool_t *scratch_pool)
 {
   int i;
-  svn_boolean_t same_repositories;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  /* Decide whether the two repositories are the same or not. */
-  {
-    const char *parent_abspath;
-    const char *src_uuid, *dst_uuid;
-
-    /* Get the repository uuid of SRC_URL */
-    SVN_ERR(svn_ra_get_uuid2(ra_session, &src_uuid, iterpool));
-
-    /* Get repository uuid of dst's parent directory, since dst may
-       not exist.  ### TODO:  we should probably walk up the wc here,
-       in case the parent dir has an imaginary URL.  */
-    if (copy_pairs->nelts == 1)
-      parent_abspath = svn_dirent_dirname(top_dst_abspath, scratch_pool);
-    else
-      parent_abspath = top_dst_abspath;
-
-    SVN_ERR(svn_client_get_repos_root(NULL /* root_url */, &dst_uuid,
-                                      parent_abspath, ctx,
-                                      iterpool, iterpool));
-    /* ### Also check repos_root_url? */
-    same_repositories = (strcmp(src_uuid, dst_uuid) == 0);
-  }
-
   /* Perform the move for each of the copy_pairs. */
   for (i = 0; i < copy_pairs->nelts; i++)
     {
@@ -2690,7 +2834,6 @@ repos_to_wc_copy_locked(svn_boolean_t *t
       SVN_ERR(repos_to_wc_copy_single(timestamp_sleep,
                                       APR_ARRAY_IDX(copy_pairs, i,
                                                     svn_client__copy_pair_t *),
-                                      same_repositories,
                                       ignore_externals,
                                       pin_externals, externals_to_pin,
                                       ra_session, ctx, iterpool));

Modified: subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_client/wc_editor.c Sat Dec 15 19:23:40 2018
@@ -209,28 +209,6 @@ dir_open(const char *path,
   return SVN_NO_ERROR;
 }
 
-/* Are RA_SESSION and the versioned *parent* dir of WC_TARGET_ABSPATH in
- * the same repository?
- */
-static svn_error_t *
-is_same_repository(svn_boolean_t *same_repository,
-                   svn_ra_session_t *ra_session,
-                   const char *wc_target_abspath,
-                   svn_client_ctx_t *ctx,
-                   apr_pool_t *scratch_pool)
-{
-  const char *src_uuid, *dst_uuid;
-
-  /* Get the repository UUIDs of copy source URL and WC parent path */
-  SVN_ERR(svn_ra_get_uuid2(ra_session, &src_uuid, scratch_pool));
-  SVN_ERR(svn_client_get_repos_root(NULL /*root_url*/, &dst_uuid,
-                                    svn_dirent_dirname(wc_target_abspath,
-                                                       scratch_pool),
-                                    ctx, scratch_pool, scratch_pool));
-  *same_repository = (strcmp(src_uuid, dst_uuid) == 0);
-  return SVN_NO_ERROR;
-}
-
 static svn_error_t *
 dir_add(const char *path,
         void *parent_baton,
@@ -242,25 +220,21 @@ dir_add(const char *path,
   struct dir_baton_t *db;
 
   SVN_ERR(dir_open_or_add(path, parent_baton, &db));
-  SVN_ERR(svn_io_make_dir_recursively(db->local_abspath, db->pool));
 
   if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
     {
-      svn_boolean_t same_repository;
-      svn_boolean_t timestamp_sleep;
-
-      SVN_ERR(is_same_repository(&same_repository,
-                                 db->eb->ra_session, db->local_abspath,
-                                 db->eb->ctx, db->pool));
-
-      SVN_ERR(svn_client__repos_to_wc_copy_dir(&timestamp_sleep,
-                                               copyfrom_path,
-                                               copyfrom_revision,
-                                               db->local_abspath,
-                                               TRUE /*ignore_externals*/,
-                                               same_repository,
-                                               db->eb->ra_session,
-                                               db->eb->ctx, db->pool));
+      SVN_ERR(svn_client__repos_to_wc_copy_internal(NULL /*timestamp_sleep*/,
+                                           svn_node_dir,
+                                           copyfrom_path,
+                                           copyfrom_revision,
+                                           db->local_abspath,
+                                           db->eb->ra_session,
+                                           db->eb->ctx, db->pool));
+      db->created = TRUE;
+    }
+  else
+    {
+      SVN_ERR(svn_io_make_dir_recursively(db->local_abspath, db->pool));
     }
 
   *child_baton = db;
@@ -436,20 +410,14 @@ file_add(const char *path,
 
   if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
     {
-      svn_boolean_t same_repository;
-      svn_boolean_t timestamp_sleep;
-
-      SVN_ERR(is_same_repository(&same_repository,
-                                 fb->eb->ra_session, fb->local_abspath,
-                                 fb->eb->ctx, fb->pool));
-
-      SVN_ERR(svn_client__repos_to_wc_copy_file(&timestamp_sleep,
-                                                copyfrom_path,
-                                                copyfrom_revision,
-                                                fb->local_abspath,
-                                                same_repository,
-                                                fb->eb->ra_session,
-                                                fb->eb->ctx, fb->pool));
+      SVN_ERR(svn_client__repos_to_wc_copy_internal(NULL /*timestamp_sleep*/,
+                                           svn_node_file,
+                                           copyfrom_path,
+                                           copyfrom_revision,
+                                           fb->local_abspath,
+                                           fb->eb->ra_session,
+                                           fb->eb->ctx, fb->pool));
+      fb->created = TRUE;
     }
 
   *file_baton = fb;

Modified: subversion/branches/swig-py3/subversion/libsvn_repos/authz.h
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/authz.h?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_repos/authz.h (original)
+++ subversion/branches/swig-py3/subversion/libsvn_repos/authz.h Sat Dec 15 19:23:40 2018
@@ -139,6 +139,10 @@ typedef struct authz_full_t
   svn_boolean_t has_authn_rights;
   authz_global_rights_t authn_rights;
 
+  /* Globally accumulated rights from inverted selectors. */
+  svn_boolean_t has_neg_rights;
+  authz_global_rights_t neg_rights;
+
   /* Globally accumulated rights, for all concrete users mentioned
      in the authz file. The key is the user name, the value is
      an authz_global_rights_t*. */
@@ -257,14 +261,19 @@ typedef struct authz_acl_t
   /* The parsed rule. */
   authz_rule_t rule;
 
-  /* Access rights for anonymous users */
+
+  /* Access rights for anonymous users. */
   svn_boolean_t has_anon_access;
   authz_access_t anon_access;
 
-  /* Access rights for authenticated users */
+  /* Access rights for authenticated users. */
   svn_boolean_t has_authn_access;
   authz_access_t authn_access;
 
+  /* Access rights from inverted selectors. */
+  svn_boolean_t has_neg_access;
+  authz_access_t neg_access;
+
   /* All other user- or group-specific access rights.
      Aliases are replaced with their definitions, rules for the same
      user or group are merged. */

Modified: subversion/branches/swig-py3/subversion/libsvn_repos/authz_info.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/authz_info.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_repos/authz_info.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_repos/authz_info.c Sat Dec 15 19:23:40 2018
@@ -148,37 +148,50 @@ svn_authz__get_global_rights(authz_right
     {
       /* Check if we have explicit rights for anonymous access. */
       if (authz->has_anon_rights)
-        return resolve_global_rights(rights_p, &authz->anon_rights, repos);
+        {
+          return resolve_global_rights(rights_p, &authz->anon_rights, repos);
+        }
+      else
+        {
+          /* Return the implicit rights, i.e., none. */
+          rights_p->min_access = authz_access_none;
+          rights_p->max_access = authz_access_none;
+          return FALSE;
+        }
     }
   else
     {
+      svn_boolean_t combine_user_rights = FALSE;
+      svn_boolean_t access = FALSE;
+
       /* Check if we have explicit rights for this user. */
       const authz_global_rights_t *const user_rights =
         svn_hash_gets(authz->user_rights, user);
 
       if (user_rights)
         {
-          svn_boolean_t explicit
-            = resolve_global_rights(rights_p, user_rights, repos);
-
-          /* Rights given to _any_ authenticated user may apply, too. */
-          if (authz->has_authn_rights)
-            {
-              authz_rights_t authn;
-              explicit |= resolve_global_rights(&authn, &authz->authn_rights,
-                                                repos);
-              combine_rights(rights_p, rights_p, &authn);
-            }
-          return explicit;
+          access = resolve_global_rights(rights_p, user_rights, repos);
+          combine_user_rights = TRUE;
+        }
+      else if (authz->has_neg_rights)
+        {
+          /* Check if inverted-rule rights apply */
+          access = resolve_global_rights(rights_p, &authz->neg_rights, repos);
+          combine_user_rights = TRUE;
         }
 
-      /* Check if we have explicit rights for authenticated access. */
+      /* Rights given to _any_ authenticated user may apply, too. */
       if (authz->has_authn_rights)
-        return resolve_global_rights(rights_p, &authz->authn_rights, repos);
-    }
+        {
+          authz_rights_t authn;
+          access |= resolve_global_rights(&authn, &authz->authn_rights, repos);
 
-  /* Fall-through: return the implicit rights, i.e., none. */
-  rights_p->min_access = authz_access_none;
-  rights_p->max_access = authz_access_none;
-  return FALSE;
+          if (combine_user_rights)
+            combine_rights(rights_p, rights_p, &authn);
+          else
+            *rights_p = authn;
+        }
+
+      return access;
+    }
 }

Modified: subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_repos/authz_parse.c Sat Dec 15 19:23:40 2018
@@ -154,6 +154,8 @@ static const char anon_access_token[] =
 /* The authenticated access token. */
 static const char authn_access_token[] = "$authenticated";
 
+/* Fake token for inverted rights. */
+static const char neg_access_token[] = "~~$inverted";
 
 /* Initialize a rights structure.
    The minimum rights start with all available access and are later
@@ -191,6 +193,8 @@ insert_default_acl(ctor_baton_t *cb)
   acl->acl.has_anon_access = TRUE;
   acl->acl.authn_access = authz_access_none;
   acl->acl.has_authn_access = TRUE;
+  acl->acl.neg_access = authz_access_none;
+  acl->acl.has_neg_access = TRUE;
   acl->acl.user_access = NULL;
   acl->aces = svn_hash__make(cb->parser_pool);
   acl->alias_aces = svn_hash__make(cb->parser_pool);
@@ -208,6 +212,7 @@ create_ctor_baton(apr_pool_t *result_poo
   authz_full_t *const authz = apr_pcalloc(result_pool, sizeof(*authz));
   init_global_rights(&authz->anon_rights, anon_access_token, result_pool);
   init_global_rights(&authz->authn_rights, authn_access_token, result_pool);
+  init_global_rights(&authz->neg_rights, neg_access_token, result_pool);
   authz->user_rights = svn_hash__make(result_pool);
   authz->pool = result_pool;
 
@@ -758,6 +763,8 @@ rules_open_section(void *baton, svn_stri
   acl.acl.has_anon_access = FALSE;
   acl.acl.authn_access = authz_access_none;
   acl.acl.has_authn_access = FALSE;
+  acl.acl.neg_access = authz_access_none;
+  acl.acl.has_neg_access = FALSE;
   acl.acl.user_access = NULL;
 
   acl.aces = svn_hash__make(cb->parser_pool);
@@ -958,6 +965,14 @@ add_access_entry(ctor_baton_t *cb, svn_s
           if (!aliased && *ace->name != '@')
             prepare_global_rights(cb, ace->name);
         }
+
+      /* Propagate rights for inverted selectors to the global rights, otherwise
+         an access check can bail out early. See: SVN-4793 */
+      if (inverted)
+        {
+          acl->acl.has_neg_access = TRUE;
+          acl->acl.neg_access |= access;
+        }
     }
 
   return SVN_NO_ERROR;
@@ -1271,6 +1286,12 @@ expand_acl_callback(void *baton,
       update_global_rights(&cb->authz->authn_rights,
                            acl->rule.repos, acl->authn_access);
     }
+  if (acl->has_neg_access)
+    {
+      cb->authz->has_neg_rights = TRUE;
+      update_global_rights(&cb->authz->neg_rights,
+                           acl->rule.repos, acl->neg_access);
+    }
   SVN_ERR(svn_iter_apr_hash(NULL, cb->authz->user_rights,
                             update_user_rights, acl, scratch_pool));
   return SVN_NO_ERROR;

Modified: subversion/branches/swig-py3/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/config_file.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_subr/config_file.c Sat Dec 15 19:23:40 2018
@@ -1045,7 +1045,7 @@ svn_config_ensure(const char *config_dir
    "The syntax of the configuration files is a subset of the one used by"    NL
    "Python's ConfigParser module; see"                                       NL
    ""                                                                        NL
-   "   http://www.python.org/doc/current/lib/module-ConfigParser.html"       NL
+   "   https://docs.python.org/3/library/configparser.html"                  NL
    ""                                                                        NL
    "Configuration data in the Windows registry"                              NL
    "=========================================="                              NL

Modified: subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_subr/dirent_uri.c Sat Dec 15 19:23:40 2018
@@ -292,8 +292,9 @@ uri_previous_segment(const char *uri,
 /* Return the canonicalized version of PATH, of type TYPE, allocated in
  * POOL.
  */
-static const char *
-canonicalize(path_type_t type, const char *path, apr_pool_t *pool)
+static svn_error_t *
+canonicalize(const char **canonical_path,
+             path_type_t type, const char *path, apr_pool_t *pool)
 {
   char *canon, *dst;
   const char *src;
@@ -307,8 +308,12 @@ canonicalize(path_type_t type, const cha
      depends on path not being zero-length.  */
   if (SVN_PATH_IS_EMPTY(path))
     {
-      assert(type != type_uri);
-      return "";
+      *canonical_path = "";
+      if (type == type_uri)
+        return svn_error_create(SVN_ERR_CANONICALIZATION_FAILED, NULL,
+                                _("An empty URI can not be canonicalized"));
+      else
+        return SVN_NO_ERROR;
     }
 
   dst = canon = apr_pcalloc(pool, strlen(path) + 1);
@@ -319,7 +324,12 @@ canonicalize(path_type_t type, const cha
   src = path;
   if (type == type_uri)
     {
-      assert(*src != '/');
+      if (*src == '/')
+        {
+          *canonical_path = src;
+          return svn_error_create(SVN_ERR_CANONICALIZATION_FAILED, NULL,
+                                  _("A URI can not start with '/'"));
+        }
 
       while (*src && (*src != '/') && (*src != ':'))
         src++;
@@ -546,7 +556,10 @@ canonicalize(path_type_t type, const cha
   if ((type == type_dirent) && canon[0] == '/' && canon[1] == '/')
     {
       if (canon_segments < 2)
-        return canon + 1;
+        {
+          *canonical_path = canon + 1;
+          return SVN_NO_ERROR;
+        }
       else
         {
           /* Now we're sure this is a valid UNC path, convert the server name
@@ -654,7 +667,8 @@ canonicalize(path_type_t type, const cha
       *dst = '\0';
     }
 
-  return canon;
+  *canonical_path = canon;
+  return SVN_NO_ERROR;
 }
 
 /* Return the string length of the longest common ancestor of PATH1 and PATH2.
@@ -883,6 +897,20 @@ svn_dirent_internal_style(const char *di
   return svn_dirent_canonicalize(internal_style(dirent, pool), pool);
 }
 
+svn_error_t *
+svn_dirent_internal_style_safe(const char **internal_style_dirent,
+                               const char **non_canonical_result,
+                               const char *dirent,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(
+      svn_dirent_canonicalize_safe(internal_style_dirent,
+                                   non_canonical_result,
+                                   internal_style(dirent, scratch_pool),
+                                   result_pool, scratch_pool));
+}
+
 const char *
 svn_dirent_local_style(const char *dirent, apr_pool_t *pool)
 {
@@ -1643,19 +1671,84 @@ svn_dirent_get_absolute(const char **pab
 const char *
 svn_uri_canonicalize(const char *uri, apr_pool_t *pool)
 {
-  return canonicalize(type_uri, uri, pool);
+  const char *result;
+  svn_error_t *const err = canonicalize(&result, type_uri, uri, pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      SVN_ERR_ASSERT_NO_RETURN(!"URI canonicalization failed");
+    }
+  return result;
+}
+
+svn_error_t *
+svn_uri_canonicalize_safe(const char **canonical_uri,
+                          const char **non_canonical_result,
+                          const char *uri,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  const char *result = NULL;
+  SVN_ERR(canonicalize(&result, type_uri, uri, result_pool));
+  if (!svn_uri_is_canonical(result, scratch_pool))
+    {
+      if (non_canonical_result)
+        *non_canonical_result = result;
+
+      return svn_error_createf(
+          SVN_ERR_CANONICALIZATION_FAILED, NULL,
+          _("Could not canonicalize URI '%s'"
+            " (the result '%s' is not canonical)"),
+          uri, result);
+    }
+  *canonical_uri = result;
+  return SVN_NO_ERROR;
 }
 
 const char *
 svn_relpath_canonicalize(const char *relpath, apr_pool_t *pool)
 {
-  return canonicalize(type_relpath, relpath, pool);
+  const char *result;
+  svn_error_t *const err = canonicalize(&result, type_relpath, relpath, pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      SVN_ERR_ASSERT_NO_RETURN(!"relpath canonicalization failed");
+    }
+  return result;
 }
 
-const char *
-svn_dirent_canonicalize(const char *dirent, apr_pool_t *pool)
+svn_error_t *
+svn_relpath_canonicalize_safe(const char **canonical_relpath,
+                              const char **non_canonical_result,
+                              const char *relpath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  const char *result = NULL;
+  SVN_ERR(canonicalize(&result, type_relpath, relpath, result_pool));
+  if (!svn_relpath_is_canonical(result))
+    {
+      if (non_canonical_result)
+        *non_canonical_result = result;
+
+      return svn_error_createf(
+          SVN_ERR_CANONICALIZATION_FAILED, NULL,
+          _("Could not canonicalize relpath '%s'"
+            " (the result '%s' is not canonical)"),
+          relpath, result);
+    }
+
+  SVN_UNUSED(scratch_pool);
+  *canonical_relpath = result;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+canonicalize_dirent(const char **result, const char *dirent, apr_pool_t *pool)
 {
-  const char *dst = canonicalize(type_dirent, dirent, pool);
+  const char *dst;
+  SVN_ERR(canonicalize(&dst, type_dirent, dirent, pool));
 
 #ifdef SVN_USE_DOS_PATHS
   /* Handle a specific case on Windows where path == "X:/". Here we have to
@@ -1671,11 +1764,50 @@ svn_dirent_canonicalize(const char *dire
       dst_slash[2] = '/';
       dst_slash[3] = '\0';
 
-      return dst_slash;
+      *result = dst_slash;
+      return SVN_NO_ERROR;
     }
 #endif /* SVN_USE_DOS_PATHS */
 
-  return dst;
+  *result = dst;
+  return SVN_NO_ERROR;
+}
+
+const char *
+svn_dirent_canonicalize(const char *dirent, apr_pool_t *pool)
+{
+  const char *result;
+  svn_error_t *const err = canonicalize_dirent(&result, dirent, pool);
+  if (err)
+    {
+      svn_error_clear(err);
+      SVN_ERR_ASSERT_NO_RETURN(!"dirent canonicalization failed");
+    }
+  return result;
+}
+
+svn_error_t *
+svn_dirent_canonicalize_safe(const char **canonical_dirent,
+                             const char **non_canonical_result,
+                             const char *dirent,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  const char *result = NULL;
+  SVN_ERR(canonicalize_dirent(&result, dirent, result_pool));
+  if (!svn_dirent_is_canonical(result, scratch_pool))
+    {
+      if (non_canonical_result)
+        *non_canonical_result = result;
+
+      return svn_error_createf(
+          SVN_ERR_CANONICALIZATION_FAILED, NULL,
+          _("Could not canonicalize dirent '%s'"
+            " (the result '%s' is not canonical)"),
+          dirent, result);
+    }
+  *canonical_dirent = result;
+  return SVN_NO_ERROR;
 }
 
 svn_boolean_t

Propchange: subversion/branches/swig-py3/subversion/libsvn_subr/lz4/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -0,0 +1 @@
+.libs

Modified: subversion/branches/swig-py3/subversion/libsvn_subr/win32_crashrpt.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/win32_crashrpt.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/libsvn_subr/win32_crashrpt.c (original)
+++ subversion/branches/swig-py3/subversion/libsvn_subr/win32_crashrpt.c Sat Dec 15 19:23:40 2018
@@ -45,9 +45,6 @@ typedef int win32_crashrpt__dummy;
 /*** Global variables ***/
 static HANDLE dbghelp_dll = INVALID_HANDLE_VALUE;
 
-/* Email address where the crash reports should be sent too. */
-#define CRASHREPORT_EMAIL "users@subversion.apache.org"
-
 #define DBGHELP_DLL "dbghelp.dll"
 
 #define LOGFILE_PREFIX "svn-crash-log"
@@ -774,7 +771,7 @@ svn__unhandled_exception_filter(PEXCEPTI
                   "usernames and passwords etc.)\n",
                   log_filename,
                   dmp_filename,
-                  CRASHREPORT_EMAIL);
+                  SVN_WIN32_CRASHREPORT_EMAIL);
 
   if (getenv("SVN_DBG_STACKTRACES_TO_STDERR") != NULL)
     {

Propchange: subversion/branches/swig-py3/subversion/svnfsfs/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -1 +1,2 @@
 svnfsfs
+.libs

Modified: subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py (original)
+++ subversion/branches/swig-py3/subversion/tests/cmdline/authz_tests.py Sat Dec 15 19:23:40 2018
@@ -1663,13 +1663,11 @@ def remove_access_after_commit(sbox):
                                         expected_status,
                                         [], True)
 
-@XFail()
+@Issue(4793)
 @Skip(svntest.main.is_ra_type_file)
 def inverted_group_membership(sbox):
   "access rights for user in inverted group"
 
-  # Bug reported here: https://lists.apache.org/thread.html/6cc7b22b211827ff946373407a516a3ab4d866fe03cdc85d22ff276b@%3Cdev.subversion.apache.org%3E
-
   sbox.build(create_wc = False)
 
   svntest.actions.enable_revprop_changes(sbox.repo_dir)
@@ -1694,6 +1692,24 @@ def inverted_group_membership(sbox):
                                      '--username', svntest.main.wc_author,
                                      sbox.repo_url)
 
+@Skip(svntest.main.is_ra_type_file)
+def group_member_empty_string(sbox):
+  "group definition ignores with empty member"
+
+  sbox.build(create_wc = False)
+
+  write_restrictive_svnserve_conf(sbox.repo_dir)
+  write_authz_file(sbox,
+                   {"/" : ("$anonymous =\n"
+                           "@readonly = r\n")},
+                   {"groups": "readonly = , %s\n" % svntest.main.wc_author})
+
+  expected_output = svntest.verify.UnorderedOutput(['A/\n', 'iota\n'])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'list',
+                                     '--username', svntest.main.wc_author,
+                                     sbox.repo_url)
+
 
 ########################################################################
 # Run the tests
@@ -1732,6 +1748,7 @@ test_list = [ None,
               authz_log_censor_revprops,
               remove_access_after_commit,
               inverted_group_membership,
+              group_member_empty_string,
              ]
 serial_only = True
 

Modified: subversion/branches/swig-py3/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/externals_tests.py?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/swig-py3/subversion/tests/cmdline/externals_tests.py Sat Dec 15 19:23:40 2018
@@ -2949,10 +2949,11 @@ def url_to_wc_copy_of_externals(sbox):
     "A         " + external_root_path + "\n",
     "\n",
     "Fetching external item into '" + external_ex_path + "':\n",
-    "A         " + external_ex_path + "\n",
-    "A         " + external_pi_path + "\n",
-    "A         " + external_rho_path + "\n",
-    "A         " + external_tau_path + "\n",
+    "A    " + external_pi_path + "\n",
+    "A    " + external_rho_path + "\n",
+    "A    " + external_tau_path + "\n",
+    "Checked out external at revision 2.\n",
+    "\n",
   ])
   exit_code, stdout, stderr = svntest.actions.run_and_verify_svn2(
     expected_stdout, [], 0, 'copy', repo_url + '/A/C',

Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py (original)
+++ subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py Sat Dec 15 19:23:40 2018
@@ -896,6 +896,75 @@ def svnauthz_compat_mode_repo_test(sbox)
       repo_url + "/zilch"
   )
 
+
+@Issue(4793)
+def svnauthz_inverted_selector_test(sbox):
+  "test inverted selector rights"
+
+  # build an authz file
+  authz_content = ("[groups]\n"
+                   "grouped = grouper\n"
+
+                   "[aliases]\n"
+                   "aliased = aliaser\n"
+
+                   "[A:/]\n"
+                   "@grouped = r\n"
+                   "~@grouped = rw\n"
+
+                   "[B:/]\n"
+                   "&aliased = r\n"
+                   "~&aliased = rw\n"
+
+                   "[C:/]\n"
+                   "user = r\n"
+                   "~user = rw\n"
+
+                   "[D:/]\n"
+                   "~@grouped = rw\n"
+                   "not-grouper = r\n"
+
+                   "[E:/]\n"
+                   "~&aliased = rw\n"
+                   "not-aliaser = r\n"
+
+                   "[F:/]\n"
+                   "~user = rw\n"
+                   "not-user = r\n")
+
+  (authz_fd, authz_path) = tempfile.mkstemp()
+  svntest.main.file_write(authz_path, authz_content)
+
+  def accessof(repos, user, expected_stdout):
+    return svntest.actions.run_and_verify_svnauthz(
+      expected_stdout, None, 0, False, 'accessof',
+      '--repository', repos, '--username', user, authz_path)
+
+  accessof('A', 'grouper', 'r')
+  accessof('A', 'not-grouper', 'rw')
+
+  accessof('B', 'aliaser', 'r')
+  accessof('B', 'not-aliaser', 'rw')
+
+  accessof('C', 'user', 'r')
+  accessof('C', 'not-user', 'rw')
+
+  accessof('D', 'grouper', 'no')
+  accessof('D', 'not-grouper', 'r')
+  accessof('D', 'other', 'rw')
+
+  accessof('E', 'aliaser', 'no')
+  accessof('E', 'not-aliaser', 'r')
+  accessof('E', 'other', 'rw')
+
+  accessof('F', 'user', 'no')
+  accessof('F', 'not-user', 'r')
+  accessof('F', 'other', 'rw')
+
+  os.close(authz_fd)
+  os.remove(authz_path)
+
+
 ########################################################################
 # Run the tests
 
@@ -914,6 +983,7 @@ test_list = [ None,
               svnauthz_accessof_txn_test,
               svnauthz_compat_mode_file_test,
               svnauthz_compat_mode_repo_test,
+              svnauthz_inverted_selector_test,
              ]
 
 if __name__ == '__main__':

Propchange: subversion/branches/swig-py3/subversion/tests/libsvn_client/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -1,4 +1,15 @@
-.libs
 *-test
 *.lo
+.libs
+mtcc-anchoring
+mtcc-file-revs
+mtcc-iprops-paths
+mtcc-mkdir
+mtcc-mkgreek
+mtcc-move-and-delete
+mtcc-overwrite
+mtcc-propset
+mtcc-replace_tree
+mtcc-swap
+mtcc-update-files
 svn-test-work

Modified: subversion/branches/swig-py3/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_client/client-test.c?rev=1849003&r1=1849002&r2=1849003&view=diff
==============================================================================
--- subversion/branches/swig-py3/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/branches/swig-py3/subversion/tests/libsvn_client/client-test.c Sat Dec 15 19:23:40 2018
@@ -31,6 +31,7 @@
 #include "../../libsvn_client/client.h"
 #include "svn_pools.h"
 #include "svn_client.h"
+#include "private/svn_client_private.h"
 #include "private/svn_client_mtcc.h"
 #include "svn_repos.h"
 #include "svn_subst.h"
@@ -765,17 +766,18 @@ test_foreign_repos_copy(const svn_test_o
 
   loc->url = svn_path_url_add_component2(repos2_url, "A", pool);
   SVN_WC__CALL_WITH_WRITE_LOCK(
-    svn_client__copy_foreign(loc,
+    svn_client__repos_to_wc_copy_by_editor(NULL /*sleep*/, svn_node_dir,
+                             loc->url, loc->rev,
                              svn_dirent_join(wc_path, "A-copied", pool),
-                             svn_depth_infinity,
                              ra_session, ctx, pool),
     ctx->wc_ctx, wc_path, FALSE, pool);
 
+  SVN_ERR(svn_ra_reparent(ra_session, repos2_url, pool));
   loc->url = svn_path_url_add_component2(repos2_url, "iota", pool);
   SVN_WC__CALL_WITH_WRITE_LOCK(
-    svn_client__copy_foreign(loc,
+    svn_client__repos_to_wc_copy_by_editor(NULL /*sleep*/, svn_node_file,
+                             loc->url, loc->rev,
                              svn_dirent_join(wc_path, "iota-copied", pool),
-                             svn_depth_infinity,
                              ra_session, ctx, pool),
     ctx->wc_ctx, wc_path, FALSE, pool);
 

Propchange: subversion/branches/swig-py3/subversion/tests/libsvn_ra/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -1,4 +1,13 @@
 *.lo
 .libs
+base_revision_above_youngest
+commit_cb_failure
+commit_empty_last_change
+delete_revision_above_youngest
+errors_from_callbacks
 ra-test
+ra_list_has_props
+ra_revision_errors
+test-get-dir
 test-repo-*
+test-run_checkout

Propchange: subversion/branches/swig-py3/subversion/tests/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -56,3 +56,6 @@ sqlite-test-*
 x509-test
 xml-test
 test_apr_trunc_workaround
+save-cleartext
+test_stream_readline_file_crlf
+test_stream_readline_file_lf

Propchange: subversion/branches/swig-py3/tools/client-side/svnconflict/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -1 +1,2 @@
 svnconflict
+.libs

Propchange: subversion/branches/swig-py3/tools/dev/svnmover/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -1 +1,2 @@
 svnmover
+.libs

Propchange: subversion/branches/swig-py3/tools/dev/wc-ng/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat Dec 15 19:23:40 2018
@@ -1 +1,2 @@
 svn-wc-db-tester
+.libs