From a55fb3c0d5eca7d887798125d5b95942b1f01d4b Mon Sep 17 00:00:00 2001 From: Peter Wemm Date: Thu, 10 Aug 2017 21:48:34 +0000 Subject: [PATCH] Import subversion-1.9.7 --- CHANGES | 76 +++++- NOTICE | 2 +- build-outputs.mk | 2 +- configure | 22 +- subversion/include/svn_version.h | 6 +- subversion/libsvn_client/copy.c | 20 +- subversion/libsvn_client/merge.c | 16 +- subversion/libsvn_fs_fs/cached_data.c | 99 +++++++- subversion/libsvn_fs_fs/cached_data.h | 12 + subversion/libsvn_fs_fs/rep-cache-db.h | 2 +- subversion/libsvn_fs_fs/rep-cache.c | 5 +- subversion/libsvn_fs_fs/transaction.c | 251 +++++++++++++------ subversion/libsvn_fs_x/rep-cache-db.h | 2 +- subversion/libsvn_ra_svn/client.c | 45 +++- subversion/libsvn_repos/dump.c | 14 +- subversion/libsvn_subr/config_file.c | 6 +- subversion/libsvn_subr/internal_statements.h | 2 +- subversion/libsvn_subr/io.c | 35 ++- subversion/libsvn_subr/version.c | 2 +- subversion/libsvn_wc/wc-checks.h | 2 +- subversion/libsvn_wc/wc-metadata.h | 2 +- subversion/libsvn_wc/wc-queries.h | 2 +- subversion/svnadmin/svnadmin.c | 1 + win-tests.py | 2 +- 24 files changed, 489 insertions(+), 139 deletions(-) diff --git a/CHANGES b/CHANGES index 084bc36c8f95..276969ac1077 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,63 @@ +Version 1.9.7 +(10 Aug 2017, from /branches/1.9.x) +http://svn.apache.org/repos/asf/subversion/tags/1.9.7 + + User-visible changes: + - Client-side bugfixes: + * Fix arbitrary code execution vulnerability CVE-2017-9800 + See + for details. + + - Server-side bugfixes: + (none) + + - Bindings bugfixes: + (none) + + Developer-visible changes: + - General: + (none) + + - API changes: + (none) + + +Version 1.9.6 +(5 Jul 2017, from /branches/1.9.x) +http://svn.apache.org/repos/asf/subversion/tags/1.9.6 + + User-visible changes: + - Client-side bugfixes: + * cp/mv: improve error message when target is an unversioned dir (r1779948) + * merge: reduce memory usage with large amounts of mergeinfo (issue #4667) + + - Server-side bugfixes: + * 'svnadmin freeze': document the purpose more clearly (r1774109) + * dump: fix segfault when a revision has no revprops (r1781507) + * fsfs: improve error message upon failure to open rep-cache (r1781655) + * fsfs: never attempt to share directory representations (r1785053) + * fsfs: make consistency independent of hash algorithms (r1785737 et al) + This change makes Subversion resilient to collision attacks, including + SHA-1 collision attacks such as . See also our + documentation at and + . + + - Client-side and server-side bugfixes: + * work around an APR bug related to file truncation (r1759116) + + - Bindings bugfixes: + * javahl: follow redirects when opening a connection (r1667738, r1796720) + + Developer-visible changes: + - General: + * win_tests.py: make the --bin option work, rather than abort (r1706432) + (regression introduced in 1.9.2) + * windows: support building with 'zlibstat.lib' in install-layout (r1783704) + + - API changes: + (none) + + Version 1.9.5 (29 Nov 2016, from /branches/1.9.x) http://svn.apache.org/repos/asf/subversion/tags/1.9.5 @@ -19,7 +79,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.9.5 * fsfs: fix "offset too large" error during pack (issue #4657) * svnserve: enable hook script environments (r1769152) * fsfs: fix possible data reconstruction error (issue #4658) - * fix source of spurious 'incoming edit' tree conflicts (r1770108) + * fix source of spurious 'incoming edit' tree conflicts (r1760570) * fsfs: improve caching for large directories (r1721285) * fsfs: fix crash when encountering all-zero checksums (r1759686) * fsfs: fix potential source of repository corruptions (r1756266) @@ -34,19 +94,19 @@ http://svn.apache.org/repos/asf/subversion/tags/1.9.5 - Bindings bugfixes: * swig-pl: do not corrupt "{DATE}" revision variable (r1767768) - * javahl: fix temporary accepting SSL server certificates (r1764851) + * javahl: fix temporarily accepting SSL server certificates (r1764851) * swig-pl: fix possible stack corruption (r1683266, r1683267) Developer-visible changes: - General: * add zlib discovery through pkg-config (issue #4655) * fix potential build issue with invalid SVN_LOCALE_DIR (issue #4653) - * ruby: fix test failures with ruby >= 2.2 (r1766621) - * fix link error with --disable-keychain on OS X (r1765385) + * ruby: fix test failures with ruby >= 2.2 (r1766240) + * fix link error with --disable-keychain on OS X (r1761755) * swig: enable building with SWIG >= 3.0.6 (r1721488 et al) * swig: fix building with -Wdate-time in $CPPFLAGS (r1722164) * update serf download URI in build scripts (r1700130 et al) - * raise minimal httpd version from 2.0 to 2.2 (r1754193) + * raise minimal httpd version from 2.0 to 2.2 (r1754190) Version 1.9.4 @@ -105,7 +165,6 @@ http://svn.apache.org/repos/asf/subversion/tags/1.9.3 * svn: report lock/unlock errors as failures (r1701598 et al) * svn: cleanup user deleted external registrations (r1705843, r1710558) * svn: allow simple resolving of binary file text conflicts (r1703581) - * svnlook: properly remove tempfiles on diff errors (r1711346) * ra_serf: report built- and run-time versions of libserf (r1704847) * ra_serf: set Content-Type header in outgoing requests (r1715224 et al) * svn: fix merging deletes of svn:eol-style CRLF/CR files (r1703689 et al) @@ -118,6 +177,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.9.3 * mod_dav_svn: use LimitXMLRequestBody for skel-encoded requests (r1687812) * svnadmin dump: preserve no-op changes (r1709388 et al, issue #4598) * fsfs: avoid unneeded I/O when opening transactions (r1715793) + * svnlook: properly remove tempfiles on diff errors (r1711346) - Client-side and server-side bugfixes: * fix heap overflow in svn:// protocol parser (CVE-2015-5259) @@ -942,18 +1002,18 @@ http://svn.apache.org/repos/asf/subversion/tags/1.8.17 - Client-side bugfixes: * fix handling of newly secured subdirectories in working copy (r1724448) * ra_serf: fix deleting directories with many files (issue #4557) - * svnlook: properly remove tempfiles on diff errors (r1711346) * gpg-agent: properly handle passwords with percent characters (issue #4611) * merge: fix crash when merging to a local add (r1702299 et al) - Server-side bugfixes: * fsfs: fix possible data reconstruction error (issue #4658) + * svnlook: properly remove tempfiles on diff errors (r1711346) - Client-side and server-side bugfixes: * fix potential memory access bugs (r1722860 et al) - Bindings bugfixes: - * javahl: fix temporary accepting SSL server certificates (r1764851) + * javahl: fix temporarily accepting SSL server certificates (r1764851) * swig-pl: do not corrupt "{DATE}" revision variable (r1767768) * swig-pl: fix possible stack corruption (r1683266) diff --git a/NOTICE b/NOTICE index 0c4fe7d4420c..811686dcb359 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache Subversion -Copyright 2016 The Apache Software Foundation +Copyright 2017 The Apache Software Foundation This product includes software developed by many people, and distributed under Contributor License Agreements to The Apache Software Foundation diff --git a/build-outputs.mk b/build-outputs.mk index 7660d313c073..e82762f59aa4 100644 --- a/build-outputs.mk +++ b/build-outputs.mk @@ -2782,7 +2782,7 @@ subversion/libsvn_ra_serf/util_error.lo: subversion/libsvn_ra_serf/util_error.c subversion/libsvn_ra_serf/xml.lo: subversion/libsvn_ra_serf/xml.c subversion/include/private/svn_dav_protocol.h subversion/include/private/svn_debug.h subversion/include/private/svn_editor.h subversion/include/private/svn_ra_private.h subversion/include/private/svn_string_private.h subversion/include/private/svn_subr_private.h subversion/include/svn_auth.h subversion/include/svn_checksum.h subversion/include/svn_config.h subversion/include/svn_dav.h subversion/include/svn_delta.h subversion/include/svn_dirent_uri.h subversion/include/svn_error.h subversion/include/svn_error_codes.h subversion/include/svn_hash.h subversion/include/svn_io.h subversion/include/svn_mergeinfo.h subversion/include/svn_path.h subversion/include/svn_pools.h subversion/include/svn_ra.h subversion/include/svn_string.h subversion/include/svn_types.h subversion/include/svn_version.h subversion/include/svn_xml.h subversion/libsvn_ra/ra_loader.h subversion/libsvn_ra_serf/blncache.h subversion/libsvn_ra_serf/ra_serf.h subversion/svn_private_config.h -subversion/libsvn_ra_svn/client.lo: subversion/libsvn_ra_svn/client.c subversion/include/private/svn_debug.h subversion/include/private/svn_editor.h subversion/include/private/svn_fspath.h subversion/include/private/svn_ra_private.h subversion/include/private/svn_ra_svn_private.h subversion/include/private/svn_subr_private.h subversion/include/svn_auth.h subversion/include/svn_checksum.h subversion/include/svn_compat.h subversion/include/svn_config.h subversion/include/svn_delta.h subversion/include/svn_dirent_uri.h subversion/include/svn_error.h subversion/include/svn_error_codes.h subversion/include/svn_hash.h subversion/include/svn_io.h subversion/include/svn_mergeinfo.h subversion/include/svn_path.h subversion/include/svn_pools.h subversion/include/svn_props.h subversion/include/svn_ra.h subversion/include/svn_ra_svn.h subversion/include/svn_string.h subversion/include/svn_time.h subversion/include/svn_types.h subversion/include/svn_version.h subversion/libsvn_ra/ra_loader.h subversion/libsvn_ra/wrapper_template.h subversion/libsvn_ra_svn/ra_svn.h subversion/svn_private_config.h +subversion/libsvn_ra_svn/client.lo: subversion/libsvn_ra_svn/client.c subversion/include/private/svn_debug.h subversion/include/private/svn_editor.h subversion/include/private/svn_fspath.h subversion/include/private/svn_ra_private.h subversion/include/private/svn_ra_svn_private.h subversion/include/private/svn_subr_private.h subversion/include/svn_auth.h subversion/include/svn_checksum.h subversion/include/svn_compat.h subversion/include/svn_config.h subversion/include/svn_ctype.h subversion/include/svn_delta.h subversion/include/svn_dirent_uri.h subversion/include/svn_error.h subversion/include/svn_error_codes.h subversion/include/svn_hash.h subversion/include/svn_io.h subversion/include/svn_mergeinfo.h subversion/include/svn_path.h subversion/include/svn_pools.h subversion/include/svn_props.h subversion/include/svn_ra.h subversion/include/svn_ra_svn.h subversion/include/svn_string.h subversion/include/svn_time.h subversion/include/svn_types.h subversion/include/svn_version.h subversion/libsvn_ra/ra_loader.h subversion/libsvn_ra/wrapper_template.h subversion/libsvn_ra_svn/ra_svn.h subversion/svn_private_config.h subversion/libsvn_ra_svn/cram.lo: subversion/libsvn_ra_svn/cram.c subversion/include/private/svn_debug.h subversion/include/private/svn_editor.h subversion/include/private/svn_ra_svn_private.h subversion/include/svn_auth.h subversion/include/svn_checksum.h subversion/include/svn_config.h subversion/include/svn_delta.h subversion/include/svn_error.h subversion/include/svn_error_codes.h subversion/include/svn_io.h subversion/include/svn_mergeinfo.h subversion/include/svn_ra.h subversion/include/svn_ra_svn.h subversion/include/svn_string.h subversion/include/svn_types.h subversion/libsvn_ra_svn/ra_svn.h subversion/svn_private_config.h diff --git a/configure b/configure index 844ec1a180ba..62356fa19994 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for subversion 1.9.5. +# Generated by GNU Autoconf 2.69 for subversion 1.9.7. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='subversion' PACKAGE_TARNAME='subversion' -PACKAGE_VERSION='1.9.5' -PACKAGE_STRING='subversion 1.9.5' +PACKAGE_VERSION='1.9.7' +PACKAGE_STRING='subversion 1.9.7' PACKAGE_BUGREPORT='http://subversion.apache.org/' PACKAGE_URL='' @@ -1471,7 +1471,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures subversion 1.9.5 to adapt to many kinds of systems. +\`configure' configures subversion 1.9.7 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1537,7 +1537,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of subversion 1.9.5:";; + short | recursive ) echo "Configuration of subversion 1.9.7:";; esac cat <<\_ACEOF @@ -1751,7 +1751,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -subversion configure 1.9.5 +subversion configure 1.9.7 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2295,7 +2295,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by subversion $as_me 1.9.5, which was +It was created by subversion $as_me 1.9.7, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2675,8 +2675,8 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. -{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuring Subversion 1.9.5" >&5 -$as_echo "$as_me: Configuring Subversion 1.9.5" >&6;} +{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuring Subversion 1.9.7" >&5 +$as_echo "$as_me: Configuring Subversion 1.9.7" >&6;} abs_srcdir="`cd $srcdir && pwd`" @@ -26756,7 +26756,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by subversion $as_me 1.9.5, which was +This file was extended by subversion $as_me 1.9.7, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -26822,7 +26822,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -subversion config.status 1.9.5 +subversion config.status 1.9.7 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/subversion/include/svn_version.h b/subversion/include/svn_version.h index 79e37d9a9b88..39f7154847e5 100644 --- a/subversion/include/svn_version.h +++ b/subversion/include/svn_version.h @@ -70,7 +70,7 @@ extern "C" { * * @since New in 1.1. */ -#define SVN_VER_PATCH 5 +#define SVN_VER_PATCH 7 /** @deprecated Provided for backward compatibility with the 1.0 API. */ @@ -93,7 +93,7 @@ extern "C" { * * Always change this at the same time as SVN_VER_NUMTAG. */ -#define SVN_VER_TAG " (r1770682)" +#define SVN_VER_TAG " (r1800392)" /** Number tag: a string describing the version. @@ -117,7 +117,7 @@ extern "C" { * file version. Its value remains 0 in the repository except in release * tags where it is the revision from which the tag was created. */ -#define SVN_VER_REVISION 1770682 +#define SVN_VER_REVISION 1800392 /* Version strings composed from the above definitions. */ diff --git a/subversion/libsvn_client/copy.c b/subversion/libsvn_client/copy.c index 12bbfe6cf687..af6a75b83698 100644 --- a/subversion/libsvn_client/copy.c +++ b/subversion/libsvn_client/copy.c @@ -1057,10 +1057,24 @@ verify_wc_dsts(const apr_array_header_t *copy_pairs, ctx->wc_ctx, pair->dst_parent_abspath, FALSE, TRUE, iterpool)); - if (make_parents && dst_parent_kind == svn_node_none) + if (dst_parent_kind == svn_node_none) { - SVN_ERR(svn_client__make_local_parents(pair->dst_parent_abspath, - TRUE, ctx, iterpool)); + if (make_parents) + SVN_ERR(svn_client__make_local_parents(pair->dst_parent_abspath, + TRUE, ctx, iterpool)); + else + { + SVN_ERR(svn_io_check_path(pair->dst_parent_abspath, + &dst_parent_kind, scratch_pool)); + return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, + (dst_parent_kind == svn_node_dir) + ? _("Directory '%s' is not under " + "version control") + : _("Path '%s' is not a directory"), + svn_dirent_local_style( + pair->dst_parent_abspath, + scratch_pool)); + } } else if (dst_parent_kind != svn_node_dir) { diff --git a/subversion/libsvn_client/merge.c b/subversion/libsvn_client/merge.c index fed848904863..aaab4e002cf5 100644 --- a/subversion/libsvn_client/merge.c +++ b/subversion/libsvn_client/merge.c @@ -6465,6 +6465,7 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo, { int i; apr_pool_t *iterpool = svn_pool_create(scratch_pool); + apr_pool_t *swmi_pool; apr_hash_t *subtrees_with_mergeinfo; apr_hash_t *excluded_subtrees; apr_hash_t *switched_subtrees; @@ -6473,10 +6474,13 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo, struct pre_merge_status_baton_t pre_merge_status_baton; /* Case 1: Subtrees with explicit mergeinfo. */ + /* Use a subpool for subtrees_with_mergeinfo, as it can be very large + and is temporary. */ + swmi_pool = svn_pool_create(scratch_pool); SVN_ERR(get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo, target->abspath, depth, ctx, - result_pool, scratch_pool)); + swmi_pool, swmi_pool)); if (subtrees_with_mergeinfo) { apr_hash_index_t *hi; @@ -6513,6 +6517,7 @@ get_mergeinfo_paths(apr_array_header_t *children_with_mergeinfo, children_with_mergeinfo->elt_size, compare_merge_path_t_as_paths); } + svn_pool_destroy(swmi_pool); /* Case 2: Switched subtrees Case 10: Paths at depths of 'empty' or 'files' @@ -12331,6 +12336,10 @@ find_last_merged_location(svn_client__pathrev_t **base_p, svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM; svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL; + /* Using a local subpool for 'target_mergeinfo_cat' can make a big + reduction in overall memory usage. */ + apr_pool_t *tmic_pool = svn_pool_create(scratch_pool); + source_peg_rev.kind = svn_opt_revision_number; source_peg_rev.value.number = source_branch->tip->rev; source_start_rev.kind = svn_opt_revision_number; @@ -12351,7 +12360,7 @@ find_last_merged_location(svn_client__pathrev_t **base_p, operative_rev_receiver, &youngest_merged_rev, ctx, ra_session, - result_pool, scratch_pool)); + tmic_pool, tmic_pool)); if (!SVN_IS_VALID_REVNUM(youngest_merged_rev)) { @@ -12387,7 +12396,7 @@ find_last_merged_location(svn_client__pathrev_t **base_p, operative_rev_receiver, &oldest_eligible_rev, ctx, ra_session, - scratch_pool, scratch_pool)); + tmic_pool, tmic_pool)); /* If there are revisions eligible for merging, use the oldest one to calculate the base. Otherwise there are no operative revisions @@ -12409,6 +12418,7 @@ find_last_merged_location(svn_client__pathrev_t **base_p, result_pool, scratch_pool)); } + svn_pool_destroy(tmic_pool); return SVN_NO_ERROR; } diff --git a/subversion/libsvn_fs_fs/cached_data.c b/subversion/libsvn_fs_fs/cached_data.c index 6e61535f46a5..6581a6c8831c 100644 --- a/subversion/libsvn_fs_fs/cached_data.c +++ b/subversion/libsvn_fs_fs/cached_data.c @@ -2029,8 +2029,13 @@ rep_read_contents(void *baton, SVN_ERR(skip_contents(rb, rb->fulltext_delivered)); } - /* Get the next block of data. */ - SVN_ERR(get_contents_from_windows(rb, buf, len)); + /* Get the next block of data. + * Keep in mind that the representation might be empty and leave us + * already positioned at the end of the rep. */ + if (rb->off == rb->len) + *len = 0; + else + SVN_ERR(get_contents_from_windows(rb, buf, len)); if (rb->current_fulltext) svn_stringbuf_appendbytes(rb->current_fulltext, buf, *len); @@ -2123,6 +2128,96 @@ svn_fs_fs__get_contents(svn_stream_t **contents_p, return SVN_NO_ERROR; } +svn_error_t * +svn_fs_fs__get_contents_from_file(svn_stream_t **contents_p, + svn_fs_t *fs, + representation_t *rep, + apr_file_t *file, + apr_off_t offset, + apr_pool_t *pool) +{ + struct rep_read_baton *rb; + pair_cache_key_t fulltext_cache_key = { SVN_INVALID_REVNUM, 0 }; + rep_state_t *rs = apr_pcalloc(pool, sizeof(*rs)); + svn_fs_fs__rep_header_t *rh; + + /* Initialize the reader baton. Some members may added lazily + * while reading from the stream. */ + SVN_ERR(rep_read_get_baton(&rb, fs, rep, fulltext_cache_key, pool)); + + /* Continue constructing RS. Leave caches as NULL. */ + rs->size = rep->size; + rs->revision = SVN_INVALID_REVNUM; + rs->item_index = 0; + rs->ver = -1; + rs->start = -1; + + /* Provide just enough file access info to allow for a basic read from + * FILE but leave all index / footer info with empty values b/c FILE + * probably is not a complete revision file. */ + rs->sfile = apr_pcalloc(pool, sizeof(*rs->sfile)); + rs->sfile->revision = rep->revision; + rs->sfile->pool = pool; + rs->sfile->fs = fs; + rs->sfile->rfile = apr_pcalloc(pool, sizeof(*rs->sfile->rfile)); + rs->sfile->rfile->start_revision = SVN_INVALID_REVNUM; + rs->sfile->rfile->file = file; + rs->sfile->rfile->stream = svn_stream_from_aprfile2(file, TRUE, pool); + + /* Read the rep header. */ + SVN_ERR(aligned_seek(fs, file, NULL, offset, pool)); + SVN_ERR(svn_fs_fs__read_rep_header(&rh, rs->sfile->rfile->stream, + pool, pool)); + SVN_ERR(get_file_offset(&rs->start, rs, pool)); + rs->header_size = rh->header_size; + + /* Log the access. */ + SVN_ERR(dbg_log_access(fs, SVN_INVALID_REVNUM, 0, rh, + SVN_FS_FS__ITEM_TYPE_ANY_REP, pool)); + + /* Build the representation list (delta chain). */ + if (rh->type == svn_fs_fs__rep_plain) + { + rb->rs_list = apr_array_make(pool, 0, sizeof(rep_state_t *)); + rb->src_state = rs; + } + else if (rh->type == svn_fs_fs__rep_self_delta) + { + rb->rs_list = apr_array_make(pool, 1, sizeof(rep_state_t *)); + APR_ARRAY_PUSH(rb->rs_list, rep_state_t *) = rs; + rb->src_state = NULL; + } + else + { + representation_t next_rep = { 0 }; + + /* skip "SVNx" diff marker */ + rs->current = 4; + + /* REP's base rep is inside a proper revision. + * It can be reconstructed in the usual way. */ + next_rep.revision = rh->base_revision; + next_rep.item_index = rh->base_item_index; + next_rep.size = rh->base_length; + svn_fs_fs__id_txn_reset(&next_rep.txn_id); + + SVN_ERR(build_rep_list(&rb->rs_list, &rb->base_window, + &rb->src_state, &rb->len, rb->fs, &next_rep, + rb->filehandle_pool)); + + /* Insert the access to REP as the first element of the delta chain. */ + svn_sort__array_insert(rb->rs_list, &rs, 0); + } + + /* Now, the baton is complete and we can assemble the stream around it. */ + *contents_p = svn_stream_create(rb, pool); + svn_stream_set_read2(*contents_p, NULL /* only full read support */, + rep_read_contents); + svn_stream_set_close(*contents_p, rep_read_contents_close); + + return SVN_NO_ERROR; +} + /* Baton for cache_access_wrapper. Wraps the original parameters of * svn_fs_fs__try_process_file_content(). */ diff --git a/subversion/libsvn_fs_fs/cached_data.h b/subversion/libsvn_fs_fs/cached_data.h index 9bdc51c3df6e..07fa956765e0 100644 --- a/subversion/libsvn_fs_fs/cached_data.h +++ b/subversion/libsvn_fs_fs/cached_data.h @@ -81,6 +81,18 @@ svn_fs_fs__get_contents(svn_stream_t **contents_p, svn_boolean_t cache_fulltext, apr_pool_t *pool); +/* Set *CONTENTS_P to be a readable svn_stream_t that receives the text + representation REP as seen in filesystem FS. Read the latest element + of the delta chain from FILE at offset OFFSET. + Use POOL for allocations. */ +svn_error_t * +svn_fs_fs__get_contents_from_file(svn_stream_t **contents_p, + svn_fs_t *fs, + representation_t *rep, + apr_file_t *file, + apr_off_t offset, + apr_pool_t *pool); + /* Attempt to fetch the text representation of node-revision NODEREV as seen in filesystem FS and pass it along with the BATON to the PROCESSOR. Set *SUCCESS only of the data could be provided and the processing diff --git a/subversion/libsvn_fs_fs/rep-cache-db.h b/subversion/libsvn_fs_fs/rep-cache-db.h index 804b669d12f4..0f2cc89aa7ff 100644 --- a/subversion/libsvn_fs_fs/rep-cache-db.h +++ b/subversion/libsvn_fs_fs/rep-cache-db.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from rep-cache-db.sql and .dist_sandbox/subversion-1.9.5/subversion/libsvn_fs_fs/token-map.h. +/* This file is automatically generated from rep-cache-db.sql and .dist_sandbox/subversion-1.9.7/subversion/libsvn_fs_fs/token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_CREATE_SCHEMA 0 diff --git a/subversion/libsvn_fs_fs/rep-cache.c b/subversion/libsvn_fs_fs/rep-cache.c index 663d11d6f09a..437d60381ddb 100644 --- a/subversion/libsvn_fs_fs/rep-cache.c +++ b/subversion/libsvn_fs_fs/rep-cache.c @@ -128,7 +128,10 @@ svn_fs_fs__open_rep_cache(svn_fs_t *fs, fs_fs_data_t *ffd = fs->fsap_data; svn_error_t *err = svn_atomic__init_once(&ffd->rep_cache_db_opened, open_rep_cache, fs, pool); - return svn_error_quick_wrap(err, _("Couldn't open rep-cache database")); + return svn_error_quick_wrapf(err, + _("Couldn't open rep-cache database '%s'"), + svn_dirent_local_style( + path_rep_cache_db(fs->path, pool), pool)); } svn_error_t * diff --git a/subversion/libsvn_fs_fs/transaction.c b/subversion/libsvn_fs_fs/transaction.c index fabfe3e3e03b..bc93a5c27b82 100644 --- a/subversion/libsvn_fs_fs/transaction.c +++ b/subversion/libsvn_fs_fs/transaction.c @@ -2128,6 +2128,11 @@ rep_write_get_baton(struct rep_write_baton **wb_p, there may be new duplicate representations within the same uncommitted revision, those can be passed in REPS_HASH (maps a sha1 digest onto representation_t*), otherwise pass in NULL for REPS_HASH. + + The content of both representations will be compared, taking REP's content + from FILE at OFFSET. Only if they actually match, will *OLD_REP not be + NULL. + Use RESULT_POOL for *OLD_REP allocations and SCRATCH_POOL for temporaries. The lifetime of *OLD_REP is limited by both, RESULT_POOL and REP lifetime. */ @@ -2135,6 +2140,8 @@ static svn_error_t * get_shared_rep(representation_t **old_rep, svn_fs_t *fs, representation_t *rep, + apr_file_t *file, + apr_off_t offset, apr_hash_t *reps_hash, apr_pool_t *result_pool, apr_pool_t *scratch_pool) @@ -2142,6 +2149,10 @@ get_shared_rep(representation_t **old_rep, svn_error_t *err; fs_fs_data_t *ffd = fs->fsap_data; + svn_checksum_t checksum; + checksum.digest = rep->sha1_digest; + checksum.kind = svn_checksum_sha1; + /* Return NULL, if rep sharing has been disabled. */ *old_rep = NULL; if (!ffd->rep_sharing_allowed) @@ -2158,9 +2169,6 @@ get_shared_rep(representation_t **old_rep, /* If we haven't found anything yet, try harder and consult our DB. */ if (*old_rep == NULL) { - svn_checksum_t checksum; - checksum.digest = rep->sha1_digest; - checksum.kind = svn_checksum_sha1; err = svn_fs_fs__get_rep_reference(old_rep, fs, &checksum, result_pool); /* ### Other error codes that we shouldn't mask out? */ if (err == SVN_NO_ERROR) @@ -2235,6 +2243,72 @@ get_shared_rep(representation_t **old_rep, (*old_rep)->uniquifier = rep->uniquifier; } + /* If we (very likely) found a matching representation, compare the actual + * contents such that we can be sure that no rep-cache.db corruption or + * hash collision produced a false positive. */ + if (*old_rep) + { + apr_off_t old_position; + svn_stream_t *contents; + svn_stream_t *old_contents; + svn_boolean_t same; + + /* The existing representation may itself be part of the current + * transaction. In that case, it may be in different stages of + * the commit finalization process. + * + * OLD_REP_NORM is the same as that OLD_REP but it is assigned + * explicitly to REP's transaction if OLD_REP does not point + * to an already committed revision. This then prevents the + * revision lookup and the txn data will be accessed. + */ + representation_t old_rep_norm = **old_rep; + if ( !SVN_IS_VALID_REVNUM(old_rep_norm.revision) + || old_rep_norm.revision > ffd->youngest_rev_cache) + old_rep_norm.txn_id = rep->txn_id; + + /* Make sure we can later restore FILE's current position. */ + SVN_ERR(svn_fs_fs__get_file_offset(&old_position, file, scratch_pool)); + + /* Compare the two representations. + * Note that the stream comparison might also produce MD5 checksum + * errors or other failures in case of SHA1 collisions. */ + SVN_ERR(svn_fs_fs__get_contents_from_file(&contents, fs, rep, file, + offset, scratch_pool)); + SVN_ERR(svn_fs_fs__get_contents(&old_contents, fs, &old_rep_norm, + FALSE, scratch_pool)); + err = svn_stream_contents_same2(&same, contents, old_contents, + scratch_pool); + + /* A mismatch should be extremely rare. + * If it does happen, reject the commit. */ + if (!same || err) + { + /* SHA1 collision or worse. */ + svn_stringbuf_t *old_rep_str + = svn_fs_fs__unparse_representation(*old_rep, + ffd->format, FALSE, + scratch_pool, + scratch_pool); + svn_stringbuf_t *rep_str + = svn_fs_fs__unparse_representation(rep, + ffd->format, FALSE, + scratch_pool, + scratch_pool); + const char *checksum__str + = svn_checksum_to_cstring_display(&checksum, scratch_pool); + + return svn_error_createf(SVN_ERR_FS_GENERAL, + err, "SHA1 of reps '%s' and '%s' " + "matches (%s) but contents differ", + old_rep_str->data, rep_str->data, + checksum__str); + } + + /* Restore FILE's read / write position. */ + SVN_ERR(svn_io_file_seek(file, APR_SET, &old_position, scratch_pool)); + } + return SVN_NO_ERROR; } @@ -2293,8 +2367,8 @@ rep_write_contents_close(void *baton) /* Check and see if we already have a representation somewhere that's identical to the one we just wrote out. */ - SVN_ERR(get_shared_rep(&old_rep, b->fs, rep, NULL, b->result_pool, - b->scratch_pool)); + SVN_ERR(get_shared_rep(&old_rep, b->fs, rep, b->file, b->rep_offset, NULL, + b->result_pool, b->scratch_pool)); if (old_rep) { @@ -2519,11 +2593,16 @@ write_directory_to_stream(svn_stream_t *stream, /* Write out the COLLECTION as a text representation to file FILE using WRITER. In the process, record position, the total size of the dump and MD5 as well as SHA1 in REP. Add the representation of type ITEM_TYPE to - the indexes if necessary. If rep sharing has been enabled and REPS_HASH - is not NULL, it will be used in addition to the on-disk cache to find - earlier reps with the same content. When such existing reps can be - found, we will truncate the one just written from the file and return - the existing rep. Perform temporary allocations in SCRATCH_POOL. */ + the indexes if necessary. + + If ALLOW_REP_SHARING is FALSE, rep-sharing will not be used, regardless + of any other option and rep-sharing settings. If rep sharing has been + enabled and REPS_HASH is not NULL, it will be used in addition to the + on-disk cache to find earlier reps with the same content. If such + existing reps can be found, we will truncate the one just written from + the file and return the existing rep. + + Perform temporary allocations in SCRATCH_POOL. */ static svn_error_t * write_container_rep(representation_t *rep, apr_file_t *file, @@ -2531,14 +2610,15 @@ write_container_rep(representation_t *rep, collection_writer_t writer, svn_fs_t *fs, apr_hash_t *reps_hash, + svn_boolean_t allow_rep_sharing, apr_uint32_t item_type, apr_pool_t *scratch_pool) { svn_stream_t *stream; struct write_container_baton *whb; svn_checksum_ctx_t *fnv1a_checksum_ctx; - representation_t *old_rep; apr_off_t offset = 0; + svn_fs_fs__p2l_entry_t entry; SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool)); @@ -2562,45 +2642,46 @@ write_container_rep(representation_t *rep, /* Store the results. */ SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, scratch_pool)); + /* Update size info. */ + rep->expanded_size = whb->size; + rep->size = whb->size; + /* Check and see if we already have a representation somewhere that's identical to the one we just wrote out. */ - SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool, - scratch_pool)); - - if (old_rep) + if (allow_rep_sharing) { - /* We need to erase from the protorev the data we just wrote. */ - SVN_ERR(svn_io_file_trunc(file, offset, scratch_pool)); + representation_t *old_rep; + SVN_ERR(get_shared_rep(&old_rep, fs, rep, file, offset, reps_hash, + scratch_pool, scratch_pool)); - /* Use the old rep for this content. */ - memcpy(rep, old_rep, sizeof (*rep)); + if (old_rep) + { + /* We need to erase from the protorev the data we just wrote. */ + SVN_ERR(svn_io_file_trunc(file, offset, scratch_pool)); + + /* Use the old rep for this content. */ + memcpy(rep, old_rep, sizeof (*rep)); + return SVN_NO_ERROR; + } } - else - { - svn_fs_fs__p2l_entry_t entry; - /* Write out our cosmetic end marker. */ - SVN_ERR(svn_stream_puts(whb->stream, "ENDREP\n")); + /* Write out our cosmetic end marker. */ + SVN_ERR(svn_stream_puts(whb->stream, "ENDREP\n")); - SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id, - offset, scratch_pool)); + SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id, + offset, scratch_pool)); - entry.offset = offset; - SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool)); - entry.size = offset - entry.offset; - entry.type = item_type; - entry.item.revision = SVN_INVALID_REVNUM; - entry.item.number = rep->item_index; - SVN_ERR(fnv1a_checksum_finalize(&entry.fnv1_checksum, - fnv1a_checksum_ctx, - scratch_pool)); + entry.offset = offset; + SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool)); + entry.size = offset - entry.offset; + entry.type = item_type; + entry.item.revision = SVN_INVALID_REVNUM; + entry.item.number = rep->item_index; + SVN_ERR(fnv1a_checksum_finalize(&entry.fnv1_checksum, + fnv1a_checksum_ctx, + scratch_pool)); - SVN_ERR(store_p2l_index_entry(fs, &rep->txn_id, &entry, scratch_pool)); - - /* update the representation */ - rep->size = whb->size; - rep->expanded_size = whb->size; - } + SVN_ERR(store_p2l_index_entry(fs, &rep->txn_id, &entry, scratch_pool)); return SVN_NO_ERROR; } @@ -2608,11 +2689,14 @@ write_container_rep(representation_t *rep, /* Write out the COLLECTION pertaining to the NODEREV in FS as a deltified text representation to file FILE using WRITER. In the process, record the total size and the md5 digest in REP and add the representation of type - ITEM_TYPE to the indexes if necessary. If rep sharing has been enabled and - REPS_HASH is not NULL, it will be used in addition to the on-disk cache to - find earlier reps with the same content. When such existing reps can be - found, we will truncate the one just written from the file and return the - existing rep. + ITEM_TYPE to the indexes if necessary. + + If ALLOW_REP_SHARING is FALSE, rep-sharing will not be used, regardless + of any other option and rep-sharing settings. If rep sharing has been + enabled and REPS_HASH is not NULL, it will be used in addition to the + on-disk cache to find earlier reps with the same content. If such + existing reps can be found, we will truncate the one just written from + the file and return the existing rep. If ITEM_TYPE is IS_PROPS equals SVN_FS_FS__ITEM_TYPE_*_PROPS, assume that we want to a props representation as the base for our delta. @@ -2626,6 +2710,7 @@ write_container_delta_rep(representation_t *rep, svn_fs_t *fs, node_revision_t *noderev, apr_hash_t *reps_hash, + svn_boolean_t allow_rep_sharing, apr_uint32_t item_type, apr_pool_t *scratch_pool) { @@ -2635,10 +2720,10 @@ write_container_delta_rep(representation_t *rep, svn_stream_t *file_stream; svn_stream_t *stream; representation_t *base_rep; - representation_t *old_rep; svn_checksum_ctx_t *fnv1a_checksum_ctx; svn_stream_t *source; svn_fs_fs__rep_header_t header = { 0 }; + svn_fs_fs__p2l_entry_t entry; apr_off_t rep_end = 0; apr_off_t delta_start = 0; @@ -2701,46 +2786,47 @@ write_container_delta_rep(representation_t *rep, /* Store the results. */ SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, scratch_pool)); + /* Update size info. */ + SVN_ERR(svn_fs_fs__get_file_offset(&rep_end, file, scratch_pool)); + rep->size = rep_end - delta_start; + rep->expanded_size = whb->size; + /* Check and see if we already have a representation somewhere that's identical to the one we just wrote out. */ - SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool, - scratch_pool)); - - if (old_rep) + if (allow_rep_sharing) { - /* We need to erase from the protorev the data we just wrote. */ - SVN_ERR(svn_io_file_trunc(file, offset, scratch_pool)); + representation_t *old_rep; + SVN_ERR(get_shared_rep(&old_rep, fs, rep, file, offset, reps_hash, + scratch_pool, scratch_pool)); - /* Use the old rep for this content. */ - memcpy(rep, old_rep, sizeof (*rep)); + if (old_rep) + { + /* We need to erase from the protorev the data we just wrote. */ + SVN_ERR(svn_io_file_trunc(file, offset, scratch_pool)); + + /* Use the old rep for this content. */ + memcpy(rep, old_rep, sizeof (*rep)); + return SVN_NO_ERROR; + } } - else - { - svn_fs_fs__p2l_entry_t entry; - /* Write out our cosmetic end marker. */ - SVN_ERR(svn_fs_fs__get_file_offset(&rep_end, file, scratch_pool)); - SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n")); + /* Write out our cosmetic end marker. */ + SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n")); - SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id, - offset, scratch_pool)); + SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id, + offset, scratch_pool)); - entry.offset = offset; - SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool)); - entry.size = offset - entry.offset; - entry.type = item_type; - entry.item.revision = SVN_INVALID_REVNUM; - entry.item.number = rep->item_index; - SVN_ERR(fnv1a_checksum_finalize(&entry.fnv1_checksum, - fnv1a_checksum_ctx, - scratch_pool)); + entry.offset = offset; + SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool)); + entry.size = offset - entry.offset; + entry.type = item_type; + entry.item.revision = SVN_INVALID_REVNUM; + entry.item.number = rep->item_index; + SVN_ERR(fnv1a_checksum_finalize(&entry.fnv1_checksum, + fnv1a_checksum_ctx, + scratch_pool)); - SVN_ERR(store_p2l_index_entry(fs, &rep->txn_id, &entry, scratch_pool)); - - /* update the representation */ - rep->expanded_size = whb->size; - rep->size = rep_end - delta_start; - } + SVN_ERR(store_p2l_index_entry(fs, &rep->txn_id, &entry, scratch_pool)); return SVN_NO_ERROR; } @@ -2920,13 +3006,14 @@ write_final_rev(const svn_fs_id_t **new_id_p, SVN_ERR(write_container_delta_rep(noderev->data_rep, file, entries, write_directory_to_stream, - fs, noderev, NULL, + fs, noderev, NULL, FALSE, SVN_FS_FS__ITEM_TYPE_DIR_REP, pool)); else SVN_ERR(write_container_rep(noderev->data_rep, file, entries, write_directory_to_stream, fs, NULL, - SVN_FS_FS__ITEM_TYPE_DIR_REP, pool)); + FALSE, SVN_FS_FS__ITEM_TYPE_DIR_REP, + pool)); reset_txn_in_rep(noderev->data_rep); } @@ -2971,11 +3058,11 @@ write_final_rev(const svn_fs_id_t **new_id_p, if (ffd->deltify_properties) SVN_ERR(write_container_delta_rep(noderev->prop_rep, file, proplist, write_hash_to_stream, fs, noderev, - reps_hash, item_type, pool)); + reps_hash, TRUE, item_type, pool)); else SVN_ERR(write_container_rep(noderev->prop_rep, file, proplist, write_hash_to_stream, fs, reps_hash, - item_type, pool)); + TRUE, item_type, pool)); reset_txn_in_rep(noderev->prop_rep); } diff --git a/subversion/libsvn_fs_x/rep-cache-db.h b/subversion/libsvn_fs_x/rep-cache-db.h index 68affb308c17..918955f51d9f 100644 --- a/subversion/libsvn_fs_x/rep-cache-db.h +++ b/subversion/libsvn_fs_x/rep-cache-db.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from rep-cache-db.sql and .dist_sandbox/subversion-1.9.5/subversion/libsvn_fs_x/token-map.h. +/* This file is automatically generated from rep-cache-db.sql and .dist_sandbox/subversion-1.9.7/subversion/libsvn_fs_x/token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_CREATE_SCHEMA 0 diff --git a/subversion/libsvn_ra_svn/client.c b/subversion/libsvn_ra_svn/client.c index 9ea59d20e147..a4939ab2ad53 100644 --- a/subversion/libsvn_ra_svn/client.c +++ b/subversion/libsvn_ra_svn/client.c @@ -46,6 +46,7 @@ #include "svn_props.h" #include "svn_mergeinfo.h" #include "svn_version.h" +#include "svn_ctype.h" #include "svn_private_config.h" @@ -396,7 +397,7 @@ static svn_error_t *find_tunnel_agent(const char *tunnel, * versions have it too. If the user is using some other ssh * implementation that doesn't accept it, they can override it * in the [tunnels] section of the config. */ - val = "$SVN_SSH ssh -q"; + val = "$SVN_SSH ssh -q --"; } if (!val || !*val) @@ -441,7 +442,7 @@ static svn_error_t *find_tunnel_agent(const char *tunnel, for (n = 0; cmd_argv[n] != NULL; n++) argv[n] = cmd_argv[n]; - argv[n++] = svn_path_uri_decode(hostinfo, pool); + argv[n++] = hostinfo; argv[n++] = "svnserve"; argv[n++] = "-t"; argv[n] = NULL; @@ -802,6 +803,32 @@ ra_svn_get_schemes(apr_pool_t *pool) } +/* A simple whitelist to ensure the following are valid: + * user@server + * [::1]:22 + * server-name + * server_name + * 127.0.0.1 + * with an extra restriction that a leading '-' is invalid. + */ +static svn_boolean_t +is_valid_hostinfo(const char *hostinfo) +{ + const char *p = hostinfo; + + if (p[0] == '-') + return FALSE; + + while (*p) + { + if (!svn_ctype_isalnum(*p) && !strchr(":.-_[]@", *p)) + return FALSE; + + ++p; + } + + return TRUE; +} static svn_error_t *ra_svn_open(svn_ra_session_t *session, const char **corrected_url, @@ -835,8 +862,18 @@ static svn_error_t *ra_svn_open(svn_ra_session_t *session, || (callbacks->check_tunnel_func && callbacks->open_tunnel_func && !callbacks->check_tunnel_func(callbacks->tunnel_baton, tunnel)))) - SVN_ERR(find_tunnel_agent(tunnel, uri.hostinfo, &tunnel_argv, config, - result_pool)); + { + const char *decoded_hostinfo; + + decoded_hostinfo = svn_path_uri_decode(uri.hostinfo, result_pool); + + if (!is_valid_hostinfo(decoded_hostinfo)) + return svn_error_createf(SVN_ERR_BAD_URL, NULL, _("Invalid host '%s'"), + uri.hostinfo); + + SVN_ERR(find_tunnel_agent(tunnel, decoded_hostinfo, &tunnel_argv, + config, result_pool)); + } else tunnel_argv = NULL; diff --git a/subversion/libsvn_repos/dump.c b/subversion/libsvn_repos/dump.c index 78cd78bebc99..189d724cd2de 100644 --- a/subversion/libsvn_repos/dump.c +++ b/subversion/libsvn_repos/dump.c @@ -546,11 +546,15 @@ svn_repos__dump_revision_record(svn_stream_t *dump_stream, "%" APR_SIZE_T_FMT, propstring->len)); } - /* Write out a regular Content-length header for the benefit of - non-Subversion RFC-822 parsers. */ - svn_hash_sets(headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH, - apr_psprintf(scratch_pool, - "%" APR_SIZE_T_FMT, propstring->len)); + if (propstring) + { + /* Write out a regular Content-length header for the benefit of + non-Subversion RFC-822 parsers. */ + svn_hash_sets(headers, SVN_REPOS_DUMPFILE_CONTENT_LENGTH, + apr_psprintf(scratch_pool, + "%" APR_SIZE_T_FMT, propstring->len)); + } + SVN_ERR(write_revision_headers(dump_stream, headers, scratch_pool)); /* End of headers */ diff --git a/subversion/libsvn_subr/config_file.c b/subversion/libsvn_subr/config_file.c index 8b4d7a35220c..e4a5936d7834 100644 --- a/subversion/libsvn_subr/config_file.c +++ b/subversion/libsvn_subr/config_file.c @@ -1248,12 +1248,12 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### passed to the tunnel agent as @.) If the" NL "### built-in ssh scheme were not predefined, it could be defined" NL "### as:" NL - "# ssh = $SVN_SSH ssh -q" 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 - "# rsh = rsh" NL + "# rsh = rsh --" NL "### Or, if you wanted to specify a full path and arguments:" NL - "# rsh = /path/to/rsh -l myusername" NL + "# rsh = /path/to/rsh -l myusername --" NL "### On Windows, if you are specifying a full path to a command," NL "### use a forward slash (/) or a paired backslash (\\\\) as the" NL "### path separator. A single backslash will be treated as an" NL diff --git a/subversion/libsvn_subr/internal_statements.h b/subversion/libsvn_subr/internal_statements.h index 39b671964787..1d0a3f8e9399 100644 --- a/subversion/libsvn_subr/internal_statements.h +++ b/subversion/libsvn_subr/internal_statements.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from internal_statements.sql and .dist_sandbox/subversion-1.9.5/subversion/libsvn_subr/token-map.h. +/* This file is automatically generated from internal_statements.sql and .dist_sandbox/subversion-1.9.7/subversion/libsvn_subr/token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_INTERNAL_SAVEPOINT_SVN 0 diff --git a/subversion/libsvn_subr/io.c b/subversion/libsvn_subr/io.c index 75e85647df72..468dd1723804 100644 --- a/subversion/libsvn_subr/io.c +++ b/subversion/libsvn_subr/io.c @@ -4044,6 +4044,26 @@ svn_io_write_atomic(const char *final_path, svn_error_t * svn_io_file_trunc(apr_file_t *file, apr_off_t offset, apr_pool_t *pool) { + /* Workaround for yet another APR issue with trunc. + + If the APR file internally is in read mode, the current buffer pointer + will not be clipped to the valid data range. get_file_offset may then + return an invalid position *after* new data was written to it. + + To prevent this, write 1 dummy byte just after the OFFSET at which we + will trunc it. That will force the APR file into write mode + internally and the flush() work-around below becomes affective. */ + apr_off_t position = 0; + + /* A frequent usage is OFFSET==0, in which case we don't need to preserve + any file content or file pointer. */ + if (offset) + { + SVN_ERR(svn_io_file_seek(file, APR_CUR, &position, pool)); + SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, pool)); + } + SVN_ERR(svn_io_file_putc(0, file, pool)); + /* This is a work-around. APR would flush the write buffer _after_ truncating the file causing now invalid buffered data to be written behind OFFSET. */ @@ -4052,10 +4072,17 @@ svn_io_file_trunc(apr_file_t *file, apr_off_t offset, apr_pool_t *pool) N_("Can't flush stream"), pool)); - return do_io_file_wrapper_cleanup(file, apr_file_trunc(file, offset), - N_("Can't truncate file '%s'"), - N_("Can't truncate stream"), - pool); + SVN_ERR(do_io_file_wrapper_cleanup(file, apr_file_trunc(file, offset), + N_("Can't truncate file '%s'"), + N_("Can't truncate stream"), + pool)); + + /* Restore original file pointer, if necessary. + It's currently at OFFSET. */ + if (position < offset) + SVN_ERR(svn_io_file_seek(file, APR_SET, &position, pool)); + + return SVN_NO_ERROR; } diff --git a/subversion/libsvn_subr/version.c b/subversion/libsvn_subr/version.c index 95cb4d399379..0210fd8836e5 100644 --- a/subversion/libsvn_subr/version.c +++ b/subversion/libsvn_subr/version.c @@ -136,7 +136,7 @@ svn_version_extended(svn_boolean_t verbose, info->build_time = __TIME__; info->build_host = SVN_BUILD_HOST; info->copyright = apr_pstrdup - (pool, _("Copyright (C) 2016 The Apache Software Foundation.\n" + (pool, _("Copyright (C) 2017 The Apache Software Foundation.\n" "This software consists of contributions made by many people;\n" "see the NOTICE file for more information.\n" "Subversion is open source software, see " diff --git a/subversion/libsvn_wc/wc-checks.h b/subversion/libsvn_wc/wc-checks.h index 09d43fb5356b..e867506d4e9b 100644 --- a/subversion/libsvn_wc/wc-checks.h +++ b/subversion/libsvn_wc/wc-checks.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.9.5/subversion/libsvn_wc/token-map.h. +/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.9.7/subversion/libsvn_wc/token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_VERIFICATION_TRIGGERS 0 diff --git a/subversion/libsvn_wc/wc-metadata.h b/subversion/libsvn_wc/wc-metadata.h index 5ff8744e0a8c..f548d9174d3a 100644 --- a/subversion/libsvn_wc/wc-metadata.h +++ b/subversion/libsvn_wc/wc-metadata.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.9.5/subversion/libsvn_wc/token-map.h. +/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.9.7/subversion/libsvn_wc/token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_CREATE_SCHEMA 0 diff --git a/subversion/libsvn_wc/wc-queries.h b/subversion/libsvn_wc/wc-queries.h index 8621cb8b5310..2a7594067ed6 100644 --- a/subversion/libsvn_wc/wc-queries.h +++ b/subversion/libsvn_wc/wc-queries.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.9.5/subversion/libsvn_wc/token-map.h. +/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.9.7/subversion/libsvn_wc/token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_SELECT_NODE_INFO 0 diff --git a/subversion/svnadmin/svnadmin.c b/subversion/svnadmin/svnadmin.c index ec98c6bb1a43..2ee5410d24e3 100644 --- a/subversion/svnadmin/svnadmin.c +++ b/subversion/svnadmin/svnadmin.c @@ -396,6 +396,7 @@ static const svn_opt_subcommand_desc2_t cmd_table[] = ("usage: 1. svnadmin freeze REPOS_PATH PROGRAM [ARG...]\n" " 2. svnadmin freeze -F FILE PROGRAM [ARG...]\n\n" "1. Run PROGRAM passing ARGS while holding a write-lock on REPOS_PATH.\n" + " Allows safe use of third-party backup tools on a live repository.\n" "\n" "2. Like 1 except all repositories listed in FILE are locked. The file\n" " format is repository paths separated by newlines. Repositories are\n" diff --git a/win-tests.py b/win-tests.py index 9c9daa307a25..44ff110b15e7 100644 --- a/win-tests.py +++ b/win-tests.py @@ -24,7 +24,7 @@ For a list of options, run this script with the --help option. """ -# $HeadURL: http://svn.apache.org/repos/asf/subversion/branches/1.9.x/win-tests.py $ +# $HeadURL: https://svn.apache.org/repos/asf/subversion/branches/1.9.x/win-tests.py $ # $LastChangedRevision: 1718291 $ import os, sys, subprocess