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 [28/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/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnserve/serve.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnserve/serve.c (original)
+++ subversion/branches/multi-wc-format/subversion/svnserve/serve.c Fri Jan 14 14:01:45 2022
@@ -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);
@@ -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);
@@ -2843,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;
@@ -2854,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);
 
@@ -2897,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));
@@ -2996,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;
@@ -3010,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
@@ -3059,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;
@@ -3071,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)
@@ -3128,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,
@@ -3179,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);
 
@@ -3192,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
@@ -3239,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;
 
@@ -3250,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)
@@ -3302,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));
@@ -3333,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;
@@ -3356,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));
 
@@ -3494,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;
 }
@@ -3518,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;
@@ -3533,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,
@@ -3608,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;
@@ -3634,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)
@@ -3793,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;
 
@@ -3812,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. */
@@ -3822,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);
@@ -3844,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)
@@ -3870,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,
@@ -4092,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
  */
@@ -4101,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));
@@ -4170,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
@@ -4214,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)
@@ -4239,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/multi-wc-format/subversion/svnserve/server.h
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnserve/server.h?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnserve/server.h (original)
+++ subversion/branches/multi-wc-format/subversion/svnserve/server.h Fri Jan 14 14:01:45 2022
@@ -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/multi-wc-format/subversion/svnserve/svnserve.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnserve/svnserve.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnserve/svnserve.c (original)
+++ subversion/branches/multi-wc-format/subversion/svnserve/svnserve.c Fri Jan 14 14:01:45 2022
@@ -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/multi-wc-format/subversion/svnsync/svnsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnsync/svnsync.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnsync/svnsync.c (original)
+++ subversion/branches/multi-wc-format/subversion/svnsync/svnsync.c Fri Jan 14 14:01:45 2022
@@ -294,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;
@@ -821,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));
@@ -998,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;
@@ -1013,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));
 

Modified: subversion/branches/multi-wc-format/subversion/svnsync/sync.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/svnsync/sync.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/svnsync/sync.c (original)
+++ subversion/branches/multi-wc-format/subversion/svnsync/sync.c Fri Jan 14 14:01:45 2022
@@ -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

Propchange: subversion/branches/multi-wc-format/subversion/tests/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Fri Jan 14 14:01:45 2022
@@ -6,4 +6,3 @@ Release
 *.o
 *~
 .*~
-svnserveautocheck.pid

Modified: subversion/branches/multi-wc-format/subversion/tests/README
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/README?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/README (original)
+++ subversion/branches/multi-wc-format/subversion/tests/README Fri Jan 14 14:01:45 2022
@@ -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/multi-wc-format/subversion/tests/afl/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Fri Jan 14 14:01:45 2022
@@ -1,3 +1,4 @@
 *.lo
 .libs
 afl-x509
+afl-svndiff

Modified: subversion/branches/multi-wc-format/subversion/tests/afl/afl-svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/afl/afl-svndiff.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/afl/afl-svndiff.c (original)
+++ subversion/branches/multi-wc-format/subversion/tests/afl/afl-svndiff.c Fri Jan 14 14:01:45 2022
@@ -56,7 +56,7 @@ parse(const char *filename, apr_pool_t *
 
   stream = svn_txdelta_parse_svndiff(txdelta_window_handler, NULL, TRUE, pool);
   SVN_ERR(svn_stream_copy3(svndiff, stream, NULL, NULL, pool));
-  
+
   return SVN_NO_ERROR;
 }
 

Propchange: subversion/branches/multi-wc-format/subversion/tests/cmdline/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Fri Jan 14 14:01:45 2022
@@ -1,5 +1,6 @@
 svn-test-work
 httpd-*
+svnserve-*
 .gdb_history
 *.pyc
 *.o
@@ -10,3 +11,4 @@ atomic-ra-revprop-change
 .libs
 .davautocheck.sh.stop
 lock-helper
