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. */
