Modified: subversion/branches/addremove/subversion/svnrdump/svnrdump.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnrdump/svnrdump.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnrdump/svnrdump.c (original)
+++ subversion/branches/addremove/subversion/svnrdump/svnrdump.c Sat May 23 
14:16:56 2020
@@ -59,6 +59,7 @@ enum svn_svnrdump__longopt_t
     opt_config_option,
     opt_auth_username,
     opt_auth_password,
+    opt_auth_password_from_stdin,
     opt_auth_nocache,
     opt_non_interactive,
     opt_skip_revprop,
@@ -73,29 +74,38 @@ enum svn_svnrdump__longopt_t
                                    opt_config_option, \
                                    opt_auth_username, \
                                    opt_auth_password, \
+                                   opt_auth_password_from_stdin, \
                                    opt_auth_nocache, \
                                    opt_trust_server_cert, \
                                    opt_trust_server_cert_failures, \
                                    opt_non_interactive, \
                                    opt_force_interactive
 
-static const svn_opt_subcommand_desc2_t svnrdump__cmd_table[] =
+static const svn_opt_subcommand_desc3_t svnrdump__cmd_table[] =
 {
-  { "dump", dump_cmd, { 0 },
-    N_("usage: svnrdump dump URL [-r LOWER[:UPPER]]\n\n"
+  { "dump", dump_cmd, { 0 }, {N_(
+       "usage: svnrdump dump URL [-r LOWER[:UPPER]]\n"
+       "\n"), N_(
        "Dump revisions LOWER to UPPER of repository at remote URL to stdout\n"
        "in a 'dumpfile' portable format.  If only LOWER is given, dump that\n"
-       "one revision.\n"),
-    { 'r', 'q', opt_incremental, SVN_SVNRDUMP__BASE_OPTIONS } },
-  { "load", load_cmd, { 0 },
-    N_("usage: svnrdump load URL\n\n"
-       "Load a 'dumpfile' given on stdin to a repository at remote URL.\n"),
-    { 'q', opt_skip_revprop, SVN_SVNRDUMP__BASE_OPTIONS } },
-  { "help", 0, { "?", "h" },
-    N_("usage: svnrdump help [SUBCOMMAND...]\n\n"
-       "Describe the usage of this program or its subcommands.\n"),
+       "one revision.\n"
+    )},
+    { 'r', 'q', opt_incremental, 'F', SVN_SVNRDUMP__BASE_OPTIONS },
+    {{'F', N_("write to file ARG instead of stdout")}} },
+  { "load", load_cmd, { 0 }, {N_(
+       "usage: svnrdump load URL\n"
+       "\n"), N_(
+       "Load a 'dumpfile' given on stdin to a repository at remote URL.\n"
+    )},
+    { 'q', opt_skip_revprop, 'F', SVN_SVNRDUMP__BASE_OPTIONS },
+    {{'F', N_("read from file ARG instead of stdin")}} },
+  { "help", 0, { "?", "h" }, {N_(
+       "usage: svnrdump help [SUBCOMMAND...]\n"
+       "\n"), N_(
+       "Describe the usage of this program or its subcommands.\n"
+    )},
     { 0 } },
-  { NULL, NULL, { 0 }, NULL, { 0 } }
+  { NULL, NULL, { 0 }, {NULL}, { 0 } }
 };
 
 static const apr_getopt_option_t svnrdump__options[] =
@@ -114,6 +124,8 @@ static const apr_getopt_option_t svnrdum
                       N_("specify a username ARG")},
     {"password",      opt_auth_password, 1,
                       N_("specify a password ARG")},
+    {"password-from-stdin",   opt_auth_password_from_stdin, 0,
+                      N_("read password from stdin")},
     {"non-interactive", opt_non_interactive, 0,
                       N_("do no interactive prompting (default is to prompt\n"
                          "                             "
@@ -154,6 +166,8 @@ static const apr_getopt_option_t svnrdum
                        "valid certificate) and 'other' (all other not\n"
                        "                             "
                        "separately classified certificate errors).")},
+    {"file",          'F', 1,
+                      N_("read/write file ARG instead of stdin/stdout")},
     {0, 0, 0, 0}
   };
 