+svneditor.sh

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/atomic-ra-revprop-change.c
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/atomic-ra-revprop-change.c?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/atomic-ra-revprop-change.c (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/atomic-ra-revprop-change.c Fri Jan 14 14:01:45 2022
@@ -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/multi-wc-format/subversion/tests/cmdline/authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/authz_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/authz_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/authz_tests.py Fri Jan 14 14:01:45 2022
@@ -1663,6 +1663,106 @@ 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)
+
+
+@Issue(4878)
+@XFail(svntest.main.is_ra_type_dav)
+@Skip(svntest.main.is_ra_type_file)
+def delete_file_with_starstar_rules(sbox):
+  "delete file with ** rules"
+
+  # mod_dav_svn unnecessarily requires svn_authz_recursive access on DELETE of
+  # a file.  See:
+  # 
+  #     https://mail-archives.apache.org/mod_mbox/subversion-users/202107.mbox/%3C20210731004148.GA26581%40tarpaulin.shahaf.local2%3E
+  #     https://mail-archives.apache.org/mod_mbox/subversion-dev/202107.mbox/%3C20210731004148.GA26581%40tarpaulin.shahaf.local2%3E
+  #     (Both links go to the same message.)
+  #
+  # The test will XPASS if the glob rule is removed.
+  #
+  # Note that the /**/lorem rule can't possibly match ^/iota, but its existence
+  # nevertheless affects the results of the authz check.
+
+  sbox.build(create_wc = False)
+
+  write_restrictive_svnserve_conf(sbox.repo_dir)
+
+  prefixed_rules = dict()
+  prefixed_rules[':glob:/**/lorem'] = '* = \n'
+  prefixed_rules['/'] = '%s = rw\n' % (svntest.main.wc_author,)
+  prefixed_rules['/A'] = '%s = \n' % (svntest.main.wc_author,)
+  prefixed_rules['/iota'] = '%s = rw\n' % (svntest.main.wc_author,)
+  write_authz_file(sbox, None, prefixed_rules = prefixed_rules)
+
+  svntest.main.run_svn(None, 'rm', sbox.repo_url + '/iota', '-m', 'rm by URL')
+
 
 ########################################################################
 # Run the tests
@@ -1700,6 +1800,10 @@ 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,
+              delete_file_with_starstar_rules,
              ]
 serial_only = True
 

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/basic_tests.py Fri Jan 14 14:01:45 2022
@@ -3050,33 +3050,6 @@ def peg_rev_on_non_existent_wc_path(sbox
                                      'cat', '-r2', sbox.ospath('mu3') + '@3')
 
 
-def do_move_with_at_signs(sbox, src, dst, dst_cmdline):
-  sbox.build()
-
-  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
-  expected_status.tweak(src, status='D ', moved_to=dst)
-  expected_status.add({dst: Item(status='A ', copied='+',
-                                 moved_from=src, wc_rev='-')})
-
-  sbox.simple_move(src, dst_cmdline)
-  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
-
-@Issue(4530)
-@XFail()
-def move_to_target_with_leading_at_sign(sbox):
-  "rename to dir/@file"
-
-  do_move_with_at_signs(sbox, 'iota', 'A/@upsilon', 'A/@upsilon')
-
-
-@Issue(4530)
-@XFail()
-def move_to_target_with_leading_and_trailing_at_sign(sbox):
-  "rename to dir/@file@"
-
-  do_move_with_at_signs(sbox, 'iota', 'A/@upsilon', 'A/@upsilon@')
-
-
 @Issue(4532)
 def diff_previous_revision_of_r0(sbox):
   """diff -rPREV on WC at revision 0"""
