You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2022/01/14 14:01:51 UTC

svn commit: r1897034 [21/37] - in /subversion/branches/multi-wc-format: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contrib/hook-scripts/ contrib/s...

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/authz_parse.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/authz_parse.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/authz_parse.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/authz_parse.c Fri Jan 14 14:01:45 2022
@@ -83,7 +83,7 @@ typedef struct ctor_baton_t
      same immutable string multiple times, we reduce the size of the
      authz representation in the result pool.
 
-     N.B.: Whilst the strings are allocated from teh result pool, the
+     N.B.: Whilst the strings are allocated from the result pool, the
      hash table itself is not. */
   apr_hash_t *strings;
 
@@ -127,6 +127,10 @@ typedef struct ctor_baton_t
   svn_membuf_t rule_path_buffer;
   svn_stringbuf_t *rule_string_buffer;
 
+  /* The warning callback and its baton. */
+  svn_repos_authz_warning_func_t warning_func;
+  void *warning_baton;
+
   /* The parser's scratch pool. This may not be the same pool as
      passed to the constructor callbacks, that is supposed to be an
      iteration pool maintained by the generic parser.
@@ -154,6 +158,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,15 +197,19 @@ 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);
 }
 
 
-/* Initialize a constuctor baton. */
+/* Initialize a constructor baton. */
 static ctor_baton_t *
