Modified: subversion/branches/swig-py3/subversion/libsvn_subr/deprecated.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/deprecated.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/deprecated.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/deprecated.c Wed Nov 28 21:25:32 2018 @@ -390,6 +390,30 @@ print_command_info(const svn_opt_subcomm return SVN_NO_ERROR; } +const svn_opt_subcommand_desc2_t * +svn_opt_get_canonical_subcommand2(const svn_opt_subcommand_desc2_t *table, + const char *cmd_name) +{ + int i = 0; + + if (cmd_name == NULL) + return NULL; + + while (table[i].name) { + int j; + if (strcmp(cmd_name, table[i].name) == 0) + return table + i; + for (j = 0; (j < SVN_OPT_MAX_ALIASES) && table[i].aliases[j]; j++) + if (strcmp(cmd_name, table[i].aliases[j]) == 0) + return table + i; + + i++; + } + + /* If we get here, there was no matching subcommand name or alias. */ + return NULL; +} + const svn_opt_subcommand_desc_t * svn_opt_get_canonical_subcommand(const svn_opt_subcommand_desc_t *table, const char *cmd_name) @@ -414,6 +438,344 @@ svn_opt_get_canonical_subcommand(const s return NULL; } +const apr_getopt_option_t * +svn_opt_get_option_from_code2(int code, + const apr_getopt_option_t *option_table, + const svn_opt_subcommand_desc2_t *command, + apr_pool_t *pool) +{ + apr_size_t i; + + for (i = 0; option_table[i].optch; i++) + if (option_table[i].optch == code) + { + if (command) + { + int j; + + for (j = 0; ((j < SVN_OPT_MAX_OPTIONS) && + command->desc_overrides[j].optch); j++) + if (command->desc_overrides[j].optch == code) + { + apr_getopt_option_t *tmpopt = + apr_palloc(pool, sizeof(*tmpopt)); + *tmpopt = option_table[i]; + tmpopt->description = command->desc_overrides[j].desc; + return tmpopt; + } + } + return &(option_table[i]); + } + + return NULL; +} + +const apr_getopt_option_t * +svn_opt_get_option_from_code(int code, + const apr_getopt_option_t *option_table) +{ + apr_size_t i; + + for (i = 0; option_table[i].optch; i++) + if (option_table[i].optch == code) + return &(option_table[i]); + + return NULL; +} + +/* Like svn_opt_get_option_from_code2(), but also, if CODE appears a second + * time in OPTION_TABLE with a different name, then set *LONG_ALIAS to that + * second name, else set it to NULL. */ +static const apr_getopt_option_t * +get_option_from_code(const char **long_alias, + int code, + const apr_getopt_option_t *option_table, + const svn_opt_subcommand_desc2_t *command, + apr_pool_t *pool) +{ + const apr_getopt_option_t *i; + const apr_getopt_option_t *opt + = svn_opt_get_option_from_code2(code, option_table, command, pool); + + /* Find a long alias in the table, if there is one. */ + *long_alias = NULL; + for (i = option_table; i->optch; i++) + { + if (i->optch == code && i->name != opt->name) + { + *long_alias = i->name; + break; + } + } + + return opt; +} + +/* Print an option OPT nicely into a STRING allocated in POOL. + * If OPT has a single-character short form, then print OPT->name (if not + * NULL) as an alias, else print LONG_ALIAS (if not NULL) as an alias. + * If DOC is set, include the generic documentation string of OPT, + * localized to the current locale if a translation is available. + */ +static void +format_option(const char **string, + const apr_getopt_option_t *opt, + const char *long_alias, + svn_boolean_t doc, + apr_pool_t *pool) +{ + char *opts; + + if (opt == NULL) + { + *string = "?"; + return; + } + + /* We have a valid option which may or may not have a "short + name" (a single-character alias for the long option). */ + if (opt->optch <= 255) + opts = apr_psprintf(pool, "-%c [--%s]", opt->optch, opt->name); + else if (long_alias) + opts = apr_psprintf(pool, "--%s [--%s]", opt->name, long_alias); + else + opts = apr_psprintf(pool, "--%s", opt->name); + + if (opt->has_arg) + opts = apr_pstrcat(pool, opts, _(" ARG"), SVN_VA_NULL); + + if (doc) + opts = apr_psprintf(pool, "%-24s : %s", opts, _(opt->description)); + + *string = opts; +} + +/* Print the canonical command name for CMD, and all its aliases, to + STREAM. If HELP is set, print CMD's help string too, in which case + obtain option usage from OPTIONS_TABLE. */ +static svn_error_t * +print_command_info2(const svn_opt_subcommand_desc2_t *cmd, + const apr_getopt_option_t *options_table, + const int *global_options, + svn_boolean_t help, + apr_pool_t *pool, + FILE *stream) +{ + svn_boolean_t first_time; + apr_size_t i; + + /* Print the canonical command name. */ + SVN_ERR(svn_cmdline_fputs(cmd->name, stream, pool)); + + /* Print the list of aliases. */ + first_time = TRUE; + for (i = 0; i < SVN_OPT_MAX_ALIASES; i++) + { + if (cmd->aliases[i] == NULL) + break; + + if (first_time) { + SVN_ERR(svn_cmdline_fputs(" (", stream, pool)); + first_time = FALSE; + } + else + SVN_ERR(svn_cmdline_fputs(", ", stream, pool)); + + SVN_ERR(svn_cmdline_fputs(cmd->aliases[i], stream, pool)); + } + + if (! first_time) + SVN_ERR(svn_cmdline_fputs(")", stream, pool)); + + if (help) + { + const apr_getopt_option_t *option; + const char *long_alias; + svn_boolean_t have_options = FALSE; + + SVN_ERR(svn_cmdline_fprintf(stream, pool, ": %s", _(cmd->help))); + + /* Loop over all valid option codes attached to the subcommand */ + for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++) + { + if (cmd->valid_options[i]) + { + if (!have_options) + { + SVN_ERR(svn_cmdline_fputs(_("\nValid options:\n"), + stream, pool)); + have_options = TRUE; + } + + /* convert each option code into an option */ + option = get_option_from_code(&long_alias, cmd->valid_options[i], + options_table, cmd, pool); + + /* print the option's docstring */ + if (option && option->description) + { + const char *optstr; + format_option(&optstr, option, long_alias, TRUE, pool); + SVN_ERR(svn_cmdline_fprintf(stream, pool, " %s\n", + optstr)); + } + } + } + /* And global options too */ + if (global_options && *global_options) + { + SVN_ERR(svn_cmdline_fputs(_("\nGlobal options:\n"), + stream, pool)); + have_options = TRUE; + + for (i = 0; global_options[i]; i++) + { + + /* convert each option code into an option */ + option = get_option_from_code(&long_alias, global_options[i], + options_table, cmd, pool); + + /* print the option's docstring */ + if (option && option->description) + { + const char *optstr; + format_option(&optstr, option, long_alias, TRUE, pool); + SVN_ERR(svn_cmdline_fprintf(stream, pool, " %s\n", + optstr)); + } + } + } + + if (have_options) + SVN_ERR(svn_cmdline_fprintf(stream, pool, "\n")); + } + + return SVN_NO_ERROR; +} + +/* The body for svn_opt_print_generic_help2() function with standard error + * handling semantic. Handling of errors implemented at caller side. */ +static svn_error_t * +print_generic_help_body(const char *header, + const svn_opt_subcommand_desc2_t *cmd_table, + const apr_getopt_option_t *opt_table, + const char *footer, + apr_pool_t *pool, FILE *stream) +{ + int i = 0; + + if (header) + SVN_ERR(svn_cmdline_fputs(header, stream, pool)); + + while (cmd_table[i].name) + { + SVN_ERR(svn_cmdline_fputs(" ", stream, pool)); + SVN_ERR(print_command_info2(cmd_table + i, opt_table, + NULL, FALSE, + pool, stream)); + SVN_ERR(svn_cmdline_fputs("\n", stream, pool)); + i++; + } + + SVN_ERR(svn_cmdline_fputs("\n", stream, pool)); + + if (footer) + SVN_ERR(svn_cmdline_fputs(footer, stream, pool)); + + return SVN_NO_ERROR; +} + +void +svn_opt_print_generic_help2(const char *header, + const svn_opt_subcommand_desc2_t *cmd_table, + const apr_getopt_option_t *opt_table, + const char *footer, + apr_pool_t *pool, FILE *stream) +{ + svn_error_t *err; + + err = print_generic_help_body(header, cmd_table, opt_table, footer, pool, + stream); + + /* Issue #3014: + * Don't print anything on broken pipes. The pipe was likely + * closed by the process at the other end. We expect that + * process to perform error reporting as necessary. + * + * ### This assumes that there is only one error in a chain for + * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */ + if (err && err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR) + svn_handle_error2(err, stderr, FALSE, "svn: "); + svn_error_clear(err); +} + +svn_boolean_t +svn_opt_subcommand_takes_option3(const svn_opt_subcommand_desc2_t *command, + int option_code, + const int *global_options) +{ + apr_size_t i; + + for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++) + if (command->valid_options[i] == option_code) + return TRUE; + + if (global_options) + for (i = 0; global_options[i]; i++) + if (global_options[i] == option_code) + return TRUE; + + return FALSE; +} + +svn_boolean_t +svn_opt_subcommand_takes_option2(const svn_opt_subcommand_desc2_t *command, + int option_code) +{ + return svn_opt_subcommand_takes_option3(command, + option_code, + NULL); +} + +svn_boolean_t +svn_opt_subcommand_takes_option(const svn_opt_subcommand_desc_t *command, + int option_code) +{ + apr_size_t i; + + for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++) + if (command->valid_options[i] == option_code) + return TRUE; + + return FALSE; +} + +void +svn_opt_subcommand_help3(const char *subcommand, + const svn_opt_subcommand_desc2_t *table, + const apr_getopt_option_t *options_table, + const int *global_options, + apr_pool_t *pool) +{ + const svn_opt_subcommand_desc2_t *cmd = + svn_opt_get_canonical_subcommand2(table, subcommand); + svn_error_t *err; + + if (cmd) + err = print_command_info2(cmd, options_table, global_options, + TRUE, pool, stdout); + else + err = svn_cmdline_fprintf(stderr, pool, + _("\"%s\": unknown command.\n\n"), subcommand); + + if (err) { + /* Issue #3014: Don't print anything on broken pipes. */ + if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR) + svn_handle_error2(err, stderr, FALSE, "svn: "); + svn_error_clear(err); + } +} + void svn_opt_subcommand_help2(const char *subcommand, const svn_opt_subcommand_desc2_t *table, @@ -521,6 +883,56 @@ svn_opt_args_to_target_array(apr_array_h return SVN_NO_ERROR; } +svn_error_t * +svn_opt_print_help4(apr_getopt_t *os, + const char *pgm_name, + svn_boolean_t print_version, + svn_boolean_t quiet, + svn_boolean_t verbose, + const char *version_footer, + const char *header, + const svn_opt_subcommand_desc2_t *cmd_table, + const apr_getopt_option_t *option_table, + const int *global_options, + const char *footer, + apr_pool_t *pool) +{ + apr_array_header_t *targets = NULL; + + if (os) + SVN_ERR(svn_opt_parse_all_args(&targets, os, pool)); + + if (os && targets->nelts) /* help on subcommand(s) requested */ + { + int i; + + for (i = 0; i < targets->nelts; i++) + { + svn_opt_subcommand_help3(APR_ARRAY_IDX(targets, i, const char *), + cmd_table, option_table, + global_options, pool); + } + } + else if (print_version) /* just --version */ + { + SVN_ERR(svn_opt__print_version_info(pgm_name, version_footer, + svn_version_extended(verbose, pool), + quiet, verbose, pool)); + } + else if (os && !targets->nelts) /* `-h', `--help', or `help' */ + svn_opt_print_generic_help2(header, + cmd_table, + option_table, + footer, + pool, + stdout); + else /* unknown option or cmd */ + SVN_ERR(svn_cmdline_fprintf(stderr, pool, + _("Type '%s help' for usage.\n"), pgm_name)); + + return SVN_NO_ERROR; +} + svn_error_t * svn_opt_print_help3(apr_getopt_t *os, const char *pgm_name,
Modified: subversion/branches/swig-py3/subversion/libsvn_subr/io.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/io.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/io.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/io.c Wed Nov 28 21:25:32 2018 @@ -342,8 +342,13 @@ io_check_path(const char *path, /* Not using svn_io_stat() here because we want to check the apr_err return explicitly. */ SVN_ERR(cstring_from_utf8(&path_apr, path, pool)); - +#ifdef WIN32 + /* on Windows, svn does not handle reparse points or hard links. + So ignore the 'resolve_symlinks' flag. */ + flags = APR_FINFO_MIN; +#else flags = resolve_symlinks ? APR_FINFO_MIN : (APR_FINFO_MIN | APR_FINFO_LINK); +#endif apr_err = apr_stat(&finfo, path_apr, flags, pool); if (APR_STATUS_IS_ENOENT(apr_err)) @@ -2541,27 +2546,37 @@ stringbuf_from_aprfile(svn_stringbuf_t * { apr_finfo_t finfo = { 0 }; - /* In some cases we get size 0 and no error for non files, - so we also check for the name. (= cached in apr_file_t) */ + /* In some cases we get size 0 and no error for non files, so we + also check for the name. (= cached in apr_file_t) */ if (! apr_file_info_get(&finfo, APR_FINFO_SIZE, file) && finfo.fname) { - /* we've got the file length. Now, read it in one go. */ + /* In general, there is no guarantee that the given file size is + correct, for instance, because the underlying handle could be + pointing to a pipe. We don't know that in advance, so attempt + to read *one more* byte than necessary. If we get an EOF, then + we're done and we have succesfully avoided reading the file chunk- + by-chunk. If we don't, we fall through and do so to read the + remaining part of the file. */ svn_boolean_t eof; - res_initial_len = (apr_size_t)finfo.size; + res_initial_len = (apr_size_t)finfo.size + 1; res = svn_stringbuf_create_ensure(res_initial_len, pool); SVN_ERR(svn_io_file_read_full2(file, res->data, res_initial_len, &res->len, &eof, pool)); res->data[res->len] = 0; - *result = res; - return SVN_NO_ERROR; + if (eof) + { + *result = res; + return SVN_NO_ERROR; + } } } /* XXX: We should check the incoming data for being of type binary. */ buf = apr_palloc(pool, SVN__STREAM_CHUNK_SIZE); - res = svn_stringbuf_create_ensure(res_initial_len, pool); + if (!res) + res = svn_stringbuf_create_ensure(res_initial_len, pool); /* apr_file_read will not return data and eof in the same call. So this loop * is safe from missing read data. */ @@ -2707,8 +2722,8 @@ svn_io_remove_dir(const char *path, apr_ directory scan. A previous workaround involving rewinddir is problematic on Win32 and some NFS clients, notably NetBSD. - See http://subversion.tigris.org/issues/show_bug.cgi?id=1896 and - http://subversion.tigris.org/issues/show_bug.cgi?id=3501. + See https://issues.apache.org/jira/browse/SVN-1896 and + https://issues.apache.org/jira/browse/SVN-3501. */ /* Neither windows nor unix allows us to delete a non-empty @@ -4631,7 +4646,7 @@ svn_io_dir_walk2(const char *dirname, } else if (finfo.filetype == APR_REG || finfo.filetype == APR_LNK) { - /* some other directory. pass it to the callback. */ + /* a regular file or a symlink. pass it to the callback. */ SVN_ERR(entry_name_to_utf8(&name_utf8, finfo.name, dirname, subpool)); full_path = svn_dirent_join(dirname, name_utf8, subpool); Modified: subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4.c Wed Nov 28 21:25:32 2018 @@ -1,5 +1,5 @@ #include "svn_private_config.h" -#if SVN_INTERNAL_LZ4 +#ifdef SVN_INTERNAL_LZ4 /* LZ4 - Fast LZ compression algorithm Copyright (C) 2011-2016, Yann Collet. @@ -1471,4 +1471,11 @@ int LZ4_decompress_fast_withPrefix64k(co } #endif /* LZ4_COMMONDEFS_ONLY */ +#else /* !SVN_INTERNAL_LZ4 */ + +/* Silence OSX ranlib warnings about object files with no symbols. */ +#include <apr.h> +extern const apr_uint32_t svn__fake__lz4internal; +const apr_uint32_t svn__fake__lz4internal = 0xdeadbeef; + #endif /* SVN_INTERNAL_LZ4 */ Modified: subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4internal.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4internal.h?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4internal.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/lz4/lz4internal.h Wed Nov 28 21:25:32 2018 @@ -1,5 +1,5 @@ #include "svn_private_config.h" -#if SVN_INTERNAL_LZ4 +#ifdef SVN_INTERNAL_LZ4 /* * LZ4 - Fast LZ compression algorithm * Header File Modified: subversion/branches/swig-py3/subversion/libsvn_subr/mergeinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/mergeinfo.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/mergeinfo.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/mergeinfo.c Wed Nov 28 21:25:32 2018 @@ -891,7 +891,7 @@ adjust_remaining_ranges(svn_rangelist_t new_modified_range->end = modified_range->end; new_modified_range->inheritable = FALSE; modified_range->end = next_range->start; - (*range_index)+=2; + (*range_index) += 2 + elements_to_delete; svn_sort__array_insert(rangelist, &new_modified_range, *range_index); /* Recurse with the new range. */ Modified: subversion/branches/swig-py3/subversion/libsvn_subr/opt.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/opt.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/opt.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/opt.c Wed Nov 28 21:25:32 2018 @@ -55,8 +55,8 @@ /*** Code. ***/ -const svn_opt_subcommand_desc2_t * -svn_opt_get_canonical_subcommand2(const svn_opt_subcommand_desc2_t *table, +const svn_opt_subcommand_desc3_t * +svn_opt_get_canonical_subcommand3(const svn_opt_subcommand_desc3_t *table, const char *cmd_name) { int i = 0; @@ -80,9 +80,9 @@ svn_opt_get_canonical_subcommand2(const } const apr_getopt_option_t * -svn_opt_get_option_from_code2(int code, +svn_opt_get_option_from_code3(int code, const apr_getopt_option_t *option_table, - const svn_opt_subcommand_desc2_t *command, + const svn_opt_subcommand_desc3_t *command, apr_pool_t *pool) { apr_size_t i; @@ -111,34 +111,19 @@ svn_opt_get_option_from_code2(int code, return NULL; } - -const apr_getopt_option_t * -svn_opt_get_option_from_code(int code, - const apr_getopt_option_t *option_table) -{ - apr_size_t i; - - for (i = 0; option_table[i].optch; i++) - if (option_table[i].optch == code) - return &(option_table[i]); - - return NULL; -} - - -/* Like svn_opt_get_option_from_code2(), but also, if CODE appears a second +/* Like svn_opt_get_option_from_code3(), but also, if CODE appears a second * time in OPTION_TABLE with a different name, then set *LONG_ALIAS to that * second name, else set it to NULL. */ static const apr_getopt_option_t * -get_option_from_code(const char **long_alias, - int code, - const apr_getopt_option_t *option_table, - const svn_opt_subcommand_desc2_t *command, - apr_pool_t *pool) +get_option_from_code3(const char **long_alias, + int code, + const apr_getopt_option_t *option_table, + const svn_opt_subcommand_desc3_t *command, + apr_pool_t *pool) { const apr_getopt_option_t *i; const apr_getopt_option_t *opt - = svn_opt_get_option_from_code2(code, option_table, command, pool); + = svn_opt_get_option_from_code3(code, option_table, command, pool); /* Find a long alias in the table, if there is one. */ *long_alias = NULL; @@ -205,7 +190,7 @@ svn_opt_format_option(const char **strin svn_boolean_t -svn_opt_subcommand_takes_option3(const svn_opt_subcommand_desc2_t *command, +svn_opt_subcommand_takes_option4(const svn_opt_subcommand_desc3_t *command, int option_code, const int *global_options) { @@ -223,35 +208,12 @@ svn_opt_subcommand_takes_option3(const s return FALSE; } -svn_boolean_t -svn_opt_subcommand_takes_option2(const svn_opt_subcommand_desc2_t *command, - int option_code) -{ - return svn_opt_subcommand_takes_option3(command, - option_code, - NULL); -} - - -svn_boolean_t -svn_opt_subcommand_takes_option(const svn_opt_subcommand_desc_t *command, - int option_code) -{ - apr_size_t i; - - for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++) - if (command->valid_options[i] == option_code) - return TRUE; - - return FALSE; -} - /* Print the canonical command name for CMD, and all its aliases, to STREAM. If HELP is set, print CMD's help string too, in which case obtain option usage from OPTIONS_TABLE. */ static svn_error_t * -print_command_info2(const svn_opt_subcommand_desc2_t *cmd, +print_command_info3(const svn_opt_subcommand_desc3_t *cmd, const apr_getopt_option_t *options_table, const int *global_options, svn_boolean_t help, @@ -290,7 +252,12 @@ print_command_info2(const svn_opt_subcom const char *long_alias; svn_boolean_t have_options = FALSE; - SVN_ERR(svn_cmdline_fprintf(stream, pool, ": %s", _(cmd->help))); + SVN_ERR(svn_cmdline_fprintf(stream, pool, ": ")); + + for (i = 0; i < SVN_OPT_MAX_PARAGRAPHS && cmd->help[i]; i++) + { + SVN_ERR(svn_cmdline_fprintf(stream, pool, "%s", _(cmd->help[i]))); + } /* Loop over all valid option codes attached to the subcommand */ for (i = 0; i < SVN_OPT_MAX_OPTIONS; i++) @@ -305,8 +272,8 @@ print_command_info2(const svn_opt_subcom } /* convert each option code into an option */ - option = get_option_from_code(&long_alias, cmd->valid_options[i], - options_table, cmd, pool); + option = get_option_from_code3(&long_alias, cmd->valid_options[i], + options_table, cmd, pool); /* print the option's docstring */ if (option && option->description) @@ -329,8 +296,8 @@ print_command_info2(const svn_opt_subcom { /* convert each option code into an option */ - option = get_option_from_code(&long_alias, global_options[i], - options_table, cmd, pool); + option = get_option_from_code3(&long_alias, global_options[i], + options_table, cmd, pool); /* print the option's docstring */ if (option && option->description) @@ -350,14 +317,14 @@ print_command_info2(const svn_opt_subcom return SVN_NO_ERROR; } -/* The body for svn_opt_print_generic_help2() function with standard error +/* The body for svn_opt_print_generic_help3() function with standard error * handling semantic. Handling of errors implemented at caller side. */ static svn_error_t * -print_generic_help_body(const char *header, - const svn_opt_subcommand_desc2_t *cmd_table, - const apr_getopt_option_t *opt_table, - const char *footer, - apr_pool_t *pool, FILE *stream) +print_generic_help_body3(const char *header, + const svn_opt_subcommand_desc3_t *cmd_table, + const apr_getopt_option_t *opt_table, + const char *footer, + apr_pool_t *pool, FILE *stream) { int i = 0; @@ -367,7 +334,7 @@ print_generic_help_body(const char *head while (cmd_table[i].name) { SVN_ERR(svn_cmdline_fputs(" ", stream, pool)); - SVN_ERR(print_command_info2(cmd_table + i, opt_table, + SVN_ERR(print_command_info3(cmd_table + i, opt_table, NULL, FALSE, pool, stream)); SVN_ERR(svn_cmdline_fputs("\n", stream, pool)); @@ -383,16 +350,16 @@ print_generic_help_body(const char *head } void -svn_opt_print_generic_help2(const char *header, - const svn_opt_subcommand_desc2_t *cmd_table, +svn_opt_print_generic_help3(const char *header, + const svn_opt_subcommand_desc3_t *cmd_table, const apr_getopt_option_t *opt_table, const char *footer, apr_pool_t *pool, FILE *stream) { svn_error_t *err; - err = print_generic_help_body(header, cmd_table, opt_table, footer, pool, - stream); + err = print_generic_help_body3(header, cmd_table, opt_table, footer, pool, + stream); /* Issue #3014: * Don't print anything on broken pipes. The pipe was likely @@ -408,18 +375,18 @@ svn_opt_print_generic_help2(const char * void -svn_opt_subcommand_help3(const char *subcommand, - const svn_opt_subcommand_desc2_t *table, +svn_opt_subcommand_help4(const char *subcommand, + const svn_opt_subcommand_desc3_t *table, const apr_getopt_option_t *options_table, const int *global_options, apr_pool_t *pool) { - const svn_opt_subcommand_desc2_t *cmd = - svn_opt_get_canonical_subcommand2(table, subcommand); + const svn_opt_subcommand_desc3_t *cmd = + svn_opt_get_canonical_subcommand3(table, subcommand); svn_error_t *err; if (cmd) - err = print_command_info2(cmd, options_table, global_options, + err = print_command_info3(cmd, options_table, global_options, TRUE, pool, stdout); else err = svn_cmdline_fprintf(stderr, pool, @@ -1194,14 +1161,14 @@ svn_opt__print_version_info(const char * } svn_error_t * -svn_opt_print_help4(apr_getopt_t *os, +svn_opt_print_help5(apr_getopt_t *os, const char *pgm_name, svn_boolean_t print_version, svn_boolean_t quiet, svn_boolean_t verbose, const char *version_footer, const char *header, - const svn_opt_subcommand_desc2_t *cmd_table, + const svn_opt_subcommand_desc3_t *cmd_table, const apr_getopt_option_t *option_table, const int *global_options, const char *footer, @@ -1218,7 +1185,7 @@ svn_opt_print_help4(apr_getopt_t *os, for (i = 0; i < targets->nelts; i++) { - svn_opt_subcommand_help3(APR_ARRAY_IDX(targets, i, const char *), + svn_opt_subcommand_help4(APR_ARRAY_IDX(targets, i, const char *), cmd_table, option_table, global_options, pool); } @@ -1230,7 +1197,7 @@ svn_opt_print_help4(apr_getopt_t *os, quiet, verbose, pool)); } else if (os && !targets->nelts) /* `-h', `--help', or `help' */ - svn_opt_print_generic_help2(header, + svn_opt_print_generic_help3(header, cmd_table, option_table, footer, Modified: subversion/branches/swig-py3/subversion/libsvn_subr/sqlite3wrapper.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/sqlite3wrapper.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/sqlite3wrapper.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/sqlite3wrapper.c Wed Nov 28 21:25:32 2018 @@ -41,6 +41,12 @@ # endif # endif # ifdef __APPLE__ + /* SQLite uses OSAtomicCompareAndSwapPtrBarrier from libkern/OSAtomic.h, + which has been deprecated since macOS 10.12. This will silence the + warning. */ +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +# endif # include <Availability.h> # if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060 /* <libkern/OSAtomic.h> is included on OS X by sqlite3.c, and Modified: subversion/branches/swig-py3/subversion/libsvn_subr/ssl_client_cert_pw_providers.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/ssl_client_cert_pw_providers.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/ssl_client_cert_pw_providers.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/ssl_client_cert_pw_providers.c Wed Nov 28 21:25:32 2018 @@ -36,7 +36,7 @@ #include "svn_private_config.h" /*-----------------------------------------------------------------------*/ -/* File provider */ +/* File password provider */ /*-----------------------------------------------------------------------*/ /* Baton type for the ssl client cert passphrase provider. */ @@ -51,6 +51,13 @@ typedef struct ssl_client_cert_pw_file_p apr_hash_t *plaintext_answers; } ssl_client_cert_pw_file_provider_baton_t; +/* The client cert password provider only deals with a password and + realm (the client cert filename), there is no username. The gnome + keyring backend based on libsecret requires a non-NULL username so + we have to invent one. An empty string is acceptable and doesn't + change the value stored by the kwallet backend. */ +#define DUMMY_USERNAME "" + /* This implements the svn_auth__password_get_t interface. Set **PASSPHRASE to the plaintext passphrase retrieved from CREDS; ignore other parameters. */ @@ -132,7 +139,8 @@ svn_auth__ssl_client_cert_pw_cache_get(v svn_boolean_t done; SVN_ERR(passphrase_get(&done, &password, creds_hash, realmstring, - NULL, parameters, non_interactive, pool)); + DUMMY_USERNAME, parameters, non_interactive, + pool)); if (!done) password = NULL; } @@ -293,7 +301,7 @@ svn_auth__ssl_client_cert_pw_cache_set(s if (may_save_passphrase) { SVN_ERR(passphrase_set(saved, creds_hash, realmstring, - NULL, creds->password, parameters, + DUMMY_USERNAME, creds->password, parameters, non_interactive, pool)); if (*saved && passtype) Modified: subversion/branches/swig-py3/subversion/libsvn_subr/sysinfo.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/sysinfo.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/sysinfo.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/sysinfo.c Wed Nov 28 21:25:32 2018 @@ -51,10 +51,22 @@ #include "sysinfo.h" #include "svn_private_config.h" +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + #if HAVE_SYS_UTSNAME_H #include <sys/utsname.h> #endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif + +#if HAVE_ELF_H +#include <elf.h> +#endif + #ifdef SVN_HAVE_MACOS_PLIST #include <CoreFoundation/CoreFoundation.h> #include <AvailabilityMacros.h> @@ -92,6 +104,7 @@ static const apr_array_header_t *macos_s #if __linux__ static const char *linux_release_name(apr_pool_t *pool); +static const apr_array_header_t *linux_shared_libs(apr_pool_t *pool); #endif const char * @@ -187,6 +200,8 @@ svn_sysinfo__loaded_libs(apr_pool_t *poo return win32_shared_libs(pool); #elif defined(SVN_HAVE_MACHO_ITERATE) return macos_shared_libs(pool); +#elif __linux__ + return linux_shared_libs(pool); #else return NULL; #endif @@ -300,6 +315,31 @@ release_name_from_uname(apr_pool_t *pool #if __linux__ +/* Find the first whitespace character in a stringbuf. + Analogous to svn_stringbuf_first_non_whitespace. */ +static apr_size_t +stringbuf_first_whitespace(const svn_stringbuf_t *str) +{ + apr_size_t i; + for (i = 0; i < str->len; ++i) + { + if (svn_ctype_isspace(str->data[i])) + return i; + } + return str->len; +} + +/* Skip a whitespace-delimited field in a stringbuf. */ +static void +stringbuf_skip_whitespace_field(svn_stringbuf_t *str) +{ + apr_size_t i; + i = stringbuf_first_whitespace(str); + svn_stringbuf_leftchop(str, i); + i = svn_stringbuf_first_non_whitespace(str); + svn_stringbuf_leftchop(str, i); +} + /* Split a stringbuf into a key/value pair. Return the key, leaving the stripped value in the stringbuf. */ static const char * @@ -635,6 +675,168 @@ linux_release_name(apr_pool_t *pool) return apr_psprintf(pool, "%s [%s]", release_name, uname_release); } + +#if HAVE_ELF_H +/* Parse a hexadecimal number as a pointer value. */ +static const unsigned char * +parse_pointer_value(const char *start, const char *limit, char **end) +{ + const unsigned char *ptr; + const apr_uint64_t val = (apr_uint64_t)apr_strtoi64(start, end, 16); + + if (errno /* overflow */ + || *end == start /* no valid digits */ + || *end >= limit) /* representation too long */ + return NULL; + + ptr = (const unsigned char*)val; + if (val != (apr_uint64_t)ptr) /* truncated value */ + return NULL; + + return ptr; +} + +/* Read the ELF header at the mapping position to check if this is a shared + library. We only look at the ELF identification and the type. The format is + described here: + http://www.skyfree.org/linux/references/ELF_Format.pdf +*/ +static svn_boolean_t +check_elf_header(const unsigned char *map_start, + const unsigned char *map_end) +{ + /* A union of all known ELF header types, for size checks. */ + union max_elf_header_size_t + { + Elf32_Ehdr header_32; + Elf64_Ehdr header_64; + }; + + /* Check the size of the mapping and the ELF magic tag. */ + if (map_end < map_start + || map_end - map_start < sizeof(union max_elf_header_size_t) + || memcmp(map_start, ELFMAG, SELFMAG)) + { + return FALSE; + } + + /* Check that this is an ELF shared library or executable file. This also + implicitly checks that the data encoding of the current process is the + same as in the loaded library. */ + if (map_start[EI_CLASS] == ELFCLASS32) + { + const Elf32_Ehdr *hdr = (void*)map_start; + return (hdr->e_type == ET_DYN || hdr->e_type == ET_EXEC); + } + else if (map_start[EI_CLASS] == ELFCLASS64) + { + const Elf64_Ehdr *hdr = (void*)map_start; + return (hdr->e_type == ET_DYN || hdr->e_type == ET_EXEC); + } + + return FALSE; +} +#endif /* HAVE_ELF_H */ + +static const apr_array_header_t * +linux_shared_libs(apr_pool_t *pool) +{ + /* Read the list of loaded modules from /proc/[pid]/maps + The format is described here: + http://man7.org/linux/man-pages/man5/proc.5.html + */ + + const char *maps = apr_psprintf(pool, "/proc/%ld/maps", (long)getpid()); + apr_array_header_t *result = NULL; + svn_boolean_t eof = FALSE; + svn_stream_t *stream; + svn_error_t *err; + + err = svn_stream_open_readonly(&stream, maps, pool, pool); + if (err) + { + svn_error_clear(err); + return NULL; + } + + /* Each line in /proc/[pid]/maps consists of whitespace-delimited fields. */ + while (!eof) + { + svn_stringbuf_t *line; + +#if HAVE_ELF_H + const unsigned char *map_start; + const unsigned char *map_end; +#endif + + err = svn_stream_readline(stream, &line, "\n", &eof, pool); + if (err) + { + svn_error_clear(err); + return NULL; + } + +#if HAVE_ELF_H + /* Address: The mapped memory address range. */ + { + const char *const limit = line->data + line->len; + char *end; + + /* The start of the address range */ + map_start = parse_pointer_value(line->data, limit, &end); + if (!map_start || *end != '-') + continue; + + /* The end of the address range */ + map_end = parse_pointer_value(end + 1, limit, &end); + if (!map_end || !svn_ctype_isspace(*end)) + continue; + } +#endif + + stringbuf_skip_whitespace_field(line); /* skip address */ + + /* Permissions: The memory region must be readable and executable. */ + if (line->len < 4 || line->data[0] != 'r' || line->data[2] != 'x') + continue; + + stringbuf_skip_whitespace_field(line); /* skip perms */ + stringbuf_skip_whitespace_field(line); /* skip offset */ + stringbuf_skip_whitespace_field(line); /* skip device */ + + /* I-Node: If it is 0, there is no file associated with the region. */ + if (line->len < 2 + || (line->data[0] == '0' && svn_ctype_isspace(line->data[1]))) + continue; + + stringbuf_skip_whitespace_field(line); /* skip inode */ + + /* Consider only things that look like absolute paths. + Files that were removed since the process was created (due to an + upgrade, for example) are marked as '(deleted)'. */ + if (line->data[0] == '/') + { + svn_version_ext_loaded_lib_t *lib; + +#if HAVE_ELF_H + if (!check_elf_header(map_start, map_end)) + continue; +#endif + + /* We've done our best to find a mapped shared library. */ + if (!result) + { + result = apr_array_make(pool, 32, sizeof(*lib)); + } + lib = &APR_ARRAY_PUSH(result, svn_version_ext_loaded_lib_t); + lib->name = line->data; + lib->version = NULL; + } + } + + svn_error_clear(svn_stream_close(stream)); + return result; +} #endif /* __linux__ */ @@ -1122,41 +1324,70 @@ value_from_dict(CFDictionaryRef plist, C return value; } -/* Return the commercial name of the OS, given the version number in +/* Return the minor version the operating system, given the number in a format that matches the regular expression /^10\.\d+(\..*)?$/ */ -static const char * -release_name_from_version(const char *osver) +static int +macos_minor_version(const char *osver) { char *end = NULL; unsigned long num = strtoul(osver, &end, 10); if (!end || *end != '.' || num != 10) - return NULL; + return -1; osver = end + 1; end = NULL; num = strtoul(osver, &end, 10); if (!end || (*end && *end != '.')) - return NULL; + return -1; + + return (int)num; +} - /* See http://en.wikipedia.org/wiki/History_of_OS_X#Release_timeline */ - switch(num) +/* Return the product name of the operating system. */ +static const char * +product_name_from_minor_version(int minor, const char* product_name) +{ + /* We can only do this if we know the official product name. */ + if (0 != strcmp(product_name, "Mac OS X")) + return product_name; + + if (minor <= 7) + return product_name; + + if (minor <= 11) + return "OS X"; + + return "macOS"; +} + +/* Return the commercial name of the operating system. */ +static const char * +release_name_from_minor_version(int minor, const char* product_name) +{ + /* We can only do this if we know the official product name. */ + if (0 == strcmp(product_name, "Mac OS X")) { - case 0: return "Cheetah"; - case 1: return "Puma"; - case 2: return "Jaguar"; - case 3: return "Panther"; - case 4: return "Tiger"; - case 5: return "Leopard"; - case 6: return "Snow Leopard"; - case 7: return "Lion"; - case 8: return "Mountain Lion"; - case 9: return "Mavericks"; - case 10: return "Yosemite"; - case 11: return "El Capitan"; - case 12: return "Sierra"; + /* See https://en.wikipedia.org/wiki/MacOS_version_history#Releases */ + switch(minor) + { + case 0: return "Cheetah"; + case 1: return "Puma"; + case 2: return "Jaguar"; + case 3: return "Panther"; + case 4: return "Tiger"; + case 5: return "Leopard"; + case 6: return "Snow Leopard"; + case 7: return "Lion"; + case 8: return "Mountain Lion"; + case 9: return "Mavericks"; + case 10: return "Yosemite"; + case 11: return "El Capitan"; + case 12: return "Sierra"; + case 13: return "High Sierra"; + case 14: return "Mojave"; + } } - return NULL; } @@ -1179,20 +1410,23 @@ macos_release_name(apr_pool_t *pool) CFSTR("ProductBuildVersion"), pool); const char *release; + int minor_version; if (!osver) osver = value_from_dict(plist, CFSTR("ProductVersion"), pool); - release = release_name_from_version(osver); + minor_version = macos_minor_version(osver); + release = release_name_from_minor_version(minor_version, osname); + osname = product_name_from_minor_version(minor_version, osname); CFRelease(plist); return apr_psprintf(pool, "%s%s%s%s%s%s%s%s", (osname ? osname : ""), - (osver ? (osname ? " " : "") : ""), - (osver ? osver : ""), - (release ? (osname||osver ? " " : "") : ""), + (release ? (osname ? " " : "") : ""), (release ? release : ""), + (osver ? (osname||release ? " " : "") : ""), + (osver ? osver : ""), (build - ? (osname||osver||release ? ", " : "") + ? (osname||release||osver ? ", " : "") : ""), (build ? (server ? "server build " : "build ") Modified: subversion/branches/swig-py3/subversion/libsvn_subr/utf.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/utf.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/utf.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/utf.c Wed Nov 28 21:25:32 2018 @@ -960,7 +960,7 @@ svn_utf__cstring_from_utf8_fuzzy(const c /* ### Check the client locale, maybe we can avoid that second * conversion! See Ulrich Drepper's patch at - * http://subversion.tigris.org/issues/show_bug.cgi?id=807. + * https://issues.apache.org/jira/browse/SVN-807. */ } Modified: subversion/branches/swig-py3/subversion/libsvn_subr/x509info.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/x509info.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/x509info.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/x509info.c Wed Nov 28 21:25:32 2018 @@ -128,7 +128,7 @@ typedef struct asn1_oid { const char *long_label; } asn1_oid; -#define CONSTANT_PAIR(c) (unsigned char *)(c), sizeof((c)) - 1 +#define CONSTANT_PAIR(c) (const unsigned char *)(c), sizeof((c)) - 1 static const asn1_oid asn1_oids[] = { { CONSTANT_PAIR(SVN_X509_OID_COMMON_NAME), "CN", "commonName" }, Modified: subversion/branches/swig-py3/subversion/libsvn_subr/x509parse.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_subr/x509parse.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_subr/x509parse.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_subr/x509parse.c Wed Nov 28 21:25:32 2018 @@ -262,13 +262,34 @@ x509_get_alg(const unsigned char **p, co if (*p == end) return SVN_NO_ERROR; + + /* The OID encoding of 1.2.840.113549.1.1.10 (id-RSASSA-PSS) */ +#define OID_RSASSA_PSS "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x0a" - /* - * assume the algorithm parameters must be NULL - */ - err = asn1_get_tag(p, end, &len, ASN1_NULL); - if (err) - return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); + if (equal(alg->p, alg->len, OID_RSASSA_PSS, sizeof(OID_RSASSA_PSS) - 1)) + { + /* Skip over algorithm parameters for id-RSASSA-PSS (RFC 8017) + * + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] TrailerField DEFAULT trailerFieldBC + * } + */ + err = asn1_get_tag(p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE); + if (err) + return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); + + *p += len; + } + else + { + /* Algorithm parameters must be NULL for other algorithms */ + err = asn1_get_tag(p, end, &len, ASN1_NULL); + if (err) + return svn_error_create(SVN_ERR_X509_CERT_INVALID_ALG, err, NULL); + } if (*p != end) { Modified: subversion/branches/swig-py3/subversion/libsvn_wc/README URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/README?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/README (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/README Wed Nov 28 21:25:32 2018 @@ -94,6 +94,10 @@ copies. .svn/wc.db /* SQLite database containing node metadata. */ pristine/ /* Sharded directory containing base files. */ tmp/ /* Local tmp area. */ + experimental/ /* Data for experimental features. */ + shelves/ /* Used by 1.10.x shelves implementation */ + entries /* Stub file. */ + format /* Stub file. */ `wc.db': A self-contained SQLite database containing all the metadata Subversion @@ -109,6 +113,17 @@ copies. Pristines are used for sending diffs back to the server, etc. +`experimental': + Experimental (unstable) features store their data here. + +`shelves': + Subversion 1.10's "svn shelve" command stores shelved changes here. + This directory is not used by any other minor release line. + +`entries', `format': + These stub files exist only to enable a pre-1.7 client to yield a clearer + error message. + How the client applies an update delta -------------------------------------- Modified: subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.c Wed Nov 28 21:25:32 2018 @@ -539,6 +539,7 @@ svn_wc__conflict_skel_add_tree_conflict( svn_wc_conflict_reason_t reason, svn_wc_conflict_action_t action, const char *move_src_op_root_abspath, + const char *move_dst_op_root_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { @@ -555,18 +556,33 @@ svn_wc__conflict_skel_add_tree_conflict( tree_conflict = svn_skel__make_empty_list(result_pool); - if (reason == svn_wc_conflict_reason_moved_away - && move_src_op_root_abspath) + if (reason == svn_wc_conflict_reason_moved_away) { - const char *move_src_op_root_relpath; + if (move_dst_op_root_abspath) + { + const char *move_dst_op_root_relpath; - SVN_ERR(svn_wc__db_to_relpath(&move_src_op_root_relpath, - db, wri_abspath, - move_src_op_root_abspath, - result_pool, scratch_pool)); + SVN_ERR(svn_wc__db_to_relpath(&move_dst_op_root_relpath, + db, wri_abspath, + move_dst_op_root_abspath, + result_pool, scratch_pool)); - svn_skel__prepend_str(move_src_op_root_relpath, tree_conflict, - result_pool); + svn_skel__prepend_str(move_dst_op_root_relpath, tree_conflict, + result_pool); + } + + if (move_src_op_root_abspath) + { + const char *move_src_op_root_relpath; + + SVN_ERR(svn_wc__db_to_relpath(&move_src_op_root_relpath, + db, wri_abspath, + move_src_op_root_abspath, + result_pool, scratch_pool)); + + svn_skel__prepend_str(move_src_op_root_relpath, tree_conflict, + result_pool); + } } svn_skel__prepend_str(svn_token__to_word(action_map, action), @@ -932,6 +948,7 @@ svn_error_t * svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *reason, svn_wc_conflict_action_t *action, const char **move_src_op_root_abspath, + const char **move_dst_op_root_abspath, svn_wc__db_t *db, const char *wri_abspath, const svn_skel_t *conflict_skel, @@ -981,10 +998,10 @@ svn_wc__conflict_read_tree_conflict(svn_ c = c->next; - if (move_src_op_root_abspath) + if (move_src_op_root_abspath || move_dst_op_root_abspath) { /* Only set for update and switch tree conflicts */ - if (c && is_moved_away) + if (c && is_moved_away && move_src_op_root_abspath) { const char *move_src_op_root_relpath = apr_pstrmemdup(scratch_pool, c->data, c->len); @@ -994,8 +1011,25 @@ svn_wc__conflict_read_tree_conflict(svn_ move_src_op_root_relpath, result_pool, scratch_pool)); } - else + else if (move_src_op_root_abspath) *move_src_op_root_abspath = NULL; + + if (c) + c = c->next; + + if (c && is_moved_away && move_dst_op_root_abspath) + { + const char *move_dst_op_root_relpath + = apr_pstrmemdup(scratch_pool, c->data, c->len); + + SVN_ERR(svn_wc__db_from_relpath(move_dst_op_root_abspath, + db, wri_abspath, + move_dst_op_root_relpath, + result_pool, scratch_pool)); + } + else if (move_dst_op_root_abspath) + *move_dst_op_root_abspath = NULL; + } return SVN_NO_ERROR; @@ -1801,7 +1835,7 @@ read_tree_conflict_desc(svn_wc_conflict_ svn_wc_conflict_action_t action; SVN_ERR(svn_wc__conflict_read_tree_conflict( - &reason, &action, NULL, + &reason, &action, NULL, NULL, db, local_abspath, conflict_skel, scratch_pool, scratch_pool)); if (reason == svn_wc_conflict_reason_missing) @@ -2676,7 +2710,7 @@ resolve_tree_conflict_on_node(svn_boolea SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, &src_op_root_abspath, - db, local_abspath, + NULL, db, local_abspath, conflicts, scratch_pool, scratch_pool)); @@ -2748,6 +2782,7 @@ resolve_tree_conflict_on_node(svn_boolea SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, &src_op_root_abspath, + NULL, db, local_abspath, new_conflicts, scratch_pool, @@ -3483,7 +3518,7 @@ svn_wc__conflict_tree_update_break_moved return SVN_NO_ERROR; SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, - &src_op_root_abspath, + &src_op_root_abspath, NULL, wc_ctx->db, local_abspath, conflict_skel, scratch_pool, scratch_pool)); @@ -3569,7 +3604,7 @@ svn_wc__conflict_tree_update_raise_moved if (!tree_conflicted) return SVN_NO_ERROR; - SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, NULL, + SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, NULL, NULL, wc_ctx->db, local_abspath, conflict_skel, scratch_pool, scratch_pool)); @@ -3648,7 +3683,7 @@ svn_wc__conflict_tree_update_moved_away_ return SVN_NO_ERROR; SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, - &src_op_root_abspath, + &src_op_root_abspath, NULL, wc_ctx->db, local_abspath, conflict_skel, scratch_pool, scratch_pool)); @@ -3734,8 +3769,8 @@ svn_wc__conflict_tree_update_incoming_mo return SVN_NO_ERROR; SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change, &incoming_change, - NULL, wc_ctx->db, local_abspath, - conflict_skel, + NULL, NULL, wc_ctx->db, + local_abspath, conflict_skel, scratch_pool, scratch_pool)); /* Make sure the expected conflict is recorded. */ @@ -3803,8 +3838,8 @@ svn_wc__conflict_tree_update_local_add(s return SVN_NO_ERROR; SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change, &incoming_change, - NULL, wc_ctx->db, local_abspath, - conflict_skel, + NULL, NULL, wc_ctx->db, + local_abspath, conflict_skel, scratch_pool, scratch_pool)); /* Make sure the expected conflict is recorded. */ @@ -3853,9 +3888,9 @@ svn_wc__guess_incoming_move_target_nodes apr_size_t longest_ancestor_len = 0; *possible_targets = apr_array_make(result_pool, 1, sizeof(const char *)); - SVN_ERR(svn_wc__find_repos_node_in_wc(&candidates, wc_ctx->db, victim_abspath, - moved_to_repos_relpath, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__db_find_repos_node_in_wc(&candidates, wc_ctx->db, victim_abspath, + moved_to_repos_relpath, + scratch_pool, scratch_pool)); /* Find a "useful move target" node in our set of candidates. * Since there is no way to be certain, filter out nodes which seem @@ -3903,7 +3938,7 @@ svn_wc__guess_incoming_move_target_nodes status != svn_wc__db_status_added) continue; - if (node_kind != victim_node_kind) + if (victim_node_kind != svn_node_none && node_kind != victim_node_kind) continue; SVN_ERR(svn_wc__db_is_switched(&is_wcroot, &is_switched, NULL, Modified: subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.h?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/conflicts.h Wed Nov 28 21:25:32 2018 @@ -219,6 +219,11 @@ svn_wc__conflict_skel_add_prop_conflict( MOVE_SRC_OP_ROOT_ABSPATH should be A for a conflict associated with (1), MOVE_SRC_OP_ROOT_ABSPATH should be A/B for a conflict associated with (2). + MOVE_DST_OP_ROOT_ABSPATH is the op-root of the move target (i.e. the + op-root of the corresponding copy). This needs to be stored because + moves in the NODE table do not always persist after an update, while + the conflict resolver may need information about the pre-update state + of the move. It is an error to add another tree conflict to a conflict skel that already contains a tree conflict. (It is not an error, at this level, @@ -233,6 +238,7 @@ svn_wc__conflict_skel_add_tree_conflict( svn_wc_conflict_reason_t local_change, svn_wc_conflict_action_t incoming_change, const char *move_src_op_root_abspath, + const char *move_dst_op_root_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool); @@ -364,6 +370,7 @@ svn_error_t * svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *local_change, svn_wc_conflict_action_t *incoming_change, const char **move_src_op_root_abspath, + const char **move_dst_op_root_abspath, svn_wc__db_t *db, const char *wri_abspath, const svn_skel_t *conflict_skel, Modified: subversion/branches/swig-py3/subversion/libsvn_wc/deprecated.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/deprecated.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/deprecated.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/deprecated.c Wed Nov 28 21:25:32 2018 @@ -2096,8 +2096,7 @@ svn_wc_get_diff_editor6(const svn_delta_ result_pool, scratch_pool)); if (reverse_order) - diff_processor = svn_diff__tree_processor_reverse_create( - diff_processor, NULL, result_pool); + diff_processor = svn_diff__tree_processor_reverse_create(diff_processor, result_pool); if (! show_copies_as_adds) diff_processor = svn_diff__tree_processor_copy_as_changed_create( Modified: subversion/branches/swig-py3/subversion/libsvn_wc/diff_local.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/diff_local.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/diff_local.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/diff_local.c Wed Nov 28 21:25:32 2018 @@ -433,8 +433,7 @@ diff_status_callback(void *baton, /* Public Interface */ svn_error_t * -svn_wc__diff7(const char **root_relpath, - svn_boolean_t *root_is_dir, +svn_wc__diff7(svn_boolean_t anchor_at_given_paths, svn_wc_context_t *wc_ctx, const char *local_abspath, svn_depth_t depth, @@ -459,26 +458,30 @@ svn_wc__diff7(const char **root_relpath, eb.anchor_abspath = local_abspath; - if (root_relpath) + if (anchor_at_given_paths) { + /* Anchor the underlying diff processor at the parent of + LOCAL_ABSPATH (if possible), and adjust so the outgoing + DIFF_PROCESSOR is always anchored at LOCAL_ABSPATH. */ + /* ### Why anchor the underlying diff processor at the parent? */ svn_boolean_t is_wcroot; SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, wc_ctx->db, local_abspath, scratch_pool)); if (!is_wcroot) - eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool); + { + const char *relpath; + + eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool); + relpath = svn_dirent_basename(local_abspath, NULL); + diff_processor = svn_diff__tree_processor_filter_create( + diff_processor, relpath, scratch_pool); + } } else if (kind != svn_node_dir) eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool); - if (root_relpath) - *root_relpath = apr_pstrdup(result_pool, - svn_dirent_skip_ancestor(eb.anchor_abspath, - local_abspath)); - if (root_is_dir) - *root_is_dir = (kind == svn_node_dir); - /* Apply changelist filtering to the output */ if (changelist_filter && changelist_filter->nelts) { @@ -572,7 +575,7 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx, processor = svn_diff__tree_processor_copy_as_changed_create(processor, scratch_pool); - return svn_error_trace(svn_wc__diff7(NULL, NULL, + return svn_error_trace(svn_wc__diff7(FALSE, wc_ctx, local_abspath, depth, ignore_ancestry, Modified: subversion/branches/swig-py3/subversion/libsvn_wc/node.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/node.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/node.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/node.c Wed Nov 28 21:25:32 2018 @@ -1126,3 +1126,17 @@ svn_wc__node_was_moved_here(const char * return SVN_NO_ERROR; } + +svn_error_t * +svn_wc__find_working_nodes_with_basename(apr_array_header_t **abspaths, + const char *wri_abspath, + const char *basename, + svn_node_kind_t kind, + svn_wc_context_t *wc_ctx, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace(svn_wc__db_find_working_nodes_with_basename( + abspaths, wc_ctx->db, wri_abspath, basename, kind, + result_pool, scratch_pool)); +} Modified: subversion/branches/swig-py3/subversion/libsvn_wc/props.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/props.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/props.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/props.c Wed Nov 28 21:25:32 2018 @@ -2236,7 +2236,9 @@ svn_wc_canonicalize_svn_prop(const svn_s if (duplicate_targets->nelts > 1) { more_str = apr_psprintf(/*scratch_*/pool, - _(" (%d more duplicate targets found)"), + Q_(" (%d more duplicate target found)", + " (%d more duplicate targets found)", + duplicate_targets->nelts - 1), duplicate_targets->nelts - 1); } return svn_error_createf( Modified: subversion/branches/swig-py3/subversion/libsvn_wc/questions.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/questions.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/questions.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/questions.c Wed Nov 28 21:25:32 2018 @@ -475,7 +475,7 @@ internal_conflicted_p(svn_boolean_t *tex svn_wc_conflict_action_t action; SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, NULL, - db, local_abspath, + NULL, db, local_abspath, conflicts, scratch_pool, scratch_pool)); Modified: subversion/branches/swig-py3/subversion/libsvn_wc/tree_conflicts.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/tree_conflicts.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/tree_conflicts.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/tree_conflicts.c Wed Nov 28 21:25:32 2018 @@ -442,7 +442,7 @@ svn_wc__add_tree_conflict(svn_wc_context conflict->local_abspath, conflict->reason, conflict->action, - NULL, + NULL, NULL, scratch_pool, scratch_pool)); switch (conflict->operation) Modified: subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/update_editor.c Wed Nov 28 21:25:32 2018 @@ -1235,9 +1235,11 @@ open_root(void *edit_baton, db->shadowed = TRUE; else if (have_work) { + const char *move_dst_op_root_abspath; const char *move_src_root_abspath; - SVN_ERR(svn_wc__db_base_moved_to(NULL, NULL, &move_src_root_abspath, + SVN_ERR(svn_wc__db_base_moved_to(NULL, &move_dst_op_root_abspath, + &move_src_root_abspath, NULL, eb->db, db->local_abspath, pool, pool)); @@ -1252,7 +1254,8 @@ open_root(void *edit_baton, tree_conflict, eb->db, move_src_root_abspath, svn_wc_conflict_reason_moved_away, svn_wc_conflict_action_edit, - move_src_root_abspath, pool, pool)); + move_src_root_abspath, + move_dst_op_root_abspath, pool, pool)); if (strcmp(db->local_abspath, move_src_root_abspath)) { @@ -1345,6 +1348,7 @@ check_tree_conflict(svn_skel_t **pconfli svn_wc_conflict_reason_t reason = SVN_WC_CONFLICT_REASON_NONE; svn_boolean_t modified = FALSE; const char *move_src_op_root_abspath = NULL; + const char *move_dst_op_root_abspath = NULL; *pconflict = NULL; @@ -1397,8 +1401,8 @@ check_tree_conflict(svn_skel_t **pconfli case svn_wc__db_status_deleted: { - SVN_ERR(svn_wc__db_base_moved_to(NULL, NULL, NULL, - &move_src_op_root_abspath, + SVN_ERR(svn_wc__db_base_moved_to(NULL, &move_dst_op_root_abspath, + NULL, &move_src_op_root_abspath, eb->db, local_abspath, scratch_pool, scratch_pool)); if (move_src_op_root_abspath) @@ -1530,6 +1534,7 @@ check_tree_conflict(svn_skel_t **pconfli reason, action, move_src_op_root_abspath, + move_dst_op_root_abspath, result_pool, scratch_pool)); return SVN_NO_ERROR; @@ -2007,11 +2012,13 @@ add_directory(const char *path, { svn_wc_conflict_reason_t reason; const char *move_src_op_root_abspath; + const char *move_dst_op_root_abspath; /* So this deletion wasn't just a deletion, it is actually a replacement. Let's install a better tree conflict. */ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, &move_src_op_root_abspath, + &move_dst_op_root_abspath, eb->db, db->local_abspath, tree_conflict, @@ -2024,6 +2031,7 @@ add_directory(const char *path, eb->db, db->local_abspath, reason, svn_wc_conflict_action_replace, move_src_op_root_abspath, + move_dst_op_root_abspath, db->pool, scratch_pool)); /* And now stop checking for conflicts here and just perform @@ -2148,8 +2156,8 @@ add_directory(const char *path, tree_conflict, eb->db, db->local_abspath, svn_wc_conflict_reason_unversioned, - svn_wc_conflict_action_add, NULL, - db->pool, scratch_pool)); + svn_wc_conflict_action_add, + NULL, NULL, db->pool, scratch_pool)); db->edit_conflict = tree_conflict; } } @@ -2336,7 +2344,7 @@ open_directory(const char *path, db->edit_conflict = tree_conflict; /* Other modifications wouldn't be a tree conflict */ - SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL, + SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL, NULL, eb->db, db->local_abspath, tree_conflict, db->pool, db->pool)); @@ -3220,11 +3228,13 @@ add_file(const char *path, { svn_wc_conflict_reason_t reason; const char *move_src_op_root_abspath; + const char *move_dst_op_root_abspath; /* So this deletion wasn't just a deletion, it is actually a replacement. Let's install a better tree conflict. */ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, &move_src_op_root_abspath, + &move_dst_op_root_abspath, eb->db, fb->local_abspath, tree_conflict, @@ -3237,6 +3247,7 @@ add_file(const char *path, eb->db, fb->local_abspath, reason, svn_wc_conflict_action_replace, move_src_op_root_abspath, + move_dst_op_root_abspath, fb->pool, scratch_pool)); /* And now stop checking for conflicts here and just perform @@ -3363,7 +3374,7 @@ add_file(const char *path, eb->db, fb->local_abspath, svn_wc_conflict_reason_unversioned, svn_wc_conflict_action_add, - NULL, + NULL, NULL, fb->pool, scratch_pool)); } } @@ -3528,7 +3539,7 @@ open_file(const char *path, fb->edit_conflict = tree_conflict; /* Other modifications wouldn't be a tree conflict */ - SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL, + SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL, NULL, eb->db, fb->local_abspath, tree_conflict, scratch_pool, scratch_pool)); @@ -3797,7 +3808,7 @@ change_file_prop(void *file_baton, eb->db, fb->local_abspath, svn_wc_conflict_reason_edited, svn_wc_conflict_action_replace, - NULL, + NULL, NULL, fb->pool, scratch_pool)); SVN_ERR(complete_conflict(fb->edit_conflict, fb->edit_baton, Modified: subversion/branches/swig-py3/subversion/libsvn_wc/upgrade.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/upgrade.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/upgrade.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/upgrade.c Wed Nov 28 21:25:32 2018 @@ -1237,7 +1237,7 @@ svn_wc__upgrade_conflict_skel_from_raw(s db, wri_abspath, tc->reason, tc->action, - NULL, + NULL, NULL, scratch_pool, scratch_pool)); Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc-queries.sql Wed Nov 28 21:25:32 2018 @@ -117,6 +117,17 @@ WHERE wc_id = ?1 AND local_relpath = ?2 ORDER BY op_depth DESC LIMIT 1 +-- STMT_SELECT_PRESENT_HIGHEST_WORKING_NODES_BY_BASENAME_AND_KIND +SELECT presence, local_relpath +FROM nodes n +WHERE wc_id = ?1 AND local_relpath = RELPATH_JOIN(parent_relpath, ?2) + AND kind = ?3 + AND presence in (MAP_NORMAL, MAP_INCOMPLETE) + AND op_depth = (SELECT MAX(op_depth) + FROM NODES w + WHERE w.wc_id = ?1 + AND w.local_relpath = n.local_relpath) + -- STMT_SELECT_ACTUAL_NODE SELECT changelist, properties, conflict_data FROM actual_node Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc.h?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc.h Wed Nov 28 21:25:32 2018 @@ -289,6 +289,7 @@ struct svn_wc_traversal_info_t #define SVN_WC__ADM_TMP "tmp" #define SVN_WC__ADM_PRISTINE "pristine" #define SVN_WC__ADM_NONEXISTENT_PATH "nonexistent-path" +#define SVN_WC__ADM_EXPERIMENTAL "experimental" /* The basename of the ".prej" file, if a directory ever has property conflicts. This .prej file will appear *within* the conflicted Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.c Wed Nov 28 21:25:32 2018 @@ -6839,7 +6839,7 @@ revert_maybe_raise_moved_away(svn_wc__db } SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, - NULL, + NULL, NULL, db, wcroot->abspath, conflict, scratch_pool, @@ -16578,12 +16578,12 @@ svn_wc__db_process_commit_queue(svn_wc__ } svn_error_t * -svn_wc__find_repos_node_in_wc(apr_array_header_t **local_abspath_list, - svn_wc__db_t *db, - const char *wri_abspath, - const char *repos_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +svn_wc__db_find_repos_node_in_wc(apr_array_header_t **local_abspath_list, + svn_wc__db_t *db, + const char *wri_abspath, + const char *repos_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_wc__db_wcroot_t *wcroot; const char *wri_relpath; @@ -16620,3 +16620,46 @@ svn_wc__find_repos_node_in_wc(apr_array_ return svn_error_trace(svn_sqlite__reset(stmt)); } +svn_error_t * +svn_wc__db_find_working_nodes_with_basename(apr_array_header_t **local_abspaths, + svn_wc__db_t *db, + const char *wri_abspath, + const char *basename, + svn_node_kind_t kind, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *wri_relpath; + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &wri_relpath, db, + wri_abspath, scratch_pool, + scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_PRESENT_HIGHEST_WORKING_NODES_BY_BASENAME_AND_KIND)); + SVN_ERR(svn_sqlite__bindf(stmt, "ist", wcroot->wc_id, basename, + kind_map, kind)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + *local_abspaths = apr_array_make(result_pool, 1, sizeof(const char *)); + + while (have_row) + { + const char *local_relpath; + const char *local_abspath; + + local_relpath = svn_sqlite__column_text(stmt, 1, NULL); + local_abspath = svn_dirent_join(wcroot->abspath, local_relpath, + result_pool); + APR_ARRAY_PUSH(*local_abspaths, const char *) = local_abspath; + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + + return svn_error_trace(svn_sqlite__reset(stmt)); +} Modified: subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h?rev=1847678&r1=1847677&r2=1847678&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h (original) +++ subversion/branches/swig-py3/subversion/libsvn_wc/wc_db.h Wed Nov 28 21:25:32 2018 @@ -3496,12 +3496,30 @@ svn_wc__required_lock_for_resolve(const * which has been replaced. */ svn_error_t * -svn_wc__find_repos_node_in_wc(apr_array_header_t **local_abspath_list, - svn_wc__db_t *db, - const char *wri_abspath, - const char *repos_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); +svn_wc__db_find_repos_node_in_wc(apr_array_header_t **local_abspath_list, + svn_wc__db_t *db, + const char *wri_abspath, + const char *repos_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Return an array of const char * elements, which represent local absolute + * paths for nodes, within the working copy indicated by WRI_ABSPATH, which + * have a basename matching BASENAME and have node kind KIND. + * If no such nodes exist, return an empty array. + * + * This function returns only paths to nodes which are present in the highest + * layer of the WC. In other words, paths to deleted and/or excluded nodes are + * never returned. + */ +svn_error_t * +svn_wc__db_find_working_nodes_with_basename(apr_array_header_t **local_abspaths, + svn_wc__db_t *db, + const char *wri_abspath, + const char *basename, + svn_node_kind_t kind, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* @} */ typedef svn_error_t * (*svn_wc__db_verify_cb_t)(void *baton,