@@ -174,6 +188,7 @@ typedef struct opt_baton_t {
   svn_client_ctx_t *ctx;
   svn_ra_session_t *session;
   const char *url;
+  const char *dumpfile;
   svn_boolean_t help;
   svn_boolean_t version;
   svn_opt_revision_t start_revision;
@@ -332,7 +347,7 @@ init_client_context(svn_client_ctx_t **c
      ### auxiliary GETs/PROPFINDs to happening (well-ordered) on a
      ### single server connection.
      ###
-     ### See http://subversion.tigris.org/issues/show_bug.cgi?id=4116.
+     ### See https://issues.apache.org/jira/browse/SVN-4116.
   */
   cfg_servers = svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_SERVERS);
   svn_config_set_bool(cfg_servers, SVN_CONFIG_SECTION_GLOBAL,
@@ -417,7 +432,7 @@ dump_initial_full_revision(svn_ra_sessio
      our update-driven dump generation work the way a replay-driven
      one would.
 
-     See http://subversion.tigris.org/issues/show_bug.cgi?id=4101
+     See https://issues.apache.org/jira/browse/SVN-4101
   */
   SVN_ERR(svn_ra_get_session_url(session, &session_url, pool));
   SVN_ERR(svn_ra_get_path_relative_to_root(session, &source_relpath,
@@ -463,31 +478,38 @@ replay_revisions(svn_ra_session_t *sessi
                  svn_revnum_t end_revision,
                  svn_boolean_t quiet,
                  svn_boolean_t incremental,
+                 const char *dumpfile,
                  apr_pool_t *pool)
 {
   struct replay_baton *replay_baton;
   const char *uuid;
-  svn_stream_t *stdout_stream;
+  svn_stream_t *output_stream;
 
-  SVN_ERR(svn_stream_for_stdout(&stdout_stream, pool));
+  if (dumpfile)
+    {
+      SVN_ERR(svn_stream_open_writable(&output_stream, dumpfile, pool, pool));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_for_stdout(&output_stream, pool));
+    }
 
   replay_baton = apr_pcalloc(pool, sizeof(*replay_baton));
-  replay_baton->stdout_stream = stdout_stream;
+  replay_baton->stdout_stream = output_stream;
   replay_baton->extra_ra_session = extra_ra_session;
   replay_baton->quiet = quiet;
 
   /* Write the magic header and UUID */
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_MAGIC_HEADER ": %d\n\n",
-                            SVN_REPOS_DUMPFILE_FORMAT_VERSION));
+  SVN_ERR(svn_repos__dump_magic_header_record(output_stream,
+                                              
SVN_REPOS_DUMPFILE_FORMAT_VERSION,
+                                              pool));
   SVN_ERR(svn_ra_get_uuid2(session, &uuid, pool));
-  SVN_ERR(svn_stream_printf(stdout_stream, pool,
-                            SVN_REPOS_DUMPFILE_UUID ": %s\n\n", uuid));
+  SVN_ERR(svn_repos__dump_uuid_header_record(output_stream, uuid, pool));
 
   /* Fake revision 0 if necessary */
   if (start_revision == 0)
     {
-      SVN_ERR(dump_revision_header(session, stdout_stream,
+      SVN_ERR(dump_revision_header(session, output_stream,
                                    start_revision, pool));
 
       /* Revision 0 has no tree changes, so we're done. */
@@ -506,7 +528,7 @@ replay_revisions(svn_ra_session_t *sessi
   if (!incremental)
     {
       SVN_ERR(dump_initial_full_revision(session, extra_ra_session,
-                                         stdout_stream, start_revision,
+                                         output_stream, start_revision,
                                          quiet, pool));
       start_revision++;
     }
@@ -526,6 +548,7 @@ replay_revisions(svn_ra_session_t *sessi
 #endif
     }
 
+  SVN_ERR(svn_stream_close(output_stream));
   return SVN_NO_ERROR;
 }
 
@@ -538,19 +561,27 @@ replay_revisions(svn_ra_session_t *sessi
 static svn_error_t *
 load_revisions(svn_ra_session_t *session,
                svn_ra_session_t *aux_session,
-               const char *url,
+               const char *dumpfile,
                svn_boolean_t quiet,
                apr_hash_t *skip_revprops,
                apr_pool_t *pool)
 {
-  svn_stream_t *stdin_stream;
+  svn_stream_t *output_stream;
 
-  SVN_ERR(svn_stream_for_stdin2(&stdin_stream, TRUE, pool));
+  if (dumpfile)
+    {
+      SVN_ERR(svn_stream_open_readonly(&output_stream, dumpfile, pool, pool));
+    }
+  else
+    {
+      SVN_ERR(svn_stream_for_stdin2(&output_stream, TRUE, pool));
+    }
 
-  SVN_ERR(svn_rdump__load_dumpstream(stdin_stream, session, aux_session,
+  SVN_ERR(svn_rdump__load_dumpstream(output_stream, session, aux_session,
                                      quiet, skip_revprops,
                                      check_cancel, NULL, pool));
 
+  SVN_ERR(svn_stream_close(output_stream));
   return SVN_NO_ERROR;
 }
 
@@ -591,7 +622,7 @@ version(const char *progname,
                          pool);
 
   SVN_ERR(svn_ra_print_modules(version_footer, pool));
-  return svn_opt_print_help4(NULL, ensure_appname(progname, pool),
+  return svn_opt_print_help5(NULL, ensure_appname(progname, pool),
                              TRUE, quiet, FALSE, version_footer->data,
                              NULL, NULL, NULL, NULL, NULL, pool);
 }
@@ -616,7 +647,8 @@ dump_cmd(apr_getopt_t *os,
   return replay_revisions(opt_baton->session, extra_ra_session,
                           opt_baton->start_revision.value.number,
                           opt_baton->end_revision.value.number,
-                          opt_baton->quiet, opt_baton->incremental, pool);
+                          opt_baton->quiet, opt_baton->incremental,
+                          opt_baton->dumpfile, pool);
 }
 
 /* Handle the "load" subcommand.  Implements `svn_opt_subcommand_t'.  */
@@ -630,8 +662,9 @@ load_cmd(apr_getopt_t *os,
 
   SVN_ERR(svn_client_open_ra_session2(&aux_session, opt_baton->url, NULL,
                                       opt_baton->ctx, pool, pool));
-  return load_revisions(opt_baton->session, aux_session, opt_baton->url,
-                        opt_baton->quiet, opt_baton->skip_revprops, pool);
+  return load_revisions(opt_baton->session, aux_session,
+                        opt_baton->dumpfile, opt_baton->quiet,
+                        opt_baton->skip_revprops, pool);
 }
 
 /* Handle the "help" subcommand.  Implements `svn_opt_subcommand_t'.  */
@@ -648,7 +681,7 @@ help_cmd(apr_getopt_t *os,
       "\n"
       "Available subcommands:\n");
 
-  return svn_opt_print_help4(os, "svnrdump", FALSE, FALSE, FALSE, NULL,
+  return svn_opt_print_help5(os, "svnrdump", FALSE, FALSE, FALSE, NULL,
                              header, svnrdump__cmd_table, svnrdump__options,
                              NULL, NULL, pool);
 }
@@ -754,7 +787,7 @@ static svn_error_t *
 sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
 {
   svn_error_t *err = SVN_NO_ERROR;
-  const svn_opt_subcommand_desc2_t *subcommand = NULL;
+  const svn_opt_subcommand_desc3_t *subcommand = NULL;
   opt_baton_t *opt_baton;
   svn_revnum_t latest_revision = SVN_INVALID_REVNUM;
   const char *config_dir = NULL;
@@ -772,12 +805,14 @@ sub_main(int *exit_code, int argc, const
   apr_getopt_t *os;
   apr_array_header_t *received_opts;
   int i;
+  svn_boolean_t read_pass_from_stdin = FALSE;
 
   opt_baton = apr_pcalloc(pool, sizeof(*opt_baton));
   opt_baton->start_revision.kind = svn_opt_revision_unspecified;
   opt_baton->end_revision.kind = svn_opt_revision_unspecified;
   opt_baton->url = NULL;
   opt_baton->skip_revprops = apr_hash_make(pool);
+  opt_baton->dumpfile = NULL;
 
   SVN_ERR(svn_cmdline__getopt_init(&os, argc, argv, pool));
 
@@ -850,6 +885,9 @@ sub_main(int *exit_code, int argc, const
         case opt_auth_password:
           SVN_ERR(svn_utf_cstring_to_utf8(&password, opt_arg, pool));
           break;
+        case opt_auth_password_from_stdin:
+          read_pass_from_stdin = TRUE;
+          break;
         case opt_auth_nocache:
           no_auth_cache = TRUE;
           break;
@@ -887,9 +925,14 @@ sub_main(int *exit_code, int argc, const
 
             SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
             SVN_ERR(svn_cmdline__parse_config_option(config_options,
-                                                     opt_arg, 
+                                                     opt_arg,
                                                      "svnrdump: ",
                                                      pool));
+          break;
+        case 'F':
+          SVN_ERR(svn_utf_cstring_to_utf8(&opt_arg, opt_arg, pool));
+          opt_baton->dumpfile = opt_arg;
+          break;
         }
     }
 
@@ -904,7 +947,7 @@ sub_main(int *exit_code, int argc, const
 
   if (opt_baton->help)
     {
-      subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
+      subcommand = svn_opt_get_canonical_subcommand3(svnrdump__cmd_table,
                                                      "help");
     }
   if (subcommand == NULL)
@@ -914,8 +957,8 @@ sub_main(int *exit_code, int argc, const
           if (opt_baton->version)
             {
               /* Use the "help" subcommand to handle the "--version" option. */
-              static const svn_opt_subcommand_desc2_t pseudo_cmd =
-                { "--version", help_cmd, {0}, "",
+              static const svn_opt_subcommand_desc3_t pseudo_cmd =
+                { "--version", help_cmd, {0}, {""},
                   {opt_version,  /* must accept its own option */
                    'q',  /* --quiet */
                   } };
@@ -935,7 +978,7 @@ sub_main(int *exit_code, int argc, const
 
           SVN_ERR(svn_utf_cstring_to_utf8(&first_arg, os->argv[os->ind++],
                                           pool));
-          subcommand = svn_opt_get_canonical_subcommand2(svnrdump__cmd_table,
+          subcommand = svn_opt_get_canonical_subcommand3(svnrdump__cmd_table,
                                                          first_arg);
 
           if (subcommand == NULL)
@@ -963,11 +1006,11 @@ sub_main(int *exit_code, int argc, const
       if (opt_id == 'h' || opt_id == '?')
         continue;
 
-      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
+      if (! svn_opt_subcommand_takes_option4(subcommand, opt_id, NULL))
         {
           const char *optstr;
           const apr_getopt_option_t *badopt =
-            svn_opt_get_option_from_code2(opt_id, svnrdump__options,
+            svn_opt_get_option_from_code3(opt_id, svnrdump__options,
                                           subcommand, pool);
           svn_opt_format_option(&optstr, badopt, FALSE, pool);
           if (subcommand->name[0] == '-')
@@ -1005,6 +1048,24 @@ sub_main(int *exit_code, int argc, const
                                   "--non-interactive"));
     }
 
+  if (read_pass_from_stdin && !non_interactive)
+    {
+      return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                              _("--password-from-stdin requires "
+                                "--non-interactive"));
+    }
+
+  if (strcmp(subcommand->name, "load") == 0)
+    {
+      if (read_pass_from_stdin && opt_baton->dumpfile == NULL)
+        {
+          /* error here, since load cannot process a password over stdin */
+          return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                  _("load subcommand with "
+                                    "--password-from-stdin requires -F"));
+        }
+    }
+
   /* Expect one more non-option argument:  the repository URL. */
   if (os->ind != os->argc - 1)
     {
@@ -1039,6 +1100,12 @@ sub_main(int *exit_code, int argc, const
         force_interactive = (username == NULL || password == NULL);
     }
 
+  /* Get password from stdin if necessary */
+  if (read_pass_from_stdin)
+    {
+      SVN_ERR(svn_cmdline__stdin_readline(&password, pool, pool));
+    }
+
   non_interactive = !svn_cmdline__be_interactive(non_interactive,
                                                  force_interactive);
 

Modified: subversion/branches/addremove/subversion/svnrdump/svnrdump.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnrdump/svnrdump.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnrdump/svnrdump.h (original)
+++ subversion/branches/addremove/subversion/svnrdump/svnrdump.h Sat May 23 
14:16:56 2020
@@ -77,12 +77,21 @@ svn_rdump__get_dump_editor_v2(svn_editor
 
 /**
  * Load the dumpstream carried in @a stream to the location described
- * by @a session.  Use @a aux_session (which is opened to the same URL
- * as @a session) for any secondary, out-of-band RA communications
- * required.  If @a quiet is set, suppress notifications.  Use @a pool
- * for all memory allocations.  Use @a cancel_func and @a cancel_baton
- * to check for user cancellation of the operation (for
- * timely-but-safe termination).
+ * by @a session.
+ *
+ * Use @a aux_session (which is opened to the same URL as @a session)
+ * for any secondary, out-of-band RA communications required. This is
+ * needed when loading a non-deltas dump, and for Ev2.
+ *
+ * Print feedback to the console for each revision, unless @a quiet is true.
+ *
+ * Ignore (don't set) any revision property whose name is a key in
+ * @a skip_revprops. The values in the hash are unimportant.
+ *
+ * Use @a cancel_func and @a cancel_baton to check for user cancellation
+ * of the operation (for timely-but-safe termination).
+ *
+ * Use @a pool for all memory allocations.
  */
 svn_error_t *
 svn_rdump__load_dumpstream(svn_stream_t *stream,

Modified: subversion/branches/addremove/subversion/svnrdump/util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnrdump/util.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnrdump/util.c (original)
+++ subversion/branches/addremove/subversion/svnrdump/util.c Sat May 23 
14:16:56 2020
@@ -46,8 +46,8 @@ svn_rdump__normalize_props(apr_hash_t **
       svn_pool_clear(iterpool);
 
       SVN_ERR(svn_repos__normalize_prop(&value, NULL, key, value,
-                                        result_pool, iterpool));
-      svn_hash_sets(*normal_props, key, value);
+                                        iterpool, iterpool));
+      svn_hash_sets(*normal_props, key, svn_string_dup(value, result_pool));
     }
   svn_pool_destroy(iterpool);
 

Modified: subversion/branches/addremove/subversion/svnserve/logger.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnserve/logger.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnserve/logger.c (original)
+++ subversion/branches/addremove/subversion/svnserve/logger.c Sat May 23 
14:16:56 2020
@@ -88,19 +88,21 @@ logger__create(logger_t **logger,
   return SVN_NO_ERROR;
 }
 
-void
-logger__log_error(logger_t *logger,
-                  svn_error_t *err,
-                  repository_t *repository,
-                  client_info_t *client_info)
+static void
+log_message(logger_t *logger,
+            const svn_error_t *err,
+            const char *prefix,
+            repository_t *repository,
+            client_info_t *client_info)
 {
   if (logger && err)
     {
       const char *timestr, *continuation;
       const char *user, *repos, *remote_host;
-      char errbuf[256];
+
       /* 8192 from MAX_STRING_LEN in from httpd-2.2.4/include/httpd.h */
-      char errstr[8192];
+      const apr_size_t errstr_size = 8192;
+      char *errstr = apr_palloc(logger->pool, errstr_size);
 
       svn_error_clear(svn_mutex__lock(logger->mutex));
 
@@ -118,21 +120,22 @@ logger__log_error(logger_t *logger,
       continuation = "";
       while (err)
         {
+          char errbuf[256];
           const char *message = svn_err_best_message(err, errbuf, 
sizeof(errbuf));
           /* based on httpd-2.2.4/server/log.c:log_error_core */
-          apr_size_t len = apr_snprintf(errstr, sizeof(errstr),
+          apr_size_t len = apr_snprintf(errstr, errstr_size,
                                         "%" APR_PID_T_FMT
-                                        " %s %s %s %s ERR%s %s %ld %d ",
+                                        " %s %s %s %s %s%s %s %ld %d ",
                                         getpid(), timestr, remote_host, user,
-                                        repos, continuation,
+                                        repos, prefix, continuation,
                                         err->file ? err->file : "-", err->line,
                                         err->apr_err);
 
           len += escape_errorlog_item(errstr + len, message,
-                                      sizeof(errstr) - len);
+                                      errstr_size - len);
           /* Truncate for the terminator (as apr_snprintf does) */
-          if (len > sizeof(errstr) - sizeof(APR_EOL_STR)) {
-            len = sizeof(errstr) - sizeof(APR_EOL_STR);
+          if (len > errstr_size - sizeof(APR_EOL_STR)) {
+            len = errstr_size - sizeof(APR_EOL_STR);
           }
 
           memcpy(errstr + len, APR_EOL_STR, sizeof(APR_EOL_STR));
@@ -150,6 +153,24 @@ logger__log_error(logger_t *logger,
     }
 }
 
+void
+logger__log_error(logger_t *logger,
+                  const svn_error_t *err,
+                  repository_t *repository,
+                  client_info_t *client_info)
+{
+  log_message(logger, err, "ERR", repository, client_info);
+}
+
+void
+logger__log_warning(logger_t *logger,
+                    const svn_error_t *err,
+                    repository_t *repository,
+                    client_info_t *client_info)
+{
+  log_message(logger, err, "WARN", repository, client_info);
+}
+
 svn_error_t *
 logger__write(logger_t *logger,
               const char *errstr,

Modified: subversion/branches/addremove/subversion/svnserve/logger.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnserve/logger.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnserve/logger.h (original)
+++ subversion/branches/addremove/subversion/svnserve/logger.h Sat May 23 
14:16:56 2020
@@ -64,14 +64,21 @@ logger__write(logger_t *logger,
 /* Write a description of ERR with additional information from REPOSITORY
  * and CLIENT_INFO to the log file managed by LOGGER.  REPOSITORY as well
  * as CLIENT_INFO may be NULL.  If either ERR or LOGGER are NULL, this
- * becomes a no-op.
+ * becomes a no-op. Does not clear ERR.
  */
 void
 logger__log_error(logger_t *logger,
-                  svn_error_t *err,
+                  const svn_error_t *err,
                   repository_t *repository,
                   client_info_t *client_info);
 
+/* Like logger__log_error() but for warnings. */
+void
+logger__log_warning(logger_t *logger,
+                    const svn_error_t *err,
+                    repository_t *repository,
+                    client_info_t *client_info);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/addremove/subversion/svnserve/serve.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnserve/serve.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnserve/serve.c (original)
+++ subversion/branches/addremove/subversion/svnserve/serve.c Sat May 23 
14:16:56 2020
@@ -107,15 +107,22 @@ typedef struct authz_baton_t {
   svn_ra_svn_conn_t *conn;
 } authz_baton_t;
 
-/* svn_error_create() a new error, log_server_error() it, and
-   return it. */
+/* Log an error. */
 static void
-log_error(svn_error_t *err, server_baton_t *server)
+log_error(const svn_error_t *err, server_baton_t *server)
 {
   logger__log_error(server->logger, err, server->repository,
                     server->client_info);
 }
 
+/* Log a warning. */
+static void
+log_warning(const svn_error_t *err, server_baton_t *server)
+{
+  logger__log_warning(server->logger, err, server->repository,
+                      server->client_info);
+}
+
 /* svn_error_create() a new error, log_server_error() it, and
    return it. */
 static svn_error_t *
@@ -264,17 +271,23 @@ canonicalize_access_file(const char **ac
 {
   if (svn_path_is_url(*access_file))
     {
-      *access_file = svn_uri_canonicalize(*access_file, pool);
+      const char *canonical_url;
+      SVN_ERR(svn_uri_canonicalize_safe(&canonical_url, NULL, *access_file,
+                                        pool, pool));
+      *access_file = canonical_url;
     }
   else if (svn_path_is_repos_relative_url(*access_file))
     {
       const char *repos_root_url;
+      const char *canonical_url;
 
       SVN_ERR(svn_uri_get_file_url_from_dirent(&repos_root_url, repos_root,
                                                pool));
       SVN_ERR(svn_path_resolve_repos_relative_url(access_file, *access_file,
                                                   repos_root_url, pool));
-      *access_file = svn_uri_canonicalize(*access_file, pool);
+      SVN_ERR(svn_uri_canonicalize_safe(&canonical_url, NULL, *access_file,
+                                        pool, pool));
+      *access_file = canonical_url;
     }
   else
     {
@@ -294,7 +307,10 @@ static svn_error_t *
 load_authz_config(repository_t *repository,
                   const char *repos_root,
                   svn_config_t *cfg,
-                  apr_pool_t *pool)
+                  svn_repos_authz_warning_func_t warning_func,
+                  void *warning_baton,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
   const char *authzdb_path;
   const char *groupsdb_path;
@@ -313,17 +329,18 @@ load_authz_config(repository_t *reposito
 
       /* Canonicalize and add the base onto the authzdb_path (if needed). */
       err = canonicalize_access_file(&authzdb_path, repository,
-                                     repos_root, pool);
+                                     repos_root, scratch_pool);
 
       /* Same for the groupsdb_path if it is present. */
       if (groupsdb_path && !err)
         err = canonicalize_access_file(&groupsdb_path, repository,
-                                       repos_root, pool);
+                                       repos_root, scratch_pool);
 
       if (!err)
-        err = svn_repos_authz_read3(&repository->authzdb, authzdb_path,
+        err = svn_repos_authz_read4(&repository->authzdb, authzdb_path,
                                     groupsdb_path, TRUE, repository->repos,
-                                    pool, pool);
+                                    warning_func, warning_baton,
+                                    result_pool, scratch_pool);
 
       if (err)
         return svn_error_create(SVN_ERR_AUTHZ_INVALID_CONFIG, err, NULL);
@@ -369,7 +386,7 @@ handle_config_error(svn_error_t *error,
 
       /* Now that we've logged the error, clear it and return a
        * nice, generic error to the user:
-       * http://subversion.tigris.org/issues/show_bug.cgi?id=2271 */
+       * https://issues.apache.org/jira/browse/SVN-2271 */
       svn_error_clear(error);
       return svn_error_create(apr_err, NULL, NULL);
     }
@@ -834,7 +851,7 @@ static svn_error_t *must_have_access(svn
 
 /* --- REPORTER COMMAND SET --- */
 
-/* To allow for pipelining, reporter commands have no reponses.  If we
+/* To allow for pipelining, reporter commands have no responses.  If we
  * get an error, we ignore all subsequent reporter commands and return
  * the error finish_report, to be handled by the calling command.
  */
@@ -843,7 +860,7 @@ static svn_error_t *set_path(svn_ra_svn_
                              svn_ra_svn__list_t *params, void *baton)
 {
   report_driver_baton_t *b = baton;
-  const char *path, *lock_token, *depth_word;
+  const char *path, *lock_token, *depth_word, *canonical_relpath;
   svn_revnum_t rev;
   /* Default to infinity, for old clients that don't send depth. */
   svn_depth_t depth = svn_depth_infinity;
@@ -854,7 +871,9 @@ static svn_error_t *set_path(svn_ra_svn_
                                   &depth_word));
   if (depth_word)
     depth = svn_depth_from_word(depth_word);
-  path = svn_relpath_canonicalize(path, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_relpath, NULL, path,
+                                        pool, pool));
+  path = canonical_relpath;
   if (b->from_rev && strcmp(path, "") == 0)
     *b->from_rev = rev;
   if (!b->err)
@@ -870,10 +889,12 @@ static svn_error_t *delete_path(svn_ra_s
                                 svn_ra_svn__list_t *params, void *baton)
 {
   report_driver_baton_t *b = baton;
-  const char *path;
+  const char *path, *canonical_relpath;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &path));
-  path = svn_relpath_canonicalize(path, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_relpath, NULL, path,
+                                        pool, pool));
+  path = canonical_relpath;
   if (!b->err)
     b->err = svn_repos_delete_path(b->report_baton, path, pool);
   return SVN_NO_ERROR;
@@ -883,7 +904,8 @@ static svn_error_t *link_path(svn_ra_svn
                               svn_ra_svn__list_t *params, void *baton)
 {
   report_driver_baton_t *b = baton;
-  const char *path, *url, *lock_token, *fs_path, *depth_word;
+  const char *path, *url, *lock_token, *fs_path, *depth_word, *canonical_url;
+  const char *canonical_path;
   svn_revnum_t rev;
   svn_boolean_t start_empty;
   /* Default to infinity, for old clients that don't send depth. */
@@ -895,8 +917,12 @@ static svn_error_t *link_path(svn_ra_svn
 
   /* ### WHAT?!  The link path is an absolute URL?!  Didn't see that
      coming...   -- cmpilato  */
-  path = svn_relpath_canonicalize(path, pool);
-  url = svn_uri_canonicalize(url, pool);
+
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
+  path = canonical_path;
+  SVN_ERR(svn_uri_canonicalize_safe(&canonical_url, NULL, url, pool, pool));
+  url = canonical_url;
   if (depth_word)
     depth = svn_depth_from_word(depth_word);
   if (!b->err)
@@ -1112,11 +1138,12 @@ reparent(svn_ra_svn_conn_t *conn,
          void *baton)
 {
   server_baton_t *b = baton;
-  const char *url;
+  const char *url, *canonical_url;
   const char *fs_path;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &url));
-  url = svn_uri_canonicalize(url, pool);
+  SVN_ERR(svn_uri_canonicalize_safe(&canonical_url, NULL, url, pool, pool));
+  url = canonical_url;
   SVN_ERR(trivial_auth_request(conn, pool, b));
   SVN_CMD_ERR(get_fs_path(svn_path_uri_decode(b->repository->repos_url, pool),
                           svn_path_uri_decode(url, pool),
@@ -1335,6 +1362,7 @@ add_lock_tokens(const svn_ra_svn__list_t
                 server_baton_t *sb,
                 apr_pool_t *pool)
 {
+  const char *canonical_path;
   int i;
   svn_fs_access_t *fs_access;
 
@@ -1364,9 +1392,10 @@ add_lock_tokens(const svn_ra_svn__list_t
                                 "Lock token isn't a string");
 
       path = path_item->u.string.data;
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                            pool, pool));
       full_path = svn_fspath__join(sb->repository->fs_path->data,
-                                   svn_relpath_canonicalize(path, pool),
-                                   pool);
+                                   canonical_path, pool);
 
       if (! lookup_access(pool, sb, svn_authz_write, full_path, TRUE))
         return error_create_and_log(SVN_ERR_RA_NOT_AUTHORIZED, NULL, NULL,
@@ -1404,6 +1433,7 @@ unlock_paths(const svn_ra_svn__list_t *l
   int i;
   apr_pool_t *subpool = svn_pool_create(pool);
   apr_hash_t *targets = apr_hash_make(subpool);
+  const char *canonical_path;
   svn_error_t *err;
 
   for (i = 0; i < lock_tokens->nelts; ++i)
@@ -1416,9 +1446,10 @@ unlock_paths(const svn_ra_svn__list_t *l
       token_item = &SVN_RA_SVN__LIST_ITEM(&item->u.list, 1);
 
       path = path_item->u.string.data;
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                            subpool, subpool));
       full_path = svn_fspath__join(sb->repository->fs_path->data,
-                                   svn_relpath_canonicalize(path, subpool),
-                                   subpool);
+                                   canonical_path, subpool);
       token = token_item->u.string.data;
       svn_hash_sets(targets, full_path, token);
     }
@@ -1558,7 +1589,7 @@ get_file(svn_ra_svn_conn_t *conn,
          void *baton)
 {
   server_baton_t *b = baton;
-  const char *path, *full_path, *hex_digest;
+  const char *path, *full_path, *hex_digest, *canonical_path;
   svn_revnum_t rev;
   svn_fs_root_t *root;
   svn_stream_t *contents;
@@ -1585,8 +1616,10 @@ get_file(svn_ra_svn_conn_t *conn,
   if (wants_inherited_props == SVN_RA_SVN_UNSPECIFIED_NUMBER)
     wants_inherited_props = FALSE;
 
-  full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path, pool,
+                                        pool));
+  full_path = svn_fspath__join(b->repository->fs_path->data, canonical_path,
+                               pool);
 
   /* Check authorizations */
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_read,
@@ -1743,7 +1776,7 @@ get_dir(svn_ra_svn_conn_t *conn,
         void *baton)
 {
   server_baton_t *b = baton;
-  const char *path, *full_path;
+  const char *path, *full_path, *canonical_path;
   svn_revnum_t rev;
   apr_hash_t *entries, *props = NULL;
   apr_array_header_t *inherited_props;
@@ -1769,8 +1802,10 @@ get_dir(svn_ra_svn_conn_t *conn,
     wants_inherited_props = FALSE;
 
   SVN_ERR(parse_dirent_fields(&dirent_fields, dirent_fields_list));
-  full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
+  full_path = svn_fspath__join(b->repository->fs_path->data, canonical_path,
+                               pool);
 
   /* Check authorizations */
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_read,
@@ -1917,7 +1952,7 @@ update(svn_ra_svn_conn_t *conn,
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
-  const char *target, *full_path, *depth_word;
+  const char *target, *full_path, *depth_word, *canonical_target;
   svn_boolean_t recurse;
   svn_tristate_t send_copyfrom_args; /* Optional; default FALSE */
   svn_tristate_t ignore_ancestry; /* Optional; default FALSE */
@@ -1930,7 +1965,9 @@ update(svn_ra_svn_conn_t *conn,
   SVN_ERR(svn_ra_svn__parse_tuple(params, "(?r)cb?w3?3", &rev, &target,
                                   &recurse, &depth_word,
                                   &send_copyfrom_args, &ignore_ancestry));
-  target = svn_relpath_canonicalize(target, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_target, NULL, target,
+                                        pool, pool));
+  target = canonical_target;
 
   if (depth_word)
     depth = svn_depth_from_word(depth_word);
@@ -1976,7 +2013,7 @@ switch_cmd(svn_ra_svn_conn_t *conn,
   server_baton_t *b = baton;
   svn_revnum_t rev;
   const char *target, *depth_word;
-  const char *switch_url, *switch_path;
+  const char *switch_url, *switch_path, *canonical_url, *canonical_target;
   svn_boolean_t recurse;
   /* Default to unknown.  Old clients won't send depth, but we'll
      handle that by converting recurse if necessary. */
@@ -1988,9 +2025,12 @@ switch_cmd(svn_ra_svn_conn_t *conn,
   SVN_ERR(svn_ra_svn__parse_tuple(params, "(?r)cbc?w?33", &rev, &target,
                                   &recurse, &switch_url, &depth_word,
                                   &send_copyfrom_args, &ignore_ancestry));
-  target = svn_relpath_canonicalize(target, pool);
-  switch_url = svn_uri_canonicalize(switch_url, pool);
-
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_target, NULL, target,
+                                        pool, pool));
+  target = canonical_target;
+  SVN_ERR(svn_uri_canonicalize_safe(&canonical_url, NULL, switch_url, pool,
+                                    pool));
+  switch_url = canonical_url;
   if (depth_word)
     depth = svn_depth_from_word(depth_word);
   else
@@ -2028,7 +2068,7 @@ status(svn_ra_svn_conn_t *conn,
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
-  const char *target, *depth_word;
+  const char *target, *depth_word, *canonical_target;
   svn_boolean_t recurse;
   /* Default to unknown.  Old clients won't send depth, but we'll
      handle that by converting recurse if necessary. */
@@ -2037,7 +2077,9 @@ status(svn_ra_svn_conn_t *conn,
   /* Parse the arguments. */
   SVN_ERR(svn_ra_svn__parse_tuple(params, "cb?(?r)?w",
                                   &target, &recurse, &rev, &depth_word));
-  target = svn_relpath_canonicalize(target, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_target, NULL, target,
+                                        pool, pool));
+  target = canonical_target;
 
   if (depth_word)
     depth = svn_depth_from_word(depth_word);
@@ -2067,7 +2109,8 @@ diff(svn_ra_svn_conn_t *conn,
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
-  const char *target, *versus_url, *versus_path, *depth_word;
+  const char *target, *versus_url, *versus_path, *depth_word, *canonical_url;
+  const char *canonical_target;
   svn_boolean_t recurse, ignore_ancestry;
   svn_boolean_t text_deltas;
   /* Default to unknown.  Old clients won't send depth, but we'll
@@ -2090,8 +2133,12 @@ diff(svn_ra_svn_conn_t *conn,
                                       &ignore_ancestry, &versus_url,
                                       &text_deltas, &depth_word));
     }
-  target = svn_relpath_canonicalize(target, pool);
-  versus_url = svn_uri_canonicalize(versus_url, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_target, NULL, target,
+                                        pool, pool));
+  target = canonical_target;
+  SVN_ERR(svn_uri_canonicalize_safe(&canonical_url, NULL, versus_url,
+                                    pool, pool));
+  versus_url = canonical_url;
 
   if (depth_word)
     depth = svn_depth_from_word(depth_word);
@@ -2216,13 +2263,15 @@ get_mergeinfo(svn_ra_svn_conn_t *conn,
   for (i = 0; i < paths->nelts; i++)
      {
         svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(paths, i);
-        const char *full_path;
+        const char *full_path, *canonical_path;
 
         if (item->kind != SVN_RA_SVN_STRING)
           return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                   _("Path is not a string"));
-        full_path = svn_relpath_canonicalize(item->u.string.data, pool);
-        full_path = svn_fspath__join(b->repository->fs_path->data, full_path, 
pool);
+        SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL,
+            item->u.string.data, pool, pool));
+        full_path = svn_fspath__join(b->repository->fs_path->data,
+                                     canonical_path, pool);
         APR_ARRAY_PUSH(canonical_paths, const char *) = full_path;
      }
 
@@ -2384,7 +2433,7 @@ log_cmd(svn_ra_svn_conn_t *conn,
   svn_error_t *err, *write_err;
   server_baton_t *b = baton;
   svn_revnum_t start_rev, end_rev;
-  const char *full_path;
+  const char *full_path, *canonical_path;
   svn_boolean_t send_changed_paths, strict_node, include_merged_revisions;
   apr_array_header_t *full_paths, *revprops;
   svn_ra_svn__list_t *paths, *revprop_items;
@@ -2448,9 +2497,10 @@ log_cmd(svn_ra_svn_conn_t *conn,
       if (elt->kind != SVN_RA_SVN_STRING)
         return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL,
                                 _("Log path entry not a string"));
-      full_path = svn_relpath_canonicalize(elt->u.string.data, pool),
-      full_path = svn_fspath__join(b->repository->fs_path->data, full_path,
-                                   pool);
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL,
+                                            elt->u.string.data, pool, pool));
+      full_path = svn_fspath__join(b->repository->fs_path->data,
+                                   canonical_path, pool);
       APR_ARRAY_PUSH(full_paths, const char *) = full_path;
     }
   SVN_ERR(trivial_auth_request(conn, pool, b));
@@ -2493,13 +2543,15 @@ check_path(svn_ra_svn_conn_t *conn,
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
-  const char *path, *full_path;
+  const char *path, *full_path, *canonical_path;
   svn_fs_root_t *root;
   svn_node_kind_t kind;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)", &path, &rev));
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));;
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+                               canonical_path, pool);
 
   /* Check authorizations */
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_read,
@@ -2526,13 +2578,15 @@ stat_cmd(svn_ra_svn_conn_t *conn,
 {
   server_baton_t *b = baton;
   svn_revnum_t rev;
-  const char *path, *full_path, *cdate;
+  const char *path, *full_path, *cdate, *canonical_path;
   svn_fs_root_t *root;
   svn_dirent_t *dirent;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)", &path, &rev));
-  full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path, pool,
+                                        pool));
+  full_path = svn_fspath__join(b->repository->fs_path->data, canonical_path,
+                               pool);
 
   /* Check authorizations */
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_read,
@@ -2581,7 +2635,7 @@ get_locations(svn_ra_svn_conn_t *conn,
   svn_ra_svn__list_t *loc_revs_proto;
   svn_ra_svn__item_t *elt;
   int i;
-  const char *relative_path;
+  const char *relative_path, *canonical_path;
   svn_revnum_t peg_revision;
   apr_hash_t *fs_locations;
   const char *abs_path;
@@ -2594,7 +2648,9 @@ get_locations(svn_ra_svn_conn_t *conn,
   SVN_ERR(svn_ra_svn__parse_tuple(params, "crl", &relative_path,
                                   &peg_revision,
                                   &loc_revs_proto));
-  relative_path = svn_relpath_canonicalize(relative_path, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, relative_path,
+                                        pool, pool));
+  relative_path = canonical_path;
 
   abs_path = svn_fspath__join(b->repository->fs_path->data, relative_path,
                               pool);
@@ -2680,7 +2736,7 @@ get_location_segments(svn_ra_svn_conn_t
   svn_error_t *err, *write_err;
   server_baton_t *b = baton;
   svn_revnum_t peg_revision, start_rev, end_rev;
-  const char *relative_path;
+  const char *relative_path, *canonical_path;
   const char *abs_path;
   authz_baton_t ab;
 
@@ -2691,7 +2747,9 @@ get_location_segments(svn_ra_svn_conn_t
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)(?r)(?r)",
                                   &relative_path, &peg_revision,
                                   &start_rev, &end_rev));
-  relative_path = svn_relpath_canonicalize(relative_path, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, relative_path,
+                                        pool, pool));
+  relative_path = canonical_path;
 
   abs_path = svn_fspath__join(b->repository->fs_path->data, relative_path,
                               pool);
@@ -2821,17 +2879,9 @@ static svn_error_t *file_rev_handler(voi
       svn_stream_set_write(stream, svndiff_handler);
       svn_stream_set_close(stream, svndiff_close_handler);
 
-      /* If the connection does not support SVNDIFF1 or if we don't want to use
-       * compression, use the non-compressing "version 0" implementation */
-      /* ### TODO: Check SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED and decide between
-       * ###       svndiff1[at compression_level] and svndiff2 */
-      if (   svn_ra_svn_compression_level(frb->conn) > 0
-          && svn_ra_svn_has_capability(frb->conn, SVN_RA_SVN_CAP_SVNDIFF1))
-        svn_txdelta_to_svndiff3(d_handler, d_baton, stream, 1,
-                                svn_ra_svn_compression_level(frb->conn), pool);
-      else
-        svn_txdelta_to_svndiff3(d_handler, d_baton, stream, 0,
-                                svn_ra_svn_compression_level(frb->conn), pool);
+      svn_txdelta_to_svndiff3(d_handler, d_baton, stream,
+                              svn_ra_svn__svndiff_version(frb->conn),
+                              svn_ra_svn_compression_level(frb->conn), pool);
     }
   else
     SVN_ERR(svn_ra_svn__write_cstring(frb->conn, pool, ""));
@@ -2851,6 +2901,7 @@ get_file_revs(svn_ra_svn_conn_t *conn,
   svn_revnum_t start_rev, end_rev;
   const char *path;
   const char *full_path;
+  const char *canonical_path;
   apr_uint64_t include_merged_revs_param;
   svn_boolean_t include_merged_revisions;
   authz_baton_t ab;
@@ -2862,7 +2913,9 @@ get_file_revs(svn_ra_svn_conn_t *conn,
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)(?r)?B",
                                   &path, &start_rev, &end_rev,
                                   &include_merged_revs_param));
-  path = svn_relpath_canonicalize(path, pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
+  path = canonical_path;
   SVN_ERR(trivial_auth_request(conn, pool, b));
   full_path = svn_fspath__join(b->repository->fs_path->data, path, pool);
 
@@ -2905,14 +2958,17 @@ lock(svn_ra_svn_conn_t *conn,
   const char *path;
   const char *comment;
   const char *full_path;
+  const char *canonical_path;
   svn_boolean_t steal_lock;
   svn_revnum_t current_rev;
   svn_lock_t *l;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?c)b(?r)", &path, &comment,
                                   &steal_lock, &current_rev));
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));;
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+                               canonical_path, pool);
 
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_write,
                            full_path, TRUE));
@@ -3004,7 +3060,7 @@ lock_many(svn_ra_svn_conn_t *conn,
   /* Parse the lock requests from PATH_REVS into TARGETS. */
   for (i = 0; i < path_revs->nelts; ++i)
     {
-      const char *path, *full_path;
+      const char *path, *full_path, *canonical_path;
       svn_revnum_t current_rev;
       svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(path_revs, i);
       svn_fs_lock_target_t *target;
@@ -3018,9 +3074,10 @@ lock_many(svn_ra_svn_conn_t *conn,
       SVN_ERR(svn_ra_svn__parse_tuple(&item->u.list, "c(?r)", &path,
                                       &current_rev));
 
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                            subpool, subpool));
       full_path = svn_fspath__join(b->repository->fs_path->data,
-                                   svn_relpath_canonicalize(path, subpool),
-                                   pool);
+                                   canonical_path, pool);
       target = svn_fs_lock_target_create(NULL, current_rev, pool);
 
       /* Any duplicate paths, once canonicalized, get collapsed into a
@@ -3067,7 +3124,7 @@ lock_many(svn_ra_svn_conn_t *conn,
   /* Return results in the same order as the paths were supplied. */
   for (i = 0; i < path_revs->nelts; ++i)
     {
-      const char *path, *full_path;
+      const char *path, *full_path, *canonical_path;
       svn_revnum_t current_rev;
       svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(path_revs, i);
       struct lock_result_t *result;
@@ -3079,9 +3136,10 @@ lock_many(svn_ra_svn_conn_t *conn,
       if (write_err)
         break;
 
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                            subpool, subpool));
       full_path = svn_fspath__join(b->repository->fs_path->data,
-                                   svn_relpath_canonicalize(path, subpool),
-                                   subpool);
+                                   canonical_path, subpool);
 
       result = svn_hash_gets(lmb.results, full_path);
       if (!result)
@@ -3136,14 +3194,16 @@ unlock(svn_ra_svn_conn_t *conn,
        void *baton)
 {
   server_baton_t *b = baton;
-  const char *path, *token, *full_path;
+  const char *path, *token, *full_path, *canonical_path;
   svn_boolean_t break_lock;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?c)b", &path, &token,
                                  &break_lock));
 
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+                               canonical_path, pool);
 
   /* Username required unless break_lock was specified. */
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_write,
@@ -3187,7 +3247,7 @@ unlock_many(svn_ra_svn_conn_t *conn,
   for (i = 0; i < unlock_tokens->nelts; i++)
     {
       svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(unlock_tokens, i);
-      const char *path, *full_path, *token;
+      const char *path, *full_path, *token, *canonical_path;
 
       svn_pool_clear(subpool);
 
@@ -3200,9 +3260,10 @@ unlock_many(svn_ra_svn_conn_t *conn,
       if (!token)
         token = "";
 
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                            subpool, subpool));
       full_path = svn_fspath__join(b->repository->fs_path->data,
-                                   svn_relpath_canonicalize(path, subpool),
-                                   pool);
+                                   canonical_path, pool);
 
       /* Any duplicate paths, once canonicalized, get collapsed into a
          single path that is processed once.  The result is then
@@ -3247,7 +3308,7 @@ unlock_many(svn_ra_svn_conn_t *conn,
   /* Return results in the same order as the paths were supplied. */
   for (i = 0; i < unlock_tokens->nelts; ++i)
     {
-      const char *path, *token, *full_path;
+      const char *path, *token, *full_path, *canonical_path;
       svn_ra_svn__item_t *item = &SVN_RA_SVN__LIST_ITEM(unlock_tokens, i);
       struct lock_result_t *result;
 
@@ -3258,9 +3319,10 @@ unlock_many(svn_ra_svn_conn_t *conn,
       if (write_err)
         break;
 
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                            subpool, subpool));
       full_path = svn_fspath__join(b->repository->fs_path->data,
-                                   svn_relpath_canonicalize(path, subpool),
-                                   pool);
+                                   canonical_path, pool);
 
       result = svn_hash_gets(lmb.results, full_path);
       if (!result)
@@ -3310,12 +3372,15 @@ get_lock(svn_ra_svn_conn_t *conn,
   server_baton_t *b = baton;
   const char *path;
   const char *full_path;
+  const char *canonical_path;
   svn_lock_t *l;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c", &path));
 
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+                               canonical_path, pool);
 
   SVN_ERR(must_have_access(conn, pool, b, svn_authz_read,
                            full_path, FALSE));
@@ -3341,6 +3406,7 @@ get_locks(svn_ra_svn_conn_t *conn,
   server_baton_t *b = baton;
   const char *path;
   const char *full_path;
+  const char *canonical_path;
   const char *depth_word;
   svn_depth_t depth;
   apr_hash_t *locks;
@@ -3364,8 +3430,10 @@ get_locks(svn_ra_svn_conn_t *conn,
       return log_fail_and_flush(err, b, conn, pool);
     }
 
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+                               canonical_path, pool);
 
   SVN_ERR(trivial_auth_request(conn, pool, b));
 
@@ -3502,19 +3570,34 @@ get_deleted_rev(svn_ra_svn_conn_t *conn,
                 void *baton)
 {
   server_baton_t *b = baton;
-  const char *path, *full_path;
+  const char *path, *full_path, *canonical_path;
   svn_revnum_t peg_revision;
   svn_revnum_t end_revision;
   svn_revnum_t revision_deleted;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, "crr",
                                  &path, &peg_revision, &end_revision));
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+                               canonical_path, pool);
   SVN_ERR(log_command(b, conn, pool, "get-deleted-rev"));
   SVN_ERR(trivial_auth_request(conn, pool, b));
-  SVN_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision,
-                                end_revision, &revision_deleted, pool));
+  SVN_CMD_ERR(svn_repos_deleted_rev(b->repository->fs, full_path, peg_revision,
+                                    end_revision, &revision_deleted, pool));
+
+  /* The protocol does not allow for a reply of SVN_INVALID_REVNUM directly.
+     Instead, return SVN_ERR_ENTRY_MISSING_REVISION. A new enough client
+     knows that this means the answer to the query is SVN_INVALID_REVNUM.
+     (An older client reports this as an error.) */
+  if (revision_deleted == SVN_INVALID_REVNUM)
+    SVN_CMD_ERR(svn_error_createf(SVN_ERR_ENTRY_MISSING_REVISION, NULL,
+                                  "svn protocol command 'get-deleted-rev': "
+                                  "path '%s' was not deleted in r%ld-%ld; "
+                                  "NOTE: newer clients handle this case "
+                                  "and do not report it as an error",
+                                  full_path, peg_revision, end_revision));
+
   SVN_ERR(svn_ra_svn__write_cmd_response(conn, pool, "r", revision_deleted));
   return SVN_NO_ERROR;
 }
@@ -3526,7 +3609,7 @@ get_inherited_props(svn_ra_svn_conn_t *c
                     void *baton)
 {
   server_baton_t *b = baton;
-  const char *path, *full_path;
+  const char *path, *full_path, *canonical_path;
   svn_revnum_t rev;
   svn_fs_root_t *root;
   apr_array_header_t *inherited_props;
@@ -3541,9 +3624,10 @@ get_inherited_props(svn_ra_svn_conn_t *c
   /* Parse arguments. */
   SVN_ERR(svn_ra_svn__parse_tuple(params, "c(?r)", &path, &rev));
 
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        iterpool, iterpool));
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, iterpool),
-                               pool);
+                               canonical_path, pool);
 
   /* Check authorizations */
   SVN_ERR(must_have_access(conn, iterpool, b, svn_authz_read,
@@ -3616,7 +3700,7 @@ list(svn_ra_svn_conn_t *conn,
      void *baton)
 {
   server_baton_t *b = baton;
-  const char *path, *full_path;
+  const char *path, *full_path, *canonical_path;
   svn_revnum_t rev;
   svn_depth_t depth;
   apr_array_header_t *patterns = NULL;
@@ -3642,8 +3726,10 @@ list(svn_ra_svn_conn_t *conn,
   SVN_ERR(parse_dirent_fields(&rb.dirent_fields, dirent_fields_list));
 
   depth = svn_depth_from_word(depth_word);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        pool, pool));
   full_path = svn_fspath__join(b->repository->fs_path->data,
-                               svn_relpath_canonicalize(path, pool), pool);
+                               canonical_path, pool);
 
   /* Read the patterns list.  */
   if (patterns_list)
@@ -3801,10 +3887,13 @@ find_repos(const char *url,
            repository_t *repository,
            svn_repos__config_pool_t *config_pool,
            apr_hash_t *fs_config,
+           svn_repos_authz_warning_func_t authz_warning_func,
+           void *authz_warning_baton,
            apr_pool_t *result_pool,
            apr_pool_t *scratch_pool)
 {
-  const char *path, *full_path, *fs_path, *hooks_env;
+  const char *path, *full_path, *fs_path, *hooks_env, *canonical_path;
+  const char *canonical_root;
   svn_stringbuf_t *url_buf;
   svn_boolean_t sasl_requested;
 
@@ -3820,8 +3909,9 @@ find_repos(const char *url,
       if (path == NULL)
         path = "";
     }
-  path = svn_relpath_canonicalize(path, scratch_pool);
-  path = svn_path_uri_decode(path, scratch_pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonical_path, NULL, path,
+                                        scratch_pool, scratch_pool));
+  path = svn_path_uri_decode(canonical_path, scratch_pool);
 
   /* Ensure that it isn't possible to escape the root by disallowing
      '..' segments. */
@@ -3830,8 +3920,9 @@ find_repos(const char *url,
                             "Couldn't determine repository path");
 
   /* Join the server-configured root with the client path. */
-  full_path = svn_dirent_join(svn_dirent_canonicalize(root, scratch_pool),
-                              path, scratch_pool);
+  SVN_ERR(svn_dirent_canonicalize_safe(&canonical_root, NULL, root,
+                                       scratch_pool, scratch_pool));
+  full_path = svn_dirent_join(canonical_root, path, scratch_pool);
 
   /* Search for a repository in the full path. */
   repository->repos_root = svn_repos_find_root_path(full_path, result_pool);
@@ -3852,7 +3943,7 @@ find_repos(const char *url,
   svn_path_remove_components(url_buf,
                         svn_path_component_count(repository->fs_path->data));
   repository->repos_url = url_buf->data;
-  repository->authz_repos_name = svn_dirent_is_child(root,
+  repository->authz_repos_name = svn_dirent_is_child(canonical_root,
                                                      repository->repos_root,
                                                      result_pool);
   if (repository->authz_repos_name == NULL)
@@ -3878,7 +3969,8 @@ find_repos(const char *url,
 
   SVN_ERR(load_pwdb_config(repository, cfg, config_pool, result_pool));
   SVN_ERR(load_authz_config(repository, repository->repos_root, cfg,
-                            result_pool));
+                            authz_warning_func, authz_warning_baton,
+                            result_pool, scratch_pool));
 
   /* Should we use Cyrus SASL? */
   SVN_ERR(svn_config_get_bool(cfg, &sasl_requested,
@@ -4100,6 +4192,16 @@ get_client_info(svn_ra_svn_conn_t *conn,
   return client_info;
 }
 
+static void
+handle_authz_warning(void *baton,
+                     const svn_error_t *err,
+                     apr_pool_t *scratch_pool)
+{
+  server_baton_t *const server_baton = baton;
+  log_warning(err, server_baton);
+  SVN_UNUSED(scratch_pool);
+}
+
 /* Construct the server baton for CONN using PARAMS and return it in *BATON.
  * It's lifetime is the same as that of CONN.  SCRATCH_POOL
  */
@@ -4109,9 +4211,9 @@ construct_server_baton(server_baton_t **
                        serve_params_t *params,
                        apr_pool_t *scratch_pool)
 {
-  svn_error_t *err, *io_err;
+  svn_error_t *err;
   apr_uint64_t ver;
-  const char *client_url, *ra_client_string, *client_string;
+  const char *client_url, *ra_client_string, *client_string, *canonical_url;
   svn_ra_svn__list_t *caplist;
   apr_pool_t *conn_pool = svn_ra_svn__get_pool(conn);
   server_baton_t *b = apr_pcalloc(conn_pool, sizeof(*b));
@@ -4178,15 +4280,21 @@ construct_server_baton(server_baton_t **
                                  &ra_client_string,
                                  &client_string));
   if (ver != 2)
-    return SVN_NO_ERROR;
-
-  client_url = svn_uri_canonicalize(client_url, conn_pool);
+    return svn_error_createf(SVN_ERR_RA_SVN_BAD_VERSION, NULL,
+                             "Unsupported ra_svn protocol version"
+                             " %"APR_UINT64_T_FMT
+                             " (supported versions: [2])", ver);
+
+  SVN_ERR(svn_uri_canonicalize_safe(&canonical_url, NULL, client_url,
+                                    conn_pool, scratch_pool));
+  client_url = canonical_url;
   SVN_ERR(svn_ra_svn__set_capabilities(conn, caplist));
 
   /* All released versions of Subversion support edit-pipeline,
    * so we do not accept connections from clients that do not. */
   if (! svn_ra_svn_has_capability(conn, SVN_RA_SVN_CAP_EDIT_PIPELINE))
-    return SVN_NO_ERROR;
+    return svn_error_create(SVN_ERR_RA_SVN_BAD_VERSION, NULL,
+                            "Missing edit-pipeline capability");
 
   /* find_repos needs the capabilities as a list of words (eventually
      they get handed to the start-commit hook).  While we could add a
@@ -4222,10 +4330,14 @@ construct_server_baton(server_baton_t **
       }
   }
 
+  /* (*b) has the logger, repository and client_info set, so it can
+     be used as the authz_warning_baton that eventyally gets passed
+     to log_warning(). */
   err = handle_config_error(find_repos(client_url, params->root, b->vhost,
                                        b->read_only, params->cfg,
                                        b->repository, params->config_pool,
                                        params->fs_config,
+                                       handle_authz_warning, b,
                                        conn_pool, scratch_pool),
                             b);
   if (!err)
@@ -4247,11 +4359,12 @@ construct_server_baton(server_baton_t **
     }
   if (err)
     {
-      log_error(err, b);
-      io_err = svn_ra_svn__write_cmd_failure(conn, scratch_pool, err);
-      svn_error_clear(err);
-      SVN_ERR(io_err);
-      return svn_ra_svn__flush(conn, scratch_pool);
+      /* Report these errors to the client before closing the connection. */
+      err = svn_error_compose_create(err,
+              svn_ra_svn__write_cmd_failure(conn, scratch_pool, err));
+      err = svn_error_compose_create(err,
+              svn_ra_svn__flush(conn, scratch_pool));
+      return err;
     }
 
   SVN_ERR(svn_fs_get_uuid(b->repository->fs, &b->repository->uuid,

Modified: subversion/branches/addremove/subversion/svnserve/server.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnserve/server.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnserve/server.h (original)
+++ subversion/branches/addremove/subversion/svnserve/server.h Sat May 23 
14:16:56 2020
@@ -71,7 +71,7 @@ typedef struct repository_t {
 #endif
 
   enum access_type auth_access; /* access granted to authenticated users */
-  enum access_type anon_access; /* access granted to annonymous users */
+  enum access_type anon_access; /* access granted to anonymous users */
 
 } repository_t;
 

Modified: subversion/branches/addremove/subversion/svnserve/svnserve.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnserve/svnserve.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/addremove/subversion/svnserve/svnserve.c Sat May 23 
14:16:56 2020
@@ -479,7 +479,7 @@ static svn_error_t * version(svn_boolean
                            _("\nCyrus SASL authentication is available.\n"));
 #endif
 
-  return svn_opt_print_help4(NULL, "svnserve", TRUE, quiet, FALSE,
+  return svn_opt_print_help5(NULL, "svnserve", TRUE, quiet, FALSE,
                              version_footer->data,
                              NULL, NULL, NULL, NULL, NULL, pool);
 }
@@ -1349,7 +1349,7 @@ sub_main(int *exit_code, int argc, const
           status = apr_proc_fork(&proc, connection->pool);
           if (status == APR_INCHILD)
             {
-              /* the child would't listen to the main server's socket */
+              /* the child wouldn't listen to the main server's socket */
               apr_socket_close(sock);
 
               /* serve_socket() logs any error it returns, so ignore it. */

Modified: subversion/branches/addremove/subversion/svnsync/svnsync.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnsync/svnsync.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/addremove/subversion/svnsync/svnsync.c Sat May 23 
14:16:56 2020
@@ -89,17 +89,17 @@ enum svnsync__opt {
                              svnsync_opt_config_dir, \
                              svnsync_opt_config_options
 
-static const svn_opt_subcommand_desc2_t svnsync_cmd_table[] =
+static const svn_opt_subcommand_desc3_t svnsync_cmd_table[] =
   {
-    { "initialize", initialize_cmd, { "init" },
-      N_("usage: svnsync initialize DEST_URL SOURCE_URL\n"
-         "\n"
+    { "initialize", initialize_cmd, { "init" }, {N_(
+         "usage: svnsync initialize DEST_URL SOURCE_URL\n"
+         "\n"), N_(
          "Initialize a destination repository for synchronization from\n"
          "another repository.\n"
-         "\n"
+         "\n"), N_(
          "If the source URL is not the root of a repository, only the\n"
          "specified part of the repository will be synchronized.\n"
-         "\n"
+         "\n"), N_(
          "The destination URL must point to the root of a repository which\n"
          "has been configured to allow revision property changes.  In\n"
          "the general case, the destination repository must contain no\n"
@@ -109,65 +109,70 @@ static const svn_opt_subcommand_desc2_t
          "their counterparts in the source repository.  (This is useful\n"
          "when initializing a copy of a repository as a mirror of that same\n"
          "repository, for example.)\n"
-         "\n"
+         "\n"), N_(
          "You should not commit to, or make revision property changes in,\n"
          "the destination repository by any method other than 'svnsync'.\n"
          "In other words, the destination repository should be a read-only\n"
-         "mirror of the source repository.\n"),
+         "mirror of the source repository.\n"
+      )},
       { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q',
         svnsync_opt_allow_non_empty, svnsync_opt_disable_locking,
         svnsync_opt_steal_lock, 'M' } },
-    { "synchronize", synchronize_cmd, { "sync" },
-      N_("usage: svnsync synchronize DEST_URL [SOURCE_URL]\n"
-         "\n"
+    { "synchronize", synchronize_cmd, { "sync" }, {N_(
+         "usage: svnsync synchronize DEST_URL [SOURCE_URL]\n"
+         "\n"), N_(
          "Transfer all pending revisions to the destination from the source\n"
          "with which it was initialized.\n"
-         "\n"
+         "\n"), N_(
          "If SOURCE_URL is provided, use that as the source repository URL,\n"
          "ignoring what is recorded in the destination repository as the\n"
          "source URL.  Specifying SOURCE_URL is recommended in particular\n"
          "if untrusted users/administrators may have write access to the\n"
-         "DEST_URL repository.\n"),
+         "DEST_URL repository.\n"
+      )},
       { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q',
         svnsync_opt_disable_locking, svnsync_opt_steal_lock, 'M' } },
-    { "copy-revprops", copy_revprops_cmd, { 0 },
-      N_("usage:\n"
-         "\n"
+    { "copy-revprops", copy_revprops_cmd, { 0 }, {N_(
+         "usage:\n"
+         "\n"), N_(
          "    1. svnsync copy-revprops DEST_URL [SOURCE_URL]\n"
          "    2. svnsync copy-revprops DEST_URL REV[:REV2]\n"
-         "\n"
+         "\n"), N_(
          "Copy the revision properties in a given range of revisions to the\n"
          "destination from the source with which it was initialized.  If the\n"
          "revision range is not specified, it defaults to all revisions in\n"
          "the DEST_URL repository.  Note also that the 'HEAD' revision is 
the\n"
          "latest in DEST_URL, not necessarily the latest in SOURCE_URL.\n"
-         "\n"
+         "\n"), N_(
          "If SOURCE_URL is provided, use that as the source repository URL,\n"
          "ignoring what is recorded in the destination repository as the\n"
          "source URL.  Specifying SOURCE_URL is recommended in particular\n"
          "if untrusted users/administrators may have write access to the\n"
          "DEST_URL repository.\n"
-         "\n"
+         "\n"), N_(
          "Unless you need to trigger the destination repositoy's revprop\n"
          "change hooks for all revision properties, it is recommended to use\n"
          "the --skip-unchanged option for best performance.\n"
-         "\n"
-         "Form 2 is deprecated syntax, equivalent to specifying 
\"-rREV[:REV2]\".\n"),
+         "\n"), N_(
+         "Form 2 is deprecated syntax, equivalent to specifying 
\"-rREV[:REV2]\".\n"
+      )},
       { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q', 'r',
         svnsync_opt_disable_locking, svnsync_opt_steal_lock,
         svnsync_opt_skip_unchanged, 'M' } },
-    { "info", info_cmd, { 0 },
-      N_("usage: svnsync info DEST_URL\n"
-         "\n"
+    { "info", info_cmd, { 0 }, {N_(
+         "usage: svnsync info DEST_URL\n"
+         "\n"), N_(
          "Print information about the synchronization destination repository\n"
-         "located at DEST_URL.\n"),
+         "located at DEST_URL.\n"
+      )},
       { SVNSYNC_OPTS_DEFAULT } },
-    { "help", help_cmd, { "?", "h" },
-      N_("usage: svnsync help [SUBCOMMAND...]\n"
-         "\n"
-         "Describe the usage of this program or its subcommands.\n"),
+    { "help", help_cmd, { "?", "h" }, {N_(
+         "usage: svnsync help [SUBCOMMAND...]\n"
+         "\n"), N_(
+         "Describe the usage of this program or its subcommands.\n"
+      )},
       { 0 } },
-    { NULL, NULL, { 0 }, NULL, { 0 } }
+    { NULL, NULL, { 0 }, {NULL}, { 0 } }
   };
 
 static const apr_getopt_option_t svnsync_options[] =
@@ -289,7 +294,7 @@ static const apr_getopt_option_t svnsync
 
 typedef struct opt_baton_t {
   svn_boolean_t non_interactive;
-  struct { 
+  struct {
     svn_boolean_t trust_server_cert_unknown_ca;
     svn_boolean_t trust_server_cert_cn_mismatch;
     svn_boolean_t trust_server_cert_expired;
@@ -816,7 +821,7 @@ do_initialize(svn_ra_session_t *to_sessi
 
   /* Now fill in our bookkeeping info in the dest repository. */
 
-  SVN_ERR(svn_ra_open4(&from_session, NULL, baton->from_url, NULL,
+  SVN_ERR(svn_ra_open5(&from_session, NULL, NULL, baton->from_url, NULL,
                        &(baton->source_callbacks), baton,
                        baton->config, pool));
   SVN_ERR(svn_ra_get_repos_root2(from_session, &root_url, pool));
@@ -993,7 +998,7 @@ open_source_session(svn_ra_session_t **f
                                           pool));
 
   /* Open the session to copy the revision data. */
-  SVN_ERR(svn_ra_open4(from_session, NULL, from_url, from_uuid_str->data,
+  SVN_ERR(svn_ra_open5(from_session, NULL, NULL, from_url, from_uuid_str->data,
                        callbacks, baton, config, pool));
 
   return SVN_NO_ERROR;
@@ -1008,7 +1013,7 @@ open_target_session(svn_ra_session_t **t
                     apr_pool_t *pool)
 {
   svn_ra_session_t *target_session;
-  SVN_ERR(svn_ra_open4(&target_session, NULL, baton->to_url, NULL,
+  SVN_ERR(svn_ra_open5(&target_session, NULL, NULL, baton->to_url, NULL,
                        &(baton->sync_callbacks), baton, baton->config, pool));
   SVN_ERR(check_if_session_is_at_repos_root(target_session, baton->to_url, 
pool));
 
@@ -1937,7 +1942,7 @@ help_cmd(apr_getopt_t *os, void *baton,
 
   SVN_ERR(svn_ra_print_modules(version_footer, pool));
 
-  SVN_ERR(svn_opt_print_help4(os, "svnsync",
+  SVN_ERR(svn_opt_print_help5(os, "svnsync",
                               opt_baton ? opt_baton->version : FALSE,
                               opt_baton ? opt_baton->quiet : FALSE,
                               /*###opt_state ? opt_state->verbose :*/ FALSE,
@@ -1960,7 +1965,7 @@ help_cmd(apr_getopt_t *os, void *baton,
 static svn_error_t *
 sub_main(int *exit_code, int argc, const char *argv[], apr_pool_t *pool)
 {
-  const svn_opt_subcommand_desc2_t *subcommand = NULL;
+  const svn_opt_subcommand_desc3_t *subcommand = NULL;
   apr_array_header_t *received_opts;
   opt_baton_t opt_baton;
   svn_config_t *config;
@@ -2189,7 +2194,7 @@ sub_main(int *exit_code, int argc, const
     }
 
   if (opt_baton.help)
-    subcommand = svn_opt_get_canonical_subcommand2(svnsync_cmd_table, "help");
+    subcommand = svn_opt_get_canonical_subcommand3(svnsync_cmd_table, "help");
 
   /* The --non-interactive and --force-interactive options are mutually
    * exclusive. */
@@ -2269,8 +2274,8 @@ sub_main(int *exit_code, int argc, const
           if (opt_baton.version)
             {
               /* Use the "help" subcommand to handle "--version". */
-              static const svn_opt_subcommand_desc2_t pseudo_cmd =
-                { "--version", help_cmd, {0}, "",
+              static const svn_opt_subcommand_desc3_t pseudo_cmd =
+                { "--version", help_cmd, {0}, {""},
                   {svnsync_opt_version,  /* must accept its own option */
                    'q',  /* --quiet */
                   } };
@@ -2290,7 +2295,7 @@ sub_main(int *exit_code, int argc, const
 
           SVN_ERR(svn_utf_cstring_to_utf8(&first_arg, os->argv[os->ind++],
                                           pool));
-          subcommand = svn_opt_get_canonical_subcommand2(svnsync_cmd_table,
+          subcommand = svn_opt_get_canonical_subcommand3(svnsync_cmd_table,
                                                          first_arg);
           if (subcommand == NULL)
             {
@@ -2308,11 +2313,11 @@ sub_main(int *exit_code, int argc, const
       if (opt_id == 'h' || opt_id == '?')
         continue;
 
-      if (! svn_opt_subcommand_takes_option3(subcommand, opt_id, NULL))
+      if (! svn_opt_subcommand_takes_option4(subcommand, opt_id, NULL))
         {
           const char *optstr;
           const apr_getopt_option_t *badopt =
-            svn_opt_get_option_from_code2(opt_id, svnsync_options, subcommand,
+            svn_opt_get_option_from_code3(opt_id, svnsync_options, subcommand,
                                           pool);
           svn_opt_format_option(&optstr, badopt, FALSE, pool);
           if (subcommand->name[0] == '-')

Modified: subversion/branches/addremove/subversion/svnsync/sync.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnsync/sync.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnsync/sync.c (original)
+++ subversion/branches/addremove/subversion/svnsync/sync.c Sat May 23 14:16:56 
2020
@@ -640,7 +640,7 @@ close_edit(void *edit_baton,
 {
   edit_baton_t *eb = edit_baton;
 
-  /* If we haven't opened the root yet, that means we're transfering
+  /* If we haven't opened the root yet, that means we're transferring
      an empty revision, probably because we aren't allowed to see the
      contents for some reason.  In any event, we need to open the root
      and close it again, before we can close out the edit, or the

Modified: subversion/branches/addremove/subversion/svnversion/svnversion.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnversion/svnversion.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnversion/svnversion.c (original)
+++ subversion/branches/addremove/subversion/svnversion/svnversion.c Sat May 23 
14:16:56 2020
@@ -38,7 +38,7 @@
 static svn_error_t *
 version(svn_boolean_t quiet, apr_pool_t *pool)
 {
-  return svn_opt_print_help4(NULL, "svnversion", TRUE, quiet, FALSE,
+  return svn_opt_print_help5(NULL, "svnversion", TRUE, quiet, FALSE,
                              NULL, NULL, NULL, NULL, NULL, NULL, pool);
 }
 

Propchange: subversion/branches/addremove/subversion/tests/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat May 23 14:16:56 2020
@@ -6,4 +6,3 @@ Release
 *.o
 *~
 .*~
-svnserveautocheck.pid

Modified: subversion/branches/addremove/subversion/tests/README
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/README?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/README (original)
+++ subversion/branches/addremove/subversion/tests/README Sat May 23 14:16:56 
2020
@@ -31,7 +31,7 @@ sub-tests it can run.  It has a standard
     regression tracking scripts), and human-readable (for the sake of
     painstaking grovelling by hand in the dead of night):
 
-      (PASS | FAIL): (argv[0]) (argv[1]): (description)
+      (PASS | XPASS | FAIL | XFAIL | SKIP): (argv[0]) (argv[1]): (description)
 
 For example,
 

Propchange: subversion/branches/addremove/subversion/tests/afl/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat May 23 14:16:56 2020
@@ -1,3 +1,4 @@
 *.lo
 .libs
 afl-x509
+afl-svndiff

Propchange: subversion/branches/addremove/subversion/tests/cmdline/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sat May 23 14:16:56 2020
@@ -1,5 +1,6 @@
 svn-test-work
 httpd-*
+svnserve-*
 .gdb_history
 *.pyc
 *.o

Modified: 
subversion/branches/addremove/subversion/tests/cmdline/atomic-ra-revprop-change.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/atomic-ra-revprop-change.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/tests/cmdline/atomic-ra-revprop-change.c
 (original)
+++ 
subversion/branches/addremove/subversion/tests/cmdline/atomic-ra-revprop-change.c
 Sat May 23 14:16:56 2020
@@ -99,8 +99,8 @@ change_rev_prop(const char *url,
   SVN_ERR(construct_auth_baton(&callbacks->auth_baton, config_dir, pool));
   SVN_ERR(construct_config(&config, config_dir, pool));
 
-  SVN_ERR(svn_ra_open4(&sess, NULL, url, NULL, callbacks, NULL /* baton */,
-                       config, pool));
+  SVN_ERR(svn_ra_open5(&sess, NULL, NULL, url, NULL,
+                       callbacks, NULL /* baton */, config, pool));
 
   SVN_ERR(svn_ra_has_capability(sess, &capable,
                                 SVN_RA_CAPABILITY_ATOMIC_REVPROPS,

Modified: subversion/branches/addremove/subversion/tests/cmdline/authz_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/authz_tests.py?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/authz_tests.py 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/authz_tests.py Sat 
May 23 14:16:56 2020
@@ -168,7 +168,7 @@ def authz_read_access(sbox):
   fws_url = B_url + '/folder with spaces'
   fws_empty_folder_url = fws_url + '/empty folder'
 
-  if sbox.repo_url.startswith("http"):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: E170001: Authorization failed.*"
@@ -280,7 +280,7 @@ def authz_write_access(sbox):
 
   write_restrictive_svnserve_conf(sbox.repo_dir)
 
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: E220004: Access denied.*"
@@ -367,7 +367,7 @@ def authz_checkout_test(sbox):
   # 1st part: disable all read access, checkout should fail
 
   # write an authz file with *= on /
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: E170001: Authorization failed.*"
@@ -502,7 +502,7 @@ def authz_log_and_tracing_test(sbox):
   write_restrictive_svnserve_conf(sbox.repo_dir)
 
   # write an authz file with *=rw on /
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: E170001: Authorization failed.*"
@@ -533,7 +533,7 @@ def authz_log_and_tracing_test(sbox):
 
   # now disable read access on the first version of rho, keep the copy in
   # /A/D readable.
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: E170001: Authorization failed.*"
@@ -551,7 +551,7 @@ def authz_log_and_tracing_test(sbox):
                                      'log', '-r', '2', '--limit', '1',
                                      wc_dir)
 
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err2 = expected_err
   else:
     expected_err2 = ".*svn: E220001: ((Unreadable path encountered; " \
@@ -593,7 +593,7 @@ def authz_log_and_tracing_test(sbox):
   svntest.actions.run_and_verify_svn(None, expected_err2,
                                      'cat', '-r', '2', D_url+'/rho')
 
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err2 = expected_err
   else:
     expected_err2 = ".*svn: E220001: Unreadable path encountered; access 
denied.*"
@@ -624,7 +624,7 @@ def authz_aliases(sbox):
 
   write_restrictive_svnserve_conf(sbox.repo_dir)
 
-  if sbox.repo_url.startswith("http"):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: E170001: Authorization failed.*"
@@ -669,9 +669,9 @@ def authz_validate(sbox):
   write_authz_file(sbox, { "/"  : "* = r",
                            "/A/B" : "@undefined_group = rw" })
 
-  if sbox.repo_url.startswith("http"):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
-  elif sbox.repo_url.startswith("svn"):
+  elif svntest.main.is_ra_type_svn():
     expected_err = ".*Invalid authz configuration"
   else:
     expected_err = ".*@undefined_group.*"
@@ -688,9 +688,9 @@ devs1 = @admins, dev1
 devs2 = @admins, dev2
 devs = @devs1, dev3, dev4""" })
 
-  if sbox.repo_url.startswith("http"):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
-  elif sbox.repo_url.startswith("svn"):
+  elif svntest.main.is_ra_type_svn():
     expected_err = ".*Invalid authz configuration"
   else:
     expected_err = ".*Circular dependency.*"
@@ -726,7 +726,7 @@ def authz_locking(sbox):
   write_authz_file(sbox, {"/": "", "/A": "jrandom = rw"})
   write_restrictive_svnserve_conf(sbox.repo_dir)
 
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: warning: W170001: Authorization failed.*"
@@ -781,7 +781,7 @@ def authz_locking(sbox):
   svntest.actions.run_and_verify_info([{'Lock Token' : None}],
                                       sbox.ospath('A/mu'))
 
-  if sbox.repo_url.startswith('http'):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: warning: W160039: .*([Aa]uth.*perf|[Ff]orbidden).*"
   else:
     expected_err = ".*svn: warning: W170001: Authorization failed.*"
@@ -863,7 +863,7 @@ def authz_svnserve_anon_access_read(sbox
   # is not really a branch (it's the same URL), but we only care about
   # authz here, not the semantics of the merge.  (Merges had been
   # failing in authz, for the reasons summarized in
-  # http://subversion.tigris.org/issues/show_bug.cgi?id=2712#desc13.)
+  # https://issues.apache.org/jira/browse/SVN-2712#desc13.)
   svntest.actions.run_and_verify_svn(None, [],
                                      'merge', '-c', '2',
                                      B_url, B_path)
@@ -981,7 +981,7 @@ def multiple_matches(sbox):
   sbox.build(create_wc = False)
   root_url = sbox.repo_url
   write_restrictive_svnserve_conf(sbox.repo_dir)
-  if sbox.repo_url.startswith("http"):
+  if svntest.main.is_ra_type_dav():
     expected_err = ".*svn: E175013: .*[Ff]orbidden.*"
   else:
     expected_err = ".*svn: E170001: Authorization failed.*"
@@ -1137,7 +1137,7 @@ def case_sensitive_authz(sbox):
   # error messages
   expected_error_for_commit = ".*Commit failed.*"
 
-  if sbox.repo_url.startswith("http"):
+  if svntest.main.is_ra_type_dav():
     expected_error_for_cat = ".*[Ff]orbidden.*"
   else:
     expected_error_for_cat = ".*svn: E170001: Authorization failed.*"
@@ -1663,6 +1663,74 @@ def remove_access_after_commit(sbox):
                                         expected_status,
                                         [], True)
 
+@Issue(4793)
+@Skip(svntest.main.is_ra_type_file)
+def inverted_group_membership(sbox):
+  "access rights for user in inverted group"
+
+  sbox.build(create_wc = False)
+
+  svntest.actions.enable_revprop_changes(sbox.repo_dir)
+  write_restrictive_svnserve_conf(sbox.repo_dir)
+  write_authz_file(sbox,
+                   {"/" : ("$anonymous =\n"
+                           "~@readonly = rw\n"
+                           "@readonly = r\n")},
+                   {"groups": "readonly = %s\n" % svntest.main.wc_author2})
+
+  expected_output = svntest.verify.UnorderedOutput(['A/\n', 'iota\n'])
+
+  # User mentioned in the @readonly group can read ...
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'list',
+                                     '--username', svntest.main.wc_author2,
+                                     sbox.repo_url)
+
+  # ... but the access control entry for the inverted group isn't applied.
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'list',
+                                     '--username', svntest.main.wc_author,
+                                     sbox.repo_url)
+
+@Skip(svntest.main.is_ra_type_file)
+def group_member_empty_string(sbox):
+  "group definition ignores 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)
+
+@Issue(4802)
+@Skip(svntest.main.is_ra_type_file)
+def empty_group(sbox):
+  "empty group is ignored"
+
+  sbox.build(create_wc = False)
+
+  write_restrictive_svnserve_conf(sbox.repo_dir)
+  write_authz_file(sbox,
+                   {"/" : ("$anonymous =\n"
+                           "@empty = rw\n"
+                           "@readonly = r\n")},
+                   {"groups": ("empty = \n"
+                               "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
@@ -1700,6 +1768,9 @@ test_list = [ None,
               authz_file_external_to_authz,
               authz_log_censor_revprops,
               remove_access_after_commit,
+              inverted_group_membership,
+              group_member_empty_string,
+              empty_group,
              ]
 serial_only = True
 


Reply via email to