-create_ctor_baton(apr_pool_t *result_pool,
+create_ctor_baton(svn_repos_authz_warning_func_t warning_func,
+                  void *warning_baton,
+                  apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
   apr_pool_t *const parser_pool = svn_pool_create(scratch_pool);
@@ -208,6 +218,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;
 
@@ -229,6 +240,9 @@ create_ctor_baton(apr_pool_t *result_poo
   svn_membuf__create(&cb->rule_path_buffer, 0, parser_pool);
   cb->rule_string_buffer = svn_stringbuf_create_empty(parser_pool);
 
+  cb->warning_func = warning_func;
+  cb->warning_baton = warning_baton;
+
   cb->parser_pool = parser_pool;
 
   insert_default_acl(cb);
@@ -237,6 +251,25 @@ create_ctor_baton(apr_pool_t *result_poo
 }
 
 
+/* Emit a warning. Clears ERROR */
+static void
+emit_parser_warning(const ctor_baton_t *cb,
+                    svn_error_t *error,
+                    apr_pool_t *scratch_pool)
+{
+  if (cb->warning_func)
+    cb->warning_func(cb->warning_baton, error, scratch_pool);
+  svn_error_clear(error);
+}
+
+/* Avoid creating an error struct if there is no warning function. */
+#define SVN_AUTHZ_PARSE_WARN(cb, err, pool)     \
+  do {                                          \
+    if ((cb) && (cb)->warning_func)             \
+      emit_parser_warning((cb), (err), (pool)); \
+  } while(0)
+
+
 /* Create and store per-user global rights.
    The USER string must be interned or statically initialized. */
 static void
@@ -536,7 +569,7 @@ parse_rule_path(authz_rule_t *rule,
               || (pattern->len == 2 && pattern->data[1] == '*'))
             {
               /* Process * and **, applying normalization as per
-                 https://wiki.apache.org/subversion/AuthzImprovements. */
+                 https://cwiki.apache.org/confluence/display/SVN/Authz+Improvements. */
 
               authz_rule_segment_t *const prev =
                 (nseg > 1 ? segment - 1 : NULL);
@@ -758,6 +791,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);
@@ -930,7 +965,7 @@ add_access_entry(ctor_baton_t *cb, svn_s
     {
       /* The inversion tag must be part of the key in the hash
          table, otherwise we can't tell regular and inverted
-         entries appart. */
+         entries apart. */
       const char *key = (inverted ? name - 1 : name);
       const apr_size_t key_len = (inverted ? name_len + 1 : name_len);
       const svn_boolean_t aliased = (*name == '&');
@@ -958,6 +993,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;
@@ -996,7 +1039,8 @@ close_section(void *baton, svn_stringbuf
 
 
 /* Add a user to GROUP.
-   GROUP is never internalized, but USER always is. */
+   GROUP is never internalized, but USER always is.
+   Adding a NULL user will create an empty group, if it doesn't exist. */
 static void
 add_to_group(ctor_baton_t *cb, const char *group, const char *user)
 {
@@ -1007,7 +1051,8 @@ add_to_group(ctor_baton_t *cb, const cha
       members = svn_hash__make(cb->authz->pool);
       svn_hash_sets(cb->expanded_groups, group, members);
     }
-  svn_hash_sets(members, user, interned_empty_string);
+  if (user)
+    svn_hash_sets(members, user, interned_empty_string);
 }
 
 
@@ -1023,8 +1068,15 @@ expand_group_callback(void *baton,
   ctor_baton_t *const cb = baton;
   const char *const group = key;
   apr_array_header_t *members = value;
-
   int i;
+
+  if (0 == members->nelts)
+    {
+      /* Create the group with no members. */
+      add_to_group(cb, group, NULL);
+      return SVN_NO_ERROR;
+    }
+
   for (i = 0; i < members->nelts; ++i)
     {
       const char *member = APR_ARRAY_IDX(members, i, const char*);
@@ -1154,10 +1206,24 @@ array_insert_ace(void *baton,
       SVN_ERR_ASSERT(ace->members == NULL);
       ace->members = svn_hash_gets(iab->cb->expanded_groups, ace->name);
       if (!ace->members)
-        return svn_error_createf(
-            SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
-            _("Access entry refers to undefined group '%s'"),
-            ace->name);
+        {
+          return svn_error_createf(
+              SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+              _("Access entry refers to undefined group '%s'"),
+              ace->name);
+        }
+      else if (0 == apr_hash_count(ace->members))
+        {
+          /* An ACE for an empty group has no effect, so ignore it. */
+          SVN_AUTHZ_PARSE_WARN(
+              iab->cb,
+              svn_error_createf(
+                  SVN_ERR_AUTHZ_INVALID_CONFIG, NULL,
+                  _("Ignoring access entry for empty group '%s'"),
+                  ace->name),
+              scratch_pool);
+          return SVN_NO_ERROR;
+        }
     }
 
   APR_ARRAY_PUSH(iab->ace_array, authz_ace_t) = *ace;
@@ -1271,6 +1337,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;
@@ -1297,10 +1369,13 @@ svn_error_t *
 svn_authz__parse(authz_full_t **authz,
                  svn_stream_t *rules,
                  svn_stream_t *groups,
+                 svn_repos_authz_warning_func_t warning_func,
+                 void *warning_baton,
                  apr_pool_t *result_pool,
                  apr_pool_t *scratch_pool)
 {
-  ctor_baton_t *const cb = create_ctor_baton(result_pool, scratch_pool);
+  ctor_baton_t *const cb = create_ctor_baton(warning_func, warning_baton,
+                                             result_pool, scratch_pool);
 
   /*
    * Pass 1: Parse the authz file.

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/commit.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/commit.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/commit.c Fri Jan 14 14:01:45 2022
@@ -124,7 +124,7 @@ struct dir_baton
   svn_revnum_t base_rev;        /* the revision I'm based on  */
   svn_boolean_t was_copied; /* was this directory added with history? */
   apr_pool_t *pool; /* my personal pool, in which I am allocated. */
-  svn_boolean_t checked_write; /* TRUE after successfull write check */
+  svn_boolean_t checked_write; /* TRUE after successful write check */
 };
 
 
@@ -132,7 +132,7 @@ struct file_baton
 {
   struct edit_baton *edit_baton;
   const char *path; /* the -absolute- path to this file in the fs */
-  svn_boolean_t checked_write; /* TRUE after successfull write check */
+  svn_boolean_t checked_write; /* TRUE after successful write check */
 };
 
 
@@ -189,7 +189,7 @@ check_out_of_date(struct edit_baton *eb,
   else if (base_rev > created_rev)
     {
       if (base_rev > svn_fs_txn_base_revision(eb->txn))
-        return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL, 
+        return svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
                                  _("No such revision %ld"),
                                  base_rev);
     }
@@ -306,13 +306,14 @@ add_file_or_directory(const char *path,
   struct edit_baton *eb = pb->edit_baton;
   apr_pool_t *subpool = svn_pool_create(pool);
   svn_boolean_t was_copied = FALSE;
-  const char *full_path;
+  const char *full_path, *canonicalized_path;
 
   /* Reject paths which contain control characters (related to issue #4340). */
   SVN_ERR(svn_path_check_valid(path, pool));
 
-  full_path = svn_fspath__join(eb->base_path,
-                               svn_relpath_canonicalize(path, pool), pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL, path,
+                                        pool, pool));
+  full_path = svn_fspath__join(eb->base_path, canonicalized_path, pool);
 
   /* Sanity check. */
   if (copy_path && (! SVN_IS_VALID_REVNUM(copy_revision)))
@@ -477,10 +478,11 @@ delete_entry(const char *path,
   struct edit_baton *eb = parent->edit_baton;
   svn_node_kind_t kind;
   svn_repos_authz_access_t required = svn_authz_write;
-  const char *full_path;
+  const char *full_path, *canonicalized_path;
 
-  full_path = svn_fspath__join(eb->base_path,
-                               svn_relpath_canonicalize(path, pool), pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL, path,
+                                        pool, pool));
+  full_path = svn_fspath__join(eb->base_path, canonicalized_path, pool);
 
   /* Check PATH in our transaction.  */
   SVN_ERR(svn_fs_check_path(&kind, eb->txn_root, full_path, pool));
@@ -538,10 +540,11 @@ open_directory(const char *path,
   struct dir_baton *pb = parent_baton;
   struct edit_baton *eb = pb->edit_baton;
   svn_node_kind_t kind;
-  const char *full_path;
+  const char *full_path, *canonicalized_path;
 
-  full_path = svn_fspath__join(eb->base_path,
-                               svn_relpath_canonicalize(path, pool), pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL, path,
+                                        pool, pool));
+  full_path = svn_fspath__join(eb->base_path, canonicalized_path, pool);
 
   /* Check PATH in our transaction.  If it does not exist,
      return a 'Path not present' error. */
@@ -611,10 +614,11 @@ open_file(const char *path,
   struct edit_baton *eb = pb->edit_baton;
   svn_revnum_t cr_rev;
   apr_pool_t *subpool = svn_pool_create(pool);
-  const char *full_path;
+  const char *full_path, *canonicalized_path;
 
-  full_path = svn_fspath__join(eb->base_path,
-                               svn_relpath_canonicalize(path, pool), pool);
+  SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL, path,
+                                        pool, pool));
+  full_path = svn_fspath__join(eb->base_path, canonicalized_path, pool);
 
   /* Check for read authorization. */
   SVN_ERR(check_authz(eb, full_path, eb->txn_root,
@@ -637,7 +641,7 @@ open_file(const char *path,
 
   *file_baton = new_fb;
 
-  /* Destory the work subpool. */
+  /* Destroy the work subpool. */
   svn_pool_destroy(subpool);
 
   return SVN_NO_ERROR;

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/compat.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/compat.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/compat.c Fri Jan 14 14:01:45 2022
@@ -98,7 +98,7 @@ log4_path_change_receiver(void *baton,
                                                  : svn_tristate_false;
 
   /* Auto-create the CHANGES container (happens for each first change
-   * in any revison. */
+   * in any revision. */
   if (b->changes == NULL)
     b->changes = svn_hash__make(b->changes_pool);
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.c Fri Jan 14 14:01:45 2022
@@ -237,6 +237,10 @@ get_repos_config(svn_stream_t **stream,
     {
       /* Search for a repository in the full path. */
       repos_root_dirent = svn_repos_find_root_path(dirent, scratch_pool);
+      if (repos_root_dirent == NULL)
+        return svn_error_trace(handle_missing_file(stream, checksum, access,
+                                                   url, must_exist,
+                                                   svn_node_none));
 
       /* Attempt to open a repository at repos_root_dirent. */
       SVN_ERR(svn_repos_open3(&access->repos, repos_root_dirent, NULL,
@@ -342,7 +346,7 @@ svn_repos__create_config_access(svn_repo
   return result;
 }
 
-void 
+void
 svn_repos__destroy_config_access(config_access_t *access)
 {
   svn_pool_destroy(access->pool);

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.h (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/config_file.h Fri Jan 14 14:01:45 2022
@@ -48,7 +48,7 @@ svn_repos__create_config_access(svn_repo
                                 apr_pool_t *result_pool);
 
 /* Release all resources allocated while using ACCESS. */
-void 
+void
 svn_repos__destroy_config_access(config_access_t *access);
 
 /* Using ACCESS as a helper object, access the textual configuration at PATH,

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/delta.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/delta.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/delta.c Fri Jan 14 14:01:45 2022
@@ -215,7 +215,7 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
 {
   void *root_baton = NULL;
   struct context c;
-  const char *src_fullpath;
+  const char *src_fullpath, *canonicalized_path;
   svn_node_kind_t src_kind, tgt_kind;
   svn_revnum_t rootrev;
   svn_fs_node_relation_t relation;
@@ -223,14 +223,22 @@ svn_repos_dir_delta2(svn_fs_root_t *src_
 
   /* SRC_PARENT_DIR must be valid. */
   if (src_parent_dir)
-    src_parent_dir = svn_relpath_canonicalize(src_parent_dir, pool);
+    {
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL,
+                                            src_parent_dir, pool, pool));
+      src_parent_dir = canonicalized_path;
+    }
   else
     return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, 0,
                             "Invalid source parent directory '(null)'");
 
   /* TGT_FULLPATH must be valid. */
   if (tgt_fullpath)
-    tgt_fullpath = svn_relpath_canonicalize(tgt_fullpath, pool);
+    {
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL,
+                                            tgt_fullpath, pool, pool));
+      tgt_fullpath = canonicalized_path;
+    }
   else
     return svn_error_create(SVN_ERR_FS_PATH_SYNTAX, 0,
                             _("Invalid target path"));

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/deprecated.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/deprecated.c Fri Jan 14 14:01:45 2022
@@ -1273,6 +1273,21 @@ svn_repos_fs_begin_txn_for_update(svn_fs
 /*** From authz.c ***/
 
 svn_error_t *
+svn_repos_authz_read3(svn_authz_t **authz_p,
+                      const char *path,
+                      const char *groups_path,
+                      svn_boolean_t must_exist,
+                      svn_repos_t *repos_hint,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(svn_repos_authz_read4(authz_p, path, groups_path,
+                                               must_exist, repos_hint,
+                                               NULL, NULL, result_pool,
+                                               scratch_pool));
+}
+
+svn_error_t *
 svn_repos_authz_read2(svn_authz_t **authz_p,
                       const char *path,
                       const char *groups_path,
@@ -1300,3 +1315,17 @@ svn_repos_authz_read(svn_authz_t **authz
   return svn_error_trace(svn_repos_authz_read2(authz_p, file, NULL,
                                                must_exist, pool));
 }
+
+svn_error_t *
+svn_repos_authz_parse(svn_authz_t **authz_p,
+                      svn_stream_t *stream,
+                      svn_stream_t *groups_stream,
+                      apr_pool_t *pool)
+{
+  apr_pool_t *scratch_pool = svn_pool_create(pool);
+  svn_error_t *err = svn_repos_authz_parse2(authz_p, stream, groups_stream,
+                                            NULL, NULL, pool, scratch_pool);
+  svn_pool_destroy(scratch_pool);
+
+  return svn_error_trace(err);
+}

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/dump.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/dump.c Fri Jan 14 14:01:45 2022
@@ -44,6 +44,7 @@
 #include "private/svn_sorts_private.h"
 #include "private/svn_utf_private.h"
 #include "private/svn_cache.h"
+#include "private/svn_fspath.h"
 
 #define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
 
@@ -737,8 +738,9 @@ struct dir_baton
    or NULL if this is the top-level directory of the edit.
 
    Perform all allocations in POOL.  */
-static struct dir_baton *
-make_dir_baton(const char *path,
+static struct svn_error_t *
+make_dir_baton(struct dir_baton **dbp,
+               const char *path,
                const char *cmp_path,
                svn_revnum_t cmp_rev,
                void *edit_baton,
@@ -747,10 +749,10 @@ make_dir_baton(const char *path,
 {
   struct edit_baton *eb = edit_baton;
   struct dir_baton *new_db = apr_pcalloc(pool, sizeof(*new_db));
-  const char *full_path;
+  const char *full_path, *canonicalized_path;
 
   /* A path relative to nothing?  I don't think so. */
-  SVN_ERR_ASSERT_NO_RETURN(!path || pb);
+  SVN_ERR_ASSERT(!path || pb);
 
   /* Construct the full path of this node. */
   if (pb)
@@ -760,7 +762,11 @@ make_dir_baton(const char *path,
 
   /* Remove leading slashes from copyfrom paths. */
   if (cmp_path)
-    cmp_path = svn_relpath_canonicalize(cmp_path, pool);
+    {
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL,
+                                            cmp_path, pool, pool));
+      cmp_path = canonicalized_path;
+    }
 
   new_db->edit_baton = eb;
   new_db->path = full_path;
@@ -771,7 +777,8 @@ make_dir_baton(const char *path,
   new_db->check_name_collision = FALSE;
   new_db->pool = pool;
 
-  return new_db;
+  *dbp = new_db;
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t *
@@ -1167,7 +1174,12 @@ dump_node(struct edit_baton *eb,
 
   /* Remove leading slashes from copyfrom paths. */
   if (cmp_path)
-    cmp_path = svn_relpath_canonicalize(cmp_path, pool);
+    {
+      const char *canonicalized_path;
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL,
+                                            cmp_path, pool, pool));
+      cmp_path = canonicalized_path;
+    }
 
   /* Validate the comparison path/rev. */
   if (ARE_VALID_COPY_ARGS(cmp_path, cmp_rev))
@@ -1537,9 +1549,9 @@ open_root(void *edit_baton,
           apr_pool_t *pool,
           void **root_baton)
 {
-  *root_baton = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                               edit_baton, NULL, pool);
-  return SVN_NO_ERROR;
+  return svn_error_trace(make_dir_baton((struct dir_baton **)root_baton,
+                                        NULL, NULL, SVN_INVALID_REVNUM,
+                                        edit_baton, NULL, pool));
 }
 
 
@@ -1571,8 +1583,10 @@ add_directory(const char *path,
   struct edit_baton *eb = pb->edit_baton;
   void *was_deleted;
   svn_boolean_t is_copy = FALSE;
-  struct dir_baton *new_db
-    = make_dir_baton(path, copyfrom_path, copyfrom_rev, eb, pb, pool);
+  struct dir_baton *new_db;
+
+  SVN_ERR(make_dir_baton(&new_db, path, copyfrom_path, copyfrom_rev, eb,
+                         pb, pool));
 
   /* This might be a replacement -- is the path already deleted? */
   was_deleted = svn_hash_gets(pb->deleted_entries, path);
@@ -1629,7 +1643,7 @@ open_directory(const char *path,
       cmp_rev = pb->cmp_rev;
     }
 
-  new_db = make_dir_baton(path, cmp_path, cmp_rev, eb, pb, pool);
+  SVN_ERR(make_dir_baton(&new_db, path, cmp_path, cmp_rev, eb, pb, pool));
   *child_baton = new_db;
   return SVN_NO_ERROR;
 }
@@ -1996,6 +2010,11 @@ dump_filter_authz_func(svn_boolean_t *al
 {
   dump_filter_baton_t *b = baton;
 
+  /* For some nodes (e.g. files under copied directory) PATH may be
+   * non-canonical (missing leading '/').  Canonicalize PATH before
+   * passing it to FILTER_FUNC. */
+  path = svn_fspath__canonicalize(path, pool);
+
   return svn_error_trace(b->filter_func(allowed, root, path, b->filter_baton,
                                         pool));
 }

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/dump_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/dump_editor.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/dump_editor.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/dump_editor.c Fri Jan 14 14:01:45 2022
@@ -61,8 +61,8 @@ normalize_props(apr_hash_t **normal_prop
       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);
 
@@ -178,8 +178,9 @@ struct dump_edit_baton {
  * this is the top-level directory of the edit.
  *
  * Perform all allocations in POOL.  */
-static struct dir_baton *
-make_dir_baton(const char *path,
+static struct svn_error_t *
+make_dir_baton(struct dir_baton **dbp,
+               const char *path,
                const char *copyfrom_path,
                svn_revnum_t copyfrom_rev,
                void *edit_baton,
@@ -192,7 +193,8 @@ make_dir_baton(const char *path,
 
   /* Construct the full path of this node. */
   if (pb)
-    repos_relpath = svn_relpath_canonicalize(path, pool);
+    SVN_ERR(svn_relpath_canonicalize_safe(&repos_relpath, NULL, path,
+                                          pool, pool));
   else
     repos_relpath = "";
 
@@ -213,7 +215,8 @@ make_dir_baton(const char *path,
   new_db->deleted_props = apr_hash_make(pool);
   new_db->deleted_entries = apr_hash_make(pool);
 
-  return new_db;
+  *dbp = new_db;
+  return SVN_NO_ERROR;
 }
 
 /* Make a file baton to represent the directory at PATH (relative to
@@ -577,8 +580,8 @@ open_root(void *edit_baton,
             {
               /* ... but for the source directory itself, we'll defer
                  to letting the typical plumbing handle this task. */
-              new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                                      edit_baton, NULL, pool);
+              SVN_ERR(make_dir_baton(&new_db, NULL, NULL, SVN_INVALID_REVNUM,
+                                     edit_baton, NULL, pool));
               SVN_ERR(dump_node(&new_db->headers,
                                 eb, new_db->repos_relpath, new_db,
                                 NULL, svn_node_action_add, FALSE,
@@ -594,8 +597,8 @@ open_root(void *edit_baton,
 
   if (! new_db)
     {
-      new_db = make_dir_baton(NULL, NULL, SVN_INVALID_REVNUM,
-                              edit_baton, NULL, pool);
+      SVN_ERR(make_dir_baton(&new_db, NULL, NULL, SVN_INVALID_REVNUM,
+                             edit_baton, NULL, pool));
     }
 
   *root_baton = new_db;
@@ -636,8 +639,8 @@ add_directory(const char *path,
 
   SVN_ERR(dump_pending_dir(pb->eb, pool));
 
-  new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb,
-                          pb, pb->pool);
+  SVN_ERR(make_dir_baton(&new_db, path, copyfrom_path, copyfrom_rev, pb->eb,
+                         pb, pb->pool));
 
   /* This might be a replacement -- is the path already deleted? */
   was_deleted = svn_hash_gets(pb->deleted_entries, path);
@@ -690,8 +693,8 @@ open_directory(const char *path,
       copyfrom_rev = pb->copyfrom_rev;
     }
 
-  new_db = make_dir_baton(path, copyfrom_path, copyfrom_rev, pb->eb, pb,
-                          pb->pool);
+  SVN_ERR(make_dir_baton(&new_db, path, copyfrom_path, copyfrom_rev,
+                         pb->eb, pb, pb->pool));
 
   *child_baton = new_db;
   return SVN_NO_ERROR;

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/fs-wrap.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/fs-wrap.c Fri Jan 14 14:01:45 2022
@@ -282,7 +282,7 @@ svn_repos__normalize_prop(const svn_stri
     }
   else
     {
-      *result_p = svn_string_dup(value, result_pool);
+      *result_p = value;
       if (normalized_p)
         *normalized_p = FALSE;
     }
@@ -1106,7 +1106,7 @@ svn_repos_fs_get_inherited_props(apr_arr
                 apr_pstrdup(result_pool, parent_path + 1);
               i_props->prop_hash = parent_properties;
               /* Build the output array in depth-first order. */
-              svn_sort__array_insert(inherited_props, &i_props, 0);
+              SVN_ERR(svn_sort__array_insert2(inherited_props, &i_props, 0));
             }
         }
     }

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/hooks.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/hooks.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/hooks.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/hooks.c Fri Jan 14 14:01:45 2022
@@ -668,7 +668,7 @@ svn_repos__hooks_pre_revprop_change(svn_
     {
       /* If the pre- hook doesn't exist at all, then default to
          MASSIVE PARANOIA.  Changing revision properties is a lossy
-         operation; so unless the repository admininstrator has
+         operation; so unless the repository administrator has
          *deliberately* created the pre-hook, disallow all changes. */
       return
         svn_error_create

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/load-fs-vtable.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/load-fs-vtable.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/load-fs-vtable.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/load-fs-vtable.c Fri Jan 14 14:01:45 2022
@@ -155,9 +155,11 @@ get_revision_mapping(apr_hash_t *rev_map
 }
 
 
-/* Change revision property NAME to VALUE for REVISION in REPOS.  If
-   VALIDATE_PROPS is set, use functions which perform validation of
-   the property value.  Otherwise, bypass those checks. */
+/* Change revision property NAME to VALUE for REVISION in REPOS.
+   If NORMALIZE_PROPS is set, attempt to normalize properties before
+   changing them, if that is needed.  If VALIDATE_PROPS is set, use
+   functions which perform validation of the property value.
+   Otherwise, bypass those checks. */
 static svn_error_t *
 change_rev_prop(svn_repos_t *repos,
                 svn_revnum_t revision,
@@ -179,17 +181,23 @@ change_rev_prop(svn_repos_t *repos,
                                    NULL, value, pool);
 }
 
-/* Change property NAME to VALUE for PATH in TXN_ROOT.  If
-   VALIDATE_PROPS is set, use functions which perform validation of
-   the property value.  Otherwise, bypass those checks. */
+/* Change property NAME to VALUE for PATH in TXN_ROOT.
+   If NORMALIZE_PROPS is set, attempt to normalize properties before
+   changing them, if that is needed.  If VALIDATE_PROPS is set, use
+   functions which perform validation of the property value.
+   Otherwise, bypass those checks. */
 static svn_error_t *
 change_node_prop(svn_fs_root_t *txn_root,
                  const char *path,
                  const char *name,
                  const svn_string_t *value,
                  svn_boolean_t validate_props,
+                 svn_boolean_t normalize_props,
                  apr_pool_t *pool)
 {
+  if (normalize_props)
+    SVN_ERR(svn_repos__normalize_prop(&value, NULL, name, value, pool, pool));
+
   if (validate_props)
     return svn_repos_fs_change_node_prop(txn_root, path, name, value, pool);
   else
@@ -213,9 +221,11 @@ prefix_mergeinfo_paths(svn_string_t **me
     {
       const char *merge_source = apr_hash_this_key(hi);
       svn_rangelist_t *rangelist = apr_hash_this_val(hi);
-      const char *path;
+      const char *path, *canonicalized_path;
 
-      merge_source = svn_relpath_canonicalize(merge_source, pool);
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL,
+                                       merge_source, pool, pool));
+      merge_source = canonicalized_path;
 
       /* The svn:mergeinfo property syntax demands a repos abspath */
       path = svn_fspath__canonicalize(svn_relpath_join(parent_dir,
@@ -377,7 +387,10 @@ make_node_baton(struct node_baton **node
   /* Then add info from the headers.  */
   if ((val = svn_hash_gets(headers, SVN_REPOS_DUMPFILE_NODE_PATH)))
   {
-    val = svn_relpath_canonicalize(val, pool);
+    const char *canonicalized_path;
+    SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL,
+                                          val, pool, pool));
+    val = canonicalized_path;
     if (rb->pb->parent_dir)
       nb->path = svn_relpath_join(rb->pb->parent_dir, val, pool);
     else
@@ -869,7 +882,8 @@ set_node_property(void *baton,
     }
 
   return change_node_prop(rb->txn_root, nb->path, name, value,
-                          pb->validate_props, nb->pool);
+                          pb->validate_props, rb->pb->normalize_props,
+                          nb->pool);
 }
 
 
@@ -885,7 +899,8 @@ delete_node_property(void *baton,
     return SVN_NO_ERROR;
 
   return change_node_prop(rb->txn_root, nb->path, name, NULL,
-                          rb->pb->validate_props, nb->pool);
+                          rb->pb->validate_props, rb->pb->normalize_props,
+                          nb->pool);
 }
 
 
@@ -909,7 +924,8 @@ remove_node_props(void *baton)
       const char *key = apr_hash_this_key(hi);
 
       SVN_ERR(change_node_prop(rb->txn_root, nb->path, key, NULL,
-                               rb->pb->validate_props, nb->pool));
+                               rb->pb->validate_props, rb->pb->normalize_props,
+                               nb->pool));
     }
 
   return SVN_NO_ERROR;
@@ -1202,7 +1218,12 @@ svn_repos_get_fs_build_parser6(const svn
   struct parse_baton *pb = apr_pcalloc(pool, sizeof(*pb));
 
   if (parent_dir)
-    parent_dir = svn_relpath_canonicalize(parent_dir, pool);
+    {
+      const char *canonicalized_path;
+      SVN_ERR(svn_relpath_canonicalize_safe(&canonicalized_path, NULL,
+                                            parent_dir, pool, pool));
+      parent_dir = canonicalized_path;
+    }
 
   SVN_ERR_ASSERT((SVN_IS_VALID_REVNUM(start_rev) &&
                   SVN_IS_VALID_REVNUM(end_rev))
@@ -1400,7 +1421,7 @@ revprops_close_revision(void *baton)
  * both of these values are #SVN_INVALID_REVNUM (in  which case no
  * revision-based filtering occurs at all), or both are valid revisions
  * (where START_REV is older than or equivalent to END_REV).
- * 
+ *
  * START_REV and END_REV act as filters, the lower and upper (inclusive)
  * range values of revisions which will
  * be loaded.  Either both of these values are #SVN_INVALID_REVNUM (in

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/load.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/load.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/load.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/load.c Fri Jan 14 14:01:45 2022
@@ -355,24 +355,62 @@ parse_text_block(svn_stream_t *stream,
 
 
 
-/* Parse VERSIONSTRING and verify that we support the dumpfile format
-   version number, setting *VERSION appropriately. */
+/* Parse VERSIONSTRING from STREAM and verify that we support the dumpfile
+   format version number, setting *VERSION appropriately. */
 static svn_error_t *
 parse_format_version(int *version,
-                     const char *versionstring)
+                     svn_stream_t *stream,
+                     apr_pool_t *scratch_pool)
 {
   static const int magic_len = sizeof(SVN_REPOS_DUMPFILE_MAGIC_HEADER) - 1;
-  const char *p = strchr(versionstring, ':');
+  svn_stringbuf_t *linebuf;
+  const char *p;
   int value;
 
+  /* No svn_stream_readline() here, because malformed streams may not have
+     the EOL at all, and currently svn_stream_readline() keeps loading the
+     whole thing into memory until it encounters an EOL or the stream ends.
+     This is particularly troublesome, because users may incorrectly attempt
+     to load arbitrary large files instead of proper dump files.
+
+     As a workaround, parse the first line with a length limit.  While this
+     is not a complete solution, doing so handles the common case described
+     above.  For a complete solution, svn_stream_readline() may need to grow
+     a `limit` argument that would allow us to safely use it everywhere within
+     this parser.
+   */
+  linebuf = svn_stringbuf_create_empty(scratch_pool);
+  while (1)
+    {
+      apr_size_t len;
+      char c;
+
+      len = 1;
+      SVN_ERR(svn_stream_read_full(stream, &c, &len));
+      if (len != 1)
+        return stream_ran_dry();
+
+      if (c == '\n')
+        break;
+
+      if (linebuf->len + 1 > 80)
+        return svn_error_createf(SVN_ERR_STREAM_MALFORMED_DATA, NULL,
+                                 _("Malformed dumpfile header '%s'"),
+                                 linebuf->data);
+
+      svn_stringbuf_appendbyte(linebuf, c);
+    }
+
+  p = strchr(linebuf->data, ':');
+
   if (p == NULL
-      || p != (versionstring + magic_len)
-      || strncmp(versionstring,
+      || p != (linebuf->data + magic_len)
+      || strncmp(linebuf->data,
                  SVN_REPOS_DUMPFILE_MAGIC_HEADER,
                  magic_len))
     return svn_error_createf(SVN_ERR_STREAM_MALFORMED_DATA, NULL,
                              _("Malformed dumpfile header '%s'"),
-                             versionstring);
+                             linebuf->data);
 
   SVN_ERR(svn_cstring_atoi(&value, p + 1));
 
@@ -542,14 +580,10 @@ svn_repos_parse_dumpstream3(svn_stream_t
   parse_fns = complete_vtable(parse_fns, pool);
 
   /* Start parsing process. */
-  SVN_ERR(svn_stream_readline(stream, &linebuf, "\n", &eof, linepool));
-  if (eof)
-    return stream_ran_dry();
-
   /* The first two lines of the stream are the dumpfile-format version
      number, and a blank line.  To preserve backward compatibility,
      don't assume the existence of newer parser-vtable functions. */
-  SVN_ERR(parse_format_version(&version, linebuf->data));
+  SVN_ERR(parse_format_version(&version, stream, linepool));
   if (parse_fns->magic_header_record != NULL)
     SVN_ERR(parse_fns->magic_header_record(version, parse_baton, pool));
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/log.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/log.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/log.c Fri Jan 14 14:01:45 2022
@@ -655,7 +655,7 @@ fs_mergeinfo_changed(svn_mergeinfo_catal
      because that greatly influences the costs for log processing.
      So, it is faster to iterate over the changes twice - in the worst
      case b/c most times there is no m/i at all and we exit out early
-     without any overhead. 
+     without any overhead.
    */
   while (change && (!any_mergeinfo || !any_copy))
     {
@@ -999,7 +999,7 @@ get_combined_mergeinfo_changes(svn_merge
       /* Issue #4022 'svn log -g interprets change in inherited mergeinfo due
          to move as a merge': A copy where the source and destination inherit
          mergeinfo from the same parent means the inherited mergeinfo of the
-         source and destination will differ, but this diffrence is not
+         source and destination will differ, but this difference is not
          indicative of a merge unless the mergeinfo on the inherited parent
          has actually changed.
 
@@ -1053,7 +1053,7 @@ get_combined_mergeinfo_changes(svn_merge
             continue;
         }
 
-      /* Compare, constrast, and combine the results. */
+      /* Compare, contrast, and combine the results. */
       SVN_ERR(svn_mergeinfo_diff2(&deleted, &added, prev_mergeinfo,
                                   mergeinfo, FALSE, result_pool, iterpool));
       SVN_ERR(svn_mergeinfo_merge2(*deleted_mergeinfo, deleted,
@@ -1227,7 +1227,7 @@ typedef struct interesting_merge_baton_t
   void *inner_baton;
 } interesting_merge_baton_t;
 
-/* Implements svn_repos_path_change_receiver_t. 
+/* Implements svn_repos_path_change_receiver_t.
  * *BATON is a interesting_merge_baton_t.
  *
  * If BATON->REV a merged revision that is not already part of
@@ -1909,7 +1909,7 @@ store_search(svn_mergeinfo_t processed,
              apr_pool_t *scratch_pool)
 {
   /* We add 1 to end so that we can use the mergeinfo API to handle
-     singe revisions where HIST_START is equal to HIST_END. */
+     single revisions where HIST_START is equal to HIST_END. */
   svn_revnum_t start = hist_start <= hist_end ? hist_start : hist_end;
   svn_revnum_t end = hist_start <= hist_end ? hist_end + 1 : hist_start + 1;
   svn_mergeinfo_t mergeinfo = svn_hash__make(scratch_pool);

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/notify.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/notify.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/notify.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/notify.c Fri Jan 14 14:01:45 2022
@@ -1,4 +1,4 @@
-/* notify.c --- notifcation system
+/* notify.c --- notification system
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/replay.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/replay.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/replay.c Fri Jan 14 14:01:45 2022
@@ -126,9 +126,6 @@ struct copy_info
 
 struct path_driver_cb_baton
 {
-  const svn_delta_editor_t *editor;
-  void *edit_baton;
-
   /* The root of the revision we're replaying. */
   svn_fs_root_t *root;
 
@@ -454,14 +451,14 @@ fill_copyfrom(svn_fs_root_t **copyfrom_r
 
 static svn_error_t *
 path_driver_cb_func(void **dir_baton,
+                    const svn_delta_editor_t *editor,
+                    void *edit_baton,
                     void *parent_baton,
                     void *callback_baton,
                     const char *edit_path,
                     apr_pool_t *pool)
 {
   struct path_driver_cb_baton *cb = callback_baton;
-  const svn_delta_editor_t *editor = cb->editor;
-  void *edit_baton = cb->edit_baton;
   svn_fs_root_t *root = cb->root;
   svn_fs_path_change3_t *change;
   svn_boolean_t do_add = FALSE, do_delete = FALSE;
@@ -894,7 +891,7 @@ get_relevant_changes(apr_hash_t **change
             }
 
           /* If the base_path doesn't match the top directory of this path
-             we don't want anything to do with it... 
+             we don't want anything to do with it...
              ...unless this was a change to one of the parent directories of
              base_path. */
           if (   svn_relpath_skip_ancestor(base_relpath, path)
@@ -957,8 +954,6 @@ svn_repos_replay2(svn_fs_root_t *root,
     low_water_mark = 0;
 
   /* Initialize our callback baton. */
-  cb_baton.editor = editor;
-  cb_baton.edit_baton = edit_baton;
   cb_baton.root = root;
   cb_baton.changed_paths = changed_paths;
   cb_baton.authz_read_func = authz_read_func;
@@ -989,7 +984,7 @@ svn_repos_replay2(svn_fs_root_t *root,
     }
 
   /* Call the path-based editor driver. */
-  return svn_delta_path_driver2(editor, edit_baton,
+  return svn_delta_path_driver3(editor, edit_baton,
                                 paths, TRUE,
                                 path_driver_cb_func, &cb_baton, pool);
 #else

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/reporter.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/reporter.c Fri Jan 14 14:01:45 2022
@@ -47,7 +47,7 @@
    the delta between the source and target revs.
 
    Spill-buffer content format: we use a simple ad-hoc format to store the
-   report operations.  Each report operation is the concatention of
+   report operations.  Each report operation is the concatenation of
    the following ("+/-" indicates the single character '+' or '-';
    <length> and <revnum> are written out as decimal strings):
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.c Fri Jan 14 14:01:45 2022
@@ -1183,7 +1183,7 @@ svn_repos_create(svn_repos_t **repos_p,
   if ((err = svn_fs_create2(&repos->fs, repos->db_path, fs_config,
                             result_pool, scratch_pool)))
     {
-      /* If there was an error making the filesytem, e.g. unknown/supported
+      /* If there was an error making the filesystem, e.g. unknown/supported
        * filesystem type.  Clean up after ourselves.  Yes this is safe because
        * create_repos_structure will fail if the path existed before we started
        * so we can't accidentally remove a directory that previously existed.
@@ -1452,7 +1452,7 @@ svn_repos_upgrade2(const char *path,
   if (notify_func)
     {
       /* We notify *twice* here, because there are two different logistical
-         actions occuring. */
+         actions occurring. */
       svn_repos_notify_t *notify = svn_repos_notify_create(
                                     svn_repos_notify_mutex_acquired, subpool);
       notify_func(notify_baton, notify, subpool);
@@ -1702,7 +1702,7 @@ svn_repos_recover4(const char *path,
   if (notify_func)
     {
       /* We notify *twice* here, because there are two different logistical
-         actions occuring. */
+         actions occurring. */
       svn_repos_notify_t *notify = svn_repos_notify_create(
                                     svn_repos_notify_mutex_acquired, subpool);
       notify_func(notify_baton, notify, subpool);

Modified: subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_repos/repos.h Fri Jan 14 14:01:45 2022
@@ -128,7 +128,7 @@ struct svn_repos_t
   /* The format number of this repository. */
   int format;
 
-  /* The path to the repository's hooks enviroment file. If NULL, hooks run
+  /* The path to the repository's hooks environment file. If NULL, hooks run
    * in an empty environment. */
   const char *hooks_env_path;
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/cache-memcache.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/cache-memcache.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_subr/cache-memcache.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_subr/cache-memcache.c Fri Jan 14 14:01:45 2022
@@ -234,7 +234,7 @@ memcache_has_key(svn_boolean_t *found,
   return SVN_NO_ERROR;
 }
 
-/* Core functionality of our setter functions: store LENGH bytes of DATA
+/* Core functionality of our setter functions: store LENGTH bytes of DATA
  * to be identified by KEY in the memcached given by CACHE_VOID. Use POOL
  * for temporary allocations.
  */

Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/cmdline.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/cmdline.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_subr/cmdline.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_subr/cmdline.c Fri Jan 14 14:01:45 2022
@@ -39,8 +39,15 @@
 
 #include <apr.h>                /* for STDIN_FILENO */
 #include <apr_errno.h>          /* for apr_strerror */
+#include <apr_version.h>
+#if APR_VERSION_AT_LEAST(1,5,0)
+#include <apr_escape.h>
+#else
+#include "private/svn_dep_compat.h"
+#endif
 #include <apr_general.h>        /* for apr_initialize/apr_terminate */
 #include <apr_strings.h>        /* for apr_snprintf */
+#include <apr_env.h>            /* for apr_env_get */
 #include <apr_pools.h>
 #include <apr_signal.h>
 
@@ -73,7 +80,7 @@
 
 #if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1400)
 /* Before Visual Studio 2005, the C runtime didn't handle encodings for the
-   for the stdio output handling. */
+   stdio output handling. */
 #define CMDLINE_USE_CUSTOM_ENCODING
 
 /* The stdin encoding. If null, it's the same as the native encoding. */
@@ -1233,39 +1240,85 @@ svn_cmdline__be_interactive(svn_boolean_
 }
 
 
-/* Helper for the next two functions.  Set *EDITOR to some path to an
-   editor binary.  Sources to search include: the EDITOR_CMD argument
-   (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
+/* Helper for the edit_externally functions.  Set *EDITOR to some path to an
+   editor binary, in native C string on Unix/Linux platforms and in UTF-8
+   string on Windows platform.  Sources to search include: the EDITOR_CMD
+   argument (if not NULL), $SVN_EDITOR, the runtime CONFIG variable (if CONFIG
    is not NULL), $VISUAL, $EDITOR.  Return
    SVN_ERR_CL_NO_EXTERNAL_EDITOR if no binary can be found. */
 static svn_error_t *
 find_editor_binary(const char **editor,
                    const char *editor_cmd,
-                   apr_hash_t *config)
+                   apr_hash_t *config,
+                   apr_pool_t *pool)
 {
   const char *e;
+  const char *e_cfg;
   struct svn_config_t *cfg;
+  apr_status_t status;
 
   /* Use the editor specified on the command line via --editor-cmd, if any. */
+#ifdef WIN32
+  /* On Windows, editor_cmd is transcoded to the system active code page
+     because we use main() as a entry point without APR's (or our own) wrapper
+     in command line tools. */
+  if (editor_cmd)
+    {
+      SVN_ERR(svn_utf_cstring_to_utf8(&e, editor_cmd, pool));
+    }
+  else
+    {
+      e = NULL;
+    }
+#else
   e = editor_cmd;
+#endif
 
   /* Otherwise look for the Subversion-specific environment variable. */
   if (! e)
-    e = getenv("SVN_EDITOR");
+    {
+      status = apr_env_get((char **)&e, "SVN_EDITOR", pool);
+      if (status || ! *e)
+        {
+           e = NULL;
+        }
+    }
 
   /* If not found then fall back on the config file. */
   if (! e)
     {
       cfg = config ? svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG) : NULL;
-      svn_config_get(cfg, &e, SVN_CONFIG_SECTION_HELPERS,
+      svn_config_get(cfg, &e_cfg, SVN_CONFIG_SECTION_HELPERS,
                      SVN_CONFIG_OPTION_EDITOR_CMD, NULL);
+#ifdef WIN32
+      if (e_cfg)
+        {
+          /* On Windows, we assume that config values are set in system active
+             code page, so we need transcode it here. */
+          SVN_ERR(svn_utf_cstring_to_utf8(&e, e_cfg, pool));
+        }
+#else
+      e = e_cfg;
+#endif
     }
 
   /* If not found yet then try general purpose environment variables. */
   if (! e)
-    e = getenv("VISUAL");
+    {
+      status = apr_env_get((char**)&e, "VISUAL", pool);
+      if (status || ! *e)
+        {
+           e = NULL;
+        }
+    }
   if (! e)
-    e = getenv("EDITOR");
+    {
+      status = apr_env_get((char**)&e, "EDITOR", pool);
+      if (status || ! *e)
+        {
+           e = NULL;
+        }
+    }
 
 #ifdef SVN_CLIENT_EDITOR
   /* If still not found then fall back on the hard-coded default. */
@@ -1299,6 +1352,98 @@ find_editor_binary(const char **editor,
   return SVN_NO_ERROR;
 }
 
+/* Wrapper around apr_pescape_shell() which also escapes whitespace. */
+static const char *
+escape_path(apr_pool_t *pool, const char *orig_path)
+{
+  apr_size_t len, esc_len;
+  apr_status_t status;
+
+  len = strlen(orig_path);
+  esc_len = 0;
+
+  status = apr_escape_shell(NULL, orig_path, len, &esc_len);
+
+  if (status == APR_NOTFOUND)
+    {
+      /* No special characters found by APR, so just surround it in double
+         quotes in case there is whitespace, which APR (as of 1.6.5) doesn't
+         consider special. */
+      return apr_psprintf(pool, "\"%s\"", orig_path);
+    }
+  else
+    {
+#ifdef WIN32
+      const char *p;
+      /* Following the advice from
+         https://docs.microsoft.com/en-us/archive/blogs/twistylittlepassagesallalike/everyone-quotes-command-line-arguments-the-wrong-way
+         1. Surround argument with double-quotes
+         2. Escape backslashes, if they're followed by a double-quote, and double-quotes
+         3. Escape any metacharacter, including double-quotes, with ^ */
+
+      /* Use APR's buffer size as an approximation for how large the escaped
+         string should be, plus 4 bytes for the leading/trailing ^" */
+      svn_stringbuf_t *buf = svn_stringbuf_create_ensure(esc_len + 4, pool);
+      svn_stringbuf_appendcstr(buf, "^\"");
+      for (p = orig_path; *p; p++)
+        {
+          int nr_backslash = 0;
+          while (*p && *p == '\\')
+            {
+              nr_backslash++;
+              p++;
+            }
+
+          if (!*p)
+            /* We've reached the end of the argument, so we need 2n backslash
+               characters.  That will be interpreted as n backslashes and the
+               final double-quote character will be interpreted as the final
+               string delimiter. */
+            svn_stringbuf_appendfill(buf, '\\', nr_backslash * 2);
+          else if (*p == '"')
+            {
+              /* Double-quote as part of the argument means we need to double
+                 any preceding backslashes and then add one to escape the
+                 double-quote. */
+              svn_stringbuf_appendfill(buf, '\\', nr_backslash * 2 + 1);
+              svn_stringbuf_appendbyte(buf, '^');
+              svn_stringbuf_appendbyte(buf, *p);
+            }
+          else
+            {
+              /* Since there's no double-quote, we just insert any backslashes
+                 literally.  No escaping needed. */
+              svn_stringbuf_appendfill(buf, '\\', nr_backslash);
+              if (strchr("()%!^<>&|", *p))
+                svn_stringbuf_appendbyte(buf, '^');
+              svn_stringbuf_appendbyte(buf, *p);
+            }
+        }
+      svn_stringbuf_appendcstr(buf, "^\"");
+      return buf->data;
+#else
+      char *path, *p, *esc_path;
+
+      /* Account for whitespace, since APR doesn't */
+      for (p = (char *)orig_path; *p; p++)
+        if (strchr(" \t\n\r", *p))
+          esc_len++;
+
+      path = apr_pcalloc(pool, esc_len);
+      apr_escape_shell(path, orig_path, len, NULL);
+
+      p = esc_path = apr_pcalloc(pool, len + esc_len + 1);
+      while (*path)
+        {
+          if (strchr(" \t\n\r", *path))
+            *p++ = '\\';
+          *p++ = *path++;
+        }
+
+      return esc_path;
+#endif
+    }
+}
 
 svn_error_t *
 svn_cmdline__edit_file_externally(const char *path,
@@ -1307,13 +1452,17 @@ svn_cmdline__edit_file_externally(const
                                   apr_pool_t *pool)
 {
   const char *editor, *cmd, *base_dir, *file_name, *base_dir_apr;
+  const char *file_name_local;
+#ifdef WIN32
+  const WCHAR *wcmd;
+#endif
   char *old_cwd;
   int sys_err;
   apr_status_t apr_err;
 
   svn_dirent_split(&base_dir, &file_name, path, pool);
 
-  SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
+  SVN_ERR(find_editor_binary(&editor, editor_cmd, config, pool));
 
   apr_err = apr_filepath_get(&old_cwd, APR_FILEPATH_NATIVE, pool);
   if (apr_err)
@@ -1330,8 +1479,18 @@ svn_cmdline__edit_file_externally(const
     return svn_error_wrap_apr
       (apr_err, _("Can't change working directory to '%s'"), base_dir);
 
-  cmd = apr_psprintf(pool, "%s %s", editor, file_name);
+  SVN_ERR(svn_path_cstring_from_utf8(&file_name_local,
+                                     escape_path(pool, file_name), pool));
+  /* editor is explicitly documented as being interpreted by the user's shell,
+     and as such should already be quoted/escaped as needed. */
+#ifndef WIN32
+  cmd = apr_psprintf(pool, "%s %s", editor, file_name_local);
   sys_err = system(cmd);
+#else
+  cmd = apr_psprintf(pool, "\"%s %s\"", editor, file_name_local);
+  SVN_ERR(svn_utf__win32_utf8_to_utf16(&wcmd, cmd, NULL, pool));
+  sys_err = _wsystem(wcmd);
+#endif
 
   apr_err = apr_filepath_set(old_cwd, pool);
   if (apr_err)
@@ -1340,10 +1499,16 @@ svn_cmdline__edit_file_externally(const
                       stderr, TRUE /* fatal */, "svn: ");
 
   if (sys_err)
-    /* Extracting any meaning from sys_err is platform specific, so just
-       use the raw value. */
-    return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
-                             _("system('%s') returned %d"), cmd, sys_err);
+    {
+      const char *cmd_utf8;
+
+      /* Extracting any meaning from sys_err is platform specific, so just
+         use the raw value. */
+      SVN_ERR(svn_path_cstring_to_utf8(&cmd_utf8, cmd, pool));
+      return svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
+                               _("system('%s') returned %d"),
+                               cmd_utf8, sys_err);
+    }
 
   return SVN_NO_ERROR;
 }
@@ -1363,6 +1528,9 @@ svn_cmdline__edit_string_externally(svn_
 {
   const char *editor;
   const char *cmd;
+#ifdef WIN32
+  const WCHAR *wcmd;
+#endif
   apr_file_t *tmp_file;
   const char *tmpfile_name;
   const char *tmpfile_native;
@@ -1376,7 +1544,7 @@ svn_cmdline__edit_string_externally(svn_
   int sys_err;
   svn_boolean_t remove_file = TRUE;
 
-  SVN_ERR(find_editor_binary(&editor, editor_cmd, config));
+  SVN_ERR(find_editor_binary(&editor, editor_cmd, config, pool));
 
   /* Convert file contents from UTF-8/LF if desired. */
   if (as_text)
@@ -1486,10 +1654,18 @@ svn_cmdline__edit_string_externally(svn_
     goto cleanup;
 
   /* Prepare the editor command line.  */
-  err = svn_utf_cstring_from_utf8(&tmpfile_native, tmpfile_name, pool);
+  err = svn_path_cstring_from_utf8(&tmpfile_native,
+                                   escape_path(pool, tmpfile_name), pool);
   if (err)
     goto cleanup;
+
+  /* editor is explicitly documented as being interpreted by the user's shell,
+     and as such should already be quoted/escaped as needed. */
+#ifndef WIN32
   cmd = apr_psprintf(pool, "%s %s", editor, tmpfile_native);
+#else
+  cmd = apr_psprintf(pool, "\"%s %s\"", editor, tmpfile_native);
+#endif
 
   /* If the caller wants us to leave the file around, return the path
      of the file we'll use, and make a note not to destroy it.  */
@@ -1500,13 +1676,22 @@ svn_cmdline__edit_string_externally(svn_
     }
 
   /* Now, run the editor command line.  */
+#ifndef WIN32
   sys_err = system(cmd);
+#else
+  SVN_ERR(svn_utf__win32_utf8_to_utf16(&wcmd, cmd, NULL, pool));
+  sys_err = _wsystem(wcmd);
+#endif
   if (sys_err != 0)
     {
+      const char *cmd_utf8;
+
       /* Extracting any meaning from sys_err is platform specific, so just
          use the raw value. */
+      SVN_ERR(svn_path_cstring_to_utf8(&cmd_utf8, cmd, pool));
       err =  svn_error_createf(SVN_ERR_EXTERNAL_PROGRAM, NULL,
-                               _("system('%s') returned %d"), cmd, sys_err);
+                               _("system('%s') returned %d"),
+                               cmd_utf8, sys_err);
       goto cleanup;
     }
 

Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/config_file.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_subr/config_file.c Fri Jan 14 14:01:45 2022
@@ -550,7 +550,7 @@ parse_option(int *pch, parse_context_t *
 }
 
 
-/* Read chars until enounter ']', then skip everything to the end of
+/* Read chars until encounter ']', then skip everything to the end of
  * the line.  Set *PCH to the character that ended the line (either
  * newline or EOF), and set CTX->section to the string of characters
  * seen before ']'.
@@ -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
@@ -1192,16 +1192,13 @@ svn_config_ensure(const char *config_dir
         "###                              may be cached to disk."            NL
         "###   username                   Specifies the default username."   NL
         "###"                                                                NL
-        "### Set store-passwords to 'no' to avoid storing passwords on disk" NL
-        "### in any way, including in password stores.  It defaults to"      NL
+        "### Set store-passwords to 'no' to avoid storing new passwords on"  NL
+        "### disk in any way, including in password stores.  It defaults to" NL
         "### 'yes', but Subversion will never save your password to disk in" NL
         "### plaintext unless explicitly configured to do so."               NL
-        "### Note that this option only prevents saving of *new* passwords;" NL
-        "### it doesn't invalidate existing passwords.  (To do that, remove" NL
-        "### the cache files by hand as described in the Subversion book.)"  NL
         "###"                                                                NL
 #ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
-        "### Set store-plaintext-passwords to 'no' to avoid storing"         NL
+        "### Set store-plaintext-passwords to 'no' to avoid storing new"     NL
         "### passwords in unencrypted form in the auth/ area of your config" NL
         "### directory. Set it to 'yes' to allow Subversion to store"        NL
         "### unencrypted passwords in the auth/ area.  The default is"       NL
@@ -1211,22 +1208,15 @@ svn_config_ensure(const char *config_dir
         "### 'store-auth-creds' is set to 'no'."                             NL
         "###"                                                                NL
 #endif
-        "### Set store-ssl-client-cert-pp to 'no' to avoid storing ssl"      NL
+        "### Set store-ssl-client-cert-pp to 'no' to avoid storing new ssl"  NL
         "### client certificate passphrases in the auth/ area of your"       NL
         "### config directory.  It defaults to 'yes', but Subversion will"   NL
         "### never save your passphrase to disk in plaintext unless"         NL
         "### explicitly configured to do so."                                NL
         "###"                                                                NL
-        "### Note store-ssl-client-cert-pp only prevents the saving of *new*"NL
-        "### passphrases; it doesn't invalidate existing passphrases.  To do"NL
-        "### that, remove the cache files by hand as described in the"       NL
-        "### Subversion book at http://svnbook.red-bean.com/nightly/en/\\"   NL
-        "###                    svn.serverconfig.netmodel.html\\"            NL
-        "###                    #svn.serverconfig.netmodel.credcache"        NL
-        "###"                                                                NL
 #ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
         "### Set store-ssl-client-cert-pp-plaintext to 'no' to avoid storing"NL
-        "### passphrases in unencrypted form in the auth/ area of your"      NL
+        "### new passphrases in unencrypted form in the auth/ area of your"  NL
         "### config directory.  Set it to 'yes' to allow Subversion to"      NL
         "### store unencrypted passphrases in the auth/ area.  The default"  NL
         "### is 'ask', which means that Subversion will prompt before"       NL
@@ -1235,12 +1225,19 @@ svn_config_ensure(const char *config_dir
         "### 'store-ssl-client-cert-pp' is set to 'no'."                     NL
         "###"                                                                NL
 #endif
-        "### Set store-auth-creds to 'no' to avoid storing any Subversion"   NL
+        "### Set store-auth-creds to 'no' to avoid storing any new Subversion"
+                                                                             NL
         "### credentials in the auth/ area of your config directory."        NL
         "### Note that this includes SSL server certificates."               NL
-        "### It defaults to 'yes'.  Note that this option only prevents"     NL
-        "### saving of *new* credentials;  it doesn't invalidate existing"   NL
-        "### caches.  (To do that, remove the cache files by hand.)"         NL
+        "### It defaults to 'yes'."                                          NL
+        "###"                                                                NL
+        "### Note that setting a 'store-*' option to 'no' only prevents"     NL
+        "### saving of *new* passwords, passphrases or other credentials."   NL
+        "### It does not remove or invalidate existing stored credentials."  NL
+        "### To do that, see the 'svn auth --remove' command, or remove the" NL
+        "### cache files by hand as described in the Subversion book at"     NL
+        "### http://svnbook.red-bean.com/nightly/en/svn.serverconfig.netmodel.html#svn.tour.initial.authn-cache-purge"
+                                                                             NL
         "###"                                                                NL
         "### HTTP timeouts, if given, are specified in seconds.  A timeout"  NL
         "### of 0, i.e. zero, causes a builtin default to be used."          NL
@@ -1445,11 +1442,12 @@ svn_config_ensure(const char *config_dir
         "### is defined.  The command (or environment variable) may contain" NL
         "### arguments, using standard shell quoting for arguments with"     NL
         "### spaces.  The command will be invoked as:"                       NL
-        "###   <command> <hostname> svnserve -t"                             NL
-        "### (If the URL includes a username, then the hostname will be"     NL
-        "### passed to the tunnel agent as <user>@<hostname>.)  If the"      NL
-        "### built-in ssh scheme were not predefined, it could be defined"   NL
-        "### as:"                                                            NL
+        "###   <command> <hostinfo> svnserve -t"                             NL
+        "### where <hostinfo> is the hostname part of the URL.  If the URL"  NL
+        "### specified a username and/or a port, those are included in the"  NL
+        "### <hostinfo> argument in the usual way: <user>@<hostname>:<port>."NL
+        "### If the built-in ssh scheme were not predefined, it could be"    NL
+        "### defined as:"                                                    NL
         "# ssh = $SVN_SSH ssh -q --"                                         NL
         "### If you wanted to define a new 'rsh' scheme, to be used with"    NL
         "### 'svn+rsh:' URLs, you could do so as follows:"                   NL

Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/date.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/date.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_subr/date.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_subr/date.c Fri Jan 14 14:01:45 2022
@@ -37,7 +37,7 @@ enum rule_action {
                if the next template character matches the current
                value character, continue processing as normal.
                Otherwise, attempt to complete matching starting
-               immediately after the first subsequent occurrance of
+               immediately after the first subsequent occurrence of
                ']' in the template. */
   SKIP,     /* Ignore this template character */
   ACCEPT    /* Accept the value */

Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/dirent_uri.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_subr/dirent_uri.c Fri Jan 14 14:01:45 2022
@@ -37,6 +37,7 @@
 #include "svn_ctype.h"
 
 #include "dirent_uri.h"
+#include "private/svn_dirent_uri_private.h"
 #include "private/svn_fspath.h"
 #include "private/svn_cert.h"
 
@@ -292,8 +293,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 +309,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 +325,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 +557,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 +668,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 +898,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)
 {
@@ -906,14 +935,18 @@ svn_dirent_local_style(const char *diren
   return dirent;
 }
 
-const char *
-svn_relpath__internal_style(const char *relpath,
-                            apr_pool_t *pool)
-{
-  return svn_relpath_canonicalize(internal_style(relpath, pool), pool);
+svn_error_t *
+svn_relpath__make_internal(const char **internal_style_relpath,
+                           const char *relpath,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(
+      svn_relpath_canonicalize_safe(internal_style_relpath, NULL,
+                                    internal_style(relpath, scratch_pool),
+                                    result_pool, scratch_pool));
 }
 
-
 /* We decided against using apr_filepath_root here because of the negative
    performance impact (creating a pool and converting strings ). */
 svn_boolean_t
@@ -1643,19 +1676,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 +1769,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

Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/error.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/error.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_subr/error.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_subr/error.c Fri Jan 14 14:01:45 2022
@@ -146,6 +146,7 @@ svn_error__locate(const char *file, long
 
 /* Cleanup function for errors.  svn_error_clear () removes this so
    errors that are properly handled *don't* hit this code. */
+#ifdef SVN_DEBUG
 static apr_status_t err_abort(void *data)
 {
   svn_error_t *err = data;  /* For easy viewing in a debugger */
@@ -155,6 +156,7 @@ static apr_status_t err_abort(void *data
     abort();
   return APR_SUCCESS;
 }
+#endif
 
 
 static svn_error_t *

Modified: subversion/branches/multi-wc-format/subversion/libsvn_subr/gpg_agent.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/libsvn_subr/gpg_agent.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/libsvn_subr/gpg_agent.c (original)
+++ subversion/branches/multi-wc-format/subversion/libsvn_subr/gpg_agent.c Fri Jan 14 14:01:45 2022
@@ -108,7 +108,7 @@ escape_blanks(char *str)
 
 #define is_hex(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'A' && (c) <= 'F'))
 #define hex_to_int(c) ((c) < '9' ? (c) - '0' : (c) - 'A' + 10)
- 
+
 /* Modify STR in-place.  '%', CR and LF are always percent escaped,
    other characters may be percent escaped, always using uppercase
    hex, see https://www.gnupg.org/documentation/manuals/assuan.pdf */
@@ -680,9 +680,9 @@ simple_gpg_agent_next_creds(void **crede
   /* TODO: This attempt limit hard codes it at 3 attempts (or 2 retries)
    * which matches svn command line client's retry_limit as set in
    * svn_cmdline_create_auth_baton().  It would be nice to have that
-   * limit reflected here but that violates the boundry between the
+   * limit reflected here but that violates the boundary between the
    * prompt provider and the cache provider.  gpg-agent is acting as
-   * both here due to the peculiarties of their design so we'll have to
+   * both here due to the peculiarities of their design so we'll have to
    * live with this for now.  Note that when these failures get exceeded
    * it'll eventually fall back on the retry limits of whatever prompt
    * provider is in effect, so this effectively doubles the limit. */