@@ -3132,7 +3105,7 @@ def plaintext_password_storage_disabled(
   servers_file = open(os.path.join(config_dir_path, "servers"), "w")
   servers_file.write("[global]\nstore-plaintext-passwords=no\n")
   servers_file.close()
-  
+
   svntest.main.run_command(svntest.main.svn_binary, False, False,
    "commit", "--config-dir", config_dir_path,
     "-m", "committing with plaintext password storage disabled",
@@ -3338,8 +3311,6 @@ test_list = [ None,
               rm_missing_with_case_clashing_ondisk_item,
               delete_conflicts_one_of_many,
               peg_rev_on_non_existent_wc_path,
-              move_to_target_with_leading_at_sign,
-              move_to_target_with_leading_and_trailing_at_sign,
               diff_previous_revision_of_r0,
               mkdir_parents_target_exists_on_disk,
               plaintext_password_storage_disabled,

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/blame_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/blame_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/blame_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/blame_tests.py Fri Jan 14 14:01:45 2022
@@ -958,8 +958,7 @@ def blame_youngest_to_oldest(sbox):
   sbox.simple_commit() #r3
 
   # Delete a line.
-  with open(iota_moved, 'w') as f:
-    f.write(line)
+  svntest.main.file_write(iota_moved, line)
   sbox.simple_commit() #r4
 
   expected_output = [

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/changelist_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/changelist_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/changelist_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/changelist_tests.py Fri Jan 14 14:01:45 2022
@@ -73,6 +73,33 @@ def changelist_all_files(wc_dir, name_fu
         else:
           svntest.main.run_svn(None, "changelist", clname, full_path)
 
+def select_paths(target_path, depth, changelists, name_func):
+  """Return the subset of paths found on disk at TARGET_PATH, to a depth
+     of DEPTH, that match CHANGELISTS.
+     NAME_FUNC, rather than the working copy, determines what
+     changelist each path is associated with.
+     Returned paths are relative to the CWD.
+
+     ### Only the paths of files are returned.
+  """
+  dot_svn = svntest.main.get_admin_name()
+  for dirpath, dirs, files in os.walk(target_path):
+    # prepare to return paths relative to WC_DIR
+    if dot_svn in dirs:
+      dirs.remove(dot_svn)
+    if not changelists:  # When changelists support dirs, add: "or name_func(name) in changelists"
+      yield os.path.normpath(dirpath)
+    if depth == 'empty':
+      dirs[:] = []  # process no subdirs
+      continue      # nor files
+    for name in files:
+      if not changelists or name_func(name) in changelists:
+        yield os.path.normpath(os.path.join(dirpath, name))
+    if depth == 'files':
+      dirs[:] = []  # process no subdirs
+    if depth == 'immediates':
+      depth = 'empty'  # process subdirs, but no files nor dirs in them
+
 def clname_from_lastchar_cb(full_path):
   """Callback for changelist_all_files() that returns a changelist
   name matching the last character in the file's name.  For example,
@@ -544,6 +571,8 @@ def info_with_changelists(sbox):
 
 #----------------------------------------------------------------------
 
+@XFail()
+@Issue(4826)
 def diff_with_changelists(sbox):
   "diff --changelist (wc-wc and repos-wc)"
 
@@ -553,31 +582,20 @@ def diff_with_changelists(sbox):
   # Add a line of text to all the versioned files in the tree.
   mod_all_files(wc_dir, "New text.\n")
 
+  # Also make a property modification on each directory.
+  svntest.main.run_svn(None, 'propset', 'p', 'v', '-R', wc_dir)
+
   # Add files to changelists based on the last character in their names.
   changelist_all_files(wc_dir, clname_from_lastchar_cb)
 
   # Now, test various combinations of changelist specification and depths.
   for is_repos_wc in [0, 1]:
-    for clname in [['a'], ['i'], ['a', 'i']]:
-      for depth in ['files', 'infinity']:
+    for clname in [['a'], ['a', 'i'], []]:
+      for depth in ['empty', 'files', 'immediates', 'infinity', None]:
+       for subdir in ['.', 'A', 'A/D']:
 
         # Figure out what we expect to see in our diff output.
-        expected_paths = []
-        if 'a' in clname:
-          if depth == 'infinity':
-            expected_paths.append('A/B/lambda')
-            expected_paths.append('A/B/E/alpha')
-            expected_paths.append('A/B/E/beta')
-            expected_paths.append('A/D/gamma')
-            expected_paths.append('A/D/H/omega')
-          if depth == 'files' or depth == 'infinity':
-            expected_paths.append('iota')
-        if 'i' in clname:
-          if depth == 'infinity':
-            expected_paths.append('A/D/G/pi')
-            expected_paths.append('A/D/H/chi')
-            expected_paths.append('A/D/H/psi')
-        expected_paths = sorted([os.path.join(wc_dir, x.replace('/', os.sep)) for x in expected_paths])
+        expected_paths = sorted(select_paths(sbox.ospath(subdir), depth, clname, clname_from_lastchar_cb))
 
         # Build the command line.
         args = ['diff']
@@ -589,11 +607,11 @@ def diff_with_changelists(sbox):
           args.append(depth)
         if is_repos_wc:
           args.append('--old')
-          args.append(sbox.repo_url)
+          args.append(sbox.repo_url + '/' + subdir)
           args.append('--new')
-          args.append(sbox.wc_dir)
+          args.append(os.path.join(wc_dir, subdir))
         else:
-          args.append(wc_dir)
+          args.append(os.path.join(wc_dir, subdir))
 
         # Run 'svn diff ...'
         exit_code, output, errput = svntest.main.run_svn(None, *args)
@@ -1180,6 +1198,44 @@ def readd_after_revert(sbox):
   svntest.actions.run_and_verify_svn(None, [],
                                      'add', dummy)
 
+#----------------------------------------------------------------------
+
+# A wc-wc diff returned no results if changelists were specified and the
+# diff target dir was not the WC root.
+@Issue(4822)
+def diff_with_changelists_subdir(sbox):
+  "diff --changelist (wc-wc) in subdir of WC"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  expected_paths = sbox.ospaths(['A/D/gamma'])
+  subdir = 'A/D'
+  clname = 'a'
+
+  for path in expected_paths:
+    svntest.main.file_append(path, "New text.\n")
+  svntest.main.run_svn(None, "changelist", clname, *expected_paths)
+
+  # Run 'svn diff ...'
+  exit_code, output, errput = svntest.main.run_svn(None,
+                                'diff', '--changelist', clname,
+                                sbox.ospath(subdir))
+
+  # Filter the output for lines that begin with 'Index:', and
+  # reduce even those lines to just the actual path.
+  paths = sorted([x[7:].rstrip() for x in output if x[:7] == 'Index: '])
+
+  # Diff output on Win32 uses '/' path separators.
+  if sys.platform == 'win32':
+    paths = [x.replace('/', os.sep) for x in paths]
+
+  # And, compare!
+  if (paths != expected_paths):
+    raise svntest.Failure("Expected paths (%s) and actual paths (%s) "
+                          "don't gel"
+                          % (str(expected_paths), str(paths)))
+
 
 ########################################################################
 # Run the tests
@@ -1203,6 +1259,7 @@ test_list = [ None,
               add_remove_non_existent_target,
               add_remove_unversioned_target,
               readd_after_revert,
+              diff_with_changelists_subdir,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/commit_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/commit_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/commit_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/commit_tests.py Fri Jan 14 14:01:45 2022
@@ -3146,6 +3146,61 @@ def commit_issue4722_checksum(sbox):
       fp.write('abcdefghijklmnopqrstuvwxyz')
   sbox.simple_commit()
 
+@XFail()
+def commit_sees_tree_conflict_on_unversioned_path(sbox):
+  "commit sees tree conflict on unversioned path"
+
+  sbox.build(empty=True)
+  was_cwd = os.getcwd()
+  os.chdir(sbox.wc_dir)
+  sbox.wc_dir = '.'
+
+  # create a tree conflict victim at an unversioned path
+  sbox.simple_mkdir('topdir')
+  sbox.simple_commit()
+  sbox.simple_mkdir('topdir/subdir')
+  sbox.simple_commit()
+  sbox.simple_update()
+  sbox.simple_rm('topdir')
+  sbox.simple_commit()
+  sbox.simple_update()
+  svntest.actions.run_and_verify_svn(
+    None, [],
+    'merge', '-c2', sbox.wc_dir, '--ignore-ancestry', '--accept', 'postpone')
+  # check that we did create a conflict
+  svntest.actions.run_and_verify_svn(
+    None, 'svn: E155015:.*existing.*conflict.*',
+    'merge', '-c1', sbox.wc_dir, '--ignore-ancestry', '--accept', 'postpone')
+
+  # attempt to commit; should fail
+  expected_err = "svn: E155015: .* '.*topdir' remains in conflict"
+  svntest.actions.run_and_verify_commit(sbox.wc_dir, None, None,
+                                        expected_err,
+                                        sbox.wc_dir)
+
+  os.chdir(was_cwd)
+
+def commit_replaced_file_with_mods(sbox):
+  "commit a replaced file with modification"
+
+  sbox.build(empty=True)
+
+  sbox.simple_append('foo', 'old foo')
+  sbox.simple_add('foo')
+  sbox.simple_append('bar', 'old bar')
+  sbox.simple_add('bar')
+  sbox.simple_commit()
+
+  sbox.simple_rm('foo')
+  sbox.simple_append('foo', 'new foo')
+  sbox.simple_add('foo')
+  sbox.simple_commit()
+
+  sbox.simple_rm('bar')
+  sbox.simple_copy('foo', 'bar')
+  sbox.simple_append('bar', 'new bar')
+  sbox.simple_commit()
+
 
 ########################################################################
 # Run the tests
@@ -3225,6 +3280,8 @@ test_list = [ None,
               mkdir_conflict_proper_error,
               commit_xml,
               commit_issue4722_checksum,
+              commit_sees_tree_conflict_on_unversioned_path,
+              commit_replaced_file_with_mods,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/copy_tests.py Fri Jan 14 14:01:45 2022
@@ -1021,6 +1021,76 @@ def repos_to_wc(sbox):
                                      os.path.join(D_dir, 'B'))
 
 #----------------------------------------------------------------------
+def foreign_repos_to_wc(sbox):
+  "foreign repository to WC copy"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  def move_url(repo_url, source, dest):
+    svntest.main.run_svn(False, 'move', '-m', svntest.main.make_log_msg(),
+                         repo_url + '/' + source,
+                         repo_url + '/' + dest)
+
+  # Scenarios:
+  # (parent-path-under-'A/', base-name, child-paths, mergeinfo-inheritance)
+  scenarios = [
+    ('B',   'E',   ['alpha','beta'], 'explicit'),
+    ('B',   'F',   [],               'inherited'),
+    ('D/G', 'pi',  [],               'explicit'),
+    ('D/G', 'rho', [],               'inherited'),
+  ]
+
+  # Add some mergeinfo, which should be discarded by a foreign repo copy.
+  # On each path of interest, add either explicit or inherited mergeinfo:
+  # the implementation handles these cases differently.
+  # (We commit these initially in the original repo just for convenience: as
+  # we already have a WC. Really they only need to be in the 'other' repo.)
+  for parent, name, children, mi_inheritance in scenarios:
+    if mi_inheritance == 'explicit':
+      sbox.simple_propset(SVN_PROP_MERGEINFO,
+                          '/branch/' + name + ':1', 'A/' + parent + '/' + name)
+    else:
+      sbox.simple_propset(SVN_PROP_MERGEINFO,
+                          '/branch/' + name + ':1', 'A/' + parent)
+  sbox.simple_commit()
+
+  # We have a standard repository and working copy.  Now we create a
+  # second repository with the same greek tree, but different UUID.
+  repo_dir       = sbox.repo_dir
+  other_repo_dir, other_repo_url = sbox.add_repo_path('other')
+  svntest.main.copy_repos(repo_dir, other_repo_dir, 2, 1)
+  move_url(other_repo_url, 'A', 'A2')
+  move_url(other_repo_url, 'A2', 'A3')
+
+  # URL->wc copy:
+  # copy a file and a directory from a foreign repository.
+  # we should get some scheduled additions *without history*.
+  peg_rev = '3'
+  op_rev = '2'
+
+  for parent, name, children, mi_inheritance in scenarios:
+    src_url = other_repo_url + '/A2/' + parent + '/' + name
+    src_url_resolved = src_url.replace('/A2/', '/A/')
+
+    expected_output = svntest.verify.UnorderedOutput([
+      '--- Copying from foreign repository URL \'%s\':\n' % src_url_resolved,
+      'A         %s\n' % sbox.ospath(name),
+    ] + [
+      'A         %s\n' % sbox.ospath(name + '/' + child)
+      for child in children
+    ])
+    svntest.actions.run_and_verify_svn(expected_output, [],
+                                       'copy', '-r' + op_rev,
+                                       src_url + '@' + peg_rev,
+                                       wc_dir)
+
+    # Validate the mergeinfo of the copy destination (we expect none)
+    svntest.actions.run_and_verify_svn([], '.*W200017: Property.*not found',
+                                       'propget', SVN_PROP_MERGEINFO,
+                                       sbox.ospath(name))
+
+#----------------------------------------------------------------------
 # Issue 1084: ra_svn move/copy bug
 @Issue(1084)
 def copy_to_root(sbox):
@@ -3738,70 +3808,49 @@ def URI_encoded_repos_to_wc(sbox):
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_disk = svntest.main.greek_state.copy()
 
+  def path_join(head, tail):
+    if not head: return tail
+    if not tail: return head
+    return head + '/' + tail
+
+  def greek_file_item(path):
+    if path[-1:].islower():
+      basename = re.sub('.*/', '', path)
+      return Item("This is the file '" + basename + "'.\n")
+    return Item()
+
+  A_paths = [
+    "",
+    "B",
+    "B/lambda",
+    "B/E",
+    "B/E/alpha",
+    "B/E/beta",
+    "B/F",
+    "mu",
+    "C",
+    "D",
+    "D/gamma",
+    "D/G",
+    "D/G/pi",
+    "D/G/rho",
+    "D/G/tau",
+    "D/H",
+    "D/H/chi",
+    "D/H/omega",
+    "D/H/psi",
+    ]
+
   def copy_URL_to_WC(URL_rel_path, dest_name, rev):
-    lines = [
-       "A    " + os.path.join(wc_dir, dest_name, "B") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "B", "lambda") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "B", "E") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "B", "E", "alpha") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "B", "E", "beta") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "B", "F") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "mu") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "C") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "gamma") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "G") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "G", "pi") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "G", "rho") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "G", "tau") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "H") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "H", "chi") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "H", "omega") + "\n",
-       "A    " + os.path.join(wc_dir, dest_name, "D", "H", "psi") + "\n",
-       "Checked out revision " + str(rev - 1) + ".\n",
-       "A         " + os.path.join(wc_dir, dest_name) + "\n"]
-    expected = svntest.verify.UnorderedOutput(lines)
-    expected_status.add({
-      dest_name + "/B"         : Item(status='  ', wc_rev=rev),
-      dest_name + "/B/lambda"  : Item(status='  ', wc_rev=rev),
-      dest_name + "/B/E"       : Item(status='  ', wc_rev=rev),
-      dest_name + "/B/E/alpha" : Item(status='  ', wc_rev=rev),
-      dest_name + "/B/E/beta"  : Item(status='  ', wc_rev=rev),
-      dest_name + "/B/F"       : Item(status='  ', wc_rev=rev),
-      dest_name + "/mu"        : Item(status='  ', wc_rev=rev),
-      dest_name + "/C"         : Item(status='  ', wc_rev=rev),
-      dest_name + "/D"         : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/gamma"   : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/G"       : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/G/pi"    : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/G/rho"   : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/G/tau"   : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/H"       : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/H/chi"   : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/H/omega" : Item(status='  ', wc_rev=rev),
-      dest_name + "/D/H/psi"   : Item(status='  ', wc_rev=rev),
-      dest_name                : Item(status='  ', wc_rev=rev)})
-    expected_disk.add({
-      dest_name                : Item(props={}),
-      dest_name + '/B'         : Item(),
-      dest_name + '/B/lambda'  : Item("This is the file 'lambda'.\n"),
-      dest_name + '/B/E'       : Item(),
-      dest_name + '/B/E/alpha' : Item("This is the file 'alpha'.\n"),
-      dest_name + '/B/E/beta'  : Item("This is the file 'beta'.\n"),
-      dest_name + '/B/F'       : Item(),
-      dest_name + '/mu'        : Item("This is the file 'mu'.\n"),
-      dest_name + '/C'         : Item(),
-      dest_name + '/D'         : Item(),
-      dest_name + '/D/gamma'   : Item("This is the file 'gamma'.\n"),
-      dest_name + '/D/G'       : Item(),
-      dest_name + '/D/G/pi'    : Item("This is the file 'pi'.\n"),
-      dest_name + '/D/G/rho'   : Item("This is the file 'rho'.\n"),
-      dest_name + '/D/G/tau'   : Item("This is the file 'tau'.\n"),
-      dest_name + '/D/H'       : Item(),
-      dest_name + '/D/H/chi'   : Item("This is the file 'chi'.\n"),
-      dest_name + '/D/H/omega' : Item("This is the file 'omega'.\n"),
-      dest_name + '/D/H/psi'   : Item("This is the file 'psi'.\n"),
-      })
+    expected = svntest.verify.UnorderedOutput(
+      [ "A         " + sbox.ospath(path_join(dest_name, p)) + "\n"
+        for p in A_paths ])
+    expected_status.add(
+      { path_join(dest_name, p) : Item(status='  ', wc_rev=rev)
+        for p in A_paths })
+    expected_disk.add(
+      { path_join(dest_name, p) : greek_file_item(p)
+        for p in A_paths })
 
     # Make a copy
     svntest.actions.run_and_verify_svn(expected, [],
@@ -6044,6 +6093,7 @@ test_list = [ None,
               ext_wc_copy_deleted,
               copy_subtree_deleted,
               resurrect_at_root,
+              foreign_repos_to_wc,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/dav_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/dav_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/dav_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/dav_tests.py Fri Jan 14 14:01:45 2022
@@ -25,7 +25,10 @@
 ######################################################################
 
 # General modules
-import os, re
+import os, sys
+import re
+import socket
+import traceback
 
 # Our testing module
 import svntest
@@ -64,6 +67,33 @@ def connect_other_dav_server(sbox):
   svntest.actions.run_and_verify_svn([], svntest.verify.AnyOutput,
                                      'info', svntest.main.other_dav_root_url)
 
+#----------------------------------------------------------------------
+
+@SkipUnless(svntest.main.is_remote_http_connection_allowed)
+def connect_to_github_server(sbox):
+  "connect to GitHub's SVN bridge"
+
+  #github_mirror_url = 'https://github.com/apache/subversion/trunk'
+  # FIXME: Subversion's mirror on GitHub seems to randomly return gateway
+  #        errors (status 504), so use this more stable one instead.
+  github_mirror_url = 'https://github.com/apache/serf/trunk'
+
+  # Skip this test if we can't connect to the GitHub server.
+  # We check this here instead of in a SkipUnless() predicate decorator,
+  # because the decorator's condition function is called seeveral times
+  # during test execution.
+  try:
+    s = socket.create_connection(('github.com', 443), 2)  # 2-second timeout
+    s.close()
+  except:
+    etype, value, _ = sys.exc_info()
+    reason = ''.join(traceback.format_exception_only(etype, value)).rstrip()
+    svntest.main.logger.warn('Connection to github.com failed: ' + reason)
+    raise svntest.Skip
+
+  svntest.actions.run_and_verify_svn(None, [], 'info', github_mirror_url)
+
+
 ########################################################################
 # Run the tests
 
@@ -72,6 +102,7 @@ def connect_other_dav_server(sbox):
 test_list = [ None,
               connect_plain_http_server,
               connect_other_dav_server,
+              connect_to_github_server,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/davautocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/davautocheck.sh?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/davautocheck.sh (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/davautocheck.sh Fri Jan 14 14:01:45 2022
@@ -547,10 +547,9 @@ Alias /fsdavroot $ABS_BUILDDIR/subversio
 
 <Location /svn-test-work/repositories>
 __EOF__
-location_common() {
+location_common_without_authz() {
 cat >> "$HTTPD_CFG" <<__EOF__
   DAV               svn
-  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
   AuthType          Basic
   AuthName          "Subversion Repository"
   AuthUserFile      $HTTPD_USERS
@@ -560,6 +559,12 @@ cat >> "$HTTPD_CFG" <<__EOF__
   SVNBlockRead      ${BLOCK_READ_SETTING}
 __EOF__
 }
+location_common() {
+location_common_without_authz
+cat >> "$HTTPD_CFG" <<__EOF__
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+__EOF__
+}
 location_common
 cat >> "$HTTPD_CFG" <<__EOF__
   SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/repositories"
@@ -583,6 +588,14 @@ cat >> "$HTTPD_CFG" <<__EOF__
   Require           valid-user
   ${SVN_PATH_AUTHZ_LINE}
 </Location>
+<Location /svn-test-work/local_tmp/trojan>
+__EOF__
+location_common
+cat >> "$HTTPD_CFG" <<__EOF__
+  SVNPath           "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp/trojan"
+  Require           valid-user
+  ${SVN_PATH_AUTHZ_LINE}
+</Location>
 <Location /authz-test-work/anon>
   DAV               svn
   SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
@@ -602,6 +615,15 @@ cat >> "$HTTPD_CFG" <<__EOF__
   </IfModule>
   ${SVN_PATH_AUTHZ_LINE}
 </Location>
+<Location /authz-test-work/in-repos-authz>
+__EOF__
+location_common_without_authz
+cat >> "$HTTPD_CFG" <<__EOF__
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/repositories"
+  Require           valid-user
+  Satisfy Any
+  AuthzSVNReposRelativeAccessFile "^/authz"
+</Location>
 <Location /authz-test-work/mixed>
 __EOF__
 location_common

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/depth_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/depth_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/depth_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/depth_tests.py Fri Jan 14 14:01:45 2022
@@ -2846,7 +2846,7 @@ def commit_excluded(sbox):
   expected_output = svntest.wc.State(wc_dir, {
     'D' : Item(verb='Adding'),
   })
-  
+
   expected_status.add({
     'D'          : Item(status='  ', wc_rev='2'),
     'D/H'        : Item(status='  ', wc_rev='2'),
@@ -2971,10 +2971,10 @@ def fold_tree_with_unversioned_items(sbo
 
   # Set A to be excluded.
   svntest.main.run_svn(None, 'update', '--set-depth=exclude', A_path)
-  
+
   # try a simple update afterwards
   sbox.simple_update()
-  
+
 #----------------------------------------------------------------------
 # list all tests here, starting with None:
 test_list = [ None,

Modified: subversion/branches/multi-wc-format/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/multi-wc-format/subversion/tests/cmdline/diff_tests.py?rev=1897034&r1=1897033&r2=1897034&view=diff
==============================================================================
--- subversion/branches/multi-wc-format/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/multi-wc-format/subversion/tests/cmdline/diff_tests.py Fri Jan 14 14:01:45 2022
@@ -2334,7 +2334,7 @@ def diff_nonrecursive_checkout_deleted_d
 # example, show an extraneous BASE->WORKING diff for the added directory
 # after the repos->WORKING output).
 def diff_repos_working_added_dir(sbox):
-  "repos->WORKING diff showing added modifed dir"
+  "repos->WORKING diff showing added modified dir"
 
   sbox.build()
 
@@ -3150,7 +3150,7 @@ def diff_url_against_local_mods(sbox):
   make_file_edit_del_add(A2)
 
   # Diff Path of A against working copy of A2.
-  # Output using arbritrary diff handling should be empty.
+  # Output using arbitrary diff handling should be empty.
   expected_output = []
   svntest.actions.run_and_verify_svn(expected_output, [],
                                      'diff', '--old', A, '--new', A2)
@@ -5253,6 +5253,83 @@ def diff_git_format_copy(sbox):
   svntest.actions.run_and_verify_svn(expected_output, [], 'diff',
                                      '--git', '.')
 
+#----------------------------------------------------------------------
+# Regression test for issue #1722: 'svn diff' produced a wrong header,
+# indicating one revision as being in the working copy when it should
+# be 'nonexistent'
+@Issue(1722)
+def diff_nonexistent_in_wc(sbox):
+  "nonexistent in working copy"
+
+  sbox.build(empty=True)
+  wc_dir = sbox.wc_dir
+
+  # We mirror the actions of the reproduction script (with one exception:
+  # we 'svn up -r 0' instead of checking out a second working copy)
+
+  sbox.simple_add_text('test\n', 'file')
+  sbox.simple_commit()
+  sbox.simple_update(revision=0)
+
+  # Expected output is empty for these cases:
+  # svn diff -r BASE
+  # svn diff -r 0:BASE
+  # svn diff -r 0
+
+  # Expected output for:
+  # svn diff -r BASE:HEAD
+  # svn diff -r 0:HEAD
+  # svn diff -r 0:1
+  expected_output_base_head = make_diff_header("file", "nonexistent",
+                                               "revision 1") + [
+  "@@ -0,0 +1 @@\n",
+  "+test\n",
+  ]
+
+  # Expected output for:
+  # svn diff -r HEAD:BASE
+  # svn diff -r HEAD
+  # svn diff -r 1:0
+  # svn diff -r 1
+  expected_output_head_base = make_diff_header("file", "revision 1",
+                                               "nonexistent") + [
+  "@@ -1 +0,0 @@\n",
+  "-test\n"
+  ]
+
+  os.chdir(wc_dir)
+
+  svntest.actions.run_and_verify_svn(expected_output_base_head, [],
+                                     'diff', '-r', 'BASE:HEAD')
+
+  svntest.actions.run_and_verify_svn(expected_output_head_base, [],
+                                     'diff', '-r', 'HEAD:BASE')
+
+  svntest.actions.run_and_verify_svn([], [],
+                                     'diff', '-r', 'BASE')
+
+  svntest.actions.run_and_verify_svn(expected_output_head_base, [],
+                                     'diff', '-r', 'HEAD')
+
+  svntest.actions.run_and_verify_svn([], [],
+                                     'diff', '-r', '0:BASE')
+
+  svntest.actions.run_and_verify_svn(expected_output_base_head, [],
+                                     'diff', '-r', '0:HEAD')
+
+  svntest.actions.run_and_verify_svn(expected_output_base_head, [],
+                                     'diff', '-r', '0:1')
+
+  svntest.actions.run_and_verify_svn(expected_output_head_base, [],
+                                     'diff', '-r', '1:0')
+
+  svntest.actions.run_and_verify_svn([], [],
+                                     'diff', '-r', '0')
+
+  svntest.actions.run_and_verify_svn(expected_output_head_base, [],
+                                     'diff', '-r', '1')
+
+
 ########################################################################
 #Run the tests
 
@@ -5353,6 +5430,7 @@ test_list = [ None,
               diff_summary_repo_wc_local_copy_unmodified,
               diff_file_replaced_by_symlink,
               diff_git_format_copy,
+              diff_nonexistent_in_wc,
               ]
 
 if __name__ == '__main__':