Update svnlite from 1.8.10 to 1.8.14. This is mostly for client-side bug
fixes and quality of life improvements. While there are security issues in this time frame that affect usage as a server (eg: linked into apache), this isn't possible here.
This commit is contained in:
commit
19f868bc90
@ -1,3 +1,138 @@
|
||||
Version 1.8.14
|
||||
(5 Aug 2015, from /branches/1.8.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.8.14
|
||||
|
||||
User-visible changes:
|
||||
- Client-side bugfixes:
|
||||
* document svn:autoprops (r1678494 et al.)
|
||||
* cp: fix 'svn cp ^/A/D/H@1 ^/A' to properly create A (r1674455, r1674456)
|
||||
* resolve: improve conflict prompts for binary files (r1667228 et al.)
|
||||
* ls: improve performance of '-v' on tag directories (r1673153)
|
||||
* improved Sqlite 3.8.9 query performance regression on externals (r1672295 et al.)
|
||||
* fixed issue #4580: 'svn -v st' on file externals reports "?" instead
|
||||
of user and revision after 'svn up' (r1680242)
|
||||
|
||||
- Server-side bugfixes:
|
||||
* mod_dav_svn: do not ignore skel parsing errors (r1658168)
|
||||
* detect invalid svndiff data earlier (r1684077)
|
||||
* prevent possible repository corruption on power/disk failures (r1680819)
|
||||
* fixed issue #4577: Read error with nodes whose DELTA chain starts with
|
||||
a PLAIN rep (r1676667, r1677267)
|
||||
* fixed issue #4531: server-side copy (over dav) is slow and uses
|
||||
too much memory (r1674627)
|
||||
|
||||
Developer-visible changes:
|
||||
- General:
|
||||
* support building on Windows with Visual Studio 2015 (r1692785)
|
||||
* avoid failing some tests on versions of Python with a very old sqlite (r1674522)
|
||||
* fix Ruby tests so they don't use the users real configuration (r1597884)
|
||||
|
||||
- Bindings:
|
||||
* swig-pl: fix some stack memory problems (r1668618, 1671388)
|
||||
|
||||
Version 1.8.13
|
||||
(31 Mar 2015, from /branches/1.8.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.8.13
|
||||
|
||||
User-visible changes:
|
||||
- Client-side bugfixes:
|
||||
* ra_serf: prevent abort of commits that have already succeeded (r1659867)
|
||||
* ra_serf: support case-insensitivity in HTTP headers (r1650481, r1650489)
|
||||
* better error message if an external is shadowed (r1655712, r1655738)
|
||||
* ra_svn: fix reporting of directory read errors (r1656713)
|
||||
* fix a redirect handling bug in 'svn log' over HTTP (r1650531)
|
||||
* properly copy tree conflict information (r1658115, r1659553, r1659554)
|
||||
* fix 'svn patch' output for reordered hunks (issue #4533)
|
||||
* svnrdump load: don't load wrong props with no-deltas dump (issue #4551)
|
||||
* fix working copy corruption with relative file external (issue #4411)
|
||||
* don't crash if config file is unreadable (r1590751, r1660350)
|
||||
* svn resolve: don't ask a question with only one answer (r1658417)
|
||||
* fix assertion failure in svn move (r1651963 et al)
|
||||
* working copy performance improvements (r1664531, r1664476, et al)
|
||||
* handle existing working copies which become externals (r1660071)
|
||||
* fix recording of WC meta-data for foreign repos copies (r1660593)
|
||||
* fix calculating repository path of replaced directories (r1660646)
|
||||
* fix calculating repository path after commit of switched nodes (r1663991)
|
||||
* svnrdump: don't provide HEAD+1 as base revision for deletes (r1664684)
|
||||
* don't leave conflict markers on files that are moved (r1660220, r1665874)
|
||||
* avoid unnecessary subtree mergeinfo recording (r1666690)
|
||||
* fix diff of a locally copied directory with props (r1619380 et al)
|
||||
|
||||
- Server-side bugfixes:
|
||||
* fsfs: fix a problem verifying pre-1.4 repos used with 1.8 (r1561419)
|
||||
* svnadmin freeze: fix memory allocation error (r1653039)
|
||||
* svnadmin load: tolerate invalid mergeinfo at r0 (r1643074, issue #4476)
|
||||
* svnadmin load: strip references to r1 from mergeinfo (issue #4538)
|
||||
* svnsync: strip any r0 references from mergeinfo (issue #4476)
|
||||
* fsfs: reduce memory consumption when operating on dag nodes (r1655651)
|
||||
* reject invalid get-location-segments requests in mod_dav_svn and
|
||||
svnserve (r1667233)
|
||||
* mod_dav_svn: reject invalid txnprop change requests (r1667235)
|
||||
|
||||
- Client-side and server-side bugfixes:
|
||||
* fix undefined behaviour in string buffer routines (r1650834)
|
||||
* fix consistency issues with APR r/w locks on Windows (r1611380 et al)
|
||||
* fix occasional SEGV if threads load DSOs in parallel (r1659013, r1659315)
|
||||
* properly duplicate svn error objects (r1651759)
|
||||
* fix use-after-free in config parser (1646785, r1646786, r1646797)
|
||||
|
||||
Developer-visible changes:
|
||||
* add lock file config for testing against HTTPD 2.4+ (r1544302, r1544303)
|
||||
* make sqlite amalgamated build work with sqlite 3.8.x+ (r1659399)
|
||||
* fix build with Ruby 2 (r1596882)
|
||||
* process 'svnadmin dump' output as binary in the test suite (r1592987)
|
||||
* simplify Windows resource compilation to avoid warnings (r1532287)
|
||||
|
||||
|
||||
Version 1.8.12
|
||||
(Not released, see changes for 1.8.13.)
|
||||
|
||||
|
||||
Version 1.8.11
|
||||
(15 Dec 2014, from /branches/1.8.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.8.11
|
||||
|
||||
User-visible changes:
|
||||
- Client-side bugfixes:
|
||||
* checkout/update: fix file externals failing to follow history and
|
||||
subsequently silently failing (issue #4185)
|
||||
* patch: don't skip targets in valid --git difs (r1592014, r1592034)
|
||||
* diff: make property output in diffs stable (r1589360)
|
||||
* diff: fix diff of local copied directory with props (r1619380, r1619393)
|
||||
* diff: fix changelist filter for repos-WC and WC-WC (r1621978, r1621981)
|
||||
* remove broken conflict resolver menu options that always error out
|
||||
(r1620332)
|
||||
* improve gpg-agent support (r1600331, r1600348, 1600368, r1600563,
|
||||
r1600781)
|
||||
* fix crash in eclipse IDE with GNOME Keyring (issue #3498)
|
||||
* fix externals shadowing a versioned directory (issue #4085)
|
||||
* fix problems working on unix file systems that don't support
|
||||
permissions (r1612225)
|
||||
* upgrade: keep external registrations (issue #4519)
|
||||
* cleanup: iprove performance of recorded timestamp fixups (r1633126)
|
||||
* translation updates for German
|
||||
|
||||
- Server-side bugfixes:
|
||||
* disable revprop caching feature due to cache invalidation problems
|
||||
(r1543594, r1619774, r1619105, r1619118, r1619153, r1619802)
|
||||
* skip generating uniquifiers if rep-sharing is not supported (r1561426)
|
||||
* mod_dav_svn: reject requests with missing repository paths (r1643409)
|
||||
* mod_dav_svn: reject requests with invalid virtual transaction names
|
||||
(r1643437)
|
||||
* mod_dav_svn: avoid unneeded memory growth in resource walking
|
||||
(issue #4531)
|
||||
|
||||
Developer-visible changes:
|
||||
- General:
|
||||
* make sure all members of the repos layer notify struct are valid,
|
||||
fixes crashes in API users using all members (r1616131)
|
||||
* properly generate a version resource when building on Windows (r1542610,
|
||||
r1564576, r1568180)
|
||||
* fix LIBTOOL_M4 and LIBTOOL_CONFIG variable not be evaluated properly
|
||||
during a unix build (r1637826)
|
||||
* allow the use of libtool 2.4.3 (r1640862, r1640873, r1643793)
|
||||
|
||||
|
||||
Version 1.8.10
|
||||
(11 Aug 2014, from /branches/1.8.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.8.10
|
||||
@ -316,7 +451,7 @@ http://svn.apache.org/repos/asf/subversion/tags/1.8.1
|
||||
* merge: rename 'automatic merge' to 'complete merge' (r1491432)
|
||||
* mergeinfo: reduce network usage for '--show-revs' (r1492005)
|
||||
* ra_serf: improve http status handling (r1495104)
|
||||
* merge: avoid unneeded ra session (r1493475)
|
||||
* merge: avoid unneeded RA session (r1493475)
|
||||
* merge: reduce network usage (r1478987)
|
||||
* merge: remove duplicated ancestry check (r1493424, r1495597)
|
||||
* ra_serf: fix 'Accept-Encoding' header for IIS interoperability (r1497551)
|
||||
@ -729,6 +864,81 @@ http://svn.apache.org/repos/asf/subversion/tags/1.8.0
|
||||
* fix some reference counting bugs in swig-py bindings (r1464899, r1466524)
|
||||
|
||||
|
||||
Version 1.7.21
|
||||
(5 Aug 2015, from /branches/1.7.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.8.21
|
||||
|
||||
User-visible changes:
|
||||
- Client-side bugfixes:
|
||||
* cp: fix 'svn cp ^/A/D/H@1 ^/A' to properly create A (r1674455, r1674456)
|
||||
* fix issue #4551: svnrdump load commits wrong properties, or fails, on a
|
||||
non-deltas dumpfile (r1652182 et al.)
|
||||
|
||||
- Server-side bugfixes:
|
||||
* fix 'svnadmin recover' for pre-1.4 FSFS repositories (r1561419)
|
||||
|
||||
Developer-visible changes:
|
||||
- General:
|
||||
* support building on Windows with Visual Studio 2012, 2013 and 2015 (r1687158, r1692783)
|
||||
|
||||
- Bindings:
|
||||
* swig-pl: fix some stack memory problems (r1668618, 1671388)
|
||||
|
||||
Version 1.7.20
|
||||
(31 Mar 2015, from /branches/1.7.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.7.20
|
||||
|
||||
User-visible changes:
|
||||
- Client-side bugfixes:
|
||||
* fix 'svn patch' output for reordered hunks (issue #4533)
|
||||
|
||||
- Server-side bugfixes:
|
||||
* reject invalid get-location-segments requests in mod_dav_svn and
|
||||
svnserve (r1667233)
|
||||
* mod_dav_svn: reject invalid txnprop change requests (r1667235)
|
||||
|
||||
- Client-side and server-side bugfixes:
|
||||
* properly duplicate svn error objects (r1651759)
|
||||
* fix use-after-free in config parser (1646785, r1646786, r1646797)
|
||||
|
||||
Developer-visible changes:
|
||||
* add lock file config for testing against HTTPD 2.4+ (r1544302, r1544303)
|
||||
* fix build with absolute path to neon install (r1664789)
|
||||
|
||||
|
||||
Version 1.7.19
|
||||
(15 Dec 2014, from /branches/1.7.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.7.19
|
||||
|
||||
User-visible changes:
|
||||
- Client-side bugfixes:
|
||||
* rm: display the proper URL in commit log editor (r1591123)
|
||||
* diff: fix invalid read during suffix scanning (issue #4339)
|
||||
* fix crash in eclipse IDE with GNOME Keyring (issue #3498)
|
||||
* checkout/update: fix file externals failing to follow history and
|
||||
subsequently silently failing (issue #4185)
|
||||
|
||||
- Server-side bugfixes:
|
||||
* svnadmin dump: don't let invalid mergeinfo prevent a dump (issue #4476)
|
||||
* mod_dav_svn: reject requests with missing repository paths (r1643409)
|
||||
* mod_dav_svn: reject requests with invalid virtual transaction names
|
||||
(r1643437)
|
||||
* mod_dav_svn: avoid unneeded memory growth in resource walking
|
||||
(issue #4531)
|
||||
|
||||
Developer-visible changes:
|
||||
- General:
|
||||
* properly generate a version resource when building on Windows (r1542610,
|
||||
r1564576, r1568180)
|
||||
* fix a problem with the unix build that could result in linking to the
|
||||
wrong Subversion libraries at build or at run time (r1594157)
|
||||
* use a proper intermediate directory when building with Visual Studio
|
||||
2003-2008 (r1595431)
|
||||
* fix LIBTOOL_M4 and LIBTOOL_CONFIG variable not be evaluated properly
|
||||
during a unix build (r1637826)
|
||||
* allow the use of libtool 2.4.3 (r1640862, r1640873, r1643793)
|
||||
|
||||
|
||||
Version 1.7.18
|
||||
(11 Aug 2014, from /branches/1.7.x)
|
||||
http://svn.apache.org/repos/asf/subversion/tags/1.7.18
|
||||
|
@ -357,6 +357,7 @@ TEST_SHLIB_VAR_SWIG_RB=\
|
||||
fi;
|
||||
|
||||
APXS = @APXS@
|
||||
HTTPD_VERSION = @HTTPD_VERSION@
|
||||
|
||||
PYTHON = @PYTHON@
|
||||
PERL = @PERL@
|
||||
@ -509,6 +510,9 @@ check: bin @TRANSFORM_LIBTOOL_SCRIPTS@ $(TEST_DEPS) @BDB_TEST_DEPS@
|
||||
if test "$(HTTP_LIBRARY)" != ""; then \
|
||||
flags="--http-library $(HTTP_LIBRARY) $$flags"; \
|
||||
fi; \
|
||||
if test "$(HTTPD_VERSION)" != ""; then \
|
||||
flags="--httpd-version $(HTTPD_VERSION) $$flags"; \
|
||||
fi; \
|
||||
if test "$(SERVER_MINOR_VERSION)" != ""; then \
|
||||
flags="--server-minor-version $(SERVER_MINOR_VERSION) $$flags"; \
|
||||
fi; \
|
||||
|
@ -1,5 +1,5 @@
|
||||
Apache Subversion
|
||||
Copyright 2014 The Apache Software Foundation
|
||||
Copyright 2015 The Apache Software Foundation
|
||||
|
||||
This product includes software developed by many people, and distributed
|
||||
under Contributor License Agreements to The Apache Software Foundation
|
||||
|
@ -23,6 +23,10 @@
|
||||
### Run this to produce everything needed for configuration. ###
|
||||
|
||||
|
||||
# Some shells can produce output when running 'cd' which interferes
|
||||
# with the construct 'abs=`cd dir && pwd`'.
|
||||
(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
|
||||
|
||||
# Run tests to ensure that our build requirements are met
|
||||
RELEASE_MODE=""
|
||||
RELEASE_ARGS=""
|
||||
@ -71,48 +75,80 @@ rm -f build/config.guess build/config.sub
|
||||
$libtoolize --copy --automake --force
|
||||
|
||||
ltpath="`dirname $libtoolize`"
|
||||
ltfile=${LIBTOOL_M4-`cd $ltpath/../share/aclocal ; pwd`/libtool.m4}
|
||||
|
||||
if [ ! -f $ltfile ]; then
|
||||
echo "$ltfile not found (try setting the LIBTOOL_M4 environment variable)"
|
||||
if [ "x$LIBTOOL_M4" = "x" ]; then
|
||||
ltm4_error='(try setting the LIBTOOL_M4 environment variable)'
|
||||
if [ -d "$ltpath/../share/aclocal/." ]; then
|
||||
ltm4=`cd "$ltpath/../share/aclocal" && pwd`
|
||||
else
|
||||
echo "Libtool helper path not found $ltm4_error"
|
||||
echo " expected at: '$ltpath/../share/aclocal'"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
ltm4_error="(the LIBTOOL_M4 environment variable is: $LIBTOOL_M4)"
|
||||
ltm4="$LIBTOOL_M4"
|
||||
fi
|
||||
|
||||
ltfile="$ltm4/libtool.m4"
|
||||
if [ ! -f "$ltfile" ]; then
|
||||
echo "$ltfile not found $ltm4_error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Copying libtool helper: $ltfile"
|
||||
echo "Copying libtool helper: $ltfile"
|
||||
# An ancient helper might already be present from previous builds,
|
||||
# and it might be write-protected (e.g. mode 444, seen on FreeBSD).
|
||||
# This would cause cp to fail and print an error message, but leave
|
||||
# behind a potentially outdated libtool helper. So, remove before
|
||||
# copying:
|
||||
rm -f build/libtool.m4
|
||||
cp $ltfile build/libtool.m4
|
||||
cp "$ltfile" build/libtool.m4
|
||||
|
||||
for file in ltoptions.m4 ltsugar.m4 ltversion.m4 lt~obsolete.m4; do
|
||||
rm -f build/$file
|
||||
|
||||
if [ $lt_major_version -ge 2 ]; then
|
||||
ltfile=${LIBTOOL_M4-`cd $ltpath/../share/aclocal ; pwd`/$file}
|
||||
ltfile="$ltm4/$file"
|
||||
|
||||
if [ ! -f $ltfile ]; then
|
||||
echo "$ltfile not found (try setting the LIBTOOL_M4 environment variable)"
|
||||
if [ ! -f "$ltfile" ]; then
|
||||
echo "$ltfile not found $ltm4_error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Copying libtool helper: $ltfile"
|
||||
cp $ltfile build/$file
|
||||
echo "Copying libtool helper: $ltfile"
|
||||
cp "$ltfile" "build/$file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $lt_major_version -ge 2 ]; then
|
||||
for file in config.guess config.sub; do
|
||||
configfile=${LIBTOOL_CONFIG-`cd $ltpath/../share/libtool/config ; pwd`/$file}
|
||||
if [ "x$LIBTOOL_CONFIG" = "x" ]; then
|
||||
ltconfig_error='(try setting the LIBTOOL_CONFIG environment variable)'
|
||||
if [ -d "$ltpath/../share/libtool/config/." ]; then
|
||||
ltconfig=`cd "$ltpath/../share/libtool/config" && pwd`
|
||||
elif [ -d "$ltpath/../share/libtool/build-aux/." ]; then
|
||||
ltconfig=`cd "$ltpath/../share/libtool/build-aux" && pwd`
|
||||
else
|
||||
echo "Autoconf helper path not found $ltconfig_error"
|
||||
echo " expected at: '$ltpath/../share/libtool/config'"
|
||||
echo " or: '$ltpath/../share/libtool/build-aux'"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
ltconfig_error="(the LIBTOOL_CONFIG environment variable is: $LIBTOOL_CONFIG)"
|
||||
ltconfig="$LIBTOOL_CONFIG"
|
||||
fi
|
||||
|
||||
if [ ! -f $configfile ]; then
|
||||
echo "$configfile not found (try setting the LIBTOOL_CONFIG environment variable)"
|
||||
for file in config.guess config.sub; do
|
||||
configfile="$ltconfig/$file"
|
||||
|
||||
if [ ! -f "$configfile" ]; then
|
||||
echo "$configfile not found $ltconfig_error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp $configfile build/$file
|
||||
echo "Copying autoconf helper: $configfile"
|
||||
cp "$configfile" build/$file
|
||||
done
|
||||
fi
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@ -1357,6 +1357,7 @@ install = tools
|
||||
libs = libsvn_repos libsvn_fs libsvn_subr apr
|
||||
|
||||
[svn-populate-node-origins-index]
|
||||
description = Tool to populate the node origins index of a repository
|
||||
type = exe
|
||||
path = tools/server-side
|
||||
sources = svn-populate-node-origins-index.c
|
||||
|
2521
contrib/subversion/configure
vendored
2521
contrib/subversion/configure
vendored
File diff suppressed because it is too large
Load Diff
@ -1246,7 +1246,7 @@ AC_PATH_PROG(PERL, perl, none)
|
||||
if test -n "$RUBY"; then
|
||||
AC_PATH_PROG(RUBY, "$RUBY", none)
|
||||
else
|
||||
AC_PATH_PROGS(RUBY, ruby ruby1.8 ruby18 ruby1.9 ruby1 ruby1.9.3 ruby193, none)
|
||||
AC_PATH_PROGS(RUBY, ruby ruby1.8 ruby18 ruby1.9 ruby1 ruby1.9.3 ruby193 ruby2.0 ruby2.1, none)
|
||||
fi
|
||||
if test "$RUBY" != "none"; then
|
||||
AC_MSG_CHECKING([rb_hash_foreach])
|
||||
@ -1255,7 +1255,7 @@ if test "$RUBY" != "none"; then
|
||||
if test -n "$RDOC"; then
|
||||
AC_PATH_PROG(RDOC, "$RDOC", none)
|
||||
else
|
||||
AC_PATH_PROGS(RDOC, rdoc rdoc1.8 rdoc18 rdoc1.9 rdoc19 rdoc1.9.3 rdoc193, none)
|
||||
AC_PATH_PROGS(RDOC, rdoc rdoc1.8 rdoc18 rdoc1.9 rdoc19 rdoc1.9.3 rdoc193 rdoc2.0 rdoc2.1, none)
|
||||
fi
|
||||
AC_CACHE_CHECK([for Ruby major version], [svn_cv_ruby_major],[
|
||||
svn_cv_ruby_major="`$RUBY -rrbconfig -e 'print RbConfig::CONFIG.fetch(%q(MAJOR))'`"
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
APR_VERSION=${APR_VERSION:-"1.4.6"}
|
||||
APU_VERSION=${APU_VERSION:-"1.5.1"}
|
||||
SERF_VERSION=${SERF_VERSION:-"1.3.4"}
|
||||
SERF_VERSION=${SERF_VERSION:-"1.3.8"}
|
||||
ZLIB_VERSION=${ZLIB_VERSION:-"1.2.8"}
|
||||
SQLITE_VERSION=${SQLITE_VERSION:-"3.7.15.1"}
|
||||
GTEST_VERSION=${GTEST_VERSION:-"1.6.0"}
|
||||
|
@ -97,7 +97,7 @@ svn_diff__unidiff_write_header(svn_stream_t *output_stream,
|
||||
* merged or reverse merged; otherwise (or if the mergeinfo property values
|
||||
* don't parse correctly) display them just like any other property.
|
||||
*
|
||||
* Use @a pool for temporary allocations.
|
||||
* Use @a scratch_pool for temporary allocations.
|
||||
*/
|
||||
svn_error_t *
|
||||
svn_diff__display_prop_diffs(svn_stream_t *outstream,
|
||||
@ -105,7 +105,7 @@ svn_diff__display_prop_diffs(svn_stream_t *outstream,
|
||||
const apr_array_header_t *propchanges,
|
||||
apr_hash_t *original_props,
|
||||
svn_boolean_t pretty_print_mergeinfo,
|
||||
apr_pool_t *pool);
|
||||
apr_pool_t *scratch_pool);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -65,6 +65,27 @@ svn_error_t *
|
||||
svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
|
||||
apr_pool_t *scratch_pool);
|
||||
|
||||
/** Canonicalize the @a rangelist: sort the ranges, and combine adjacent or
|
||||
* overlapping ranges into single ranges where possible.
|
||||
*
|
||||
* If overlapping ranges have different inheritability, return an error.
|
||||
*
|
||||
* Modify @a rangelist in place. Use @a scratch_pool for temporary
|
||||
* allocations.
|
||||
*/
|
||||
svn_error_t *
|
||||
svn_rangelist__canonicalize(svn_rangelist_t *rangelist,
|
||||
apr_pool_t *scratch_pool);
|
||||
|
||||
/** Canonicalize the revision range lists in the @a mergeinfo.
|
||||
*
|
||||
* Modify @a mergeinfo in place. Use @a scratch_pool for temporary
|
||||
* allocations.
|
||||
*/
|
||||
svn_error_t *
|
||||
svn_mergeinfo__canonicalize_ranges(svn_mergeinfo_t mergeinfo,
|
||||
apr_pool_t *scratch_pool);
|
||||
|
||||
/* Set inheritability of all rangelists in MERGEINFO to INHERITABLE.
|
||||
If MERGEINFO is NULL do nothing. If a rangelist in MERGEINFO is
|
||||
NULL leave it alone. */
|
||||
|
@ -113,6 +113,10 @@ svn_repos__replay_ev2(svn_fs_root_t *root,
|
||||
void *authz_read_baton,
|
||||
apr_pool_t *scratch_pool);
|
||||
|
||||
/* A private addition to svn_repos_notify_warning_t. */
|
||||
#define svn_repos__notify_warning_invalid_mergeinfo \
|
||||
((svn_repos_notify_warning_t)(-1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -484,6 +484,32 @@ svn_sqlite__with_immediate_transaction(svn_sqlite__db_t *db,
|
||||
SVN_ERR(svn_sqlite__finish_savepoint(svn_sqlite__db, svn_sqlite__err)); \
|
||||
} while (0)
|
||||
|
||||
/* Evaluate the expression EXPR1..EXPR4 within a 'savepoint'. Savepoints can
|
||||
* be nested.
|
||||
*
|
||||
* Begin a savepoint in DB; evaluate the expression EXPR1, which would
|
||||
* typically be a function call that does some work in DB; if no error occurred,
|
||||
* run EXPR2; if no error occurred EXPR3; ... and finally release
|
||||
* the savepoint if EXPR evaluated to SVN_NO_ERROR, otherwise roll back
|
||||
* to the savepoint and then release it.
|
||||
*/
|
||||
#define SVN_SQLITE__WITH_LOCK4(expr1, expr2, expr3, expr4, db) \
|
||||
do { \
|
||||
svn_sqlite__db_t *svn_sqlite__db = (db); \
|
||||
svn_error_t *svn_sqlite__err; \
|
||||
\
|
||||
SVN_ERR(svn_sqlite__begin_savepoint(svn_sqlite__db)); \
|
||||
svn_sqlite__err = (expr1); \
|
||||
if (!svn_sqlite__err) \
|
||||
svn_sqlite__err = (expr2); \
|
||||
if (!svn_sqlite__err) \
|
||||
svn_sqlite__err = (expr3); \
|
||||
if (!svn_sqlite__err) \
|
||||
svn_sqlite__err = (expr4); \
|
||||
SVN_ERR(svn_sqlite__finish_savepoint(svn_sqlite__db, svn_sqlite__err)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Helper function to handle several SQLite operations inside a shared lock.
|
||||
This callback is similar to svn_sqlite__with_transaction(), but can be
|
||||
nested (even with a transaction).
|
||||
|
@ -1148,6 +1148,8 @@ svn_stream_read(svn_stream_t *stream,
|
||||
* of reads or a simple seek operation. If the stream implementation has
|
||||
* not provided a skip function, this will read from the stream and
|
||||
* discard the data.
|
||||
*
|
||||
* @since New in 1.7.
|
||||
*/
|
||||
svn_error_t *
|
||||
svn_stream_skip(svn_stream_t *stream,
|
||||
|
@ -28,15 +28,13 @@
|
||||
#define SVN_VERSION_H
|
||||
|
||||
/* Hack to prevent the resource compiler from including
|
||||
apr_general.h. It doesn't resolve the include paths
|
||||
correctly and blows up without this.
|
||||
*/
|
||||
#ifndef APR_STRINGIFY
|
||||
apr and other headers. */
|
||||
#ifndef SVN_WIN32_RESOURCE_COMPILATION
|
||||
#include <apr_general.h>
|
||||
#endif
|
||||
#include <apr_tables.h>
|
||||
|
||||
#include "svn_types.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -72,7 +70,7 @@ extern "C" {
|
||||
*
|
||||
* @since New in 1.1.
|
||||
*/
|
||||
#define SVN_VER_PATCH 10
|
||||
#define SVN_VER_PATCH 14
|
||||
|
||||
|
||||
/** @deprecated Provided for backward compatibility with the 1.0 API. */
|
||||
@ -95,7 +93,7 @@ extern "C" {
|
||||
*
|
||||
* Always change this at the same time as SVN_VER_NUMTAG.
|
||||
*/
|
||||
#define SVN_VER_TAG " (r1615264)"
|
||||
#define SVN_VER_TAG " (r1692801)"
|
||||
|
||||
|
||||
/** Number tag: a string describing the version.
|
||||
@ -121,7 +119,7 @@ extern "C" {
|
||||
* When rolling a tarball, we automatically replace it with what we
|
||||
* guess to be the correct revision number.
|
||||
*/
|
||||
#define SVN_VER_REVISION 1615264
|
||||
#define SVN_VER_REVISION 1692801
|
||||
|
||||
|
||||
/* Version strings composed from the above definitions. */
|
||||
|
@ -49,120 +49,19 @@
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
|
||||
struct gnome_keyring_baton
|
||||
{
|
||||
const char *keyring_name;
|
||||
GnomeKeyringInfo *info;
|
||||
GMainLoop *loop;
|
||||
};
|
||||
|
||||
|
||||
/* Callback function to destroy gnome_keyring_baton. */
|
||||
static void
|
||||
callback_destroy_data_keyring(void *data)
|
||||
{
|
||||
struct gnome_keyring_baton *key_info = data;
|
||||
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
free((void*)key_info->keyring_name);
|
||||
key_info->keyring_name = NULL;
|
||||
|
||||
if (key_info->info)
|
||||
{
|
||||
gnome_keyring_info_free(key_info->info);
|
||||
key_info->info = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Callback function to complete the keyring operation. */
|
||||
static void
|
||||
callback_done(GnomeKeyringResult result,
|
||||
gpointer data)
|
||||
{
|
||||
struct gnome_keyring_baton *key_info = data;
|
||||
|
||||
g_main_loop_quit(key_info->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Callback function to get the keyring info. */
|
||||
static void
|
||||
callback_get_info_keyring(GnomeKeyringResult result,
|
||||
GnomeKeyringInfo *info,
|
||||
void *data)
|
||||
{
|
||||
struct gnome_keyring_baton *key_info = data;
|
||||
|
||||
if (result == GNOME_KEYRING_RESULT_OK && info != NULL)
|
||||
{
|
||||
key_info->info = gnome_keyring_info_copy(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key_info->info != NULL)
|
||||
gnome_keyring_info_free(key_info->info);
|
||||
|
||||
key_info->info = NULL;
|
||||
}
|
||||
|
||||
g_main_loop_quit(key_info->loop);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Callback function to get the default keyring string name. */
|
||||
static void
|
||||
callback_default_keyring(GnomeKeyringResult result,
|
||||
const char *string,
|
||||
void *data)
|
||||
{
|
||||
struct gnome_keyring_baton *key_info = data;
|
||||
|
||||
if (result == GNOME_KEYRING_RESULT_OK && string != NULL)
|
||||
{
|
||||
key_info->keyring_name = strdup(string);
|
||||
}
|
||||
else
|
||||
{
|
||||
free((void*)key_info->keyring_name);
|
||||
key_info->keyring_name = NULL;
|
||||
}
|
||||
|
||||
g_main_loop_quit(key_info->loop);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Returns the default keyring name, allocated in RESULT_POOL. */
|
||||
static char*
|
||||
get_default_keyring_name(apr_pool_t *result_pool)
|
||||
{
|
||||
char *def = NULL;
|
||||
struct gnome_keyring_baton key_info;
|
||||
char *name, *def;
|
||||
GnomeKeyringResult gkr;
|
||||
|
||||
key_info.info = NULL;
|
||||
key_info.keyring_name = NULL;
|
||||
gkr = gnome_keyring_get_default_keyring_sync(&name);
|
||||
if (gkr != GNOME_KEYRING_RESULT_OK)
|
||||
return NULL;
|
||||
|
||||
/* Finds default keyring. */
|
||||
key_info.loop = g_main_loop_new(NULL, FALSE);
|
||||
gnome_keyring_get_default_keyring(callback_default_keyring, &key_info, NULL);
|
||||
g_main_loop_run(key_info.loop);
|
||||
|
||||
if (key_info.keyring_name == NULL)
|
||||
{
|
||||
callback_destroy_data_keyring(&key_info);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
def = apr_pstrdup(result_pool, key_info.keyring_name);
|
||||
callback_destroy_data_keyring(&key_info);
|
||||
def = apr_pstrdup(result_pool, name);
|
||||
g_free(name);
|
||||
|
||||
return def;
|
||||
}
|
||||
@ -171,28 +70,22 @@ get_default_keyring_name(apr_pool_t *result_pool)
|
||||
static svn_boolean_t
|
||||
check_keyring_is_locked(const char *keyring_name)
|
||||
{
|
||||
struct gnome_keyring_baton key_info;
|
||||
GnomeKeyringInfo *info;
|
||||
svn_boolean_t locked;
|
||||
GnomeKeyringResult gkr;
|
||||
|
||||
key_info.info = NULL;
|
||||
key_info.keyring_name = NULL;
|
||||
|
||||
/* Get details about the default keyring. */
|
||||
key_info.loop = g_main_loop_new(NULL, FALSE);
|
||||
gnome_keyring_get_info(keyring_name, callback_get_info_keyring, &key_info,
|
||||
NULL);
|
||||
g_main_loop_run(key_info.loop);
|
||||
|
||||
if (key_info.info == NULL)
|
||||
{
|
||||
callback_destroy_data_keyring(&key_info);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check if keyring is locked. */
|
||||
if (gnome_keyring_info_get_is_locked(key_info.info))
|
||||
return TRUE;
|
||||
else
|
||||
gkr = gnome_keyring_get_info_sync(keyring_name, &info);
|
||||
if (gkr != GNOME_KEYRING_RESULT_OK)
|
||||
return FALSE;
|
||||
|
||||
if (gnome_keyring_info_get_is_locked(info))
|
||||
locked = TRUE;
|
||||
else
|
||||
locked = FALSE;
|
||||
|
||||
gnome_keyring_info_free(info);
|
||||
|
||||
return locked;
|
||||
}
|
||||
|
||||
/* Unlock the KEYRING_NAME with the KEYRING_PASSWORD. If KEYRING was
|
||||
@ -202,34 +95,19 @@ unlock_gnome_keyring(const char *keyring_name,
|
||||
const char *keyring_password,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
struct gnome_keyring_baton key_info;
|
||||
GnomeKeyringInfo *info;
|
||||
GnomeKeyringResult gkr;
|
||||
|
||||
key_info.info = NULL;
|
||||
key_info.keyring_name = NULL;
|
||||
|
||||
/* Get details about the default keyring. */
|
||||
key_info.loop = g_main_loop_new(NULL, FALSE);
|
||||
gnome_keyring_get_info(keyring_name, callback_get_info_keyring,
|
||||
&key_info, NULL);
|
||||
g_main_loop_run(key_info.loop);
|
||||
|
||||
if (key_info.info == NULL)
|
||||
{
|
||||
callback_destroy_data_keyring(&key_info);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
key_info.loop = g_main_loop_new(NULL, FALSE);
|
||||
gnome_keyring_unlock(keyring_name, keyring_password,
|
||||
callback_done, &key_info, NULL);
|
||||
g_main_loop_run(key_info.loop);
|
||||
}
|
||||
callback_destroy_data_keyring(&key_info);
|
||||
if (check_keyring_is_locked(keyring_name))
|
||||
gkr = gnome_keyring_get_info_sync(keyring_name, &info);
|
||||
if (gkr != GNOME_KEYRING_RESULT_OK)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
gkr = gnome_keyring_unlock_sync(keyring_name, keyring_password);
|
||||
gnome_keyring_info_free(info);
|
||||
if (gkr != GNOME_KEYRING_RESULT_OK)
|
||||
return FALSE;
|
||||
|
||||
return check_keyring_is_locked(keyring_name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1006,7 +1006,10 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
|
||||
&& (relpath != NULL && *relpath != '\0'))
|
||||
{
|
||||
info->resurrection = TRUE;
|
||||
top_url = svn_uri_dirname(top_url, pool);
|
||||
top_url = svn_uri_get_longest_ancestor(
|
||||
top_url,
|
||||
svn_uri_dirname(pair->dst_abspath_or_url, pool),
|
||||
pool);
|
||||
SVN_ERR(svn_ra_reparent(ra_session, top_url, pool));
|
||||
}
|
||||
}
|
||||
|
@ -146,6 +146,7 @@ relegate_dir_external(svn_wc_context_t *wc_ctx,
|
||||
static svn_error_t *
|
||||
switch_dir_external(const char *local_abspath,
|
||||
const char *url,
|
||||
const char *url_from_externals_definition,
|
||||
const svn_opt_revision_t *peg_revision,
|
||||
const svn_opt_revision_t *revision,
|
||||
const char *defining_abspath,
|
||||
@ -169,6 +170,46 @@ switch_dir_external(const char *local_abspath,
|
||||
if (revision->kind == svn_opt_revision_number)
|
||||
external_rev = revision->value.number;
|
||||
|
||||
/*
|
||||
* The code below assumes existing versioned paths are *not* part of
|
||||
* the external's defining working copy.
|
||||
* The working copy library does not support registering externals
|
||||
* on top of existing BASE nodes and will error out if we try.
|
||||
* So if the external target is part of the defining working copy's
|
||||
* BASE tree, don't attempt to create the external. Doing so would
|
||||
* leave behind a switched path instead of an external (since the
|
||||
* switch succeeds but registration of the external in the DB fails).
|
||||
* The working copy then cannot be updated until the path is switched back.
|
||||
* See issue #4085.
|
||||
*/
|
||||
SVN_ERR(svn_wc__node_get_base(&kind, NULL, NULL,
|
||||
&repos_root_url, &repos_uuid,
|
||||
NULL, ctx->wc_ctx, local_abspath,
|
||||
TRUE, /* ignore_enoent */
|
||||
TRUE, /* show hidden */
|
||||
pool, pool));
|
||||
if (kind != svn_node_unknown)
|
||||
{
|
||||
const char *wcroot_abspath;
|
||||
const char *defining_wcroot_abspath;
|
||||
|
||||
SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, ctx->wc_ctx,
|
||||
local_abspath, pool, pool));
|
||||
SVN_ERR(svn_wc__get_wcroot(&defining_wcroot_abspath, ctx->wc_ctx,
|
||||
defining_abspath, pool, pool));
|
||||
if (strcmp(wcroot_abspath, defining_wcroot_abspath) == 0)
|
||||
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
|
||||
_("The external '%s' defined in %s at '%s' "
|
||||
"cannot be checked out because '%s' is "
|
||||
"already a versioned path."),
|
||||
url_from_externals_definition,
|
||||
SVN_PROP_EXTERNALS,
|
||||
svn_dirent_local_style(defining_abspath,
|
||||
pool),
|
||||
svn_dirent_local_style(local_abspath,
|
||||
pool));
|
||||
}
|
||||
|
||||
/* If path is a directory, try to update/switch to the correct URL
|
||||
and revision. */
|
||||
SVN_ERR(svn_io_check_path(local_abspath, &kind, pool));
|
||||
@ -201,6 +242,20 @@ switch_dir_external(const char *local_abspath,
|
||||
FALSE, TRUE,
|
||||
timestamp_sleep,
|
||||
ctx, subpool));
|
||||
|
||||
/* We just decided that this existing directory is an external,
|
||||
so update the external registry with this information, like
|
||||
when checking out an external */
|
||||
SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
|
||||
defining_abspath,
|
||||
local_abspath, svn_node_dir,
|
||||
repos_root_url, repos_uuid,
|
||||
svn_uri_skip_ancestor(repos_root_url,
|
||||
url, pool),
|
||||
external_peg_rev,
|
||||
external_rev,
|
||||
pool));
|
||||
|
||||
svn_pool_destroy(subpool);
|
||||
goto cleanup;
|
||||
}
|
||||
@ -460,7 +515,10 @@ switch_file_external(const char *local_abspath,
|
||||
|
||||
svn_dirent_split(&dir_abspath, &target, local_abspath, scratch_pool);
|
||||
|
||||
/* Open an RA session to 'source' URL */
|
||||
/* ### Why do we open a new session? RA_SESSION is a valid
|
||||
### session -- the caller used it to call svn_ra_check_path on
|
||||
### this very URL, the caller also did the resolving and
|
||||
### reparenting that is repeated here. */
|
||||
SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &switch_loc,
|
||||
url, dir_abspath,
|
||||
peg_revision, revision,
|
||||
@ -497,7 +555,7 @@ switch_file_external(const char *local_abspath,
|
||||
invalid revnum, that means RA will use the latest revision. */
|
||||
SVN_ERR(svn_ra_do_switch3(ra_session, &reporter, &report_baton,
|
||||
switch_loc->rev,
|
||||
target, svn_depth_unknown, url,
|
||||
target, svn_depth_unknown, switch_loc->url,
|
||||
FALSE /* send_copyfrom */,
|
||||
TRUE /* ignore_ancestry */,
|
||||
switch_editor, switch_baton,
|
||||
@ -738,6 +796,7 @@ handle_external_item_change(svn_client_ctx_t *ctx,
|
||||
{
|
||||
case svn_node_dir:
|
||||
SVN_ERR(switch_dir_external(local_abspath, new_loc->url,
|
||||
new_item->url,
|
||||
&(new_item->peg_revision),
|
||||
&(new_item->revision),
|
||||
parent_dir_abspath,
|
||||
|
@ -814,10 +814,12 @@ svn_client_log5(const apr_array_header_t *targets,
|
||||
svn_ra_session_t *ra_session;
|
||||
const char *old_session_url;
|
||||
const char *ra_target;
|
||||
const char *path_or_url;
|
||||
svn_opt_revision_t youngest_opt_rev;
|
||||
svn_revnum_t youngest_rev;
|
||||
svn_revnum_t oldest_rev;
|
||||
svn_opt_revision_t peg_rev;
|
||||
svn_client__pathrev_t *ra_session_loc;
|
||||
svn_client__pathrev_t *actual_loc;
|
||||
apr_array_header_t *log_segments;
|
||||
apr_array_header_t *revision_ranges;
|
||||
@ -837,7 +839,7 @@ svn_client_log5(const apr_array_header_t *targets,
|
||||
SVN_ERR(resolve_log_targets(&relative_targets, &ra_target, &peg_rev,
|
||||
targets, ctx, pool, pool));
|
||||
|
||||
SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &actual_loc,
|
||||
SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &ra_session_loc,
|
||||
ra_target, NULL, &peg_rev, &peg_rev,
|
||||
ctx, pool));
|
||||
|
||||
@ -851,11 +853,22 @@ svn_client_log5(const apr_array_header_t *targets,
|
||||
opt_rev_ranges, &peg_rev,
|
||||
ctx, pool, pool));
|
||||
|
||||
/* For some peg revisions we must resolve revision and url via a local path
|
||||
so use the original RA_TARGET. For others, use the potentially corrected
|
||||
(redirected) ra session URL. */
|
||||
if (peg_rev.kind == svn_opt_revision_previous ||
|
||||
peg_rev.kind == svn_opt_revision_base ||
|
||||
peg_rev.kind == svn_opt_revision_committed ||
|
||||
peg_rev.kind == svn_opt_revision_working)
|
||||
path_or_url = ra_target;
|
||||
else
|
||||
path_or_url = ra_session_loc->url;
|
||||
|
||||
/* Make ACTUAL_LOC and RA_SESSION point to the youngest operative rev. */
|
||||
youngest_opt_rev.kind = svn_opt_revision_number;
|
||||
youngest_opt_rev.value.number = youngest_rev;
|
||||
SVN_ERR(svn_client__resolve_rev_and_url(&actual_loc, ra_session,
|
||||
ra_target, &peg_rev,
|
||||
path_or_url, &peg_rev,
|
||||
&youngest_opt_rev, ctx, pool));
|
||||
SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
|
||||
actual_loc->url, pool));
|
||||
|
@ -1258,13 +1258,14 @@ record_skip(merge_cmd_baton_t *merge_b,
|
||||
svn_node_kind_t kind,
|
||||
svn_wc_notify_action_t action,
|
||||
svn_wc_notify_state_t state,
|
||||
struct merge_dir_baton_t *pdb,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
if (merge_b->record_only)
|
||||
return SVN_NO_ERROR; /* ### Why? - Legacy compatibility */
|
||||
|
||||
if (merge_b->merge_source.ancestral
|
||||
|| merge_b->reintegrate_merge)
|
||||
if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
|
||||
&& !(pdb && pdb->shadowed))
|
||||
{
|
||||
store_path(merge_b->skipped_abspaths, local_abspath);
|
||||
}
|
||||
@ -1979,7 +1980,8 @@ merge_file_changed(const char *relpath,
|
||||
/* We haven't notified for this node yet: report a skip */
|
||||
SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
|
||||
svn_wc_notify_update_shadowed_update,
|
||||
fb->skip_reason, scratch_pool));
|
||||
fb->skip_reason, fb->parent_baton,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -2148,7 +2150,8 @@ merge_file_added(const char *relpath,
|
||||
/* We haven't notified for this node yet: report a skip */
|
||||
SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
|
||||
svn_wc_notify_update_shadowed_add,
|
||||
fb->skip_reason, scratch_pool));
|
||||
fb->skip_reason, fb->parent_baton,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -2359,7 +2362,8 @@ merge_file_deleted(const char *relpath,
|
||||
/* We haven't notified for this node yet: report a skip */
|
||||
SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
|
||||
svn_wc_notify_update_shadowed_delete,
|
||||
fb->skip_reason, scratch_pool));
|
||||
fb->skip_reason, fb->parent_baton,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -2723,6 +2727,12 @@ merge_dir_opened(void **new_dir_baton,
|
||||
/* Set a tree conflict */
|
||||
db->shadowed = TRUE;
|
||||
db->tree_conflict_reason = svn_wc_conflict_reason_obstructed;
|
||||
|
||||
if ((merge_b->merge_source.ancestral || merge_b->reintegrate_merge)
|
||||
&& !(pdb && pdb->shadowed))
|
||||
{
|
||||
store_path(merge_b->skipped_abspaths, local_abspath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2847,7 +2857,8 @@ merge_dir_changed(const char *relpath,
|
||||
/* We haven't notified for this node yet: report a skip */
|
||||
SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
|
||||
svn_wc_notify_update_shadowed_update,
|
||||
db->skip_reason, scratch_pool));
|
||||
db->skip_reason, db->parent_baton,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -2931,7 +2942,8 @@ merge_dir_added(const char *relpath,
|
||||
/* We haven't notified for this node yet: report a skip */
|
||||
SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
|
||||
svn_wc_notify_update_shadowed_add,
|
||||
db->skip_reason, scratch_pool));
|
||||
db->skip_reason, db->parent_baton,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -3098,7 +3110,8 @@ merge_dir_deleted(const char *relpath,
|
||||
/* We haven't notified for this node yet: report a skip */
|
||||
SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
|
||||
svn_wc_notify_update_shadowed_delete,
|
||||
db->skip_reason, scratch_pool));
|
||||
db->skip_reason, db->parent_baton,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -3278,13 +3291,14 @@ merge_node_absent(const char *relpath,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
merge_cmd_baton_t *merge_b = processor->baton;
|
||||
struct merge_dir_baton_t *db = dir_baton;
|
||||
|
||||
const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
|
||||
relpath, scratch_pool);
|
||||
|
||||
SVN_ERR(record_skip(merge_b, local_abspath, svn_node_unknown,
|
||||
svn_wc_notify_skip, svn_wc_notify_state_missing,
|
||||
scratch_pool));
|
||||
db, scratch_pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
@ -2057,6 +2057,56 @@ send_patch_notification(const patch_target_t *target,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static void
|
||||
svn_sort__array(apr_array_header_t *array,
|
||||
int (*comparison_func)(const void *,
|
||||
const void *))
|
||||
{
|
||||
qsort(array->elts, array->nelts, array->elt_size, comparison_func);
|
||||
}
|
||||
|
||||
/* Implements the callback for svn_sort__array. Puts hunks that match
|
||||
before hunks that do not match, puts hunks that match in order
|
||||
based on postion matched, puts hunks that do not match in order
|
||||
based on original position. */
|
||||
static int
|
||||
sort_matched_hunks(const void *a, const void *b)
|
||||
{
|
||||
const hunk_info_t *item1 = *((const hunk_info_t * const *)a);
|
||||
const hunk_info_t *item2 = *((const hunk_info_t * const *)b);
|
||||
svn_boolean_t matched1 = !item1->rejected && !item1->already_applied;
|
||||
svn_boolean_t matched2 = !item2->rejected && !item2->already_applied;
|
||||
svn_linenum_t original1, original2;
|
||||
|
||||
if (matched1 && matched2)
|
||||
{
|
||||
/* Both match so use order matched in file. */
|
||||
if (item1->matched_line > item2->matched_line)
|
||||
return 1;
|
||||
else if (item1->matched_line == item2->matched_line)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (matched2)
|
||||
/* Only second matches, put it before first. */
|
||||
return 1;
|
||||
else if (matched1)
|
||||
/* Only first matches, put it before second. */
|
||||
return -1;
|
||||
|
||||
/* Neither matches, sort by original_start. */
|
||||
original1 = svn_diff_hunk_get_original_start(item1->hunk);
|
||||
original2 = svn_diff_hunk_get_original_start(item2->hunk);
|
||||
if (original1 > original2)
|
||||
return 1;
|
||||
else if (original1 == original2)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Apply a PATCH to a working copy at ABS_WC_PATH and put the result
|
||||
* into temporary files, to be installed in the working copy later.
|
||||
* Return information about the patch target in *PATCH_TARGET, allocated
|
||||
@ -2138,6 +2188,10 @@ apply_one_patch(patch_target_t **patch_target, svn_patch_t *patch,
|
||||
APR_ARRAY_PUSH(target->content->hunks, hunk_info_t *) = hi;
|
||||
}
|
||||
|
||||
/* Hunks are applied in the order determined by the matched line and
|
||||
this may be different from the order of the original lines. */
|
||||
svn_sort__array(target->content->hunks, sort_matched_hunks);
|
||||
|
||||
/* Apply or reject hunks. */
|
||||
for (i = 0; i < target->content->hunks->nelts; i++)
|
||||
{
|
||||
|
@ -82,6 +82,14 @@ fetch_repos_info(const char **repos_root,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Forward definition. Upgrades svn:externals properties in the working copy
|
||||
LOCAL_ABSPATH to the WC-NG storage.
|
||||
*/
|
||||
static svn_error_t *
|
||||
upgrade_externals_from_properties(svn_client_ctx_t *ctx,
|
||||
const char *local_abspath,
|
||||
apr_pool_t *scratch_pool);
|
||||
|
||||
svn_error_t *
|
||||
svn_client_upgrade(const char *path,
|
||||
svn_client_ctx_t *ctx,
|
||||
@ -89,10 +97,6 @@ svn_client_upgrade(const char *path,
|
||||
{
|
||||
const char *local_abspath;
|
||||
apr_hash_t *externals;
|
||||
apr_hash_index_t *hi;
|
||||
apr_pool_t *iterpool;
|
||||
apr_pool_t *iterpool2;
|
||||
svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
|
||||
struct repos_info_baton info_baton;
|
||||
|
||||
info_baton.state_pool = scratch_pool;
|
||||
@ -111,6 +115,80 @@ svn_client_upgrade(const char *path,
|
||||
ctx->notify_func2, ctx->notify_baton2,
|
||||
scratch_pool));
|
||||
|
||||
SVN_ERR(svn_wc__externals_defined_below(&externals,
|
||||
ctx->wc_ctx, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
|
||||
if (apr_hash_count(externals) > 0)
|
||||
{
|
||||
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
|
||||
apr_hash_index_t *hi;
|
||||
|
||||
/* We are upgrading from >= 1.7. No need to upgrade from
|
||||
svn:externals properties. And by that avoiding the removal
|
||||
of recorded externals information (issue #4519)
|
||||
|
||||
Only directory externals need an explicit upgrade */
|
||||
for (hi = apr_hash_first(scratch_pool, externals);
|
||||
hi;
|
||||
hi = apr_hash_next(hi))
|
||||
{
|
||||
const char *ext_abspath;
|
||||
svn_node_kind_t kind;
|
||||
|
||||
svn_pool_clear(iterpool);
|
||||
|
||||
ext_abspath = svn__apr_hash_index_key(hi);
|
||||
|
||||
SVN_ERR(svn_wc__read_external_info(&kind, NULL, NULL, NULL, NULL,
|
||||
ctx->wc_ctx, local_abspath,
|
||||
ext_abspath, FALSE,
|
||||
iterpool, iterpool));
|
||||
|
||||
if (kind == svn_node_dir)
|
||||
{
|
||||
svn_error_t *err = svn_client_upgrade(ext_abspath, ctx, iterpool);
|
||||
|
||||
if (err)
|
||||
{
|
||||
svn_wc_notify_t *notify =
|
||||
svn_wc_create_notify(ext_abspath,
|
||||
svn_wc_notify_failed_external,
|
||||
iterpool);
|
||||
notify->err = err;
|
||||
ctx->notify_func2(ctx->notify_baton2,
|
||||
notify, iterpool);
|
||||
svn_error_clear(err);
|
||||
/* Next external node, please... */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svn_pool_destroy(iterpool);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Upgrading from <= 1.6, or no svn:properties defined.
|
||||
(There is no way to detect the difference from libsvn_client :( ) */
|
||||
|
||||
SVN_ERR(upgrade_externals_from_properties(ctx, local_abspath,
|
||||
scratch_pool));
|
||||
}
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
upgrade_externals_from_properties(svn_client_ctx_t *ctx,
|
||||
const char *local_abspath,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
apr_hash_index_t *hi;
|
||||
apr_pool_t *iterpool;
|
||||
apr_pool_t *iterpool2;
|
||||
apr_hash_t *externals;
|
||||
svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
|
||||
struct repos_info_baton info_baton;
|
||||
|
||||
/* Now it's time to upgrade the externals too. We do it after the wc
|
||||
upgrade to avoid that errors in the externals causes the wc upgrade to
|
||||
fail. Thanks to caching the performance penalty of walking the wc a
|
||||
@ -163,7 +241,7 @@ svn_client_upgrade(const char *path,
|
||||
iterpool);
|
||||
if (!err)
|
||||
err = svn_wc_parse_externals_description3(
|
||||
&externals_p, svn_dirent_dirname(path, iterpool),
|
||||
&externals_p, svn_dirent_dirname(local_abspath, iterpool),
|
||||
external_desc->data, FALSE, iterpool);
|
||||
if (err)
|
||||
{
|
||||
|
@ -830,23 +830,23 @@ write_handler(void *baton,
|
||||
|
||||
p = decode_file_offset(&sview_offset, p, end);
|
||||
if (p == NULL)
|
||||
return SVN_NO_ERROR;
|
||||
break;
|
||||
|
||||
p = decode_size(&sview_len, p, end);
|
||||
if (p == NULL)
|
||||
return SVN_NO_ERROR;
|
||||
break;
|
||||
|
||||
p = decode_size(&tview_len, p, end);
|
||||
if (p == NULL)
|
||||
return SVN_NO_ERROR;
|
||||
break;
|
||||
|
||||
p = decode_size(&inslen, p, end);
|
||||
if (p == NULL)
|
||||
return SVN_NO_ERROR;
|
||||
break;
|
||||
|
||||
p = decode_size(&newlen, p, end);
|
||||
if (p == NULL)
|
||||
return SVN_NO_ERROR;
|
||||
break;
|
||||
|
||||
if (tview_len > SVN_DELTA_WINDOW_SIZE ||
|
||||
sview_len > SVN_DELTA_WINDOW_SIZE ||
|
||||
@ -904,7 +904,15 @@ write_handler(void *baton,
|
||||
db->subpool = newpool;
|
||||
}
|
||||
|
||||
/* NOTREACHED */
|
||||
/* At this point we processed all integral windows and DB->BUFFER is empty
|
||||
or contains partially read window header.
|
||||
Check that unprocessed data is not larger that theoretical maximum
|
||||
window header size. */
|
||||
if (db->buffer->len > 5 * MAX_ENCODED_INT_LEN)
|
||||
return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
|
||||
_("Svndiff contains a too-large window header"));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Minimal svn_stream_t write handler, doing nothing */
|
||||
|
@ -1313,6 +1313,7 @@ svn_diff_parse_next_patch(svn_patch_t **patch,
|
||||
line_after_tree_header_read = TRUE;
|
||||
}
|
||||
else if (! valid_header_line && state != state_start
|
||||
&& state != state_git_diff_seen
|
||||
&& !starts_with(line->data, "index "))
|
||||
{
|
||||
/* We've encountered an invalid diff header.
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "svn_diff.h"
|
||||
#include "svn_types.h"
|
||||
#include "svn_ctype.h"
|
||||
#include "svn_sorts.h"
|
||||
#include "svn_utf.h"
|
||||
#include "svn_version.h"
|
||||
|
||||
@ -486,23 +487,37 @@ display_mergeinfo_diff(const char *old_mergeinfo_val,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* qsort callback handling svn_prop_t by name */
|
||||
static int
|
||||
propchange_sort(const void *k1, const void *k2)
|
||||
{
|
||||
const svn_prop_t *propchange1 = k1;
|
||||
const svn_prop_t *propchange2 = k2;
|
||||
|
||||
return strcmp(propchange1->name, propchange2->name);
|
||||
}
|
||||
|
||||
svn_error_t *
|
||||
svn_diff__display_prop_diffs(svn_stream_t *outstream,
|
||||
const char *encoding,
|
||||
const apr_array_header_t *propchanges,
|
||||
apr_hash_t *original_props,
|
||||
svn_boolean_t pretty_print_mergeinfo,
|
||||
apr_pool_t *pool)
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
apr_pool_t *pool = scratch_pool;
|
||||
apr_pool_t *iterpool = svn_pool_create(pool);
|
||||
apr_array_header_t *changes = apr_array_copy(scratch_pool, propchanges);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < propchanges->nelts; i++)
|
||||
qsort(changes->elts, changes->nelts, changes->elt_size, propchange_sort);
|
||||
|
||||
for (i = 0; i < changes->nelts; i++)
|
||||
{
|
||||
const char *action;
|
||||
const svn_string_t *original_value;
|
||||
const svn_prop_t *propchange
|
||||
= &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
|
||||
= &APR_ARRAY_IDX(changes, i, svn_prop_t);
|
||||
|
||||
if (original_props)
|
||||
original_value = svn_hash_gets(original_props, propchange->name);
|
||||
|
@ -89,7 +89,7 @@ read_config(svn_memcache_t **memcache_p,
|
||||
fs_fs_data_t *ffd = fs->fsap_data;
|
||||
|
||||
SVN_ERR(svn_cache__make_memcache_from_config(memcache_p, ffd->config,
|
||||
fs->pool));
|
||||
fs->pool));
|
||||
|
||||
/* No cache namespace by default. I.e. all FS instances share the
|
||||
* cached data. If you specify different namespaces, the data will
|
||||
@ -129,23 +129,9 @@ read_config(svn_memcache_t **memcache_p,
|
||||
SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
|
||||
TRUE);
|
||||
|
||||
/* don't cache revprops by default.
|
||||
* Revprop caching significantly speeds up operations like
|
||||
* svn ls -v. However, it requires synchronization that may
|
||||
* not be available or efficient in the current server setup.
|
||||
*
|
||||
* If the caller chose option "2", enable revprop caching if
|
||||
* the required API support is there to make it efficient.
|
||||
/* For now, always disable revprop caching.
|
||||
*/
|
||||
if (strcmp(svn_hash__get_cstring(fs->config,
|
||||
SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
|
||||
""), "2"))
|
||||
*cache_revprops
|
||||
= svn_hash__get_bool(fs->config,
|
||||
SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
|
||||
FALSE);
|
||||
else
|
||||
*cache_revprops = svn_named_atomic__is_efficient();
|
||||
*cache_revprops = FALSE;
|
||||
|
||||
return svn_config_get_bool(ffd->config, fail_stop,
|
||||
CONFIG_SECTION_CACHES, CONFIG_OPTION_FAIL_STOP,
|
||||
|
@ -3988,17 +3988,23 @@ write_non_packed_revprop(const char **final_path,
|
||||
apr_hash_t *proplist,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_file_t *file;
|
||||
svn_stream_t *stream;
|
||||
*final_path = path_revprops(fs, rev, pool);
|
||||
|
||||
/* ### do we have a directory sitting around already? we really shouldn't
|
||||
### have to get the dirname here. */
|
||||
SVN_ERR(svn_stream_open_unique(&stream, tmp_path,
|
||||
svn_dirent_dirname(*final_path, pool),
|
||||
svn_io_file_del_none, pool, pool));
|
||||
SVN_ERR(svn_io_open_unique_file3(&file, tmp_path,
|
||||
svn_dirent_dirname(*final_path, pool),
|
||||
svn_io_file_del_none, pool, pool));
|
||||
stream = svn_stream_from_aprfile2(file, TRUE, pool);
|
||||
SVN_ERR(svn_hash_write2(proplist, stream, SVN_HASH_TERMINATOR, pool));
|
||||
SVN_ERR(svn_stream_close(stream));
|
||||
|
||||
/* Flush temporary file to disk and close it. */
|
||||
SVN_ERR(svn_io_file_flush_to_disk(file, pool));
|
||||
SVN_ERR(svn_io_file_close(file, pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -4085,7 +4091,7 @@ serialize_revprops_header(svn_stream_t *stream,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Writes the a pack file to FILE_STREAM. It copies the serialized data
|
||||
/* Writes the a pack file to FILE. It copies the serialized data
|
||||
* from REVPROPS for the indexes [START,END) except for index CHANGED_INDEX.
|
||||
*
|
||||
* The data for the latter is taken from NEW_SERIALIZED. Note, that
|
||||
@ -4103,7 +4109,7 @@ repack_revprops(svn_fs_t *fs,
|
||||
int changed_index,
|
||||
svn_stringbuf_t *new_serialized,
|
||||
apr_off_t new_total_size,
|
||||
svn_stream_t *file_stream,
|
||||
apr_file_t *file,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
fs_fs_data_t *ffd = fs->fsap_data;
|
||||
@ -4151,9 +4157,11 @@ repack_revprops(svn_fs_t *fs,
|
||||
? SVN_DELTA_COMPRESSION_LEVEL_DEFAULT
|
||||
: SVN_DELTA_COMPRESSION_LEVEL_NONE));
|
||||
|
||||
/* finally, write the content to the target stream and close it */
|
||||
SVN_ERR(svn_stream_write(file_stream, compressed->data, &compressed->len));
|
||||
SVN_ERR(svn_stream_close(file_stream));
|
||||
/* finally, write the content to the target file, flush and close it */
|
||||
SVN_ERR(svn_io_file_write_full(file, compressed->data, compressed->len,
|
||||
NULL, pool));
|
||||
SVN_ERR(svn_io_file_flush_to_disk(file, pool));
|
||||
SVN_ERR(svn_io_file_close(file, pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -4161,23 +4169,22 @@ repack_revprops(svn_fs_t *fs,
|
||||
/* Allocate a new pack file name for revisions
|
||||
* [REVPROPS->START_REVISION + START, REVPROPS->START_REVISION + END - 1]
|
||||
* of REVPROPS->MANIFEST. Add the name of old file to FILES_TO_DELETE,
|
||||
* auto-create that array if necessary. Return an open file stream to
|
||||
* the new file in *STREAM allocated in POOL.
|
||||
* auto-create that array if necessary. Return an open file *FILE that is
|
||||
* allocated in POOL.
|
||||
*/
|
||||
static svn_error_t *
|
||||
repack_stream_open(svn_stream_t **stream,
|
||||
svn_fs_t *fs,
|
||||
packed_revprops_t *revprops,
|
||||
int start,
|
||||
int end,
|
||||
apr_array_header_t **files_to_delete,
|
||||
apr_pool_t *pool)
|
||||
repack_file_open(apr_file_t **file,
|
||||
svn_fs_t *fs,
|
||||
packed_revprops_t *revprops,
|
||||
int start,
|
||||
int end,
|
||||
apr_array_header_t **files_to_delete,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_int64_t tag;
|
||||
const char *tag_string;
|
||||
svn_string_t *new_filename;
|
||||
int i;
|
||||
apr_file_t *file;
|
||||
int manifest_offset
|
||||
= (int)(revprops->start_revision - revprops->manifest_start);
|
||||
|
||||
@ -4209,12 +4216,11 @@ repack_stream_open(svn_stream_t **stream,
|
||||
APR_ARRAY_IDX(revprops->manifest, i + manifest_offset, const char*)
|
||||
= new_filename->data;
|
||||
|
||||
/* create a file stream for the new file */
|
||||
SVN_ERR(svn_io_file_open(&file, svn_dirent_join(revprops->folder,
|
||||
new_filename->data,
|
||||
pool),
|
||||
/* open the file */
|
||||
SVN_ERR(svn_io_file_open(file, svn_dirent_join(revprops->folder,
|
||||
new_filename->data,
|
||||
pool),
|
||||
APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pool));
|
||||
*stream = svn_stream_from_aprfile2(file, FALSE, pool);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -4238,6 +4244,7 @@ write_packed_revprop(const char **final_path,
|
||||
packed_revprops_t *revprops;
|
||||
apr_int64_t generation = 0;
|
||||
svn_stream_t *stream;
|
||||
apr_file_t *file;
|
||||
svn_stringbuf_t *serialized;
|
||||
apr_off_t new_total_size;
|
||||
int changed_index;
|
||||
@ -4273,11 +4280,11 @@ write_packed_revprop(const char **final_path,
|
||||
|
||||
*final_path = svn_dirent_join(revprops->folder, revprops->filename,
|
||||
pool);
|
||||
SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
|
||||
svn_io_file_del_none, pool, pool));
|
||||
SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
|
||||
svn_io_file_del_none, pool, pool));
|
||||
SVN_ERR(repack_revprops(fs, revprops, 0, revprops->sizes->nelts,
|
||||
changed_index, serialized, new_total_size,
|
||||
stream, pool));
|
||||
file, pool));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4323,50 +4330,53 @@ write_packed_revprop(const char **final_path,
|
||||
/* write the new, split files */
|
||||
if (left_count)
|
||||
{
|
||||
SVN_ERR(repack_stream_open(&stream, fs, revprops, 0,
|
||||
left_count, files_to_delete, pool));
|
||||
SVN_ERR(repack_file_open(&file, fs, revprops, 0,
|
||||
left_count, files_to_delete, pool));
|
||||
SVN_ERR(repack_revprops(fs, revprops, 0, left_count,
|
||||
changed_index, serialized, new_total_size,
|
||||
stream, pool));
|
||||
file, pool));
|
||||
}
|
||||
|
||||
if (left_count + right_count < revprops->sizes->nelts)
|
||||
{
|
||||
SVN_ERR(repack_stream_open(&stream, fs, revprops, changed_index,
|
||||
changed_index + 1, files_to_delete,
|
||||
pool));
|
||||
SVN_ERR(repack_file_open(&file, fs, revprops, changed_index,
|
||||
changed_index + 1, files_to_delete,
|
||||
pool));
|
||||
SVN_ERR(repack_revprops(fs, revprops, changed_index,
|
||||
changed_index + 1,
|
||||
changed_index, serialized, new_total_size,
|
||||
stream, pool));
|
||||
file, pool));
|
||||
}
|
||||
|
||||
if (right_count)
|
||||
{
|
||||
SVN_ERR(repack_stream_open(&stream, fs, revprops,
|
||||
revprops->sizes->nelts - right_count,
|
||||
revprops->sizes->nelts,
|
||||
files_to_delete, pool));
|
||||
SVN_ERR(repack_file_open(&file, fs, revprops,
|
||||
revprops->sizes->nelts - right_count,
|
||||
revprops->sizes->nelts,
|
||||
files_to_delete, pool));
|
||||
SVN_ERR(repack_revprops(fs, revprops,
|
||||
revprops->sizes->nelts - right_count,
|
||||
revprops->sizes->nelts, changed_index,
|
||||
serialized, new_total_size, stream,
|
||||
serialized, new_total_size, file,
|
||||
pool));
|
||||
}
|
||||
|
||||
/* write the new manifest */
|
||||
*final_path = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
|
||||
SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
|
||||
svn_io_file_del_none, pool, pool));
|
||||
SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
|
||||
svn_io_file_del_none, pool, pool));
|
||||
|
||||
for (i = 0; i < revprops->manifest->nelts; ++i)
|
||||
{
|
||||
const char *filename = APR_ARRAY_IDX(revprops->manifest, i,
|
||||
const char*);
|
||||
SVN_ERR(svn_stream_printf(stream, pool, "%s\n", filename));
|
||||
SVN_ERR(svn_io_file_write_full(file, filename, strlen(filename),
|
||||
NULL, pool));
|
||||
SVN_ERR(svn_io_file_putc('\n', file, pool));
|
||||
}
|
||||
|
||||
SVN_ERR(svn_stream_close(stream));
|
||||
SVN_ERR(svn_io_file_flush_to_disk(file, pool));
|
||||
SVN_ERR(svn_io_file_close(file, pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -5062,9 +5072,11 @@ get_combined_window(svn_stringbuf_t **result,
|
||||
/* Maybe, we've got a PLAIN start representation. If we do, read
|
||||
as much data from it as the needed for the txdelta window's source
|
||||
view.
|
||||
Note that BUF / SOURCE may only be NULL in the first iteration. */
|
||||
Note that BUF / SOURCE may only be NULL in the first iteration.
|
||||
Also note that we may have short-cut reading the delta chain --
|
||||
in which case SRC_OPS is 0 and it might not be a PLAIN rep. */
|
||||
source = buf;
|
||||
if (source == NULL && rb->src_state != NULL)
|
||||
if (source == NULL && rb->src_state != NULL && window->src_ops)
|
||||
SVN_ERR(read_plain_window(&source, rb->src_state, window->sview_len,
|
||||
pool));
|
||||
|
||||
@ -6966,8 +6978,13 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
|
||||
rep = apr_pcalloc(pool, sizeof(*rep));
|
||||
rep->revision = SVN_INVALID_REVNUM;
|
||||
rep->txn_id = txn_id;
|
||||
SVN_ERR(get_new_txn_node_id(&unique_suffix, fs, txn_id, pool));
|
||||
rep->uniquifier = apr_psprintf(pool, "%s/%s", txn_id, unique_suffix);
|
||||
|
||||
if (ffd->format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT)
|
||||
{
|
||||
SVN_ERR(get_new_txn_node_id(&unique_suffix, fs, txn_id, pool));
|
||||
rep->uniquifier = apr_psprintf(pool, "%s/%s", txn_id, unique_suffix);
|
||||
}
|
||||
|
||||
parent_noderev->data_rep = rep;
|
||||
SVN_ERR(svn_fs_fs__put_node_revision(fs, parent_noderev->id,
|
||||
parent_noderev, FALSE, pool));
|
||||
@ -7551,6 +7568,7 @@ rep_write_contents_close(void *baton)
|
||||
representation_t *rep;
|
||||
representation_t *old_rep;
|
||||
apr_off_t offset;
|
||||
fs_fs_data_t *ffd = b->fs->fsap_data;
|
||||
|
||||
rep = apr_pcalloc(b->parent_pool, sizeof(*rep));
|
||||
rep->offset = b->rep_offset;
|
||||
@ -7567,9 +7585,13 @@ rep_write_contents_close(void *baton)
|
||||
/* Fill in the rest of the representation field. */
|
||||
rep->expanded_size = b->rep_size;
|
||||
rep->txn_id = svn_fs_fs__id_txn_id(b->noderev->id);
|
||||
SVN_ERR(get_new_txn_node_id(&unique_suffix, b->fs, rep->txn_id, b->pool));
|
||||
rep->uniquifier = apr_psprintf(b->parent_pool, "%s/%s", rep->txn_id,
|
||||
unique_suffix);
|
||||
|
||||
if (ffd->format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT)
|
||||
{
|
||||
SVN_ERR(get_new_txn_node_id(&unique_suffix, b->fs, rep->txn_id, b->pool));
|
||||
rep->uniquifier = apr_psprintf(b->parent_pool, "%s/%s", rep->txn_id,
|
||||
unique_suffix);
|
||||
}
|
||||
rep->revision = SVN_INVALID_REVNUM;
|
||||
|
||||
/* Finalize the checksum. */
|
||||
@ -7842,7 +7864,7 @@ write_hash_rep(representation_t *rep,
|
||||
|
||||
/* update the representation */
|
||||
rep->size = whb->size;
|
||||
rep->expanded_size = 0;
|
||||
rep->expanded_size = whb->size;
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -9070,7 +9092,9 @@ recover_find_max_ids(svn_fs_t *fs, svn_revnum_t rev,
|
||||
stored in the representation. */
|
||||
baton.file = rev_file;
|
||||
baton.pool = pool;
|
||||
baton.remaining = data_rep->expanded_size;
|
||||
baton.remaining = data_rep->expanded_size
|
||||
? data_rep->expanded_size
|
||||
: data_rep->size;
|
||||
stream = svn_stream_create(&baton, pool);
|
||||
svn_stream_set_read(stream, read_handler_recover);
|
||||
|
||||
@ -10912,6 +10936,9 @@ hotcopy_update_current(svn_revnum_t *dst_youngest,
|
||||
{
|
||||
apr_off_t root_offset;
|
||||
apr_file_t *rev_file;
|
||||
char max_node_id[MAX_KEY_SIZE] = "0";
|
||||
char max_copy_id[MAX_KEY_SIZE] = "0";
|
||||
apr_size_t len;
|
||||
|
||||
if (dst_ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
|
||||
SVN_ERR(update_min_unpacked_rev(dst_fs, scratch_pool));
|
||||
@ -10921,9 +10948,15 @@ hotcopy_update_current(svn_revnum_t *dst_youngest,
|
||||
SVN_ERR(get_root_changes_offset(&root_offset, NULL, rev_file,
|
||||
dst_fs, new_youngest, scratch_pool));
|
||||
SVN_ERR(recover_find_max_ids(dst_fs, new_youngest, rev_file,
|
||||
root_offset, next_node_id, next_copy_id,
|
||||
root_offset, max_node_id, max_copy_id,
|
||||
scratch_pool));
|
||||
SVN_ERR(svn_io_file_close(rev_file, scratch_pool));
|
||||
|
||||
/* We store the _next_ ids. */
|
||||
len = strlen(max_node_id);
|
||||
svn_fs_fs__next_key(max_node_id, &len, next_node_id);
|
||||
len = strlen(max_copy_id);
|
||||
svn_fs_fs__next_key(max_copy_id, &len, next_copy_id);
|
||||
}
|
||||
|
||||
/* Update 'current'. */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This file is automatically generated from rep-cache-db.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_fs_fs/token-map.h.
|
||||
/* This file is automatically generated from rep-cache-db.sql and .dist_sandbox/subversion-1.8.14/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
|
||||
|
@ -127,7 +127,6 @@ typedef struct fs_txn_root_data_t
|
||||
static svn_error_t * get_dag(dag_node_t **dag_node_p,
|
||||
svn_fs_root_t *root,
|
||||
const char *path,
|
||||
svn_boolean_t needs_lock_cache,
|
||||
apr_pool_t *pool);
|
||||
|
||||
static svn_fs_root_t *make_revision_root(svn_fs_t *fs, svn_revnum_t rev,
|
||||
@ -178,34 +177,10 @@ typedef struct cache_entry_t
|
||||
*/
|
||||
enum { BUCKET_COUNT = 256 };
|
||||
|
||||
/* Each pool that has received a DAG node, will hold at least on lock on
|
||||
our cache to ensure that the node remains valid despite being allocated
|
||||
in the cache's pool. This is the structure to represent the lock.
|
||||
*/
|
||||
typedef struct cache_lock_t
|
||||
{
|
||||
/* pool holding the lock */
|
||||
apr_pool_t *pool;
|
||||
|
||||
/* cache being locked */
|
||||
fs_fs_dag_cache_t *cache;
|
||||
|
||||
/* next lock. NULL at EOL */
|
||||
struct cache_lock_t *next;
|
||||
|
||||
/* previous lock. NULL at list head. Only then this==cache->first_lock */
|
||||
struct cache_lock_t *prev;
|
||||
} cache_lock_t;
|
||||
|
||||
/* The actual cache structure. All nodes will be allocated in POOL.
|
||||
When the number of INSERTIONS (i.e. objects created form that pool)
|
||||
exceeds a certain threshold, the pool will be cleared and the cache
|
||||
with it.
|
||||
|
||||
To ensure that nodes returned from this structure remain valid, the
|
||||
cache will get locked for the lifetime of the _receiving_ pools (i.e.
|
||||
those in which we would allocate the node if there was no cache.).
|
||||
The cache will only be cleared FIRST_LOCK is 0.
|
||||
*/
|
||||
struct fs_fs_dag_cache_t
|
||||
{
|
||||
@ -221,106 +196,23 @@ struct fs_fs_dag_cache_t
|
||||
/* Property lookups etc. have a very high locality (75% re-hit).
|
||||
Thus, remember the last hit location for optimistic lookup. */
|
||||
apr_size_t last_hit;
|
||||
|
||||
/* List of receiving pools that are still alive. */
|
||||
cache_lock_t *first_lock;
|
||||
};
|
||||
|
||||
/* Cleanup function to be called when a receiving pool gets cleared.
|
||||
Unlocks the cache once.
|
||||
*/
|
||||
static apr_status_t
|
||||
unlock_cache(void *baton_void)
|
||||
{
|
||||
cache_lock_t *lock = baton_void;
|
||||
|
||||
/* remove lock from chain. Update the head */
|
||||
if (lock->next)
|
||||
lock->next->prev = lock->prev;
|
||||
if (lock->prev)
|
||||
lock->prev->next = lock->next;
|
||||
else
|
||||
lock->cache->first_lock = lock->next;
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Cleanup function to be called when the cache itself gets destroyed.
|
||||
In that case, we must unregister all unlock requests.
|
||||
*/
|
||||
static apr_status_t
|
||||
unregister_locks(void *baton_void)
|
||||
{
|
||||
fs_fs_dag_cache_t *cache = baton_void;
|
||||
cache_lock_t *lock;
|
||||
|
||||
for (lock = cache->first_lock; lock; lock = lock->next)
|
||||
apr_pool_cleanup_kill(lock->pool,
|
||||
lock,
|
||||
unlock_cache);
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
fs_fs_dag_cache_t*
|
||||
svn_fs_fs__create_dag_cache(apr_pool_t *pool)
|
||||
{
|
||||
fs_fs_dag_cache_t *result = apr_pcalloc(pool, sizeof(*result));
|
||||
result->pool = svn_pool_create(pool);
|
||||
|
||||
apr_pool_cleanup_register(pool,
|
||||
result,
|
||||
unregister_locks,
|
||||
apr_pool_cleanup_null);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Prevent the entries in CACHE from being destroyed, for as long as the
|
||||
POOL lives.
|
||||
*/
|
||||
static void
|
||||
lock_cache(fs_fs_dag_cache_t* cache, apr_pool_t *pool)
|
||||
{
|
||||
/* we only need to lock / unlock once per pool. Since we will often ask
|
||||
for multiple nodes with the same pool, we can reduce the overhead.
|
||||
However, if e.g. pools are being used in an alternating pattern,
|
||||
we may lock the cache more than once for the same pool (and register
|
||||
just as many cleanup actions).
|
||||
*/
|
||||
cache_lock_t *lock = cache->first_lock;
|
||||
|
||||
/* try to find an existing lock for POOL.
|
||||
But limit the time spent on chasing pointers. */
|
||||
int limiter = 8;
|
||||
while (lock && --limiter)
|
||||
if (lock->pool == pool)
|
||||
return;
|
||||
|
||||
/* create a new lock and put it at the beginning of the lock chain */
|
||||
lock = apr_palloc(pool, sizeof(*lock));
|
||||
lock->cache = cache;
|
||||
lock->pool = pool;
|
||||
lock->next = cache->first_lock;
|
||||
lock->prev = NULL;
|
||||
|
||||
if (cache->first_lock)
|
||||
cache->first_lock->prev = lock;
|
||||
cache->first_lock = lock;
|
||||
|
||||
/* instruct POOL to remove the look upon cleanup */
|
||||
apr_pool_cleanup_register(pool,
|
||||
lock,
|
||||
unlock_cache,
|
||||
apr_pool_cleanup_null);
|
||||
}
|
||||
|
||||
/* Clears the CACHE at regular intervals (destroying all cached nodes)
|
||||
*/
|
||||
static void
|
||||
auto_clear_dag_cache(fs_fs_dag_cache_t* cache)
|
||||
{
|
||||
if (cache->first_lock == NULL && cache->insertions > BUCKET_COUNT)
|
||||
if (cache->insertions > BUCKET_COUNT)
|
||||
{
|
||||
svn_pool_clear(cache->pool);
|
||||
|
||||
@ -433,18 +325,12 @@ locate_cache(svn_cache__t **cache,
|
||||
}
|
||||
}
|
||||
|
||||
/* Return NODE for PATH from ROOT's node cache, or NULL if the node
|
||||
isn't cached; read it from the FS. *NODE remains valid until either
|
||||
POOL or the FS gets cleared or destroyed (whichever comes first).
|
||||
|
||||
Since locking can be expensive and POOL may be long-living, for
|
||||
nodes that will not need to survive the next call to this function,
|
||||
set NEEDS_LOCK_CACHE to FALSE. */
|
||||
/* Return NODE_P for PATH from ROOT's node cache, or NULL if the node
|
||||
isn't cached; read it from the FS. *NODE_P is allocated in POOL. */
|
||||
static svn_error_t *
|
||||
dag_node_cache_get(dag_node_t **node_p,
|
||||
svn_fs_root_t *root,
|
||||
const char *path,
|
||||
svn_boolean_t needs_lock_cache,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
svn_boolean_t found;
|
||||
@ -466,25 +352,23 @@ dag_node_cache_get(dag_node_t **node_p,
|
||||
if (bucket->node == NULL)
|
||||
{
|
||||
locate_cache(&cache, &key, root, path, pool);
|
||||
SVN_ERR(svn_cache__get((void **)&node, &found, cache, key,
|
||||
ffd->dag_node_cache->pool));
|
||||
SVN_ERR(svn_cache__get((void **)&node, &found, cache, key, pool));
|
||||
if (found && node)
|
||||
{
|
||||
/* Patch up the FS, since this might have come from an old FS
|
||||
* object. */
|
||||
svn_fs_fs__dag_set_fs(node, root->fs);
|
||||
bucket->node = node;
|
||||
|
||||
/* Retain the DAG node in L1 cache. */
|
||||
bucket->node = svn_fs_fs__dag_dup(node,
|
||||
ffd->dag_node_cache->pool);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node = bucket->node;
|
||||
/* Copy the node from L1 cache into the passed-in POOL. */
|
||||
node = svn_fs_fs__dag_dup(bucket->node, pool);
|
||||
}
|
||||
|
||||
/* if we found a node, make sure it remains valid at least as long
|
||||
as it would when allocated in POOL. */
|
||||
if (node && needs_lock_cache)
|
||||
lock_cache(ffd->dag_node_cache, pool);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -822,7 +706,7 @@ get_copy_inheritance(copy_id_inherit_t *inherit_p,
|
||||
SVN_ERR(svn_fs_fs__dag_get_copyroot(©root_rev, ©root_path,
|
||||
child->node));
|
||||
SVN_ERR(svn_fs_fs__revision_root(©root_root, fs, copyroot_rev, pool));
|
||||
SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, FALSE, pool));
|
||||
SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, pool));
|
||||
copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
|
||||
|
||||
if (svn_fs_fs__id_compare(copyroot_id, child_id) == -1)
|
||||
@ -938,7 +822,7 @@ open_path(parent_path_t **parent_path_p,
|
||||
{
|
||||
directory = svn_dirent_dirname(path, pool);
|
||||
if (directory[1] != 0) /* root nodes are covered anyway */
|
||||
SVN_ERR(dag_node_cache_get(&here, root, directory, TRUE, pool));
|
||||
SVN_ERR(dag_node_cache_get(&here, root, directory, pool));
|
||||
}
|
||||
|
||||
/* did the shortcut work? */
|
||||
@ -998,8 +882,8 @@ open_path(parent_path_t **parent_path_p,
|
||||
element if we already know the lookup to fail for the
|
||||
complete path. */
|
||||
if (next || !(flags & open_path_uncached))
|
||||
SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far,
|
||||
TRUE, pool));
|
||||
SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far, pool));
|
||||
|
||||
if (cached_node)
|
||||
child = cached_node;
|
||||
else
|
||||
@ -1136,8 +1020,7 @@ make_path_mutable(svn_fs_root_t *root,
|
||||
parent_path->node));
|
||||
SVN_ERR(svn_fs_fs__revision_root(©root_root, root->fs,
|
||||
copyroot_rev, pool));
|
||||
SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path,
|
||||
FALSE, pool));
|
||||
SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, pool));
|
||||
|
||||
child_id = svn_fs_fs__dag_get_id(parent_path->node);
|
||||
copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
|
||||
@ -1174,16 +1057,11 @@ make_path_mutable(svn_fs_root_t *root,
|
||||
|
||||
/* Open the node identified by PATH in ROOT. Set DAG_NODE_P to the
|
||||
node we find, allocated in POOL. Return the error
|
||||
SVN_ERR_FS_NOT_FOUND if this node doesn't exist.
|
||||
|
||||
Since locking can be expensive and POOL may be long-living, for
|
||||
nodes that will not need to survive the next call to this function,
|
||||
set NEEDS_LOCK_CACHE to FALSE. */
|
||||
SVN_ERR_FS_NOT_FOUND if this node doesn't exist. */
|
||||
static svn_error_t *
|
||||
get_dag(dag_node_t **dag_node_p,
|
||||
svn_fs_root_t *root,
|
||||
const char *path,
|
||||
svn_boolean_t needs_lock_cache,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
parent_path_t *parent_path;
|
||||
@ -1192,7 +1070,7 @@ get_dag(dag_node_t **dag_node_p,
|
||||
/* First we look for the DAG in our cache
|
||||
(if the path may be canonical). */
|
||||
if (*path == '/')
|
||||
SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache, pool));
|
||||
SVN_ERR(dag_node_cache_get(&node, root, path, pool));
|
||||
|
||||
if (! node)
|
||||
{
|
||||
@ -1202,8 +1080,7 @@ get_dag(dag_node_t **dag_node_p,
|
||||
path = svn_fs__canonicalize_abspath(path, pool);
|
||||
|
||||
/* Try again with the corrected path. */
|
||||
SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache,
|
||||
pool));
|
||||
SVN_ERR(dag_node_cache_get(&node, root, path, pool));
|
||||
}
|
||||
|
||||
if (! node)
|
||||
@ -1281,7 +1158,7 @@ svn_fs_fs__node_id(const svn_fs_id_t **id_p,
|
||||
{
|
||||
dag_node_t *node;
|
||||
|
||||
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
*id_p = svn_fs_fs__id_copy(svn_fs_fs__dag_get_id(node), pool);
|
||||
}
|
||||
return SVN_NO_ERROR;
|
||||
@ -1296,7 +1173,7 @@ svn_fs_fs__node_created_rev(svn_revnum_t *revision,
|
||||
{
|
||||
dag_node_t *node;
|
||||
|
||||
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
return svn_fs_fs__dag_get_revision(revision, node, pool);
|
||||
}
|
||||
|
||||
@ -1311,7 +1188,7 @@ fs_node_created_path(const char **created_path,
|
||||
{
|
||||
dag_node_t *node;
|
||||
|
||||
SVN_ERR(get_dag(&node, root, path, TRUE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
*created_path = svn_fs_fs__dag_get_created_path(node);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -1375,7 +1252,7 @@ fs_node_prop(svn_string_t **value_p,
|
||||
dag_node_t *node;
|
||||
apr_hash_t *proplist;
|
||||
|
||||
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
SVN_ERR(svn_fs_fs__dag_get_proplist(&proplist, node, pool));
|
||||
*value_p = NULL;
|
||||
if (proplist)
|
||||
@ -1398,7 +1275,7 @@ fs_node_proplist(apr_hash_t **table_p,
|
||||
apr_hash_t *table;
|
||||
dag_node_t *node;
|
||||
|
||||
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
SVN_ERR(svn_fs_fs__dag_get_proplist(&table, node, pool));
|
||||
*table_p = table ? table : apr_hash_make(pool);
|
||||
|
||||
@ -1515,8 +1392,8 @@ fs_props_changed(svn_boolean_t *changed_p,
|
||||
(SVN_ERR_FS_GENERAL, NULL,
|
||||
_("Cannot compare property value between two different filesystems"));
|
||||
|
||||
SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
|
||||
SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
|
||||
SVN_ERR(get_dag(&node1, root1, path1, pool));
|
||||
SVN_ERR(get_dag(&node2, root2, path2, pool));
|
||||
return svn_fs_fs__dag_things_different(changed_p, NULL,
|
||||
node1, node2);
|
||||
}
|
||||
@ -1529,7 +1406,7 @@ fs_props_changed(svn_boolean_t *changed_p,
|
||||
static svn_error_t *
|
||||
get_root(dag_node_t **node, svn_fs_root_t *root, apr_pool_t *pool)
|
||||
{
|
||||
return get_dag(node, root, "/", TRUE, pool);
|
||||
return get_dag(node, root, "/", pool);
|
||||
}
|
||||
|
||||
|
||||
@ -2193,7 +2070,7 @@ fs_dir_entries(apr_hash_t **table_p,
|
||||
dag_node_t *node;
|
||||
|
||||
/* Get the entries for this path in the caller's pool. */
|
||||
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
return svn_fs_fs__dag_dir_entries(table_p, node, pool);
|
||||
}
|
||||
|
||||
@ -2365,7 +2242,7 @@ copy_helper(svn_fs_root_t *from_root,
|
||||
_("Copy from mutable tree not currently supported"));
|
||||
|
||||
/* Get the NODE for FROM_PATH in FROM_ROOT.*/
|
||||
SVN_ERR(get_dag(&from_node, from_root, from_path, TRUE, pool));
|
||||
SVN_ERR(get_dag(&from_node, from_root, from_path, pool));
|
||||
|
||||
/* Build up the parent path from TO_PATH in TO_ROOT. If the last
|
||||
component does not exist, it's not that big a deal. We'll just
|
||||
@ -2442,7 +2319,7 @@ copy_helper(svn_fs_root_t *from_root,
|
||||
pool));
|
||||
|
||||
/* Make a record of this modification in the changes table. */
|
||||
SVN_ERR(get_dag(&new_node, to_root, to_path, TRUE, pool));
|
||||
SVN_ERR(get_dag(&new_node, to_root, to_path, pool));
|
||||
SVN_ERR(add_change(to_root->fs, txn_id, to_path,
|
||||
svn_fs_fs__dag_get_id(new_node), kind, FALSE, FALSE,
|
||||
svn_fs_fs__dag_node_kind(from_node),
|
||||
@ -2553,7 +2430,7 @@ fs_copied_from(svn_revnum_t *rev_p,
|
||||
{
|
||||
/* There is no cached entry, look it up the old-fashioned
|
||||
way. */
|
||||
SVN_ERR(get_dag(&node, root, path, TRUE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(©from_rev, node));
|
||||
SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(©from_path, node));
|
||||
}
|
||||
@ -2628,7 +2505,7 @@ fs_file_length(svn_filesize_t *length_p,
|
||||
dag_node_t *file;
|
||||
|
||||
/* First create a dag_node_t from the root/path pair. */
|
||||
SVN_ERR(get_dag(&file, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&file, root, path, pool));
|
||||
|
||||
/* Now fetch its length */
|
||||
return svn_fs_fs__dag_file_length(length_p, file, pool);
|
||||
@ -2647,7 +2524,7 @@ fs_file_checksum(svn_checksum_t **checksum,
|
||||
{
|
||||
dag_node_t *file;
|
||||
|
||||
SVN_ERR(get_dag(&file, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&file, root, path, pool));
|
||||
return svn_fs_fs__dag_file_checksum(checksum, file, kind, pool);
|
||||
}
|
||||
|
||||
@ -2666,7 +2543,7 @@ fs_file_contents(svn_stream_t **contents,
|
||||
svn_stream_t *file_stream;
|
||||
|
||||
/* First create a dag_node_t from the root/path pair. */
|
||||
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
|
||||
/* Then create a readable stream from the dag_node_t. */
|
||||
SVN_ERR(svn_fs_fs__dag_get_contents(&file_stream, node, pool));
|
||||
@ -2689,7 +2566,7 @@ fs_try_process_file_contents(svn_boolean_t *success,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
dag_node_t *node;
|
||||
SVN_ERR(get_dag(&node, root, path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, root, path, pool));
|
||||
|
||||
return svn_fs_fs__dag_try_process_file_contents(success, node,
|
||||
processor, baton, pool);
|
||||
@ -3071,8 +2948,8 @@ fs_contents_changed(svn_boolean_t *changed_p,
|
||||
(SVN_ERR_FS_GENERAL, NULL, _("'%s' is not a file"), path2);
|
||||
}
|
||||
|
||||
SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
|
||||
SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
|
||||
SVN_ERR(get_dag(&node1, root1, path1, pool));
|
||||
SVN_ERR(get_dag(&node2, root2, path2, pool));
|
||||
return svn_fs_fs__dag_things_different(NULL, changed_p,
|
||||
node1, node2);
|
||||
}
|
||||
@ -3092,10 +2969,10 @@ fs_get_file_delta_stream(svn_txdelta_stream_t **stream_p,
|
||||
dag_node_t *source_node, *target_node;
|
||||
|
||||
if (source_root && source_path)
|
||||
SVN_ERR(get_dag(&source_node, source_root, source_path, TRUE, pool));
|
||||
SVN_ERR(get_dag(&source_node, source_root, source_path, pool));
|
||||
else
|
||||
source_node = NULL;
|
||||
SVN_ERR(get_dag(&target_node, target_root, target_path, TRUE, pool));
|
||||
SVN_ERR(get_dag(&target_node, target_root, target_path, pool));
|
||||
|
||||
/* Create a delta stream that turns the source into the target. */
|
||||
return svn_fs_fs__dag_get_file_delta_stream(stream_p, source_node,
|
||||
@ -3588,7 +3465,7 @@ history_prev(void *baton, apr_pool_t *pool)
|
||||
|
||||
SVN_ERR(svn_fs_fs__revision_root(©root_root, fs, copyroot_rev,
|
||||
pool));
|
||||
SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, FALSE, pool));
|
||||
SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, pool));
|
||||
copy_dst = svn_fs_fs__dag_get_created_path(node);
|
||||
|
||||
/* If our current path was the very destination of the copy,
|
||||
@ -3785,7 +3662,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs_root_t *root,
|
||||
svn_pool_clear(iterpool);
|
||||
|
||||
kid_path = svn_fspath__join(this_path, dirent->name, iterpool);
|
||||
SVN_ERR(get_dag(&kid_dag, root, kid_path, TRUE, iterpool));
|
||||
SVN_ERR(get_dag(&kid_dag, root, kid_path, iterpool));
|
||||
|
||||
SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, kid_dag));
|
||||
SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down, kid_dag));
|
||||
@ -4031,7 +3908,7 @@ add_descendant_mergeinfo(svn_mergeinfo_catalog_t result_catalog,
|
||||
dag_node_t *this_dag;
|
||||
svn_boolean_t go_down;
|
||||
|
||||
SVN_ERR(get_dag(&this_dag, root, path, TRUE, scratch_pool));
|
||||
SVN_ERR(get_dag(&this_dag, root, path, scratch_pool));
|
||||
SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down,
|
||||
this_dag));
|
||||
if (go_down)
|
||||
|
@ -2234,6 +2234,7 @@ close_edit(void *edit_baton,
|
||||
ctx->activity_url ? ctx->activity_url : ctx->txn_url;
|
||||
const svn_commit_info_t *commit_info;
|
||||
int response_code;
|
||||
svn_error_t *err = NULL;
|
||||
|
||||
/* MERGE our activity */
|
||||
SVN_ERR(svn_ra_serf__run_merge(&commit_info, &response_code,
|
||||
@ -2252,9 +2253,11 @@ close_edit(void *edit_baton,
|
||||
response_code);
|
||||
}
|
||||
|
||||
ctx->txn_url = NULL; /* If HTTPv2, the txn is now done */
|
||||
|
||||
/* Inform the WC that we did a commit. */
|
||||
if (ctx->callback)
|
||||
SVN_ERR(ctx->callback(commit_info, ctx->callback_baton, pool));
|
||||
err = ctx->callback(commit_info, ctx->callback_baton, pool);
|
||||
|
||||
/* If we're using activities, DELETE our completed activity. */
|
||||
if (ctx->activity_url)
|
||||
@ -2271,11 +2274,17 @@ close_edit(void *edit_baton,
|
||||
handler->response_handler = svn_ra_serf__expect_empty_body;
|
||||
handler->response_baton = handler;
|
||||
|
||||
SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
|
||||
ctx->activity_url = NULL; /* Don't try again in abort_edit() on fail */
|
||||
|
||||
SVN_ERR(svn_error_compose_create(
|
||||
err,
|
||||
svn_ra_serf__context_run_one(handler, pool)));
|
||||
|
||||
SVN_ERR_ASSERT(handler->sline.code == 204);
|
||||
}
|
||||
|
||||
SVN_ERR(err);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "svn_ra.h"
|
||||
#include "svn_dav.h"
|
||||
#include "svn_xml.h"
|
||||
#include "svn_ctype.h"
|
||||
|
||||
#include "../libsvn_ra/ra_loader.h"
|
||||
#include "svn_private_config.h"
|
||||
@ -227,7 +228,9 @@ capabilities_headers_iterator_callback(void *baton,
|
||||
}
|
||||
|
||||
/* SVN-specific headers -- if present, server supports HTTP protocol v2 */
|
||||
else if (strncmp(key, "SVN", 3) == 0)
|
||||
else if (!svn_ctype_casecmp(key[0], 'S')
|
||||
&& !svn_ctype_casecmp(key[1], 'V')
|
||||
&& !svn_ctype_casecmp(key[2], 'N'))
|
||||
{
|
||||
/* If we've not yet seen any information about supported POST
|
||||
requests, we'll initialize the list/hash with "create-txn"
|
||||
|
@ -777,6 +777,13 @@ close_edit(void *edit_baton,
|
||||
post_commit_err = svn_repos__post_commit_error_str(err, pool);
|
||||
svn_error_clear(err);
|
||||
}
|
||||
|
||||
/* Make sure a future abort doesn't perform
|
||||
any work. This may occur if the commit
|
||||
callback returns an error! */
|
||||
|
||||
eb->txn = NULL;
|
||||
eb->txn_root = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -40,6 +40,7 @@
|
||||
|
||||
#include <apr_lib.h>
|
||||
|
||||
#include "private/svn_repos_private.h"
|
||||
#include "private/svn_fspath.h"
|
||||
#include "private/svn_dep_compat.h"
|
||||
#include "private/svn_mergeinfo_private.h"
|
||||
@ -61,7 +62,7 @@ struct parse_baton
|
||||
const char *parent_dir; /* repository relpath, or NULL */
|
||||
svn_repos_notify_func_t notify_func;
|
||||
void *notify_baton;
|
||||
svn_repos_notify_t *notify;
|
||||
apr_pool_t *notify_pool; /* scratch pool for notifications */
|
||||
apr_pool_t *pool;
|
||||
|
||||
/* Start and end (inclusive) of revision range we'll pay attention
|
||||
@ -329,16 +330,7 @@ renumber_mergeinfo_revs(svn_string_t **final_val,
|
||||
SVN_ERR(svn_mergeinfo_merge2(final_mergeinfo, predates_stream_mergeinfo,
|
||||
subpool, subpool));
|
||||
|
||||
SVN_ERR(svn_mergeinfo_sort(final_mergeinfo, subpool));
|
||||
|
||||
/* Mergeinfo revision sources for r0 and r1 are invalid; you can't merge r0
|
||||
or r1. However, svndumpfilter can be abused to produce r1 merge source
|
||||
revs. So if we encounter any, then strip them out, no need to put them
|
||||
into the load target. */
|
||||
SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(&final_mergeinfo,
|
||||
final_mergeinfo,
|
||||
1, 0, FALSE,
|
||||
subpool, subpool));
|
||||
SVN_ERR(svn_mergeinfo__canonicalize_ranges(final_mergeinfo, subpool));
|
||||
|
||||
SVN_ERR(svn_mergeinfo_to_string(final_val, final_mergeinfo, pool));
|
||||
svn_pool_destroy(subpool);
|
||||
@ -502,9 +494,14 @@ new_revision_record(void **revision_baton,
|
||||
|
||||
if (pb->notify_func)
|
||||
{
|
||||
pb->notify->action = svn_repos_notify_load_txn_start;
|
||||
pb->notify->old_revision = rb->rev;
|
||||
pb->notify_func(pb->notify_baton, pb->notify, rb->pool);
|
||||
/* ### TODO: Use proper scratch pool instead of pb->notify_pool */
|
||||
svn_repos_notify_t *notify = svn_repos_notify_create(
|
||||
svn_repos_notify_load_txn_start,
|
||||
pb->notify_pool);
|
||||
|
||||
notify->old_revision = rb->rev;
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
|
||||
/* Stash the oldest "old" revision committed from the load stream. */
|
||||
@ -515,9 +512,14 @@ new_revision_record(void **revision_baton,
|
||||
/* If we're skipping this revision, try to notify someone. */
|
||||
if (rb->skipped && pb->notify_func)
|
||||
{
|
||||
pb->notify->action = svn_repos_notify_load_skipped_rev;
|
||||
pb->notify->old_revision = rb->rev;
|
||||
pb->notify_func(pb->notify_baton, pb->notify, rb->pool);
|
||||
/* ### TODO: Use proper scratch pool instead of pb->notify_pool */
|
||||
svn_repos_notify_t *notify = svn_repos_notify_create(
|
||||
svn_repos_notify_load_skipped_rev,
|
||||
pb->notify_pool);
|
||||
|
||||
notify->old_revision = rb->rev;
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
|
||||
/* If we're parsing revision 0, only the revision are (possibly)
|
||||
@ -586,8 +588,13 @@ maybe_add_with_history(struct node_baton *nb,
|
||||
|
||||
if (pb->notify_func)
|
||||
{
|
||||
pb->notify->action = svn_repos_notify_load_copied_node;
|
||||
pb->notify_func(pb->notify_baton, pb->notify, rb->pool);
|
||||
/* ### TODO: Use proper scratch pool instead of pb->notify_pool */
|
||||
svn_repos_notify_t *notify = svn_repos_notify_create(
|
||||
svn_repos_notify_load_copied_node,
|
||||
pb->notify_pool);
|
||||
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,10 +663,14 @@ new_node_record(void **node_baton,
|
||||
|
||||
if (pb->notify_func)
|
||||
{
|
||||
pb->notify->action = svn_repos_notify_load_node_start;
|
||||
pb->notify->node_action = nb->action;
|
||||
pb->notify->path = nb->path;
|
||||
pb->notify_func(pb->notify_baton, pb->notify, rb->pool);
|
||||
/* ### TODO: Use proper scratch pool instead of pb->notify_pool */
|
||||
svn_repos_notify_t *notify = svn_repos_notify_create(
|
||||
svn_repos_notify_load_node_start,
|
||||
pb->notify_pool);
|
||||
|
||||
notify->path = nb->path;
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
|
||||
switch (nb->action)
|
||||
@ -726,6 +737,67 @@ set_revision_property(void *baton,
|
||||
}
|
||||
|
||||
|
||||
/* Adjust mergeinfo:
|
||||
* - normalize line endings (if all CRLF, change to LF; but error if mixed);
|
||||
* - adjust revision numbers (see renumber_mergeinfo_revs());
|
||||
* - adjust paths (see prefix_mergeinfo_paths()).
|
||||
*/
|
||||
static svn_error_t *
|
||||
adjust_mergeinfo_property(struct revision_baton *rb,
|
||||
svn_string_t **new_value_p,
|
||||
const svn_string_t *old_value,
|
||||
apr_pool_t *result_pool)
|
||||
{
|
||||
struct parse_baton *pb = rb->pb;
|
||||
svn_string_t prop_val = *old_value;
|
||||
|
||||
/* Tolerate mergeinfo with "\r\n" line endings because some
|
||||
dumpstream sources might contain as much. If so normalize
|
||||
the line endings to '\n' and make a notification to
|
||||
PARSE_BATON->FEEDBACK_STREAM that we have made this
|
||||
correction. */
|
||||
if (strstr(prop_val.data, "\r"))
|
||||
{
|
||||
const char *prop_eol_normalized;
|
||||
|
||||
SVN_ERR(svn_subst_translate_cstring2(prop_val.data,
|
||||
&prop_eol_normalized,
|
||||
"\n", /* translate to LF */
|
||||
FALSE, /* no repair */
|
||||
NULL, /* no keywords */
|
||||
FALSE, /* no expansion */
|
||||
result_pool));
|
||||
prop_val.data = prop_eol_normalized;
|
||||
prop_val.len = strlen(prop_eol_normalized);
|
||||
|
||||
if (pb->notify_func)
|
||||
{
|
||||
/* ### TODO: Use proper scratch pool instead of pb->notify_pool */
|
||||
svn_repos_notify_t *notify
|
||||
= svn_repos_notify_create(
|
||||
svn_repos_notify_load_normalized_mergeinfo,
|
||||
pb->notify_pool);
|
||||
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
}
|
||||
|
||||
/* Renumber mergeinfo as appropriate. */
|
||||
SVN_ERR(renumber_mergeinfo_revs(new_value_p, &prop_val, rb,
|
||||
result_pool));
|
||||
if (pb->parent_dir)
|
||||
{
|
||||
/* Prefix the merge source paths with PB->parent_dir. */
|
||||
/* ASSUMPTION: All source paths are included in the dump stream. */
|
||||
SVN_ERR(prefix_mergeinfo_paths(new_value_p, *new_value_p,
|
||||
pb->parent_dir, result_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static svn_error_t *
|
||||
set_node_property(void *baton,
|
||||
const char *name,
|
||||
@ -739,51 +811,42 @@ set_node_property(void *baton,
|
||||
if (rb->skipped)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
/* Adjust mergeinfo. If this fails, presumably because the mergeinfo
|
||||
property has an ill-formed value, then we must not fail to load
|
||||
the repository (at least if it's a simple load with no revision
|
||||
offset adjustments, path changes, etc.) so just warn and leave it
|
||||
as it is. */
|
||||
if (strcmp(name, SVN_PROP_MERGEINFO) == 0)
|
||||
{
|
||||
svn_string_t *renumbered_mergeinfo;
|
||||
/* ### Need to cast away const. We cannot change the declaration of
|
||||
* ### this function since it is part of svn_repos_parse_fns2_t. */
|
||||
svn_string_t *prop_val = (svn_string_t *)value;
|
||||
svn_string_t *new_value;
|
||||
svn_error_t *err;
|
||||
|
||||
/* Tolerate mergeinfo with "\r\n" line endings because some
|
||||
dumpstream sources might contain as much. If so normalize
|
||||
the line endings to '\n' and make a notification to
|
||||
PARSE_BATON->FEEDBACK_STREAM that we have made this
|
||||
correction. */
|
||||
if (strstr(prop_val->data, "\r"))
|
||||
err = adjust_mergeinfo_property(rb, &new_value, value, nb->pool);
|
||||
if (err)
|
||||
{
|
||||
const char *prop_eol_normalized;
|
||||
|
||||
SVN_ERR(svn_subst_translate_cstring2(prop_val->data,
|
||||
&prop_eol_normalized,
|
||||
"\n", /* translate to LF */
|
||||
FALSE, /* no repair */
|
||||
NULL, /* no keywords */
|
||||
FALSE, /* no expansion */
|
||||
nb->pool));
|
||||
prop_val->data = prop_eol_normalized;
|
||||
prop_val->len = strlen(prop_eol_normalized);
|
||||
|
||||
if (pb->validate_props)
|
||||
{
|
||||
return svn_error_quick_wrap(
|
||||
err,
|
||||
_("Invalid svn:mergeinfo value"));
|
||||
}
|
||||
if (pb->notify_func)
|
||||
{
|
||||
pb->notify->action = svn_repos_notify_load_normalized_mergeinfo;
|
||||
pb->notify_func(pb->notify_baton, pb->notify, nb->pool);
|
||||
}
|
||||
}
|
||||
svn_repos_notify_t *notify
|
||||
= svn_repos_notify_create(svn_repos_notify_warning,
|
||||
pb->notify_pool);
|
||||
|
||||
/* Renumber mergeinfo as appropriate. */
|
||||
SVN_ERR(renumber_mergeinfo_revs(&renumbered_mergeinfo, prop_val, rb,
|
||||
nb->pool));
|
||||
value = renumbered_mergeinfo;
|
||||
if (pb->parent_dir)
|
||||
notify->warning = svn_repos__notify_warning_invalid_mergeinfo;
|
||||
notify->warning_str = _("Invalid svn:mergeinfo value; "
|
||||
"leaving unchanged");
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
svn_error_clear(err);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Prefix the merge source paths with PB->parent_dir. */
|
||||
/* ASSUMPTION: All source paths are included in the dump stream. */
|
||||
svn_string_t *mergeinfo_val;
|
||||
SVN_ERR(prefix_mergeinfo_paths(&mergeinfo_val, value,
|
||||
pb->parent_dir, nb->pool));
|
||||
value = mergeinfo_val;
|
||||
value = new_value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -896,8 +959,13 @@ close_node(void *baton)
|
||||
|
||||
if (pb->notify_func)
|
||||
{
|
||||
pb->notify->action = svn_repos_notify_load_node_done;
|
||||
pb->notify_func(pb->notify_baton, pb->notify, rb->pool);
|
||||
/* ### TODO: Use proper scratch pool instead of pb->notify_pool */
|
||||
svn_repos_notify_t *notify = svn_repos_notify_create(
|
||||
svn_repos_notify_load_node_done,
|
||||
pb->notify_pool);
|
||||
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -1016,12 +1084,17 @@ close_revision(void *baton)
|
||||
|
||||
if (pb->notify_func)
|
||||
{
|
||||
pb->notify->action = svn_repos_notify_load_txn_committed;
|
||||
pb->notify->new_revision = committed_rev;
|
||||
pb->notify->old_revision = ((committed_rev == rb->rev)
|
||||
/* ### TODO: Use proper scratch pool instead of pb->notify_pool */
|
||||
svn_repos_notify_t *notify = svn_repos_notify_create(
|
||||
svn_repos_notify_load_txn_committed,
|
||||
pb->notify_pool);
|
||||
|
||||
notify->new_revision = committed_rev;
|
||||
notify->old_revision = ((committed_rev == rb->rev)
|
||||
? SVN_INVALID_REVNUM
|
||||
: rb->rev);
|
||||
pb->notify_func(pb->notify_baton, pb->notify, rb->pool);
|
||||
pb->notify_func(pb->notify_baton, notify, pb->notify_pool);
|
||||
svn_pool_clear(pb->notify_pool);
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -1079,10 +1152,10 @@ svn_repos_get_fs_build_parser4(const svn_repos_parse_fns3_t **callbacks,
|
||||
pb->validate_props = validate_props;
|
||||
pb->notify_func = notify_func;
|
||||
pb->notify_baton = notify_baton;
|
||||
pb->notify = svn_repos_notify_create(svn_repos_notify_load_txn_start, pool);
|
||||
pb->uuid_action = uuid_action;
|
||||
pb->parent_dir = parent_dir;
|
||||
pb->pool = pool;
|
||||
pb->notify_pool = svn_pool_create(pool);
|
||||
pb->rev_map = apr_hash_make(pool);
|
||||
pb->oldest_old_rev = SVN_INVALID_REVNUM;
|
||||
pb->last_rev_mapped = SVN_INVALID_REVNUM;
|
||||
|
@ -726,23 +726,6 @@ svn_repos_trace_node_locations(svn_fs_t *fs,
|
||||
if (! prev_path)
|
||||
break;
|
||||
|
||||
if (authz_read_func)
|
||||
{
|
||||
svn_boolean_t readable;
|
||||
svn_fs_root_t *tmp_root;
|
||||
|
||||
SVN_ERR(svn_fs_revision_root(&tmp_root, fs, revision, currpool));
|
||||
SVN_ERR(authz_read_func(&readable, tmp_root, path,
|
||||
authz_read_baton, currpool));
|
||||
if (! readable)
|
||||
{
|
||||
svn_pool_destroy(lastpool);
|
||||
svn_pool_destroy(currpool);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign the current path to all younger revisions until we reach
|
||||
the copy target rev. */
|
||||
while ((revision_ptr < revision_ptr_end)
|
||||
@ -765,6 +748,20 @@ svn_repos_trace_node_locations(svn_fs_t *fs,
|
||||
path = prev_path;
|
||||
revision = prev_rev;
|
||||
|
||||
if (authz_read_func)
|
||||
{
|
||||
svn_boolean_t readable;
|
||||
SVN_ERR(svn_fs_revision_root(&root, fs, revision, currpool));
|
||||
SVN_ERR(authz_read_func(&readable, root, path,
|
||||
authz_read_baton, currpool));
|
||||
if (!readable)
|
||||
{
|
||||
svn_pool_destroy(lastpool);
|
||||
svn_pool_destroy(currpool);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear last pool and switch. */
|
||||
svn_pool_clear(lastpool);
|
||||
tmppool = lastpool;
|
||||
|
@ -101,6 +101,21 @@
|
||||
* on their hash key.
|
||||
*/
|
||||
|
||||
/* APR's read-write lock implementation on Windows is horribly inefficient.
|
||||
* Even with very low contention a runtime overhead of 35% percent has been
|
||||
* measured for 'svn-bench null-export' over ra_serf.
|
||||
*
|
||||
* Use a simple mutex on Windows. Because there is one mutex per segment,
|
||||
* large machines should (and usually can) be configured with large caches
|
||||
* such that read contention is kept low. This is basically the situation
|
||||
* we head before 1.8.
|
||||
*/
|
||||
#ifdef WIN32
|
||||
# define USE_SIMPLE_MUTEX 1
|
||||
#else
|
||||
# define USE_SIMPLE_MUTEX 0
|
||||
#endif
|
||||
|
||||
/* A 16-way associative cache seems to be a good compromise between
|
||||
* performance (worst-case lookups) and efficiency-loss due to collisions.
|
||||
*
|
||||
@ -465,11 +480,15 @@ struct svn_membuffer_t
|
||||
* the cache's creator doesn't feel the cache needs to be
|
||||
* thread-safe.
|
||||
*/
|
||||
# if USE_SIMPLE_MUTEX
|
||||
svn_mutex__t *lock;
|
||||
# else
|
||||
apr_thread_rwlock_t *lock;
|
||||
# endif
|
||||
|
||||
/* If set, write access will wait until they get exclusive access.
|
||||
* Otherwise, they will become no-ops if the segment is currently
|
||||
* read-locked.
|
||||
* read-locked. Only used when LOCK is an r/w lock.
|
||||
*/
|
||||
svn_boolean_t allow_blocking_writes;
|
||||
#endif
|
||||
@ -489,12 +508,16 @@ static svn_error_t *
|
||||
read_lock_cache(svn_membuffer_t *cache)
|
||||
{
|
||||
#if APR_HAS_THREADS
|
||||
# if USE_SIMPLE_MUTEX
|
||||
return svn_mutex__lock(cache->lock);
|
||||
# else
|
||||
if (cache->lock)
|
||||
{
|
||||
apr_status_t status = apr_thread_rwlock_rdlock(cache->lock);
|
||||
if (status)
|
||||
return svn_error_wrap_apr(status, _("Can't lock cache mutex"));
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -505,6 +528,12 @@ static svn_error_t *
|
||||
write_lock_cache(svn_membuffer_t *cache, svn_boolean_t *success)
|
||||
{
|
||||
#if APR_HAS_THREADS
|
||||
# if USE_SIMPLE_MUTEX
|
||||
|
||||
return svn_mutex__lock(cache->lock);
|
||||
|
||||
# else
|
||||
|
||||
if (cache->lock)
|
||||
{
|
||||
apr_status_t status;
|
||||
@ -526,6 +555,8 @@ write_lock_cache(svn_membuffer_t *cache, svn_boolean_t *success)
|
||||
return svn_error_wrap_apr(status,
|
||||
_("Can't write-lock cache mutex"));
|
||||
}
|
||||
|
||||
# endif
|
||||
#endif
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -537,10 +568,18 @@ static svn_error_t *
|
||||
force_write_lock_cache(svn_membuffer_t *cache)
|
||||
{
|
||||
#if APR_HAS_THREADS
|
||||
# if USE_SIMPLE_MUTEX
|
||||
|
||||
return svn_mutex__lock(cache->lock);
|
||||
|
||||
# else
|
||||
|
||||
apr_status_t status = apr_thread_rwlock_wrlock(cache->lock);
|
||||
if (status)
|
||||
return svn_error_wrap_apr(status,
|
||||
_("Can't write-lock cache mutex"));
|
||||
|
||||
# endif
|
||||
#endif
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -552,6 +591,12 @@ static svn_error_t *
|
||||
unlock_cache(svn_membuffer_t *cache, svn_error_t *err)
|
||||
{
|
||||
#if APR_HAS_THREADS
|
||||
# if USE_SIMPLE_MUTEX
|
||||
|
||||
return svn_mutex__unlock(cache->lock, err);
|
||||
|
||||
# else
|
||||
|
||||
if (cache->lock)
|
||||
{
|
||||
apr_status_t status = apr_thread_rwlock_unlock(cache->lock);
|
||||
@ -561,6 +606,8 @@ unlock_cache(svn_membuffer_t *cache, svn_error_t *err)
|
||||
if (status)
|
||||
return svn_error_wrap_apr(status, _("Can't unlock cache mutex"));
|
||||
}
|
||||
|
||||
# endif
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
@ -1290,6 +1337,12 @@ svn_cache__membuffer_cache_create(svn_membuffer_t **cache,
|
||||
* the cache's creator doesn't feel the cache needs to be
|
||||
* thread-safe.
|
||||
*/
|
||||
# if USE_SIMPLE_MUTEX
|
||||
|
||||
SVN_ERR(svn_mutex__init(&c[seg].lock, thread_safe, pool));
|
||||
|
||||
# else
|
||||
|
||||
c[seg].lock = NULL;
|
||||
if (thread_safe)
|
||||
{
|
||||
@ -1299,6 +1352,8 @@ svn_cache__membuffer_cache_create(svn_membuffer_t **cache,
|
||||
return svn_error_wrap_apr(status, _("Can't create cache mutex"));
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
/* Select the behavior of write operations.
|
||||
*/
|
||||
c[seg].allow_blocking_writes = allow_blocking_writes;
|
||||
|
@ -487,14 +487,15 @@ make_string_from_option(const char **valuep, svn_config_t *cfg,
|
||||
expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
|
||||
opt->expanded = TRUE;
|
||||
|
||||
if (!x_pool)
|
||||
if (x_pool != cfg->x_pool)
|
||||
{
|
||||
/* Grab the fully expanded value from tmp_pool before its
|
||||
disappearing act. */
|
||||
if (opt->x_value)
|
||||
opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value,
|
||||
strlen(opt->x_value));
|
||||
svn_pool_destroy(tmp_pool);
|
||||
if (!x_pool)
|
||||
svn_pool_destroy(tmp_pool);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "svn_private_config.h"
|
||||
|
||||
#include "private/svn_mutex.h"
|
||||
#include "private/svn_atomic.h"
|
||||
|
||||
/* A mutex to protect our global pool and cache. */
|
||||
static svn_mutex__t *dso_mutex = NULL;
|
||||
@ -41,18 +42,18 @@ static apr_hash_t *dso_cache;
|
||||
/* Just an arbitrary location in memory... */
|
||||
static int not_there_sentinel;
|
||||
|
||||
static volatile svn_atomic_t atomic_init_status = 0;
|
||||
|
||||
/* A specific value we store in the dso_cache to indicate that the
|
||||
library wasn't found. This keeps us from allocating extra memory
|
||||
from dso_pool when trying to find libraries we already know aren't
|
||||
there. */
|
||||
#define NOT_THERE ((void *) ¬_there_sentinel)
|
||||
|
||||
svn_error_t *
|
||||
svn_dso_initialize2(void)
|
||||
static svn_error_t *
|
||||
atomic_init_func(void *baton,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
if (dso_pool)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
dso_pool = svn_pool_create(NULL);
|
||||
|
||||
SVN_ERR(svn_mutex__init(&dso_mutex, TRUE, dso_pool));
|
||||
@ -61,6 +62,15 @@ svn_dso_initialize2(void)
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
svn_error_t *
|
||||
svn_dso_initialize2(void)
|
||||
{
|
||||
SVN_ERR(svn_atomic__init_once(&atomic_init_status, atomic_init_func,
|
||||
NULL, NULL));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
#if APR_HAS_DSO
|
||||
static svn_error_t *
|
||||
svn_dso_load_internal(apr_dso_handle_t **dso, const char *fname)
|
||||
@ -107,8 +117,7 @@ svn_dso_load_internal(apr_dso_handle_t **dso, const char *fname)
|
||||
svn_error_t *
|
||||
svn_dso_load(apr_dso_handle_t **dso, const char *fname)
|
||||
{
|
||||
if (! dso_pool)
|
||||
SVN_ERR(svn_dso_initialize2());
|
||||
SVN_ERR(svn_dso_initialize2());
|
||||
|
||||
SVN_MUTEX__WITH_LOCK(dso_mutex, svn_dso_load_internal(dso, fname));
|
||||
|
||||
|
@ -289,6 +289,8 @@ svn_error_compose(svn_error_t *chain, svn_error_t *new_err)
|
||||
*chain = *new_err;
|
||||
if (chain->message)
|
||||
chain->message = apr_pstrdup(pool, new_err->message);
|
||||
if (chain->file)
|
||||
chain->file = apr_pstrdup(pool, new_err->file);
|
||||
chain->pool = pool;
|
||||
#if defined(SVN_DEBUG)
|
||||
if (! new_err->child)
|
||||
@ -358,6 +360,8 @@ svn_error_dup(svn_error_t *err)
|
||||
tmp_err->pool = pool;
|
||||
if (tmp_err->message)
|
||||
tmp_err->message = apr_pstrdup(pool, tmp_err->message);
|
||||
if (tmp_err->file)
|
||||
tmp_err->file = apr_pstrdup(pool, tmp_err->file);
|
||||
}
|
||||
|
||||
#if defined(SVN_DEBUG)
|
||||
|
@ -72,6 +72,9 @@
|
||||
#include "svn_cmdline.h"
|
||||
#include "svn_checksum.h"
|
||||
#include "svn_string.h"
|
||||
#include "svn_hash.h"
|
||||
#include "svn_user.h"
|
||||
#include "svn_dirent_uri.h"
|
||||
|
||||
#include "private/svn_auth_private.h"
|
||||
|
||||
@ -80,6 +83,7 @@
|
||||
#ifdef SVN_HAVE_GPG_AGENT
|
||||
|
||||
#define BUFFER_SIZE 1024
|
||||
#define ATTEMPT_PARAMETER "svn.simple.gpg_agent.attempt"
|
||||
|
||||
/* Modify STR in-place such that blanks are escaped as required by the
|
||||
* gpg-agent protocol. Return a pointer to STR. */
|
||||
@ -98,6 +102,24 @@ escape_blanks(char *str)
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Generate the string CACHE_ID_P based on the REALMSTRING allocated in
|
||||
* RESULT_POOL using SCRATCH_POOL for temporary allocations. This is similar
|
||||
* to other password caching mechanisms. */
|
||||
static svn_error_t *
|
||||
get_cache_id(const char **cache_id_p, const char *realmstring,
|
||||
apr_pool_t *scratch_pool, apr_pool_t *result_pool)
|
||||
{
|
||||
const char *cache_id = NULL;
|
||||
svn_checksum_t *digest = NULL;
|
||||
|
||||
SVN_ERR(svn_checksum(&digest, svn_checksum_md5, realmstring,
|
||||
strlen(realmstring), scratch_pool));
|
||||
cache_id = svn_checksum_to_cstring(digest, result_pool);
|
||||
*cache_id_p = cache_id;
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Attempt to read a gpg-agent response message from the socket SD into
|
||||
* buffer BUF. Buf is assumed to be N bytes large. Return TRUE if a response
|
||||
* message could be read that fits into the buffer. Else return FALSE.
|
||||
@ -156,6 +178,17 @@ send_option(int sd, char *buf, size_t n, const char *option, const char *value,
|
||||
return (strncmp(buf, "OK", 2) == 0);
|
||||
}
|
||||
|
||||
/* Send the BYE command and disconnect from the gpg-agent. Doing this avoids
|
||||
* gpg-agent emitting a "Connection reset by peer" log message with some
|
||||
* versions of gpg-agent. */
|
||||
static void
|
||||
bye_gpg_agent(int sd)
|
||||
{
|
||||
/* don't bother to check the result of the write, it either worked or it
|
||||
* didn't, but either way we're closing. */
|
||||
write(sd, "BYE\n", 4);
|
||||
close(sd);
|
||||
}
|
||||
|
||||
/* Locate a running GPG Agent, and return an open file descriptor
|
||||
* for communication with the agent in *NEW_SD. If no running agent
|
||||
@ -173,17 +206,34 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)
|
||||
|
||||
*new_sd = -1;
|
||||
|
||||
/* This implements the method of finding the socket as described in
|
||||
* the gpg-agent man page under the --use-standard-socket option.
|
||||
* The manage page misleadingly says the standard socket is
|
||||
* "named 'S.gpg-agent' located in the home directory." The standard
|
||||
* socket path is actually in the .gnupg directory in the home directory,
|
||||
* i.e. ~/.gnupg/S.gpg-agent */
|
||||
gpg_agent_info = getenv("GPG_AGENT_INFO");
|
||||
if (gpg_agent_info != NULL)
|
||||
{
|
||||
apr_array_header_t *socket_details;
|
||||
|
||||
/* For reference GPG_AGENT_INFO consists of 3 : separated fields.
|
||||
* The path to the socket, the pid of the gpg-agent process and
|
||||
* finally the version of the protocol the agent talks. */
|
||||
socket_details = svn_cstring_split(gpg_agent_info, ":", TRUE,
|
||||
pool);
|
||||
socket_name = APR_ARRAY_IDX(socket_details, 0, const char *);
|
||||
}
|
||||
else
|
||||
return SVN_NO_ERROR;
|
||||
{
|
||||
const char *homedir = svn_user_get_homedir(pool);
|
||||
|
||||
if (!homedir)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
socket_name = svn_dirent_join_many(pool, homedir, ".gnupg",
|
||||
"S.gpg-agent", NULL);
|
||||
}
|
||||
|
||||
if (socket_name != NULL)
|
||||
{
|
||||
@ -210,13 +260,13 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)
|
||||
buffer = apr_palloc(pool, BUFFER_SIZE);
|
||||
if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE))
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(buffer, "OK", 2) != 0)
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -226,19 +276,19 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)
|
||||
request = "GETINFO socket_name\n";
|
||||
if (write(sd, request, strlen(request)) == -1)
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE))
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
if (strncmp(buffer, "D", 1) == 0)
|
||||
p = &buffer[2];
|
||||
if (!p)
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
ep = strchr(p, '\n');
|
||||
@ -246,18 +296,18 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)
|
||||
*ep = '\0';
|
||||
if (strcmp(socket_name, p) != 0)
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
/* The agent will terminate its response with "OK". */
|
||||
if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE))
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
if (strncmp(buffer, "OK", 2) != 0)
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -265,6 +315,55 @@ find_running_gpg_agent(int *new_sd, apr_pool_t *pool)
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_boolean_t
|
||||
send_options(int sd, char *buf, size_t n, apr_pool_t *scratch_pool)
|
||||
{
|
||||
const char *tty_name;
|
||||
const char *tty_type;
|
||||
const char *lc_ctype;
|
||||
const char *display;
|
||||
|
||||
/* Send TTY_NAME to the gpg-agent daemon. */
|
||||
tty_name = getenv("GPG_TTY");
|
||||
if (tty_name != NULL)
|
||||
{
|
||||
if (!send_option(sd, buf, n, "ttyname", tty_name, scratch_pool))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Send TTY_TYPE to the gpg-agent daemon. */
|
||||
tty_type = getenv("TERM");
|
||||
if (tty_type != NULL)
|
||||
{
|
||||
if (!send_option(sd, buf, n, "ttytype", tty_type, scratch_pool))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Compute LC_CTYPE. */
|
||||
lc_ctype = getenv("LC_ALL");
|
||||
if (lc_ctype == NULL)
|
||||
lc_ctype = getenv("LC_CTYPE");
|
||||
if (lc_ctype == NULL)
|
||||
lc_ctype = getenv("LANG");
|
||||
|
||||
/* Send LC_CTYPE to the gpg-agent daemon. */
|
||||
if (lc_ctype != NULL)
|
||||
{
|
||||
if (!send_option(sd, buf, n, "lc-ctype", lc_ctype, scratch_pool))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Send DISPLAY to the gpg-agent daemon. */
|
||||
display = getenv("DISPLAY");
|
||||
if (display != NULL)
|
||||
{
|
||||
if (!send_option(sd, buf, n, "display", display, scratch_pool))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Implementation of svn_auth__password_get_t that retrieves the password
|
||||
from gpg-agent */
|
||||
static svn_error_t *
|
||||
@ -283,101 +382,59 @@ password_get_gpg_agent(svn_boolean_t *done,
|
||||
char *buffer;
|
||||
const char *request = NULL;
|
||||
const char *cache_id = NULL;
|
||||
const char *tty_name;
|
||||
const char *tty_type;
|
||||
const char *lc_ctype;
|
||||
const char *display;
|
||||
svn_checksum_t *digest = NULL;
|
||||
char *password_prompt;
|
||||
char *realm_prompt;
|
||||
char *error_prompt;
|
||||
int *attempt;
|
||||
|
||||
*done = FALSE;
|
||||
|
||||
attempt = svn_hash_gets(parameters, ATTEMPT_PARAMETER);
|
||||
|
||||
SVN_ERR(find_running_gpg_agent(&sd, pool));
|
||||
if (sd == -1)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
buffer = apr_palloc(pool, BUFFER_SIZE);
|
||||
|
||||
/* Send TTY_NAME to the gpg-agent daemon. */
|
||||
tty_name = getenv("GPG_TTY");
|
||||
if (tty_name != NULL)
|
||||
if (!send_options(sd, buffer, BUFFER_SIZE, pool))
|
||||
{
|
||||
if (!send_option(sd, buffer, BUFFER_SIZE, "ttyname", tty_name, pool))
|
||||
{
|
||||
close(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Send TTY_TYPE to the gpg-agent daemon. */
|
||||
tty_type = getenv("TERM");
|
||||
if (tty_type != NULL)
|
||||
{
|
||||
if (!send_option(sd, buffer, BUFFER_SIZE, "ttytype", tty_type, pool))
|
||||
{
|
||||
close(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute LC_CTYPE. */
|
||||
lc_ctype = getenv("LC_ALL");
|
||||
if (lc_ctype == NULL)
|
||||
lc_ctype = getenv("LC_CTYPE");
|
||||
if (lc_ctype == NULL)
|
||||
lc_ctype = getenv("LANG");
|
||||
|
||||
/* Send LC_CTYPE to the gpg-agent daemon. */
|
||||
if (lc_ctype != NULL)
|
||||
{
|
||||
if (!send_option(sd, buffer, BUFFER_SIZE, "lc-ctype", lc_ctype, pool))
|
||||
{
|
||||
close(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send DISPLAY to the gpg-agent daemon. */
|
||||
display = getenv("DISPLAY");
|
||||
if (display != NULL)
|
||||
{
|
||||
if (!send_option(sd, buffer, BUFFER_SIZE, "display", display, pool))
|
||||
{
|
||||
close(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the CACHE_ID which will be generated based on REALMSTRING similar
|
||||
to other password caching mechanisms. */
|
||||
SVN_ERR(svn_checksum(&digest, svn_checksum_md5, realmstring,
|
||||
strlen(realmstring), pool));
|
||||
cache_id = svn_checksum_to_cstring(digest, pool);
|
||||
SVN_ERR(get_cache_id(&cache_id, realmstring, pool, pool));
|
||||
|
||||
password_prompt = apr_psprintf(pool, _("Password for '%s': "), username);
|
||||
realm_prompt = apr_psprintf(pool, _("Enter your Subversion password for %s"),
|
||||
realmstring);
|
||||
if (*attempt == 1)
|
||||
/* X means no error to the gpg-agent protocol */
|
||||
error_prompt = apr_pstrdup(pool, "X");
|
||||
else
|
||||
error_prompt = apr_pstrdup(pool, _("Authentication failed"));
|
||||
|
||||
request = apr_psprintf(pool,
|
||||
"GET_PASSPHRASE --data %s--repeat=1 "
|
||||
"%s X %s %s\n",
|
||||
"GET_PASSPHRASE --data %s"
|
||||
"%s %s %s %s\n",
|
||||
non_interactive ? "--no-ask " : "",
|
||||
cache_id,
|
||||
escape_blanks(error_prompt),
|
||||
escape_blanks(password_prompt),
|
||||
escape_blanks(realm_prompt));
|
||||
|
||||
if (write(sd, request, strlen(request)) == -1)
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE))
|
||||
{
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
|
||||
if (strncmp(buffer, "ERR", 3) == 0)
|
||||
return SVN_NO_ERROR;
|
||||
@ -424,7 +481,7 @@ password_set_gpg_agent(svn_boolean_t *done,
|
||||
if (sd == -1)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
close(sd);
|
||||
bye_gpg_agent(sd);
|
||||
*done = TRUE;
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
@ -440,11 +497,108 @@ simple_gpg_agent_first_creds(void **credentials,
|
||||
const char *realmstring,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
return svn_auth__simple_creds_cache_get(credentials, iter_baton,
|
||||
provider_baton, parameters,
|
||||
realmstring, password_get_gpg_agent,
|
||||
SVN_AUTH__GPG_AGENT_PASSWORD_TYPE,
|
||||
pool);
|
||||
svn_error_t *err;
|
||||
int *attempt = apr_palloc(pool, sizeof(*attempt));
|
||||
|
||||
*attempt = 1;
|
||||
svn_hash_sets(parameters, ATTEMPT_PARAMETER, attempt);
|
||||
err = svn_auth__simple_creds_cache_get(credentials, iter_baton,
|
||||
provider_baton, parameters,
|
||||
realmstring, password_get_gpg_agent,
|
||||
SVN_AUTH__GPG_AGENT_PASSWORD_TYPE,
|
||||
pool);
|
||||
*iter_baton = attempt;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* An implementation of svn_auth_provider_t::next_credentials() */
|
||||
static svn_error_t *
|
||||
simple_gpg_agent_next_creds(void **credentials,
|
||||
void *iter_baton,
|
||||
void *provider_baton,
|
||||
apr_hash_t *parameters,
|
||||
const char *realmstring,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
int *attempt = (int *)iter_baton;
|
||||
int sd;
|
||||
char *buffer;
|
||||
const char *cache_id = NULL;
|
||||
const char *request = NULL;
|
||||
|
||||
*credentials = NULL;
|
||||
|
||||
/* The users previous credentials failed so first remove the cached entry,
|
||||
* before trying to retrieve them again. Because gpg-agent stores cached
|
||||
* credentials immediately upon retrieving them, this gives us the
|
||||
* opportunity to remove the invalid credentials and prompt the
|
||||
* user again. While it's possible that server side issues could trigger
|
||||
* this, this cache is ephemeral so at worst we're just speeding up
|
||||
* when the user would need to re-enter their password. */
|
||||
|
||||
if (svn_hash_gets(parameters, SVN_AUTH_PARAM_NON_INTERACTIVE))
|
||||
{
|
||||
/* In this case since we're running non-interactively we do not
|
||||
* want to clear the cache since the user was never prompted by
|
||||
* gpg-agent to set a password. */
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
*attempt = *attempt + 1;
|
||||
|
||||
SVN_ERR(find_running_gpg_agent(&sd, pool));
|
||||
if (sd == -1)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
buffer = apr_palloc(pool, BUFFER_SIZE);
|
||||
|
||||
if (!send_options(sd, buffer, BUFFER_SIZE, pool))
|
||||
{
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
SVN_ERR(get_cache_id(&cache_id, realmstring, pool, pool));
|
||||
|
||||
request = apr_psprintf(pool, "CLEAR_PASSPHRASE %s\n", cache_id);
|
||||
|
||||
if (write(sd, request, strlen(request)) == -1)
|
||||
{
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
if (!receive_from_gpg_agent(sd, buffer, BUFFER_SIZE))
|
||||
{
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(buffer, "OK\n", 3) != 0)
|
||||
{
|
||||
bye_gpg_agent(sd);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* TODO: This attempt limit hard codes it at 3 attempts (or 2 retries)
|
||||
* which matches svn command line client's retry_limit as set in
|
||||
* svn_cmdline_create_auth_baton(). It would be nice to have that
|
||||
* limit reflected here but that violates the boundry between the
|
||||
* prompt provider and the cache provider. gpg-agent is acting as
|
||||
* both here due to the peculiarties of their design so we'll have to
|
||||
* live with this for now. Note that when these failures get exceeded
|
||||
* it'll eventually fall back on the retry limits of whatever prompt
|
||||
* provider is in effect, so this effectively doubles the limit. */
|
||||
if (*attempt < 4)
|
||||
return svn_auth__simple_creds_cache_get(credentials, &iter_baton,
|
||||
provider_baton, parameters,
|
||||
realmstring,
|
||||
password_get_gpg_agent,
|
||||
SVN_AUTH__GPG_AGENT_PASSWORD_TYPE,
|
||||
pool);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
@ -468,7 +622,7 @@ simple_gpg_agent_save_creds(svn_boolean_t *saved,
|
||||
static const svn_auth_provider_t gpg_agent_simple_provider = {
|
||||
SVN_AUTH_CRED_SIMPLE,
|
||||
simple_gpg_agent_first_creds,
|
||||
NULL,
|
||||
simple_gpg_agent_next_creds,
|
||||
simple_gpg_agent_save_creds
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This file is automatically generated from internal_statements.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_subr/token-map.h.
|
||||
/* This file is automatically generated from internal_statements.sql and .dist_sandbox/subversion-1.8.14/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
|
||||
|
@ -4675,8 +4675,25 @@ svn_io_open_unique_file3(apr_file_t **file,
|
||||
* case, but only if the umask allows it. */
|
||||
if (!using_system_temp_dir)
|
||||
{
|
||||
svn_error_t *err;
|
||||
|
||||
SVN_ERR(merge_default_file_perms(tempfile, &perms, scratch_pool));
|
||||
SVN_ERR(file_perms_set2(tempfile, perms, scratch_pool));
|
||||
err = file_perms_set2(tempfile, perms, scratch_pool);
|
||||
if (err)
|
||||
{
|
||||
if (APR_STATUS_IS_INCOMPLETE(err->apr_err) ||
|
||||
APR_STATUS_IS_ENOTIMPL(err->apr_err))
|
||||
svn_error_clear(err);
|
||||
else
|
||||
{
|
||||
const char *message;
|
||||
message = apr_psprintf(scratch_pool,
|
||||
_("Can't set permissions on '%s'"),
|
||||
svn_dirent_local_style(tempname,
|
||||
scratch_pool));
|
||||
return svn_error_quick_wrap(err, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -611,6 +611,43 @@ svn_rangelist__parse(svn_rangelist_t **rangelist,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Return TRUE, if all ranges in RANGELIST are in ascending order and do
|
||||
* not overlap and are not adjacent.
|
||||
*
|
||||
* ### Can yield false negatives: ranges of differing inheritance are
|
||||
* allowed to be adjacent.
|
||||
*
|
||||
* If this returns FALSE, you probaly want to qsort() the
|
||||
* ranges and then call svn_rangelist__combine_adjacent_ranges().
|
||||
*/
|
||||
static svn_boolean_t
|
||||
is_rangelist_normalized(svn_rangelist_t *rangelist)
|
||||
{
|
||||
int i;
|
||||
svn_merge_range_t **ranges = (svn_merge_range_t **)rangelist->elts;
|
||||
|
||||
for (i = 0; i < rangelist->nelts-1; ++i)
|
||||
if (ranges[i]->end >= ranges[i+1]->start)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
svn_error_t *
|
||||
svn_rangelist__canonicalize(svn_rangelist_t *rangelist,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
if (! is_rangelist_normalized(rangelist))
|
||||
{
|
||||
qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
|
||||
svn_sort_compare_ranges);
|
||||
|
||||
SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
svn_error_t *
|
||||
svn_rangelist__combine_adjacent_ranges(svn_rangelist_t *rangelist,
|
||||
apr_pool_t *scratch_pool)
|
||||
@ -692,15 +729,11 @@ parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,
|
||||
if (*input != end)
|
||||
*input = *input + 1;
|
||||
|
||||
/* Sort the rangelist, combine adjacent ranges into single ranges,
|
||||
and make sure there are no overlapping ranges. */
|
||||
if (rangelist->nelts > 1)
|
||||
{
|
||||
qsort(rangelist->elts, rangelist->nelts, rangelist->elt_size,
|
||||
svn_sort_compare_ranges);
|
||||
|
||||
SVN_ERR(svn_rangelist__combine_adjacent_ranges(rangelist, scratch_pool));
|
||||
}
|
||||
/* Sort the rangelist, combine adjacent ranges into single ranges, and
|
||||
make sure there are no overlapping ranges. Luckily, most data in
|
||||
svn:mergeinfo will already be in normalized form and this will be quick.
|
||||
*/
|
||||
SVN_ERR(svn_rangelist__canonicalize(rangelist, scratch_pool));
|
||||
|
||||
/* Handle any funky mergeinfo with relative merge source paths that
|
||||
might exist due to issue #3547. It's possible that this issue allowed
|
||||
@ -1973,6 +2006,22 @@ svn_mergeinfo_sort(svn_mergeinfo_t input, apr_pool_t *pool)
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
svn_error_t *
|
||||
svn_mergeinfo__canonicalize_ranges(svn_mergeinfo_t mergeinfo,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
apr_hash_index_t *hi;
|
||||
|
||||
for (hi = apr_hash_first(scratch_pool, mergeinfo); hi; hi = apr_hash_next(hi))
|
||||
{
|
||||
apr_array_header_t *rl = svn__apr_hash_index_val(hi);
|
||||
|
||||
SVN_ERR(svn_rangelist__canonicalize(rl, scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
svn_mergeinfo_catalog_t
|
||||
svn_mergeinfo_catalog_dup(svn_mergeinfo_catalog_t mergeinfo_catalog,
|
||||
apr_pool_t *pool)
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
/* Include sqlite3 inline, making all symbols private. */
|
||||
#ifdef SVN_SQLITE_INLINE
|
||||
# define SQLITE_OMIT_DEPRECATED
|
||||
# define SQLITE_OMIT_DEPRECATED 1
|
||||
# define SQLITE_API static
|
||||
# if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6 || __APPLE_CC__))
|
||||
# if !__APPLE_CC__ || __GNUC_MINOR__ >= 6
|
||||
|
@ -619,7 +619,7 @@ svn_stringbuf_insert(svn_stringbuf_t *str,
|
||||
if (bytes + count > str->data && bytes < str->data + str->blocksize)
|
||||
{
|
||||
/* special case: BYTES overlaps with this string -> copy the source */
|
||||
const char *temp = apr_pstrndup(str->pool, bytes, count);
|
||||
const char *temp = apr_pmemdup(str->pool, bytes, count);
|
||||
svn_stringbuf_insert(str, pos, temp, count);
|
||||
}
|
||||
else
|
||||
@ -659,7 +659,7 @@ svn_stringbuf_replace(svn_stringbuf_t *str,
|
||||
if (bytes + new_count > str->data && bytes < str->data + str->blocksize)
|
||||
{
|
||||
/* special case: BYTES overlaps with this string -> copy the source */
|
||||
const char *temp = apr_pstrndup(str->pool, bytes, new_count);
|
||||
const char *temp = apr_pmemdup(str->pool, bytes, new_count);
|
||||
svn_stringbuf_replace(str, pos, old_count, temp, new_count);
|
||||
}
|
||||
else
|
||||
|
@ -136,7 +136,7 @@ svn_version_extended(svn_boolean_t verbose,
|
||||
info->build_time = NULL;
|
||||
info->build_host = SVN_BUILD_HOST;
|
||||
info->copyright = apr_pstrdup
|
||||
(pool, _("Copyright (C) 2014 The Apache Software Foundation.\n"
|
||||
(pool, _("Copyright (C) 2015 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 "
|
||||
|
@ -965,7 +965,8 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
|
||||
repos_relpath,
|
||||
repos_root_url, repos_uuid,
|
||||
copyfrom_rev,
|
||||
NULL /* children */, FALSE, depth,
|
||||
NULL /* children */, depth,
|
||||
FALSE /* is_move */,
|
||||
NULL /* conflicts */,
|
||||
NULL /* work items */,
|
||||
scratch_pool));
|
||||
|
@ -67,69 +67,13 @@ can_be_cleaned(int *wc_format,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Do a modifed check for LOCAL_ABSPATH, and all working children, to force
|
||||
timestamp repair. */
|
||||
/* Dummy svn_wc_status_func4_t implementation */
|
||||
static svn_error_t *
|
||||
repair_timestamps(svn_wc__db_t *db,
|
||||
const char *local_abspath,
|
||||
svn_cancel_func_t cancel_func,
|
||||
void *cancel_baton,
|
||||
apr_pool_t *scratch_pool)
|
||||
status_dummy_callback(void *baton,
|
||||
const char *local_abspath,
|
||||
const svn_wc_status3_t *status,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
svn_node_kind_t kind;
|
||||
svn_wc__db_status_t status;
|
||||
|
||||
if (cancel_func)
|
||||
SVN_ERR(cancel_func(cancel_baton));
|
||||
|
||||
SVN_ERR(svn_wc__db_read_info(&status, &kind,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
db, local_abspath, scratch_pool, scratch_pool));
|
||||
|
||||
if (status == svn_wc__db_status_server_excluded
|
||||
|| status == svn_wc__db_status_deleted
|
||||
|| status == svn_wc__db_status_excluded
|
||||
|| status == svn_wc__db_status_not_present)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
if (kind == svn_node_file
|
||||
|| kind == svn_node_symlink)
|
||||
{
|
||||
svn_boolean_t modified;
|
||||
SVN_ERR(svn_wc__internal_file_modified_p(&modified,
|
||||
db, local_abspath, FALSE,
|
||||
scratch_pool));
|
||||
}
|
||||
else if (kind == svn_node_dir)
|
||||
{
|
||||
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
|
||||
const apr_array_header_t *children;
|
||||
int i;
|
||||
|
||||
SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
|
||||
local_abspath,
|
||||
scratch_pool,
|
||||
iterpool));
|
||||
for (i = 0; i < children->nelts; ++i)
|
||||
{
|
||||
const char *child_abspath;
|
||||
|
||||
svn_pool_clear(iterpool);
|
||||
|
||||
child_abspath = svn_dirent_join(local_abspath,
|
||||
APR_ARRAY_IDX(children, i,
|
||||
const char *),
|
||||
iterpool);
|
||||
|
||||
SVN_ERR(repair_timestamps(db, child_abspath,
|
||||
cancel_func, cancel_baton, iterpool));
|
||||
}
|
||||
svn_pool_destroy(iterpool);
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -184,8 +128,17 @@ cleanup_internal(svn_wc__db_t *db,
|
||||
SVN_ERR(svn_wc__db_pristine_cleanup(db, dir_abspath, scratch_pool));
|
||||
}
|
||||
|
||||
SVN_ERR(repair_timestamps(db, dir_abspath, cancel_func, cancel_baton,
|
||||
scratch_pool));
|
||||
/* Instead of implementing a separate repair step here, use the standard
|
||||
status walker's optimized implementation, which performs repairs when
|
||||
there is a lock. */
|
||||
SVN_ERR(svn_wc__internal_walk_status(db, dir_abspath, svn_depth_infinity,
|
||||
FALSE /* get_all */,
|
||||
FALSE /* no_ignore */,
|
||||
FALSE /* ignore_text_mods */,
|
||||
NULL /* ignore patterns */,
|
||||
status_dummy_callback, NULL,
|
||||
cancel_func, cancel_baton,
|
||||
scratch_pool));
|
||||
|
||||
/* All done, toss the lock */
|
||||
SVN_ERR(svn_wc__db_wclock_release(db, dir_abspath, scratch_pool));
|
||||
|
@ -1642,7 +1642,13 @@ eval_text_conflict_func_result(svn_skel_t **work_items,
|
||||
}
|
||||
}
|
||||
|
||||
SVN_ERR_ASSERT(install_from_abspath != NULL);
|
||||
if (install_from_abspath == NULL)
|
||||
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
|
||||
_("Conflict on '%s' could not be resolved "
|
||||
"because the chosen version of the file "
|
||||
"is not available."),
|
||||
svn_dirent_local_style(local_abspath,
|
||||
scratch_pool));
|
||||
|
||||
{
|
||||
svn_skel_t *work_item;
|
||||
@ -1761,6 +1767,7 @@ resolve_text_conflict(svn_skel_t **work_items,
|
||||
svn_skel_t *work_item;
|
||||
svn_wc_conflict_description2_t *cdesc;
|
||||
apr_hash_t *props;
|
||||
const char *mime_type;
|
||||
|
||||
*work_items = NULL;
|
||||
*was_resolved = FALSE;
|
||||
@ -1773,8 +1780,9 @@ resolve_text_conflict(svn_skel_t **work_items,
|
||||
|
||||
cdesc = svn_wc_conflict_description_create_text2(local_abspath,
|
||||
scratch_pool);
|
||||
cdesc->is_binary = FALSE;
|
||||
cdesc->mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
|
||||
mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
|
||||
cdesc->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
|
||||
cdesc->mime_type = mime_type;
|
||||
cdesc->base_abspath = left_abspath;
|
||||
cdesc->their_abspath = right_abspath;
|
||||
cdesc->my_abspath = detranslated_target;
|
||||
@ -2262,6 +2270,8 @@ svn_wc__read_conflicts(const apr_array_header_t **conflicts,
|
||||
|
||||
if (text_conflicted)
|
||||
{
|
||||
apr_hash_t *props;
|
||||
const char *mime_type;
|
||||
svn_wc_conflict_description2_t *desc;
|
||||
desc = svn_wc_conflict_description_create_text2(local_abspath,
|
||||
result_pool);
|
||||
@ -2270,6 +2280,12 @@ svn_wc__read_conflicts(const apr_array_header_t **conflicts,
|
||||
desc->src_left_version = left_version;
|
||||
desc->src_right_version = right_version;
|
||||
|
||||
SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
|
||||
desc->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
|
||||
desc->mime_type = mime_type;
|
||||
|
||||
SVN_ERR(svn_wc__conflict_read_text_conflict(&desc->my_abspath,
|
||||
&desc->base_abspath,
|
||||
&desc->their_abspath,
|
||||
@ -2913,6 +2929,13 @@ conflict_status_walker(void *baton,
|
||||
|
||||
cd = APR_ARRAY_IDX(conflicts, i, const svn_wc_conflict_description2_t *);
|
||||
|
||||
if ((cd->kind == svn_wc_conflict_kind_property && !cswb->resolve_prop)
|
||||
|| (cd->kind == svn_wc_conflict_kind_text && !cswb->resolve_text)
|
||||
|| (cd->kind == svn_wc_conflict_kind_tree && !cswb->resolve_tree))
|
||||
{
|
||||
continue; /* Easy out. Don't call resolver func and ignore result */
|
||||
}
|
||||
|
||||
svn_pool_clear(iterpool);
|
||||
|
||||
if (my_choice == svn_wc_conflict_choose_unspecified)
|
||||
|
@ -891,18 +891,18 @@ remove_node_conflict_markers(svn_wc__db_t *db,
|
||||
{
|
||||
const char *marker_abspath;
|
||||
const char *child_relpath;
|
||||
const char *child_abpath;
|
||||
const char *child_abspath;
|
||||
|
||||
marker_abspath = APR_ARRAY_IDX(markers, i, const char *);
|
||||
|
||||
child_relpath = svn_dirent_is_child(src_dir, marker_abspath, NULL);
|
||||
child_relpath = svn_dirent_skip_ancestor(src_dir, marker_abspath);
|
||||
|
||||
if (child_relpath)
|
||||
{
|
||||
child_abpath = svn_dirent_join(dst_dir, child_relpath,
|
||||
scratch_pool);
|
||||
child_abspath = svn_dirent_join(dst_dir, child_relpath,
|
||||
scratch_pool);
|
||||
|
||||
SVN_ERR(svn_io_remove_file2(child_abpath, TRUE, scratch_pool));
|
||||
SVN_ERR(svn_io_remove_file2(child_abspath, TRUE, scratch_pool));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -922,7 +922,7 @@ remove_node_conflict_markers(svn_wc__db_t *db,
|
||||
static svn_error_t *
|
||||
remove_all_conflict_markers(svn_wc__db_t *db,
|
||||
const char *src_dir_abspath,
|
||||
const char *wc_dir_abspath,
|
||||
const char *dst_dir_abspath,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
|
||||
@ -951,7 +951,7 @@ remove_all_conflict_markers(svn_wc__db_t *db,
|
||||
SVN_ERR(remove_node_conflict_markers(
|
||||
db,
|
||||
svn_dirent_join(src_dir_abspath, name, iterpool),
|
||||
svn_dirent_join(wc_dir_abspath, name, iterpool),
|
||||
svn_dirent_join(dst_dir_abspath, name, iterpool),
|
||||
iterpool));
|
||||
}
|
||||
if (info->kind == svn_node_dir)
|
||||
@ -960,7 +960,7 @@ remove_all_conflict_markers(svn_wc__db_t *db,
|
||||
SVN_ERR(remove_all_conflict_markers(
|
||||
db,
|
||||
svn_dirent_join(src_dir_abspath, name, iterpool),
|
||||
svn_dirent_join(wc_dir_abspath, name, iterpool),
|
||||
svn_dirent_join(dst_dir_abspath, name, iterpool),
|
||||
iterpool));
|
||||
}
|
||||
}
|
||||
@ -1033,8 +1033,16 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
|
||||
scratch_pool));
|
||||
|
||||
if (conflicted)
|
||||
SVN_ERR(remove_node_conflict_markers(db, src_abspath, dst_abspath,
|
||||
scratch_pool));
|
||||
{
|
||||
/* When we moved a directory, we moved the conflict markers
|
||||
with the target... if we moved a file we only moved the
|
||||
file itself and the markers are still in the old location */
|
||||
SVN_ERR(remove_node_conflict_markers(db, src_abspath,
|
||||
(kind == svn_node_dir)
|
||||
? dst_abspath
|
||||
: src_abspath,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
SVN_ERR(svn_wc__db_op_delete(db, src_abspath,
|
||||
move_degraded_to_copy ? NULL : dst_abspath,
|
||||
|
@ -47,9 +47,6 @@ extern "C" {
|
||||
svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine
|
||||
version of LOCAL_ABSPATH as ADDED. In this case an
|
||||
svn_wc__db_status_deleted may shadow an added or deleted node.
|
||||
|
||||
If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not
|
||||
in the changelist, don't report the node.
|
||||
*/
|
||||
svn_error_t *
|
||||
svn_wc__diff_local_only_file(svn_wc__db_t *db,
|
||||
@ -57,7 +54,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
|
||||
const char *relpath,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
void *processor_parent_baton,
|
||||
apr_hash_t *changelist_hash,
|
||||
svn_boolean_t diff_pristine,
|
||||
svn_cancel_func_t cancel_func,
|
||||
void *cancel_baton,
|
||||
@ -73,9 +69,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
|
||||
svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine
|
||||
version of LOCAL_ABSPATH as ADDED. In this case an
|
||||
svn_wc__db_status_deleted may shadow an added or deleted node.
|
||||
|
||||
If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not
|
||||
in the changelist, don't report the node.
|
||||
*/
|
||||
svn_error_t *
|
||||
svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
@ -84,7 +77,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
svn_depth_t depth,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
void *processor_parent_baton,
|
||||
apr_hash_t *changelist_hash,
|
||||
svn_boolean_t diff_pristine,
|
||||
svn_cancel_func_t cancel_func,
|
||||
void *cancel_baton,
|
||||
@ -132,7 +124,6 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
|
||||
const char *local_abspath,
|
||||
const char *relpath,
|
||||
svn_revnum_t revision,
|
||||
apr_hash_t *changelist_hash,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
void *processor_dir_baton,
|
||||
svn_boolean_t diff_pristine,
|
||||
@ -140,6 +131,32 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
|
||||
void *cancel_baton,
|
||||
apr_pool_t *scratch_pool);
|
||||
|
||||
/* Return a tree processor filter that filters by changelist membership.
|
||||
*
|
||||
* This filter only passes on the changes for a file if the file's path
|
||||
* (in the WC) is assigned to one of the changelists in @a changelist_hash.
|
||||
* It also passes on the opening and closing of each directory that contains
|
||||
* such a change, and possibly also of other directories, but not addition
|
||||
* or deletion or changes to a directory.
|
||||
*
|
||||
* If @a changelist_hash is null then no filtering is performed and the
|
||||
* returned diff processor is driven exactly like the input @a processor.
|
||||
*
|
||||
* @a wc_ctx is the WC context and @a root_local_abspath is the WC path of
|
||||
* the root of the diff (for which relpath = "" in the diff processor).
|
||||
*
|
||||
* Allocate the returned diff processor in @a result_pool, or if no
|
||||
* filtering is required then the input pointer @a processor itself may be
|
||||
* returned.
|
||||
*/
|
||||
const svn_diff_tree_processor_t *
|
||||
svn_wc__changelist_filter_tree_processor_create(
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
svn_wc_context_t *wc_ctx,
|
||||
const char *root_local_abspath,
|
||||
apr_hash_t *changelist_hash,
|
||||
apr_pool_t *result_pool);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -114,9 +114,6 @@ struct edit_baton_t
|
||||
/* Possibly diff repos against text-bases instead of working files. */
|
||||
svn_boolean_t diff_pristine;
|
||||
|
||||
/* Hash whose keys are const char * changelist names. */
|
||||
apr_hash_t *changelist_hash;
|
||||
|
||||
/* Cancel function/baton */
|
||||
svn_cancel_func_t cancel_func;
|
||||
void *cancel_baton;
|
||||
@ -238,43 +235,26 @@ struct file_baton_t
|
||||
* calculating diffs. USE_TEXT_BASE defines whether to compare
|
||||
* against working files or text-bases. REVERSE_ORDER defines which
|
||||
* direction to perform the diff.
|
||||
*
|
||||
* CHANGELIST_FILTER is a list of const char * changelist names, used to
|
||||
* filter diff output responses to only those items in one of the
|
||||
* specified changelists, empty (or NULL altogether) if no changelist
|
||||
* filtering is requested.
|
||||
*/
|
||||
static svn_error_t *
|
||||
make_edit_baton(struct edit_baton_t **edit_baton,
|
||||
svn_wc__db_t *db,
|
||||
const char *anchor_abspath,
|
||||
const char *target,
|
||||
const svn_wc_diff_callbacks4_t *callbacks,
|
||||
void *callback_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
svn_depth_t depth,
|
||||
svn_boolean_t ignore_ancestry,
|
||||
svn_boolean_t show_copies_as_adds,
|
||||
svn_boolean_t use_text_base,
|
||||
svn_boolean_t reverse_order,
|
||||
const apr_array_header_t *changelist_filter,
|
||||
svn_cancel_func_t cancel_func,
|
||||
void *cancel_baton,
|
||||
apr_pool_t *pool)
|
||||
{
|
||||
apr_hash_t *changelist_hash = NULL;
|
||||
struct edit_baton_t *eb;
|
||||
const svn_diff_tree_processor_t *processor;
|
||||
|
||||
SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
|
||||
|
||||
if (changelist_filter && changelist_filter->nelts)
|
||||
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
|
||||
pool));
|
||||
|
||||
SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
|
||||
callbacks, callback_baton, TRUE,
|
||||
pool, pool));
|
||||
|
||||
if (reverse_order)
|
||||
processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool);
|
||||
|
||||
@ -295,7 +275,6 @@ make_edit_baton(struct edit_baton_t **edit_baton,
|
||||
eb->ignore_ancestry = ignore_ancestry;
|
||||
eb->local_before_remote = reverse_order;
|
||||
eb->diff_pristine = use_text_base;
|
||||
eb->changelist_hash = changelist_hash;
|
||||
eb->cancel_func = cancel_func;
|
||||
eb->cancel_baton = cancel_baton;
|
||||
eb->pool = pool;
|
||||
@ -409,7 +388,6 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
|
||||
const char *local_abspath,
|
||||
const char *relpath,
|
||||
svn_revnum_t revision,
|
||||
apr_hash_t *changelist_hash,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
void *processor_dir_baton,
|
||||
svn_boolean_t diff_pristine,
|
||||
@ -436,12 +414,11 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
|
||||
apr_hash_t *base_props;
|
||||
apr_hash_t *local_props;
|
||||
apr_array_header_t *prop_changes;
|
||||
const char *changelist;
|
||||
|
||||
SVN_ERR(svn_wc__db_read_info(&status, NULL, &db_revision, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, &working_checksum, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, &recorded_size,
|
||||
&recorded_time, &changelist, NULL, NULL,
|
||||
&recorded_time, NULL, NULL, NULL,
|
||||
&had_props, &props_mod, NULL, NULL, NULL,
|
||||
db, local_abspath, scratch_pool, scratch_pool));
|
||||
checksum = working_checksum;
|
||||
@ -450,12 +427,6 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
|
||||
|| status == svn_wc__db_status_added
|
||||
|| (status == svn_wc__db_status_deleted && diff_pristine));
|
||||
|
||||
/* If the item is not a member of a specified changelist (and there are
|
||||
some specified changelists), skip it. */
|
||||
if (changelist_hash && !svn_hash_gets(changelist_hash, changelist))
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
|
||||
if (status != svn_wc__db_status_normal)
|
||||
{
|
||||
SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &db_revision,
|
||||
@ -780,7 +751,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
|
||||
SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
|
||||
child_relpath,
|
||||
eb->processor, dir_baton,
|
||||
eb->changelist_hash,
|
||||
eb->diff_pristine,
|
||||
eb->cancel_func,
|
||||
eb->cancel_baton,
|
||||
@ -790,7 +760,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
|
||||
child_relpath,
|
||||
depth_below_here,
|
||||
eb->processor, dir_baton,
|
||||
eb->changelist_hash,
|
||||
eb->diff_pristine,
|
||||
eb->cancel_func,
|
||||
eb->cancel_baton,
|
||||
@ -826,7 +795,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
|
||||
db, child_abspath,
|
||||
child_relpath,
|
||||
eb->revnum,
|
||||
eb->changelist_hash,
|
||||
eb->processor, dir_baton,
|
||||
eb->diff_pristine,
|
||||
eb->cancel_func,
|
||||
@ -849,7 +817,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
|
||||
SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
|
||||
child_relpath,
|
||||
eb->processor, dir_baton,
|
||||
eb->changelist_hash,
|
||||
eb->diff_pristine,
|
||||
eb->cancel_func,
|
||||
eb->cancel_baton,
|
||||
@ -858,7 +825,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
|
||||
SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
|
||||
child_relpath, depth_below_here,
|
||||
eb->processor, dir_baton,
|
||||
eb->changelist_hash,
|
||||
eb->diff_pristine,
|
||||
eb->cancel_func,
|
||||
eb->cancel_baton,
|
||||
@ -870,13 +836,9 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
|
||||
if (compared)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
/* Check for local property mods on this directory, if we haven't
|
||||
already reported them and we aren't changelist-filted.
|
||||
### it should be noted that we do not currently allow directories
|
||||
### to be part of changelists, so if a changelist is provided, the
|
||||
### changelist check will always fail. */
|
||||
/* Check for local property mods on this directory, if we haven't
|
||||
already reported them. */
|
||||
if (! skip
|
||||
&& ! eb->changelist_hash
|
||||
&& ! in_anchor_not_target
|
||||
&& props_mod)
|
||||
{
|
||||
@ -919,7 +881,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
|
||||
const char *relpath,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
void *processor_parent_baton,
|
||||
apr_hash_t *changelist_hash,
|
||||
svn_boolean_t diff_pristine,
|
||||
svn_cancel_func_t cancel_func,
|
||||
void *cancel_baton,
|
||||
@ -932,7 +893,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
|
||||
const svn_checksum_t *checksum;
|
||||
const char *original_repos_relpath;
|
||||
svn_revnum_t original_revision;
|
||||
const char *changelist;
|
||||
svn_boolean_t had_props;
|
||||
svn_boolean_t props_mod;
|
||||
apr_hash_t *pristine_props;
|
||||
@ -948,7 +908,7 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
|
||||
NULL, NULL, NULL, NULL, &checksum, NULL,
|
||||
&original_repos_relpath, NULL, NULL,
|
||||
&original_revision, NULL, NULL, NULL,
|
||||
&changelist, NULL, NULL, &had_props,
|
||||
NULL, NULL, NULL, &had_props,
|
||||
&props_mod, NULL, NULL, NULL,
|
||||
db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
@ -959,10 +919,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
|
||||
|| (status == svn_wc__db_status_deleted && diff_pristine)));
|
||||
|
||||
|
||||
if (changelist && changelist_hash
|
||||
&& !svn_hash_gets(changelist_hash, changelist))
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
if (status == svn_wc__db_status_deleted)
|
||||
{
|
||||
assert(diff_pristine);
|
||||
@ -1065,12 +1021,19 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
svn_depth_t depth,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
void *processor_parent_baton,
|
||||
apr_hash_t *changelist_hash,
|
||||
svn_boolean_t diff_pristine,
|
||||
svn_cancel_func_t cancel_func,
|
||||
void *cancel_baton,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
svn_wc__db_status_t status;
|
||||
svn_node_kind_t kind;
|
||||
svn_boolean_t had_props;
|
||||
svn_boolean_t props_mod;
|
||||
const char *original_repos_relpath;
|
||||
svn_revnum_t original_revision;
|
||||
svn_diff_source_t *copyfrom_src = NULL;
|
||||
apr_hash_t *pristine_props;
|
||||
const apr_array_header_t *children;
|
||||
int i;
|
||||
apr_pool_t *iterpool;
|
||||
@ -1083,6 +1046,47 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
apr_hash_t *nodes;
|
||||
apr_hash_t *conflicts;
|
||||
|
||||
SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
&original_repos_relpath, NULL, NULL,
|
||||
&original_revision, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, &had_props,
|
||||
&props_mod, NULL, NULL, NULL,
|
||||
db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
if (original_repos_relpath)
|
||||
{
|
||||
copyfrom_src = svn_diff__source_create(original_revision, scratch_pool);
|
||||
copyfrom_src->repos_relpath = original_repos_relpath;
|
||||
}
|
||||
|
||||
/* svn_wc__db_status_incomplete should never happen, as the result won't be
|
||||
stable or guaranteed related to what is in the repository for this
|
||||
revision, but without this it would be hard to diagnose that status... */
|
||||
assert(kind == svn_node_dir
|
||||
&& (status == svn_wc__db_status_normal
|
||||
|| status == svn_wc__db_status_incomplete
|
||||
|| status == svn_wc__db_status_added
|
||||
|| (status == svn_wc__db_status_deleted && diff_pristine)));
|
||||
|
||||
if (status == svn_wc__db_status_deleted)
|
||||
{
|
||||
assert(diff_pristine);
|
||||
|
||||
SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, &had_props,
|
||||
&pristine_props,
|
||||
db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
props_mod = FALSE;
|
||||
}
|
||||
else if (!had_props)
|
||||
pristine_props = apr_hash_make(scratch_pool);
|
||||
else
|
||||
SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props,
|
||||
db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
|
||||
/* Report the addition of the directory's contents. */
|
||||
iterpool = svn_pool_create(scratch_pool);
|
||||
|
||||
@ -1090,10 +1094,11 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
relpath,
|
||||
NULL,
|
||||
right_src,
|
||||
NULL /* copyfrom_src */,
|
||||
copyfrom_src,
|
||||
processor_parent_baton,
|
||||
processor,
|
||||
scratch_pool, iterpool));
|
||||
/* ### skip_children is not used */
|
||||
|
||||
SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db, local_abspath,
|
||||
scratch_pool, iterpool));
|
||||
@ -1138,7 +1143,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
|
||||
child_relpath,
|
||||
processor, pdb,
|
||||
changelist_hash,
|
||||
diff_pristine,
|
||||
cancel_func, cancel_baton,
|
||||
scratch_pool));
|
||||
@ -1150,7 +1154,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
|
||||
child_relpath, depth_below_here,
|
||||
processor, pdb,
|
||||
changelist_hash,
|
||||
diff_pristine,
|
||||
cancel_func, cancel_baton,
|
||||
iterpool));
|
||||
@ -1165,17 +1168,19 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
|
||||
if (!skip)
|
||||
{
|
||||
apr_hash_t *right_props;
|
||||
if (diff_pristine)
|
||||
SVN_ERR(svn_wc__db_read_pristine_props(&right_props, db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
|
||||
if (props_mod && !diff_pristine)
|
||||
SVN_ERR(svn_wc__db_read_props(&right_props, db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
else
|
||||
SVN_ERR(svn_wc__get_actual_props(&right_props, db, local_abspath,
|
||||
scratch_pool, scratch_pool));
|
||||
right_props = svn_prop_hash_dup(pristine_props, scratch_pool);
|
||||
|
||||
SVN_ERR(processor->dir_added(relpath,
|
||||
NULL /* copyfrom_src */,
|
||||
copyfrom_src,
|
||||
right_src,
|
||||
NULL,
|
||||
copyfrom_src
|
||||
? pristine_props
|
||||
: NULL,
|
||||
right_props,
|
||||
pdb,
|
||||
processor,
|
||||
@ -1246,7 +1251,6 @@ handle_local_only(struct dir_baton_t *pb,
|
||||
svn_relpath_join(pb->relpath, name, scratch_pool),
|
||||
repos_delete ? svn_depth_infinity : depth,
|
||||
eb->processor, pb->pdb,
|
||||
eb->changelist_hash,
|
||||
eb->diff_pristine,
|
||||
eb->cancel_func, eb->cancel_baton,
|
||||
scratch_pool));
|
||||
@ -1257,7 +1261,6 @@ handle_local_only(struct dir_baton_t *pb,
|
||||
svn_dirent_join(pb->local_abspath, name, scratch_pool),
|
||||
svn_relpath_join(pb->relpath, name, scratch_pool),
|
||||
eb->processor, pb->pdb,
|
||||
eb->changelist_hash,
|
||||
eb->diff_pristine,
|
||||
eb->cancel_func, eb->cancel_baton,
|
||||
scratch_pool));
|
||||
@ -2032,7 +2035,14 @@ close_file(void *file_baton,
|
||||
const char *repos_file;
|
||||
apr_hash_t *repos_props;
|
||||
|
||||
if (!fb->skip && expected_md5_digest != NULL)
|
||||
if (fb->skip)
|
||||
{
|
||||
svn_pool_destroy(fb->pool); /* destroys scratch_pool and fb */
|
||||
SVN_ERR(maybe_done(pb));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
if (expected_md5_digest != NULL)
|
||||
{
|
||||
svn_checksum_t *expected_checksum;
|
||||
const svn_checksum_t *result_checksum;
|
||||
@ -2087,11 +2097,7 @@ close_file(void *file_baton,
|
||||
}
|
||||
}
|
||||
|
||||
if (fb->skip)
|
||||
{
|
||||
/* Diff processor requested skipping information */
|
||||
}
|
||||
else if (fb->repos_only)
|
||||
if (fb->repos_only)
|
||||
{
|
||||
SVN_ERR(eb->processor->file_deleted(fb->relpath,
|
||||
fb->left_src,
|
||||
@ -2271,6 +2277,7 @@ svn_wc__get_diff_editor(const svn_delta_editor_t **editor,
|
||||
struct svn_wc__shim_fetch_baton_t *sfb;
|
||||
svn_delta_shim_callbacks_t *shim_callbacks =
|
||||
svn_delta_shim_callbacks_default(result_pool);
|
||||
const svn_diff_tree_processor_t *diff_processor;
|
||||
|
||||
SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
|
||||
|
||||
@ -2278,12 +2285,28 @@ svn_wc__get_diff_editor(const svn_delta_editor_t **editor,
|
||||
if (use_git_diff_format)
|
||||
show_copies_as_adds = TRUE;
|
||||
|
||||
SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
|
||||
callbacks, callback_baton, TRUE,
|
||||
result_pool, scratch_pool));
|
||||
|
||||
/* Apply changelist filtering to the output */
|
||||
if (changelist_filter && changelist_filter->nelts)
|
||||
{
|
||||
apr_hash_t *changelist_hash;
|
||||
|
||||
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
|
||||
result_pool));
|
||||
diff_processor = svn_wc__changelist_filter_tree_processor_create(
|
||||
diff_processor, wc_ctx, anchor_abspath,
|
||||
changelist_hash, result_pool);
|
||||
}
|
||||
|
||||
SVN_ERR(make_edit_baton(&eb,
|
||||
wc_ctx->db,
|
||||
anchor_abspath, target,
|
||||
callbacks, callback_baton,
|
||||
diff_processor,
|
||||
depth, ignore_ancestry, show_copies_as_adds,
|
||||
use_text_base, reverse_order, changelist_filter,
|
||||
use_text_base, reverse_order,
|
||||
cancel_func, cancel_baton,
|
||||
result_pool));
|
||||
|
||||
@ -2390,8 +2413,8 @@ wrap_dir_opened(void **new_dir_baton,
|
||||
wc_diff_wrap_baton_t *wb = processor->baton;
|
||||
svn_boolean_t tree_conflicted = FALSE;
|
||||
|
||||
assert(left_source || right_source);
|
||||
assert(!copyfrom_source || !right_source);
|
||||
assert(left_source || right_source); /* Must exist at one point. */
|
||||
assert(!left_source || !copyfrom_source); /* Either existed or added. */
|
||||
|
||||
/* Maybe store state and tree_conflicted in baton? */
|
||||
if (left_source != NULL)
|
||||
@ -2749,3 +2772,329 @@ svn_wc__wrap_diff_callbacks(const svn_diff_tree_processor_t **diff_processor,
|
||||
*diff_processor = processor;
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
* A tree processor filter that filters by changelist membership
|
||||
* =====================================================================
|
||||
*
|
||||
* The current implementation queries the WC for the changelist of each
|
||||
* file as it comes through, and sets the 'skip' flag for a non-matching
|
||||
* file.
|
||||
*
|
||||
* (It doesn't set the 'skip' flag for a directory, as we need to receive
|
||||
* the changed/added/deleted/closed call to know when it is closed, in
|
||||
* order to preserve the strict open-close semantics for the wrapped tree
|
||||
* processor.)
|
||||
*
|
||||
* It passes on the opening and closing of every directory, even if there
|
||||
* are no file changes to be passed on inside that directory.
|
||||
*/
|
||||
|
||||
typedef struct filter_tree_baton_t
|
||||
{
|
||||
const svn_diff_tree_processor_t *processor;
|
||||
svn_wc_context_t *wc_ctx;
|
||||
/* WC path of the root of the diff (where relpath = "") */
|
||||
const char *root_local_abspath;
|
||||
/* Hash whose keys are const char * changelist names. */
|
||||
apr_hash_t *changelist_hash;
|
||||
} filter_tree_baton_t;
|
||||
|
||||
static svn_error_t *
|
||||
filter_dir_opened(void **new_dir_baton,
|
||||
svn_boolean_t *skip,
|
||||
svn_boolean_t *skip_children,
|
||||
const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
const svn_diff_source_t *copyfrom_source,
|
||||
void *parent_dir_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *result_pool,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children,
|
||||
relpath,
|
||||
left_source, right_source,
|
||||
copyfrom_source,
|
||||
parent_dir_baton,
|
||||
fb->processor,
|
||||
result_pool, scratch_pool));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_dir_added(const char *relpath,
|
||||
const svn_diff_source_t *copyfrom_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
/*const*/ apr_hash_t *copyfrom_props,
|
||||
/*const*/ apr_hash_t *right_props,
|
||||
void *dir_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->dir_closed(relpath,
|
||||
NULL,
|
||||
right_source,
|
||||
dir_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_dir_deleted(const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
/*const*/ apr_hash_t *left_props,
|
||||
void *dir_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->dir_closed(relpath,
|
||||
left_source,
|
||||
NULL,
|
||||
dir_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_dir_changed(const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
/*const*/ apr_hash_t *left_props,
|
||||
/*const*/ apr_hash_t *right_props,
|
||||
const apr_array_header_t *prop_changes,
|
||||
void *dir_baton,
|
||||
const struct svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->dir_closed(relpath,
|
||||
left_source,
|
||||
right_source,
|
||||
dir_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_dir_closed(const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
void *dir_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->dir_closed(relpath,
|
||||
left_source,
|
||||
right_source,
|
||||
dir_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_file_opened(void **new_file_baton,
|
||||
svn_boolean_t *skip,
|
||||
const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
const svn_diff_source_t *copyfrom_source,
|
||||
void *dir_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *result_pool,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
const char *local_abspath
|
||||
= svn_dirent_join(fb->root_local_abspath, relpath, scratch_pool);
|
||||
|
||||
/* Skip if not a member of a given changelist */
|
||||
if (! svn_wc__changelist_match(fb->wc_ctx, local_abspath,
|
||||
fb->changelist_hash, scratch_pool))
|
||||
{
|
||||
*skip = TRUE;
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
SVN_ERR(fb->processor->file_opened(new_file_baton,
|
||||
skip,
|
||||
relpath,
|
||||
left_source,
|
||||
right_source,
|
||||
copyfrom_source,
|
||||
dir_baton,
|
||||
fb->processor,
|
||||
result_pool,
|
||||
scratch_pool));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_file_added(const char *relpath,
|
||||
const svn_diff_source_t *copyfrom_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
const char *copyfrom_file,
|
||||
const char *right_file,
|
||||
/*const*/ apr_hash_t *copyfrom_props,
|
||||
/*const*/ apr_hash_t *right_props,
|
||||
void *file_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->file_added(relpath,
|
||||
copyfrom_source,
|
||||
right_source,
|
||||
copyfrom_file,
|
||||
right_file,
|
||||
copyfrom_props,
|
||||
right_props,
|
||||
file_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_file_deleted(const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
const char *left_file,
|
||||
/*const*/ apr_hash_t *left_props,
|
||||
void *file_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->file_deleted(relpath,
|
||||
left_source,
|
||||
left_file,
|
||||
left_props,
|
||||
file_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_file_changed(const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
const char *left_file,
|
||||
const char *right_file,
|
||||
/*const*/ apr_hash_t *left_props,
|
||||
/*const*/ apr_hash_t *right_props,
|
||||
svn_boolean_t file_modified,
|
||||
const apr_array_header_t *prop_changes,
|
||||
void *file_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->file_changed(relpath,
|
||||
left_source,
|
||||
right_source,
|
||||
left_file,
|
||||
right_file,
|
||||
left_props,
|
||||
right_props,
|
||||
file_modified,
|
||||
prop_changes,
|
||||
file_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_file_closed(const char *relpath,
|
||||
const svn_diff_source_t *left_source,
|
||||
const svn_diff_source_t *right_source,
|
||||
void *file_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->file_closed(relpath,
|
||||
left_source,
|
||||
right_source,
|
||||
file_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
filter_node_absent(const char *relpath,
|
||||
void *dir_baton,
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb = processor->baton;
|
||||
|
||||
SVN_ERR(fb->processor->node_absent(relpath,
|
||||
dir_baton,
|
||||
fb->processor,
|
||||
scratch_pool));
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
const svn_diff_tree_processor_t *
|
||||
svn_wc__changelist_filter_tree_processor_create(
|
||||
const svn_diff_tree_processor_t *processor,
|
||||
svn_wc_context_t *wc_ctx,
|
||||
const char *root_local_abspath,
|
||||
apr_hash_t *changelist_hash,
|
||||
apr_pool_t *result_pool)
|
||||
{
|
||||
struct filter_tree_baton_t *fb;
|
||||
svn_diff_tree_processor_t *filter;
|
||||
|
||||
if (! changelist_hash)
|
||||
return processor;
|
||||
|
||||
fb = apr_pcalloc(result_pool, sizeof(*fb));
|
||||
fb->processor = processor;
|
||||
fb->wc_ctx = wc_ctx;
|
||||
fb->root_local_abspath = root_local_abspath;
|
||||
fb->changelist_hash = changelist_hash;
|
||||
|
||||
filter = svn_diff__tree_processor_create(fb, result_pool);
|
||||
filter->dir_opened = filter_dir_opened;
|
||||
filter->dir_added = filter_dir_added;
|
||||
filter->dir_deleted = filter_dir_deleted;
|
||||
filter->dir_changed = filter_dir_changed;
|
||||
filter->dir_closed = filter_dir_closed;
|
||||
|
||||
filter->file_opened = filter_file_opened;
|
||||
filter->file_added = filter_file_added;
|
||||
filter->file_deleted = filter_file_deleted;
|
||||
filter->file_changed = filter_file_changed;
|
||||
filter->file_closed = filter_file_closed;
|
||||
|
||||
filter->node_absent = filter_node_absent;
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
@ -92,9 +92,6 @@ struct diff_baton
|
||||
/* Should this diff not compare copied files with their source? */
|
||||
svn_boolean_t show_copies_as_adds;
|
||||
|
||||
/* Hash whose keys are const char * changelist names. */
|
||||
apr_hash_t *changelist_hash;
|
||||
|
||||
/* Cancel function/baton */
|
||||
svn_cancel_func_t cancel_func;
|
||||
void *cancel_baton;
|
||||
@ -252,11 +249,6 @@ diff_status_callback(void *baton,
|
||||
if (eb->cur && eb->cur->skip_children)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
if (eb->changelist_hash != NULL
|
||||
&& (!status->changelist
|
||||
|| ! svn_hash_gets(eb->changelist_hash, status->changelist)))
|
||||
return SVN_NO_ERROR; /* Filtered via changelist */
|
||||
|
||||
/* This code does about the same thing as the inner body of
|
||||
walk_local_nodes_diff() in diff_editor.c, except that
|
||||
it is already filtered by the status walker, doesn't have to
|
||||
@ -361,7 +353,6 @@ diff_status_callback(void *baton,
|
||||
SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
|
||||
child_relpath,
|
||||
SVN_INVALID_REVNUM,
|
||||
eb->changelist_hash,
|
||||
eb->processor,
|
||||
eb->cur
|
||||
? eb->cur->baton
|
||||
@ -405,7 +396,6 @@ diff_status_callback(void *baton,
|
||||
child_relpath,
|
||||
eb->processor,
|
||||
eb->cur ? eb->cur->baton : NULL,
|
||||
eb->changelist_hash,
|
||||
FALSE,
|
||||
eb->cancel_func,
|
||||
eb->cancel_baton,
|
||||
@ -415,7 +405,6 @@ diff_status_callback(void *baton,
|
||||
child_relpath, depth_below_here,
|
||||
eb->processor,
|
||||
eb->cur ? eb->cur->baton : NULL,
|
||||
eb->changelist_hash,
|
||||
FALSE,
|
||||
eb->cancel_func,
|
||||
eb->cancel_baton,
|
||||
@ -482,16 +471,24 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
|
||||
processor = svn_diff__tree_processor_copy_as_changed_create(processor,
|
||||
scratch_pool);
|
||||
|
||||
/* Apply changelist filtering to the output */
|
||||
if (changelist_filter && changelist_filter->nelts)
|
||||
{
|
||||
apr_hash_t *changelist_hash;
|
||||
|
||||
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
|
||||
scratch_pool));
|
||||
processor = svn_wc__changelist_filter_tree_processor_create(
|
||||
processor, wc_ctx, local_abspath,
|
||||
changelist_hash, scratch_pool);
|
||||
}
|
||||
|
||||
eb.db = wc_ctx->db;
|
||||
eb.processor = processor;
|
||||
eb.ignore_ancestry = ignore_ancestry;
|
||||
eb.show_copies_as_adds = show_copies_as_adds;
|
||||
eb.pool = scratch_pool;
|
||||
|
||||
if (changelist_filter && changelist_filter->nelts)
|
||||
SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter,
|
||||
scratch_pool));
|
||||
|
||||
if (show_copies_as_adds || use_git_diff_format || !ignore_ancestry)
|
||||
get_all = TRUE; /* We need unmodified descendants of copies */
|
||||
else
|
||||
|
@ -2140,17 +2140,18 @@ write_entry(struct write_baton **entry_node,
|
||||
below_working_node->presence = svn_wc__db_status_normal;
|
||||
below_working_node->kind = entry->kind;
|
||||
below_working_node->repos_id = work->repos_id;
|
||||
below_working_node->revision = work->revision;
|
||||
|
||||
/* This is just guessing. If the node below would have been switched
|
||||
or if it was updated to a different version, the guess would
|
||||
fail. But we don't have better information pre wc-ng :( */
|
||||
if (work->repos_relpath)
|
||||
below_working_node->repos_relpath
|
||||
= svn_relpath_join(work->repos_relpath, entry->name,
|
||||
= svn_relpath_join(work->repos_relpath,
|
||||
svn_relpath_basename(local_relpath, NULL),
|
||||
result_pool);
|
||||
else
|
||||
below_working_node->repos_relpath = NULL;
|
||||
below_working_node->revision = parent_node->work->revision;
|
||||
|
||||
/* The revert_base checksum isn't available in the entry structure,
|
||||
so the caller provides it. */
|
||||
|
@ -405,9 +405,10 @@ struct edit_baton
|
||||
const apr_array_header_t *ext_patterns;
|
||||
const char *diff3cmd;
|
||||
|
||||
const char *url;
|
||||
const char *repos_root_url;
|
||||
const char *repos_uuid;
|
||||
const char *old_repos_relpath;
|
||||
const char *new_repos_relpath;
|
||||
|
||||
const char *record_ancestor_abspath;
|
||||
const char *recorded_repos_relpath;
|
||||
@ -517,7 +518,8 @@ open_file(const char *path,
|
||||
|
||||
*file_baton = eb;
|
||||
SVN_ERR(svn_wc__db_base_get_info(NULL, &kind, &eb->original_revision,
|
||||
NULL, NULL, NULL, &eb->changed_rev,
|
||||
&eb->old_repos_relpath, NULL, NULL,
|
||||
&eb->changed_rev,
|
||||
&eb->changed_date, &eb->changed_author,
|
||||
NULL, &eb->original_checksum, NULL, NULL,
|
||||
&eb->had_props, NULL, NULL,
|
||||
@ -677,8 +679,6 @@ close_file(void *file_baton,
|
||||
const svn_checksum_t *original_checksum = NULL;
|
||||
|
||||
svn_boolean_t added = !SVN_IS_VALID_REVNUM(eb->original_revision);
|
||||
const char *repos_relpath = svn_uri_skip_ancestor(eb->repos_root_url,
|
||||
eb->url, pool);
|
||||
|
||||
if (! added)
|
||||
{
|
||||
@ -853,14 +853,14 @@ close_file(void *file_baton,
|
||||
svn_wc_conflict_version_create2(
|
||||
eb->repos_root_url,
|
||||
eb->repos_uuid,
|
||||
repos_relpath,
|
||||
eb->old_repos_relpath,
|
||||
eb->original_revision,
|
||||
svn_node_file,
|
||||
pool),
|
||||
svn_wc_conflict_version_create2(
|
||||
eb->repos_root_url,
|
||||
eb->repos_uuid,
|
||||
repos_relpath,
|
||||
eb->new_repos_relpath,
|
||||
*eb->target_revision,
|
||||
svn_node_file,
|
||||
pool),
|
||||
@ -878,7 +878,7 @@ close_file(void *file_baton,
|
||||
eb->db,
|
||||
eb->local_abspath,
|
||||
eb->wri_abspath,
|
||||
repos_relpath,
|
||||
eb->new_repos_relpath,
|
||||
eb->repos_root_url,
|
||||
eb->repos_uuid,
|
||||
*eb->target_revision,
|
||||
@ -945,10 +945,15 @@ close_edit(void *edit_baton,
|
||||
{
|
||||
struct edit_baton *eb = edit_baton;
|
||||
|
||||
if (!eb->file_closed
|
||||
|| eb->iprops)
|
||||
if (!eb->file_closed)
|
||||
{
|
||||
apr_hash_t *wcroot_iprops = NULL;
|
||||
/* The file wasn't updated, but its url or revision might have...
|
||||
e.g. switch between branches for relative externals.
|
||||
|
||||
Just bump the information as that is just as expensive as
|
||||
investigating when we should and shouldn't update it...
|
||||
and avoid hard to debug edge cases */
|
||||
|
||||
if (eb->iprops)
|
||||
{
|
||||
@ -956,13 +961,15 @@ close_edit(void *edit_baton,
|
||||
svn_hash_sets(wcroot_iprops, eb->local_abspath, eb->iprops);
|
||||
}
|
||||
|
||||
/* The node wasn't updated, so we just have to bump its revision */
|
||||
SVN_ERR(svn_wc__db_op_bump_revisions_post_update(eb->db,
|
||||
eb->local_abspath,
|
||||
svn_depth_infinity,
|
||||
NULL, NULL, NULL,
|
||||
eb->new_repos_relpath,
|
||||
eb->repos_root_url,
|
||||
eb->repos_uuid,
|
||||
*eb->target_revision,
|
||||
apr_hash_make(pool),
|
||||
apr_hash_make(pool)
|
||||
/* exclude_relpaths */,
|
||||
wcroot_iprops,
|
||||
eb->notify_func,
|
||||
eb->notify_baton,
|
||||
@ -1014,9 +1021,12 @@ svn_wc__get_file_external_editor(const svn_delta_editor_t **editor,
|
||||
eb->name = svn_dirent_basename(eb->local_abspath, NULL);
|
||||
eb->target_revision = target_revision;
|
||||
|
||||
eb->url = apr_pstrdup(edit_pool, url);
|
||||
eb->repos_root_url = apr_pstrdup(edit_pool, repos_root_url);
|
||||
eb->repos_uuid = apr_pstrdup(edit_pool, repos_uuid);
|
||||
eb->new_repos_relpath = svn_uri_skip_ancestor(eb->repos_root_url, url, edit_pool);
|
||||
eb->old_repos_relpath = eb->new_repos_relpath;
|
||||
|
||||
eb->original_revision = SVN_INVALID_REVNUM;
|
||||
|
||||
eb->iprops = iprops;
|
||||
|
||||
|
@ -2125,13 +2125,12 @@ add_directory(const char *path,
|
||||
if (tree_conflict)
|
||||
{
|
||||
svn_wc_conflict_reason_t reason;
|
||||
const char *move_src_op_root_abspath;
|
||||
/* So this deletion wasn't just a deletion, it is actually a
|
||||
replacement. Let's install a better tree conflict. */
|
||||
|
||||
/* ### Should store the conflict in DB to allow reinstalling
|
||||
### with theoretically more data in close_directory() */
|
||||
|
||||
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
|
||||
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
|
||||
&move_src_op_root_abspath,
|
||||
eb->db,
|
||||
db->local_abspath,
|
||||
tree_conflict,
|
||||
@ -2143,7 +2142,7 @@ add_directory(const char *path,
|
||||
tree_conflict,
|
||||
eb->db, db->local_abspath,
|
||||
reason, svn_wc_conflict_action_replace,
|
||||
NULL,
|
||||
move_src_op_root_abspath,
|
||||
db->pool, db->pool));
|
||||
|
||||
/* And now stop checking for conflicts here and just perform
|
||||
@ -3266,13 +3265,12 @@ add_file(const char *path,
|
||||
if (tree_conflict)
|
||||
{
|
||||
svn_wc_conflict_reason_t reason;
|
||||
const char *move_src_op_root_abspath;
|
||||
/* So this deletion wasn't just a deletion, it is actually a
|
||||
replacement. Let's install a better tree conflict. */
|
||||
|
||||
/* ### Should store the conflict in DB to allow reinstalling
|
||||
### with theoretically more data in close_directory() */
|
||||
|
||||
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
|
||||
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
|
||||
&move_src_op_root_abspath,
|
||||
eb->db,
|
||||
fb->local_abspath,
|
||||
tree_conflict,
|
||||
@ -3284,7 +3282,7 @@ add_file(const char *path,
|
||||
tree_conflict,
|
||||
eb->db, fb->local_abspath,
|
||||
reason, svn_wc_conflict_action_replace,
|
||||
NULL,
|
||||
move_src_op_root_abspath,
|
||||
fb->pool, fb->pool));
|
||||
|
||||
/* And now stop checking for conflicts here and just perform
|
||||
@ -5553,8 +5551,8 @@ svn_wc__complete_directory_add(svn_wc_context_t *wc_ctx,
|
||||
original_repos_relpath, original_root_url,
|
||||
original_uuid, original_revision,
|
||||
NULL /* children */,
|
||||
FALSE /* is_move */,
|
||||
svn_depth_infinity,
|
||||
FALSE /* is_move */,
|
||||
NULL /* conflict */,
|
||||
NULL /* work_items */,
|
||||
scratch_pool));
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_wc/token-map.h.
|
||||
/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
|
||||
* Do not edit this file -- edit the source and rerun gen-make.py */
|
||||
|
||||
#define STMT_VERIFICATION_TRIGGERS 0
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_wc/token-map.h.
|
||||
/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
|
||||
* Do not edit this file -- edit the source and rerun gen-make.py */
|
||||
|
||||
#define STMT_CREATE_SCHEMA 0
|
||||
@ -164,21 +164,25 @@
|
||||
#define STMT_4 \
|
||||
"ANALYZE sqlite_master; " \
|
||||
"DELETE FROM sqlite_stat1 " \
|
||||
"WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS'); " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('NODES', 'sqlite_autoindex_NODES_1', '8000 8000 2 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('NODES', 'I_NODES_PARENT', '8000 8000 10 2 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('NODES', 'I_NODES_MOVED', '8000 8000 1 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('ACTUAL_NODE', 'sqlite_autoindex_ACTUAL_NODE_1', '8000 8000 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('ACTUAL_NODE', 'I_ACTUAL_PARENT', '8000 8000 10 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('LOCK', 'sqlite_autoindex_LOCK_1', '100 100 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('WC_LOCK', 'sqlite_autoindex_WC_LOCK_1', '100 100 1'); " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('EXTERNALS','sqlite_autoindex_EXTERNALS_1', '100 100 1'); " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('EXTERNALS','I_EXTERNALS_DEFINED', '100 100 3 1'); " \
|
||||
"ANALYZE sqlite_master; " \
|
||||
""
|
||||
|
||||
|
@ -598,27 +598,32 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id,
|
||||
ANALYZE sqlite_master; /* Creates empty sqlite_stat1 if necessary */
|
||||
|
||||
DELETE FROM sqlite_stat1
|
||||
WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK');
|
||||
WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS');
|
||||
|
||||
INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('NODES', 'sqlite_autoindex_NODES_1', '8000 8000 2 1');
|
||||
INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('NODES', 'I_NODES_PARENT', '8000 8000 10 2 1');
|
||||
/* Tell a lie: We ignore that 99.9% of all moved_to values are NULL */
|
||||
INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('NODES', 'I_NODES_MOVED', '8000 8000 1 1');
|
||||
|
||||
INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('ACTUAL_NODE', 'sqlite_autoindex_ACTUAL_NODE_1', '8000 8000 1');
|
||||
INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('ACTUAL_NODE', 'I_ACTUAL_PARENT', '8000 8000 10 1');
|
||||
|
||||
INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('LOCK', 'sqlite_autoindex_LOCK_1', '100 100 1');
|
||||
|
||||
INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('WC_LOCK', 'sqlite_autoindex_WC_LOCK_1', '100 100 1');
|
||||
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('EXTERNALS','sqlite_autoindex_EXTERNALS_1', '100 100 1');
|
||||
INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
|
||||
('EXTERNALS','I_EXTERNALS_DEFINED', '100 100 3 1');
|
||||
|
||||
/* sqlite_autoindex_WORK_QUEUE_1 doesn't exist because WORK_QUEUE is
|
||||
a INTEGER PRIMARY KEY AUTOINCREMENT table */
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_wc/token-map.h.
|
||||
/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.8.14/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
|
||||
@ -2172,9 +2172,16 @@
|
||||
" AND (inherited_props not null) " \
|
||||
""
|
||||
|
||||
#define STMT_CREATE_SCHEMA 207
|
||||
#define STMT_207_INFO {"STMT_CREATE_SCHEMA", NULL}
|
||||
#define STMT_HAVE_STAT1_TABLE 207
|
||||
#define STMT_207_INFO {"STMT_HAVE_STAT1_TABLE", NULL}
|
||||
#define STMT_207 \
|
||||
"SELECT 1 FROM sqlite_master WHERE name='sqlite_stat1' AND type='table' " \
|
||||
"LIMIT 1 " \
|
||||
""
|
||||
|
||||
#define STMT_CREATE_SCHEMA 208
|
||||
#define STMT_208_INFO {"STMT_CREATE_SCHEMA", NULL}
|
||||
#define STMT_208 \
|
||||
"CREATE TABLE REPOSITORY ( " \
|
||||
" id INTEGER PRIMARY KEY AUTOINCREMENT, " \
|
||||
" root TEXT UNIQUE NOT NULL, " \
|
||||
@ -2239,9 +2246,9 @@
|
||||
"; " \
|
||||
""
|
||||
|
||||
#define STMT_CREATE_NODES 208
|
||||
#define STMT_208_INFO {"STMT_CREATE_NODES", NULL}
|
||||
#define STMT_208 \
|
||||
#define STMT_CREATE_NODES 209
|
||||
#define STMT_209_INFO {"STMT_CREATE_NODES", NULL}
|
||||
#define STMT_209 \
|
||||
"CREATE TABLE NODES ( " \
|
||||
" wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \
|
||||
" local_relpath TEXT NOT NULL, " \
|
||||
@ -2281,9 +2288,9 @@
|
||||
" WHERE op_depth = 0; " \
|
||||
""
|
||||
|
||||
#define STMT_CREATE_NODES_TRIGGERS 209
|
||||
#define STMT_209_INFO {"STMT_CREATE_NODES_TRIGGERS", NULL}
|
||||
#define STMT_209 \
|
||||
#define STMT_CREATE_NODES_TRIGGERS 210
|
||||
#define STMT_210_INFO {"STMT_CREATE_NODES_TRIGGERS", NULL}
|
||||
#define STMT_210 \
|
||||
"CREATE TRIGGER nodes_insert_trigger " \
|
||||
"AFTER INSERT ON nodes " \
|
||||
"WHEN NEW.checksum IS NOT NULL " \
|
||||
@ -2309,9 +2316,9 @@
|
||||
"END; " \
|
||||
""
|
||||
|
||||
#define STMT_CREATE_EXTERNALS 210
|
||||
#define STMT_210_INFO {"STMT_CREATE_EXTERNALS", NULL}
|
||||
#define STMT_210 \
|
||||
#define STMT_CREATE_EXTERNALS 211
|
||||
#define STMT_211_INFO {"STMT_CREATE_EXTERNALS", NULL}
|
||||
#define STMT_211 \
|
||||
"CREATE TABLE EXTERNALS ( " \
|
||||
" wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \
|
||||
" local_relpath TEXT NOT NULL, " \
|
||||
@ -2330,32 +2337,36 @@
|
||||
" local_relpath); " \
|
||||
""
|
||||
|
||||
#define STMT_INSTALL_SCHEMA_STATISTICS 211
|
||||
#define STMT_211_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL}
|
||||
#define STMT_211 \
|
||||
#define STMT_INSTALL_SCHEMA_STATISTICS 212
|
||||
#define STMT_212_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL}
|
||||
#define STMT_212 \
|
||||
"ANALYZE sqlite_master; " \
|
||||
"DELETE FROM sqlite_stat1 " \
|
||||
"WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS'); " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('NODES', 'sqlite_autoindex_NODES_1', '8000 8000 2 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('NODES', 'I_NODES_PARENT', '8000 8000 10 2 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('NODES', 'I_NODES_MOVED', '8000 8000 1 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('ACTUAL_NODE', 'sqlite_autoindex_ACTUAL_NODE_1', '8000 8000 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('ACTUAL_NODE', 'I_ACTUAL_PARENT', '8000 8000 10 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('LOCK', 'sqlite_autoindex_LOCK_1', '100 100 1'); " \
|
||||
"INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('WC_LOCK', 'sqlite_autoindex_WC_LOCK_1', '100 100 1'); " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('EXTERNALS','sqlite_autoindex_EXTERNALS_1', '100 100 1'); " \
|
||||
"INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
|
||||
" ('EXTERNALS','I_EXTERNALS_DEFINED', '100 100 3 1'); " \
|
||||
"ANALYZE sqlite_master; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_20 212
|
||||
#define STMT_212_INFO {"STMT_UPGRADE_TO_20", NULL}
|
||||
#define STMT_212 \
|
||||
#define STMT_UPGRADE_TO_20 213
|
||||
#define STMT_213_INFO {"STMT_UPGRADE_TO_20", NULL}
|
||||
#define STMT_213 \
|
||||
"UPDATE BASE_NODE SET checksum = (SELECT checksum FROM pristine " \
|
||||
" WHERE md5_checksum = BASE_NODE.checksum) " \
|
||||
"WHERE EXISTS (SELECT 1 FROM pristine WHERE md5_checksum = BASE_NODE.checksum); " \
|
||||
@ -2396,59 +2407,59 @@
|
||||
"PRAGMA user_version = 20; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_21 213
|
||||
#define STMT_213_INFO {"STMT_UPGRADE_TO_21", NULL}
|
||||
#define STMT_213 \
|
||||
#define STMT_UPGRADE_TO_21 214
|
||||
#define STMT_214_INFO {"STMT_UPGRADE_TO_21", NULL}
|
||||
#define STMT_214 \
|
||||
"PRAGMA user_version = 21; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT 214
|
||||
#define STMT_214_INFO {"STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT", NULL}
|
||||
#define STMT_214 \
|
||||
#define STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT 215
|
||||
#define STMT_215_INFO {"STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT", NULL}
|
||||
#define STMT_215 \
|
||||
"SELECT wc_id, local_relpath, tree_conflict_data " \
|
||||
"FROM actual_node " \
|
||||
"WHERE tree_conflict_data IS NOT NULL " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_21_ERASE_OLD_CONFLICTS 215
|
||||
#define STMT_215_INFO {"STMT_UPGRADE_21_ERASE_OLD_CONFLICTS", NULL}
|
||||
#define STMT_215 \
|
||||
#define STMT_UPGRADE_21_ERASE_OLD_CONFLICTS 216
|
||||
#define STMT_216_INFO {"STMT_UPGRADE_21_ERASE_OLD_CONFLICTS", NULL}
|
||||
#define STMT_216 \
|
||||
"UPDATE actual_node SET tree_conflict_data = NULL " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_22 216
|
||||
#define STMT_216_INFO {"STMT_UPGRADE_TO_22", NULL}
|
||||
#define STMT_216 \
|
||||
#define STMT_UPGRADE_TO_22 217
|
||||
#define STMT_217_INFO {"STMT_UPGRADE_TO_22", NULL}
|
||||
#define STMT_217 \
|
||||
"UPDATE actual_node SET tree_conflict_data = conflict_data; " \
|
||||
"UPDATE actual_node SET conflict_data = NULL; " \
|
||||
"PRAGMA user_version = 22; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_23 217
|
||||
#define STMT_217_INFO {"STMT_UPGRADE_TO_23", NULL}
|
||||
#define STMT_217 \
|
||||
#define STMT_UPGRADE_TO_23 218
|
||||
#define STMT_218_INFO {"STMT_UPGRADE_TO_23", NULL}
|
||||
#define STMT_218 \
|
||||
"PRAGMA user_version = 23; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_23_HAS_WORKING_NODES 218
|
||||
#define STMT_218_INFO {"STMT_UPGRADE_23_HAS_WORKING_NODES", NULL}
|
||||
#define STMT_218 \
|
||||
#define STMT_UPGRADE_23_HAS_WORKING_NODES 219
|
||||
#define STMT_219_INFO {"STMT_UPGRADE_23_HAS_WORKING_NODES", NULL}
|
||||
#define STMT_219 \
|
||||
"SELECT 1 FROM nodes WHERE op_depth > 0 " \
|
||||
"LIMIT 1 " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_24 219
|
||||
#define STMT_219_INFO {"STMT_UPGRADE_TO_24", NULL}
|
||||
#define STMT_219 \
|
||||
#define STMT_UPGRADE_TO_24 220
|
||||
#define STMT_220_INFO {"STMT_UPGRADE_TO_24", NULL}
|
||||
#define STMT_220 \
|
||||
"UPDATE pristine SET refcount = " \
|
||||
" (SELECT COUNT(*) FROM nodes " \
|
||||
" WHERE checksum = pristine.checksum ); " \
|
||||
"PRAGMA user_version = 24; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_25 220
|
||||
#define STMT_220_INFO {"STMT_UPGRADE_TO_25", NULL}
|
||||
#define STMT_220 \
|
||||
#define STMT_UPGRADE_TO_25 221
|
||||
#define STMT_221_INFO {"STMT_UPGRADE_TO_25", NULL}
|
||||
#define STMT_221 \
|
||||
"DROP VIEW IF EXISTS NODES_CURRENT; " \
|
||||
"CREATE VIEW NODES_CURRENT AS " \
|
||||
" SELECT * FROM nodes " \
|
||||
@ -2460,9 +2471,9 @@
|
||||
"PRAGMA user_version = 25; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_26 221
|
||||
#define STMT_221_INFO {"STMT_UPGRADE_TO_26", NULL}
|
||||
#define STMT_221 \
|
||||
#define STMT_UPGRADE_TO_26 222
|
||||
#define STMT_222_INFO {"STMT_UPGRADE_TO_26", NULL}
|
||||
#define STMT_222 \
|
||||
"DROP VIEW IF EXISTS NODES_BASE; " \
|
||||
"CREATE VIEW NODES_BASE AS " \
|
||||
" SELECT * FROM nodes " \
|
||||
@ -2470,15 +2481,15 @@
|
||||
"PRAGMA user_version = 26; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_27 222
|
||||
#define STMT_222_INFO {"STMT_UPGRADE_TO_27", NULL}
|
||||
#define STMT_222 \
|
||||
#define STMT_UPGRADE_TO_27 223
|
||||
#define STMT_223_INFO {"STMT_UPGRADE_TO_27", NULL}
|
||||
#define STMT_223 \
|
||||
"PRAGMA user_version = 27; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS 223
|
||||
#define STMT_223_INFO {"STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS", NULL}
|
||||
#define STMT_223 \
|
||||
#define STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS 224
|
||||
#define STMT_224_INFO {"STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS", NULL}
|
||||
#define STMT_224 \
|
||||
"SELECT 1 FROM actual_node " \
|
||||
"WHERE NOT ((prop_reject IS NULL) AND (conflict_old IS NULL) " \
|
||||
" AND (conflict_new IS NULL) AND (conflict_working IS NULL) " \
|
||||
@ -2486,18 +2497,18 @@
|
||||
"LIMIT 1 " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_28 224
|
||||
#define STMT_224_INFO {"STMT_UPGRADE_TO_28", NULL}
|
||||
#define STMT_224 \
|
||||
#define STMT_UPGRADE_TO_28 225
|
||||
#define STMT_225_INFO {"STMT_UPGRADE_TO_28", NULL}
|
||||
#define STMT_225 \
|
||||
"UPDATE NODES SET checksum = (SELECT checksum FROM pristine " \
|
||||
" WHERE md5_checksum = nodes.checksum) " \
|
||||
"WHERE EXISTS (SELECT 1 FROM pristine WHERE md5_checksum = nodes.checksum); " \
|
||||
"PRAGMA user_version = 28; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_29 225
|
||||
#define STMT_225_INFO {"STMT_UPGRADE_TO_29", NULL}
|
||||
#define STMT_225 \
|
||||
#define STMT_UPGRADE_TO_29 226
|
||||
#define STMT_226_INFO {"STMT_UPGRADE_TO_29", NULL}
|
||||
#define STMT_226 \
|
||||
"DROP TRIGGER IF EXISTS nodes_update_checksum_trigger; " \
|
||||
"DROP TRIGGER IF EXISTS nodes_insert_trigger; " \
|
||||
"DROP TRIGGER IF EXISTS nodes_delete_trigger; " \
|
||||
@ -2527,9 +2538,9 @@
|
||||
"PRAGMA user_version = 29; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_30 226
|
||||
#define STMT_226_INFO {"STMT_UPGRADE_TO_30", NULL}
|
||||
#define STMT_226 \
|
||||
#define STMT_UPGRADE_TO_30 227
|
||||
#define STMT_227_INFO {"STMT_UPGRADE_TO_30", NULL}
|
||||
#define STMT_227 \
|
||||
"CREATE UNIQUE INDEX IF NOT EXISTS I_NODES_MOVED " \
|
||||
"ON NODES (wc_id, moved_to, op_depth); " \
|
||||
"CREATE INDEX IF NOT EXISTS I_PRISTINE_MD5 ON PRISTINE (md5_checksum); " \
|
||||
@ -2537,9 +2548,9 @@
|
||||
"UPDATE nodes SET file_external=1 WHERE file_external IS NOT NULL; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE 227
|
||||
#define STMT_227_INFO {"STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE", NULL}
|
||||
#define STMT_227 \
|
||||
#define STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE 228
|
||||
#define STMT_228_INFO {"STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE", NULL}
|
||||
#define STMT_228 \
|
||||
"SELECT wc_id, local_relpath, " \
|
||||
" conflict_old, conflict_working, conflict_new, prop_reject, tree_conflict_data " \
|
||||
"FROM actual_node " \
|
||||
@ -2551,24 +2562,24 @@
|
||||
"ORDER by wc_id, local_relpath " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_30_SET_CONFLICT 228
|
||||
#define STMT_228_INFO {"STMT_UPGRADE_30_SET_CONFLICT", NULL}
|
||||
#define STMT_228 \
|
||||
#define STMT_UPGRADE_30_SET_CONFLICT 229
|
||||
#define STMT_229_INFO {"STMT_UPGRADE_30_SET_CONFLICT", NULL}
|
||||
#define STMT_229 \
|
||||
"UPDATE actual_node SET conflict_data = ?3, conflict_old = NULL, " \
|
||||
" conflict_working = NULL, conflict_new = NULL, prop_reject = NULL, " \
|
||||
" tree_conflict_data = NULL " \
|
||||
"WHERE wc_id = ?1 and local_relpath = ?2 " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_31_ALTER_TABLE 229
|
||||
#define STMT_229_INFO {"STMT_UPGRADE_TO_31_ALTER_TABLE", NULL}
|
||||
#define STMT_229 \
|
||||
#define STMT_UPGRADE_TO_31_ALTER_TABLE 230
|
||||
#define STMT_230_INFO {"STMT_UPGRADE_TO_31_ALTER_TABLE", NULL}
|
||||
#define STMT_230 \
|
||||
"ALTER TABLE NODES ADD COLUMN inherited_props BLOB; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_31_FINALIZE 230
|
||||
#define STMT_230_INFO {"STMT_UPGRADE_TO_31_FINALIZE", NULL}
|
||||
#define STMT_230 \
|
||||
#define STMT_UPGRADE_TO_31_FINALIZE 231
|
||||
#define STMT_231_INFO {"STMT_UPGRADE_TO_31_FINALIZE", NULL}
|
||||
#define STMT_231 \
|
||||
"DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST; " \
|
||||
"DROP INDEX IF EXISTS I_EXTERNALS_PARENT; " \
|
||||
"DROP INDEX I_NODES_PARENT; " \
|
||||
@ -2580,9 +2591,9 @@
|
||||
"PRAGMA user_version = 31; " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_31_SELECT_WCROOT_NODES 231
|
||||
#define STMT_231_INFO {"STMT_UPGRADE_31_SELECT_WCROOT_NODES", NULL}
|
||||
#define STMT_231 \
|
||||
#define STMT_UPGRADE_31_SELECT_WCROOT_NODES 232
|
||||
#define STMT_232_INFO {"STMT_UPGRADE_31_SELECT_WCROOT_NODES", NULL}
|
||||
#define STMT_232 \
|
||||
"SELECT l.wc_id, l.local_relpath FROM nodes as l " \
|
||||
"LEFT OUTER JOIN nodes as r " \
|
||||
"ON l.wc_id = r.wc_id " \
|
||||
@ -2594,9 +2605,9 @@
|
||||
" OR (l.repos_path IS NOT (CASE WHEN (r.local_relpath) = '' THEN (CASE WHEN (r.repos_path) = '' THEN (l.local_relpath) WHEN (l.local_relpath) = '' THEN (r.repos_path) ELSE (r.repos_path) || '/' || (l.local_relpath) END) WHEN (r.repos_path) = '' THEN (CASE WHEN (r.local_relpath) = '' THEN (l.local_relpath) WHEN SUBSTR((l.local_relpath), 1, LENGTH(r.local_relpath)) = (r.local_relpath) THEN CASE WHEN LENGTH(r.local_relpath) = LENGTH(l.local_relpath) THEN '' WHEN SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+1, 1) = '/' THEN SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+2) END END) WHEN SUBSTR((l.local_relpath), 1, LENGTH(r.local_relpath)) = (r.local_relpath) THEN CASE WHEN LENGTH(r.local_relpath) = LENGTH(l.local_relpath) THEN (r.repos_path) WHEN SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+1, 1) = '/' THEN (r.repos_path) || SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+1) END END))) " \
|
||||
""
|
||||
|
||||
#define STMT_UPGRADE_TO_32 232
|
||||
#define STMT_232_INFO {"STMT_UPGRADE_TO_32", NULL}
|
||||
#define STMT_232 \
|
||||
#define STMT_UPGRADE_TO_32 233
|
||||
#define STMT_233_INFO {"STMT_UPGRADE_TO_32", NULL}
|
||||
#define STMT_233 \
|
||||
"DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST; " \
|
||||
"DROP INDEX IF EXISTS I_EXTERNALS_PARENT; " \
|
||||
"CREATE INDEX I_EXTERNALS_PARENT ON EXTERNALS (wc_id, parent_relpath); " \
|
||||
@ -2649,9 +2660,9 @@
|
||||
"DROP TABLE ACTUAL_NODE_BACKUP; " \
|
||||
""
|
||||
|
||||
#define STMT_VERIFICATION_TRIGGERS 233
|
||||
#define STMT_233_INFO {"STMT_VERIFICATION_TRIGGERS", NULL}
|
||||
#define STMT_233 \
|
||||
#define STMT_VERIFICATION_TRIGGERS 234
|
||||
#define STMT_234_INFO {"STMT_VERIFICATION_TRIGGERS", NULL}
|
||||
#define STMT_234 \
|
||||
"CREATE TEMPORARY TRIGGER no_repository_updates BEFORE UPDATE ON repository " \
|
||||
"BEGIN " \
|
||||
" SELECT RAISE(FAIL, 'Updates to REPOSITORY are not allowed.'); " \
|
||||
@ -2926,6 +2937,7 @@
|
||||
STMT_231, \
|
||||
STMT_232, \
|
||||
STMT_233, \
|
||||
STMT_234, \
|
||||
NULL \
|
||||
}
|
||||
|
||||
@ -3165,5 +3177,6 @@
|
||||
STMT_231_INFO, \
|
||||
STMT_232_INFO, \
|
||||
STMT_233_INFO, \
|
||||
STMT_234_INFO, \
|
||||
{NULL, NULL} \
|
||||
}
|
||||
|
@ -1716,6 +1716,10 @@ WHERE wc_id = ?1
|
||||
AND op_depth = 0
|
||||
AND (inherited_props not null)
|
||||
|
||||
-- STMT_HAVE_STAT1_TABLE
|
||||
SELECT 1 FROM sqlite_master WHERE name='sqlite_stat1' AND type='table'
|
||||
LIMIT 1
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Grab all the statements related to the schema. */
|
||||
|
@ -190,6 +190,10 @@ extern "C" {
|
||||
/* A version < this has no work queue (see workqueue.h). */
|
||||
#define SVN_WC__HAS_WORK_QUEUE 13
|
||||
|
||||
/* While we still have this DB version we should verify if there is
|
||||
sqlite_stat1 table on opening */
|
||||
#define SVN_WC__ENSURE_STAT1_TABLE 31
|
||||
|
||||
/* Return a string indicating the released version (or versions) of
|
||||
* Subversion that used WC format number WC_FORMAT, or some other
|
||||
* suitable string if no released version used WC_FORMAT.
|
||||
|
@ -708,6 +708,7 @@ insert_base_node(const insert_base_baton_t *pibb,
|
||||
svn_sqlite__stmt_t *stmt;
|
||||
svn_filesize_t recorded_size = SVN_INVALID_FILESIZE;
|
||||
apr_int64_t recorded_time;
|
||||
svn_boolean_t present;
|
||||
|
||||
/* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
|
||||
bind the appropriate parent_relpath. */
|
||||
@ -738,6 +739,9 @@ insert_base_node(const insert_base_baton_t *pibb,
|
||||
SVN_ERR(svn_sqlite__reset(stmt));
|
||||
}
|
||||
|
||||
present = (pibb->status == svn_wc__db_status_normal
|
||||
|| pibb->status == svn_wc__db_status_incomplete);
|
||||
|
||||
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
|
||||
SVN_ERR(svn_sqlite__bindf(stmt, "isdsisr"
|
||||
"tstr" /* 8 - 11 */
|
||||
@ -750,15 +754,16 @@ insert_base_node(const insert_base_baton_t *pibb,
|
||||
pibb->repos_relpath,
|
||||
pibb->revision,
|
||||
presence_map, pibb->status, /* 8 */
|
||||
(pibb->kind == svn_node_dir) ? /* 9 */
|
||||
svn_token__to_word(depth_map, pibb->depth) : NULL,
|
||||
(pibb->kind == svn_node_dir && present) /* 9 */
|
||||
? svn_token__to_word(depth_map, pibb->depth)
|
||||
: NULL,
|
||||
kind_map, pibb->kind, /* 10 */
|
||||
pibb->changed_rev, /* 11 */
|
||||
pibb->changed_date, /* 12 */
|
||||
pibb->changed_author, /* 13 */
|
||||
(pibb->kind == svn_node_symlink) ?
|
||||
(pibb->kind == svn_node_symlink && present) ?
|
||||
pibb->target : NULL)); /* 19 */
|
||||
if (pibb->kind == svn_node_file)
|
||||
if (pibb->kind == svn_node_file && present)
|
||||
{
|
||||
if (!pibb->checksum
|
||||
&& pibb->status != svn_wc__db_status_not_present
|
||||
@ -783,11 +788,14 @@ insert_base_node(const insert_base_baton_t *pibb,
|
||||
assert(pibb->status == svn_wc__db_status_normal
|
||||
|| pibb->status == svn_wc__db_status_incomplete
|
||||
|| pibb->props == NULL);
|
||||
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props,
|
||||
scratch_pool));
|
||||
if (present)
|
||||
{
|
||||
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props,
|
||||
scratch_pool));
|
||||
|
||||
SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops,
|
||||
SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops,
|
||||
scratch_pool));
|
||||
}
|
||||
|
||||
if (pibb->dav_cache)
|
||||
SVN_ERR(svn_sqlite__bind_properties(stmt, 18, pibb->dav_cache,
|
||||
@ -992,6 +1000,7 @@ insert_working_node(const insert_working_baton_t *piwb,
|
||||
const char *moved_to_relpath = NULL;
|
||||
svn_sqlite__stmt_t *stmt;
|
||||
svn_boolean_t have_row;
|
||||
svn_boolean_t present;
|
||||
|
||||
SVN_ERR_ASSERT(piwb->op_depth > 0);
|
||||
|
||||
@ -1010,6 +1019,9 @@ insert_working_node(const insert_working_baton_t *piwb,
|
||||
moved_to_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
|
||||
SVN_ERR(svn_sqlite__reset(stmt));
|
||||
|
||||
present = (piwb->presence == svn_wc__db_status_normal
|
||||
|| piwb->presence == svn_wc__db_status_incomplete);
|
||||
|
||||
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
|
||||
SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnntstrisn"
|
||||
"nnnn" /* properties translated_size last_mod_time dav_cache */
|
||||
@ -1018,14 +1030,14 @@ insert_working_node(const insert_working_baton_t *piwb,
|
||||
piwb->op_depth,
|
||||
parent_relpath,
|
||||
presence_map, piwb->presence,
|
||||
(piwb->kind == svn_node_dir)
|
||||
(piwb->kind == svn_node_dir && present)
|
||||
? svn_token__to_word(depth_map, piwb->depth) : NULL,
|
||||
kind_map, piwb->kind,
|
||||
piwb->changed_rev,
|
||||
piwb->changed_date,
|
||||
piwb->changed_author,
|
||||
/* Note: incomplete nodes may have a NULL target. */
|
||||
(piwb->kind == svn_node_symlink)
|
||||
(piwb->kind == svn_node_symlink && present)
|
||||
? piwb->target : NULL,
|
||||
moved_to_relpath));
|
||||
|
||||
@ -1034,7 +1046,7 @@ insert_working_node(const insert_working_baton_t *piwb,
|
||||
SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE));
|
||||
}
|
||||
|
||||
if (piwb->kind == svn_node_file)
|
||||
if (piwb->kind == svn_node_file && present)
|
||||
{
|
||||
SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, piwb->checksum,
|
||||
scratch_pool));
|
||||
@ -1051,7 +1063,8 @@ insert_working_node(const insert_working_baton_t *piwb,
|
||||
assert(piwb->presence == svn_wc__db_status_normal
|
||||
|| piwb->presence == svn_wc__db_status_incomplete
|
||||
|| piwb->props == NULL);
|
||||
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool));
|
||||
if (present && piwb->original_repos_relpath)
|
||||
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool));
|
||||
|
||||
SVN_ERR(svn_sqlite__insert(NULL, stmt));
|
||||
|
||||
@ -2615,17 +2628,21 @@ svn_wc__db_base_get_info(svn_wc__db_status_t *status,
|
||||
local_abspath, scratch_pool, scratch_pool));
|
||||
VERIFY_USABLE_WCROOT(wcroot);
|
||||
|
||||
SVN_ERR(svn_wc__db_base_get_info_internal(status, kind, revision,
|
||||
SVN_WC__DB_WITH_TXN4(
|
||||
svn_wc__db_base_get_info_internal(status, kind, revision,
|
||||
repos_relpath, &repos_id,
|
||||
changed_rev, changed_date,
|
||||
changed_author, depth,
|
||||
checksum, target, lock,
|
||||
had_props, props, update_root,
|
||||
wcroot, local_relpath,
|
||||
result_pool, scratch_pool));
|
||||
result_pool, scratch_pool),
|
||||
svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
|
||||
wcroot->sdb, repos_id, result_pool),
|
||||
SVN_NO_ERROR,
|
||||
SVN_NO_ERROR,
|
||||
wcroot);
|
||||
SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
|
||||
SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
|
||||
wcroot->sdb, repos_id, result_pool));
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -5339,8 +5356,8 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
|
||||
const char *original_uuid,
|
||||
svn_revnum_t original_revision,
|
||||
const apr_array_header_t *children,
|
||||
svn_boolean_t is_move,
|
||||
svn_depth_t depth,
|
||||
svn_boolean_t is_move,
|
||||
const svn_skel_t *conflict,
|
||||
const svn_skel_t *work_items,
|
||||
apr_pool_t *scratch_pool)
|
||||
@ -5367,11 +5384,6 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
|
||||
iwb.presence = svn_wc__db_status_normal;
|
||||
iwb.kind = svn_node_dir;
|
||||
|
||||
iwb.props = props;
|
||||
iwb.changed_rev = changed_rev;
|
||||
iwb.changed_date = changed_date;
|
||||
iwb.changed_author = changed_author;
|
||||
|
||||
if (original_root_url != NULL)
|
||||
{
|
||||
SVN_ERR(create_repos_id(&iwb.original_repos_id,
|
||||
@ -5379,6 +5391,11 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
|
||||
wcroot->sdb, scratch_pool));
|
||||
iwb.original_repos_relpath = original_repos_relpath;
|
||||
iwb.original_revnum = original_revision;
|
||||
|
||||
iwb.props = props;
|
||||
iwb.changed_rev = changed_rev;
|
||||
iwb.changed_date = changed_date;
|
||||
iwb.changed_author = changed_author;
|
||||
}
|
||||
|
||||
/* ### Should we do this inside the transaction? */
|
||||
@ -5447,11 +5464,6 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db,
|
||||
iwb.presence = svn_wc__db_status_normal;
|
||||
iwb.kind = svn_node_file;
|
||||
|
||||
iwb.props = props;
|
||||
iwb.changed_rev = changed_rev;
|
||||
iwb.changed_date = changed_date;
|
||||
iwb.changed_author = changed_author;
|
||||
|
||||
if (original_root_url != NULL)
|
||||
{
|
||||
SVN_ERR(create_repos_id(&iwb.original_repos_id,
|
||||
@ -5459,6 +5471,11 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db,
|
||||
wcroot->sdb, scratch_pool));
|
||||
iwb.original_repos_relpath = original_repos_relpath;
|
||||
iwb.original_revnum = original_revision;
|
||||
|
||||
iwb.props = props;
|
||||
iwb.changed_rev = changed_rev;
|
||||
iwb.changed_date = changed_date;
|
||||
iwb.changed_author = changed_author;
|
||||
}
|
||||
|
||||
/* ### Should we do this inside the transaction? */
|
||||
@ -5501,6 +5518,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
|
||||
const char *original_uuid,
|
||||
svn_revnum_t original_revision,
|
||||
const char *target,
|
||||
svn_boolean_t is_move,
|
||||
const svn_skel_t *conflict,
|
||||
const svn_skel_t *work_items,
|
||||
apr_pool_t *scratch_pool)
|
||||
@ -5525,11 +5543,6 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
|
||||
iwb.presence = svn_wc__db_status_normal;
|
||||
iwb.kind = svn_node_symlink;
|
||||
|
||||
iwb.props = props;
|
||||
iwb.changed_rev = changed_rev;
|
||||
iwb.changed_date = changed_date;
|
||||
iwb.changed_author = changed_author;
|
||||
iwb.moved_here = FALSE;
|
||||
|
||||
if (original_root_url != NULL)
|
||||
{
|
||||
@ -5538,6 +5551,11 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
|
||||
wcroot->sdb, scratch_pool));
|
||||
iwb.original_repos_relpath = original_repos_relpath;
|
||||
iwb.original_revnum = original_revision;
|
||||
|
||||
iwb.props = props;
|
||||
iwb.changed_rev = changed_rev;
|
||||
iwb.changed_date = changed_date;
|
||||
iwb.changed_author = changed_author;
|
||||
}
|
||||
|
||||
/* ### Should we do this inside the transaction? */
|
||||
@ -5547,6 +5565,8 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
|
||||
wcroot, local_relpath, scratch_pool));
|
||||
|
||||
iwb.target = target;
|
||||
iwb.moved_here = is_move && (parent_op_depth == 0 ||
|
||||
iwb.op_depth == parent_op_depth);
|
||||
|
||||
iwb.work_items = work_items;
|
||||
iwb.conflict = conflict;
|
||||
@ -7518,7 +7538,11 @@ delete_update_movedto(svn_wc__db_wcroot_t *wcroot,
|
||||
op_depth,
|
||||
new_moved_to_relpath));
|
||||
SVN_ERR(svn_sqlite__update(&affected, stmt));
|
||||
assert(affected == 1);
|
||||
#ifdef SVN_DEBUG
|
||||
/* Not fatal in release mode. The move recording is broken,
|
||||
but the rest of the working copy can handle this. */
|
||||
SVN_ERR_ASSERT(affected == 1);
|
||||
#endif
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -7908,7 +7932,12 @@ delete_node(void *baton,
|
||||
child_relpath))
|
||||
child_op_depth = delete_op_depth;
|
||||
else
|
||||
child_op_depth = relpath_depth(child_relpath);
|
||||
{
|
||||
/* Calculate depth of the shadowing at the new location */
|
||||
child_op_depth = child_op_depth
|
||||
- relpath_depth(local_relpath)
|
||||
+ relpath_depth(b->moved_to_relpath);
|
||||
}
|
||||
|
||||
fixup = TRUE;
|
||||
}
|
||||
@ -8734,19 +8763,22 @@ svn_wc__db_read_info(svn_wc__db_status_t *status,
|
||||
local_abspath, scratch_pool, scratch_pool));
|
||||
VERIFY_USABLE_WCROOT(wcroot);
|
||||
|
||||
SVN_ERR(read_info(status, kind, revision, repos_relpath, &repos_id,
|
||||
SVN_WC__DB_WITH_TXN4(
|
||||
read_info(status, kind, revision, repos_relpath, &repos_id,
|
||||
changed_rev, changed_date, changed_author,
|
||||
depth, checksum, target, original_repos_relpath,
|
||||
&original_repos_id, original_revision, lock,
|
||||
recorded_size, recorded_time, changelist, conflicted,
|
||||
op_root, have_props, props_mod,
|
||||
have_base, have_more_work, have_work,
|
||||
wcroot, local_relpath, result_pool, scratch_pool));
|
||||
SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
|
||||
wcroot->sdb, repos_id, result_pool));
|
||||
SVN_ERR(svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
|
||||
wcroot, local_relpath, result_pool, scratch_pool),
|
||||
svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
|
||||
wcroot->sdb, repos_id, result_pool),
|
||||
svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
|
||||
wcroot->sdb, original_repos_id,
|
||||
result_pool));
|
||||
result_pool),
|
||||
SVN_NO_ERROR,
|
||||
wcroot);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
@ -10865,59 +10897,86 @@ svn_wc__db_global_relocate(svn_wc__db_t *db,
|
||||
}
|
||||
|
||||
|
||||
/* Set *REPOS_ID and *REPOS_RELPATH to the BASE repository location of
|
||||
/* Helper for commit_node()
|
||||
Set *REPOS_ID and *REPOS_RELPATH to the BASE repository location of
|
||||
(WCROOT, LOCAL_RELPATH), directly if its BASE row exists or implied from
|
||||
its parent's BASE row if not. In the latter case, error if the parent
|
||||
BASE row does not exist. */
|
||||
static svn_error_t *
|
||||
determine_repos_info(apr_int64_t *repos_id,
|
||||
const char **repos_relpath,
|
||||
svn_wc__db_wcroot_t *wcroot,
|
||||
const char *local_relpath,
|
||||
apr_pool_t *result_pool,
|
||||
apr_pool_t *scratch_pool)
|
||||
determine_commit_repos_info(apr_int64_t *repos_id,
|
||||
const char **repos_relpath,
|
||||
svn_wc__db_wcroot_t *wcroot,
|
||||
const char *local_relpath,
|
||||
apr_pool_t *result_pool,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
svn_sqlite__stmt_t *stmt;
|
||||
svn_boolean_t have_row;
|
||||
const char *repos_parent_relpath;
|
||||
const char *local_parent_relpath, *name;
|
||||
|
||||
/* ### is it faster to fetch fewer columns? */
|
||||
int op_depth;
|
||||
|
||||
/* Prefer the current node's repository information. */
|
||||
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
|
||||
STMT_SELECT_BASE_NODE));
|
||||
STMT_SELECT_NODE_INFO));
|
||||
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
|
||||
SVN_ERR(svn_sqlite__step(&have_row, stmt));
|
||||
|
||||
if (have_row)
|
||||
if (!have_row)
|
||||
return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
|
||||
svn_sqlite__reset(stmt),
|
||||
_("The node '%s' was not found."),
|
||||
path_for_error_message(wcroot, local_relpath,
|
||||
scratch_pool));
|
||||
|
||||
op_depth = svn_sqlite__column_int(stmt, 0);
|
||||
|
||||
if (op_depth > 0)
|
||||
{
|
||||
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 0));
|
||||
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1));
|
||||
svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 3,
|
||||
presence_map);
|
||||
|
||||
*repos_id = svn_sqlite__column_int64(stmt, 0);
|
||||
*repos_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
|
||||
if (presence == svn_wc__db_status_base_deleted)
|
||||
{
|
||||
SVN_ERR(svn_sqlite__step_row(stmt)); /* There must be a row */
|
||||
op_depth = svn_sqlite__column_int(stmt, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *parent_repos_relpath;
|
||||
const char *parent_relpath;
|
||||
const char *name;
|
||||
|
||||
return svn_error_trace(svn_sqlite__reset(stmt));
|
||||
SVN_ERR(svn_sqlite__reset(stmt));
|
||||
|
||||
/* The repository relative path of an add/copy is based on its
|
||||
ancestor, not on the shadowed base layer.
|
||||
|
||||
As this function is only used from the commit processing we know
|
||||
the parent directory has only a BASE row, so we can just obtain
|
||||
the information directly by recursing (once!) */
|
||||
|
||||
svn_relpath_split(&parent_relpath, &name, local_relpath,
|
||||
scratch_pool);
|
||||
|
||||
SVN_ERR(determine_commit_repos_info(repos_id, &parent_repos_relpath,
|
||||
wcroot, parent_relpath,
|
||||
scratch_pool, scratch_pool));
|
||||
|
||||
*repos_relpath = svn_relpath_join(parent_repos_relpath, name,
|
||||
result_pool);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
SVN_ERR(svn_sqlite__reset(stmt));
|
||||
|
||||
/* This was a child node within this wcroot. We want to look at the
|
||||
BASE node of the directory. */
|
||||
svn_relpath_split(&local_parent_relpath, &name, local_relpath, scratch_pool);
|
||||
SVN_ERR_ASSERT(op_depth == 0); /* And that row must be BASE */
|
||||
|
||||
/* The REPOS_ID will be the same (### until we support mixed-repos) */
|
||||
SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
|
||||
&repos_parent_relpath, repos_id,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL,
|
||||
wcroot, local_parent_relpath,
|
||||
scratch_pool, scratch_pool));
|
||||
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1));
|
||||
SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 2));
|
||||
|
||||
*repos_relpath = svn_relpath_join(repos_parent_relpath, name, result_pool);
|
||||
*repos_id = svn_sqlite__column_int64(stmt, 1);
|
||||
*repos_relpath = svn_sqlite__column_text(stmt, 2, result_pool);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
return svn_error_trace(svn_sqlite__reset(stmt));
|
||||
}
|
||||
|
||||
/* Helper for svn_wc__db_global_commit()
|
||||
@ -11103,9 +11162,9 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
|
||||
|
||||
For existing nodes, we should retain the (potentially-switched)
|
||||
repository information. */
|
||||
SVN_ERR(determine_repos_info(&repos_id, &repos_relpath,
|
||||
wcroot, local_relpath,
|
||||
scratch_pool, scratch_pool));
|
||||
SVN_ERR(determine_commit_repos_info(&repos_id, &repos_relpath,
|
||||
wcroot, local_relpath,
|
||||
scratch_pool, scratch_pool));
|
||||
|
||||
/* ### is it better to select only the data needed? */
|
||||
SVN_ERR(svn_sqlite__get_statement(&stmt_info, wcroot->sdb,
|
||||
|
@ -1361,8 +1361,8 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
|
||||
const char *original_uuid,
|
||||
svn_revnum_t original_revision,
|
||||
const apr_array_header_t *children,
|
||||
svn_boolean_t is_move,
|
||||
svn_depth_t depth,
|
||||
svn_boolean_t is_move,
|
||||
const svn_skel_t *conflict,
|
||||
const svn_skel_t *work_items,
|
||||
apr_pool_t *scratch_pool);
|
||||
@ -1403,6 +1403,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
|
||||
const char *original_uuid,
|
||||
svn_revnum_t original_revision,
|
||||
const char *target,
|
||||
svn_boolean_t is_move,
|
||||
const svn_skel_t *conflict,
|
||||
const svn_skel_t *work_items,
|
||||
apr_pool_t *scratch_pool);
|
||||
|
@ -358,6 +358,18 @@ svn_wc__db_with_txn(svn_wc__db_wcroot_t *wcroot,
|
||||
SVN_SQLITE__WITH_LOCK(expr, (wcroot)->sdb)
|
||||
|
||||
|
||||
/* Evaluate the expressions EXPR1..EXPR4 within a transaction, returning the
|
||||
* first error if an error occurs.
|
||||
*
|
||||
* Begin a transaction in WCROOT's DB; evaluate the expressions, which would
|
||||
* typically be function calls that do some work in DB; finally commit
|
||||
* the transaction if EXPR evaluated to SVN_NO_ERROR, otherwise roll back
|
||||
* the transaction.
|
||||
*/
|
||||
#define SVN_WC__DB_WITH_TXN4(expr1, expr2, expr3, expr4, wcroot) \
|
||||
SVN_SQLITE__WITH_LOCK4(expr1, expr2, expr3, expr4, (wcroot)->sdb)
|
||||
|
||||
|
||||
/* Return CHILDREN mapping const char * names to svn_node_kind_t * for the
|
||||
children of LOCAL_RELPATH at OP_DEPTH. */
|
||||
svn_error_t *
|
||||
|
@ -262,7 +262,7 @@ svn_wc__db_pdh_create_wcroot(svn_wc__db_wcroot_t **wcroot,
|
||||
apr_pool_t *result_pool,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
if (sdb != NULL)
|
||||
if (sdb && format == FORMAT_FROM_SDB)
|
||||
SVN_ERR(svn_sqlite__read_schema_version(&format, sdb, scratch_pool));
|
||||
|
||||
/* If we construct a wcroot, then we better have a format. */
|
||||
@ -414,6 +414,56 @@ read_link_target(const char **link_target_abspath,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Verify if the sqlite_stat1 table exists and if not tries to add
|
||||
this table (but ignores errors on adding the schema) */
|
||||
static svn_error_t *
|
||||
verify_stats_table(svn_sqlite__db_t *sdb,
|
||||
int format,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
svn_sqlite__stmt_t *stmt;
|
||||
svn_boolean_t have_row;
|
||||
|
||||
if (format != SVN_WC__ENSURE_STAT1_TABLE)
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
|
||||
STMT_HAVE_STAT1_TABLE));
|
||||
SVN_ERR(svn_sqlite__step(&have_row, stmt));
|
||||
SVN_ERR(svn_sqlite__reset(stmt));
|
||||
|
||||
if (!have_row)
|
||||
{
|
||||
svn_error_clear(
|
||||
svn_wc__db_install_schema_statistics(sdb, scratch_pool));
|
||||
}
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Sqlite transaction helper for opening the db in
|
||||
svn_wc__db_wcroot_parse_local_abspath() to avoid multiple
|
||||
db operations that each obtain and release a lock */
|
||||
static svn_error_t *
|
||||
fetch_sdb_info(apr_int64_t *wc_id,
|
||||
int *format,
|
||||
svn_sqlite__db_t *sdb,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
*wc_id = -1;
|
||||
*format = -1;
|
||||
|
||||
SVN_SQLITE__WITH_LOCK4(
|
||||
svn_wc__db_util_fetch_wc_id(wc_id, sdb, scratch_pool),
|
||||
svn_sqlite__read_schema_version(format, sdb, scratch_pool),
|
||||
verify_stats_table(sdb, *format, scratch_pool),
|
||||
SVN_NO_ERROR,
|
||||
sdb);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
svn_error_t *
|
||||
svn_wc__db_wcroot_parse_local_abspath(svn_wc__db_wcroot_t **wcroot,
|
||||
const char **local_relpath,
|
||||
@ -654,9 +704,10 @@ svn_wc__db_wcroot_parse_local_abspath(svn_wc__db_wcroot_t **wcroot,
|
||||
/* We finally found the database. Construct a wcroot_t for it. */
|
||||
|
||||
apr_int64_t wc_id;
|
||||
int format;
|
||||
svn_error_t *err;
|
||||
|
||||
err = svn_wc__db_util_fetch_wc_id(&wc_id, sdb, scratch_pool);
|
||||
err = fetch_sdb_info(&wc_id, &format, sdb, scratch_pool);
|
||||
if (err)
|
||||
{
|
||||
if (err->apr_err == SVN_ERR_WC_CORRUPT)
|
||||
@ -677,7 +728,7 @@ svn_wc__db_wcroot_parse_local_abspath(svn_wc__db_wcroot_t **wcroot,
|
||||
symlink_wcroot_abspath
|
||||
? symlink_wcroot_abspath
|
||||
: local_abspath),
|
||||
sdb, wc_id, FORMAT_FROM_SDB,
|
||||
sdb, wc_id, format,
|
||||
db->verify_format, db->enforce_empty_wq,
|
||||
db->state_pool, scratch_pool);
|
||||
if (err && (err->apr_err == SVN_ERR_WC_UNSUPPORTED_FORMAT ||
|
||||
|
@ -509,24 +509,6 @@ static const resolver_option_t prop_conflict_options[] =
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Resolver options for an obstructued addition */
|
||||
static const resolver_option_t obstructed_add_options[] =
|
||||
{
|
||||
{ "mf", N_("my version"), N_("accept pre-existing item (ignore "
|
||||
"upstream addition) [mine-full]"),
|
||||
svn_wc_conflict_choose_mine_full },
|
||||
{ "tf", N_("their version"), N_("accept incoming item (overwrite "
|
||||
"pre-existing item) [theirs-full]"),
|
||||
svn_wc_conflict_choose_theirs_full },
|
||||
{ "p", N_("postpone"), N_("mark the conflict to be resolved later"
|
||||
" [postpone]"),
|
||||
svn_wc_conflict_choose_postpone },
|
||||
{ "q", N_("quit resolution"), N_("postpone all remaining conflicts"),
|
||||
svn_wc_conflict_choose_postpone },
|
||||
{ "h", N_("help"), N_("show this help (also '?')"), -1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Resolver options for a tree conflict */
|
||||
static const resolver_option_t tree_conflict_options[] =
|
||||
{
|
||||
@ -1132,56 +1114,6 @@ handle_tree_conflict(svn_wc_conflict_result_t *result,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Ask the user what to do about the obstructed add described by DESC.
|
||||
* Return the answer in RESULT. B is the conflict baton for this
|
||||
* conflict resolution session.
|
||||
* SCRATCH_POOL is used for temporary allocations. */
|
||||
static svn_error_t *
|
||||
handle_obstructed_add(svn_wc_conflict_result_t *result,
|
||||
const svn_wc_conflict_description2_t *desc,
|
||||
svn_cl__interactive_conflict_baton_t *b,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
apr_pool_t *iterpool;
|
||||
|
||||
SVN_ERR(svn_cmdline_fprintf(
|
||||
stderr, scratch_pool,
|
||||
_("Conflict discovered when trying to add '%s'.\n"
|
||||
"An object of the same name already exists.\n"),
|
||||
svn_cl__local_style_skip_ancestor(b->path_prefix,
|
||||
desc->local_abspath,
|
||||
scratch_pool)));
|
||||
|
||||
iterpool = svn_pool_create(scratch_pool);
|
||||
while (1)
|
||||
{
|
||||
const resolver_option_t *opt;
|
||||
|
||||
svn_pool_clear(iterpool);
|
||||
|
||||
SVN_ERR(prompt_user(&opt, obstructed_add_options, NULL, b->pb,
|
||||
iterpool));
|
||||
if (! opt)
|
||||
continue;
|
||||
|
||||
if (strcmp(opt->code, "q") == 0)
|
||||
{
|
||||
result->choice = opt->choice;
|
||||
b->accept_which = svn_cl__accept_postpone;
|
||||
b->quit = TRUE;
|
||||
break;
|
||||
}
|
||||
else if (opt->choice != -1)
|
||||
{
|
||||
result->choice = opt->choice;
|
||||
break;
|
||||
}
|
||||
}
|
||||
svn_pool_destroy(iterpool);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* The body of svn_cl__conflict_func_interactive(). */
|
||||
static svn_error_t *
|
||||
conflict_func_interactive(svn_wc_conflict_result_t **result,
|
||||
@ -1330,29 +1262,6 @@ conflict_func_interactive(svn_wc_conflict_result_t **result,
|
||||
SVN_ERR(handle_text_conflict(*result, desc, b, scratch_pool));
|
||||
else if (desc->kind == svn_wc_conflict_kind_property)
|
||||
SVN_ERR(handle_prop_conflict(*result, desc, b, result_pool, scratch_pool));
|
||||
|
||||
/*
|
||||
Dealing with obstruction of additions can be tricky. The
|
||||
obstructing item could be unversioned, versioned, or even
|
||||
schedule-add. Here's a matrix of how the caller should behave,
|
||||
based on results we return.
|
||||
|
||||
Unversioned Versioned Schedule-Add
|
||||
|
||||
choose_mine skip addition, skip addition skip addition
|
||||
add existing item
|
||||
|
||||
choose_theirs destroy file, schedule-delete, revert add,
|
||||
add new item. add new item. rm file,
|
||||
add new item
|
||||
|
||||
postpone [ bail out ]
|
||||
|
||||
*/
|
||||
else if ((desc->action == svn_wc_conflict_action_add)
|
||||
&& (desc->reason == svn_wc_conflict_reason_obstructed))
|
||||
SVN_ERR(handle_obstructed_add(*result, desc, b, scratch_pool));
|
||||
|
||||
else if (desc->kind == svn_wc_conflict_kind_tree)
|
||||
SVN_ERR(handle_tree_conflict(*result, desc, b, scratch_pool));
|
||||
|
||||
|
@ -49,6 +49,12 @@ struct print_baton {
|
||||
svn_boolean_t in_external;
|
||||
};
|
||||
|
||||
/* Field flags required for this function */
|
||||
static const apr_uint32_t print_dirent_fields = SVN_DIRENT_KIND;
|
||||
static const apr_uint32_t print_dirent_fields_verbose = (
|
||||
SVN_DIRENT_KIND | SVN_DIRENT_SIZE | SVN_DIRENT_TIME |
|
||||
SVN_DIRENT_CREATED_REV | SVN_DIRENT_LAST_AUTHOR);
|
||||
|
||||
/* This implements the svn_client_list_func2_t API, printing a single
|
||||
directory entry in text format. */
|
||||
static svn_error_t *
|
||||
@ -161,7 +167,10 @@ print_dirent(void *baton,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Field flags required for this function */
|
||||
static const apr_uint32_t print_dirent_xml_fields = (
|
||||
SVN_DIRENT_KIND | SVN_DIRENT_SIZE | SVN_DIRENT_TIME |
|
||||
SVN_DIRENT_CREATED_REV | SVN_DIRENT_LAST_AUTHOR);
|
||||
/* This implements the svn_client_list_func2_t API, printing a single dirent
|
||||
in XML format. */
|
||||
static svn_error_t *
|
||||
@ -313,10 +322,12 @@ svn_cl__list(apr_getopt_t *os,
|
||||
"mode"));
|
||||
}
|
||||
|
||||
if (opt_state->verbose || opt_state->xml)
|
||||
dirent_fields = SVN_DIRENT_ALL;
|
||||
if (opt_state->xml)
|
||||
dirent_fields = print_dirent_xml_fields;
|
||||
else if (opt_state->verbose)
|
||||
dirent_fields = print_dirent_fields_verbose;
|
||||
else
|
||||
dirent_fields = SVN_DIRENT_KIND; /* the only thing we actually need... */
|
||||
dirent_fields = print_dirent_fields;
|
||||
|
||||
pb.ctx = ctx;
|
||||
pb.verbose = opt_state->verbose;
|
||||
|
@ -1327,6 +1327,13 @@ const svn_opt_subcommand_desc2_t svn_cl__cmd_table[] =
|
||||
" directory:\n"
|
||||
" svn:ignore - A list of file glob patterns to ignore, one per line.\n"
|
||||
" svn:global-ignores - Like svn:ignore, but inheritable.\n"
|
||||
" svn:auto-props - Automatically set properties on files when they are\n"
|
||||
" added or imported. Contains key-value pairs, one per line, in the format:\n"
|
||||
" PATTERN = PROPNAME=VALUE[;PROPNAME=VALUE ...]\n"
|
||||
" Example (where a literal ';' is escaped by adding another ';'):\n"
|
||||
" *.html = svn:eol-style=native;svn:mime-type=text/html;; charset=UTF8\n"
|
||||
" Applies recursively to all files added or imported under the directory\n"
|
||||
" it is set on. See also [auto-props] in the client configuration file.\n"
|
||||
" svn:externals - A list of module specifiers, one per line, in the\n"
|
||||
" following format similar to the syntax of 'svn checkout':\n"
|
||||
" [-r REV] URL[@PEG] LOCALPATH\n"
|
||||
@ -2514,9 +2521,15 @@ sub_main(int argc, const char *argv[], apr_pool_t *pool)
|
||||
if (APR_STATUS_IS_EACCES(err->apr_err)
|
||||
|| SVN__APR_STATUS_IS_ENOTDIR(err->apr_err))
|
||||
{
|
||||
svn_config_t *empty_cfg;
|
||||
|
||||
svn_handle_warning2(stderr, err, "svn: ");
|
||||
svn_error_clear(err);
|
||||
cfg_hash = NULL;
|
||||
cfg_hash = apr_hash_make(pool);
|
||||
SVN_INT_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool));
|
||||
svn_hash_sets(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, empty_cfg);
|
||||
SVN_INT_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool));
|
||||
svn_hash_sets(cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, empty_cfg);
|
||||
}
|
||||
else
|
||||
return EXIT_ERROR(err);
|
||||
|
@ -91,8 +91,7 @@
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#undef HAVE_ZLIB_H
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
@ -116,6 +115,9 @@
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Defined to allow building against httpd 2.4 with broken auth */
|
||||
#undef SVN_ALLOW_BROKEN_HTTPD_AUTH
|
||||
|
||||
/* Define to the Python/C API format character suitable for apr_int64_t */
|
||||
#undef SVN_APR_INT64_T_PYCFMT
|
||||
|
||||
|
@ -1084,7 +1084,7 @@ subcommand_freeze(apr_getopt_t *os, void *baton, apr_pool_t *pool)
|
||||
}
|
||||
|
||||
b.command = APR_ARRAY_IDX(args, 0, const char *);
|
||||
b.args = apr_palloc(pool, sizeof(char *) * args->nelts + 1);
|
||||
b.args = apr_palloc(pool, sizeof(char *) * (args->nelts + 1));
|
||||
for (i = 0; i < args->nelts; ++i)
|
||||
b.args[i] = APR_ARRAY_IDX(args, i, const char *);
|
||||
b.args[args->nelts] = NULL;
|
||||
|
@ -791,8 +791,7 @@ adjust_mergeinfo(svn_string_t **final_val, const svn_string_t *initial_val,
|
||||
start of all history. E.g. if we dump -r100:400 then dumpfilter the
|
||||
result with --skip-missing-merge-sources, any mergeinfo with revision
|
||||
100 implies a change of -r99:100, but r99 is part of the history we
|
||||
want filtered. This is analogous to how r1 is always meaningless as
|
||||
a merge source revision.
|
||||
want filtered.
|
||||
|
||||
If the oldest rev is r0 then there is nothing to filter. */
|
||||
if (rb->pb->skip_missing_merge_sources && rb->pb->oldest_original_rev > 0)
|
||||
@ -852,7 +851,7 @@ adjust_mergeinfo(svn_string_t **final_val, const svn_string_t *initial_val,
|
||||
svn_hash_sets(final_mergeinfo, merge_source, rangelist);
|
||||
}
|
||||
|
||||
SVN_ERR(svn_mergeinfo_sort(final_mergeinfo, subpool));
|
||||
SVN_ERR(svn_mergeinfo__canonicalize_ranges(final_mergeinfo, subpool));
|
||||
SVN_ERR(svn_mergeinfo_to_string(final_val, final_mergeinfo, pool));
|
||||
svn_pool_destroy(subpool);
|
||||
|
||||
|
@ -41,6 +41,8 @@
|
||||
|
||||
#define SVNRDUMP_PROP_LOCK SVN_PROP_PREFIX "rdump-lock"
|
||||
|
||||
#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
|
||||
|
||||
#if 0
|
||||
#define LDR_DBG(x) SVN_DBG(x)
|
||||
#else
|
||||
@ -102,6 +104,15 @@ struct directory_baton
|
||||
void *baton;
|
||||
const char *relpath;
|
||||
int depth;
|
||||
|
||||
/* The copy-from source of this directory, no matter whether it is
|
||||
copied explicitly (the root node of a copy) or implicitly (being an
|
||||
existing child of a copied directory). For a node that is newly
|
||||
added (without history), even inside a copied parent, these are
|
||||
NULL and SVN_INVALID_REVNUM. */
|
||||
const char *copyfrom_path;
|
||||
svn_revnum_t copyfrom_rev;
|
||||
|
||||
struct directory_baton *parent;
|
||||
};
|
||||
|
||||
@ -115,12 +126,20 @@ struct node_baton
|
||||
svn_node_kind_t kind;
|
||||
enum svn_node_action action;
|
||||
|
||||
/* Is this directory explicitly added? If not, then it already existed
|
||||
or is a child of a copy. */
|
||||
svn_boolean_t is_added;
|
||||
|
||||
svn_revnum_t copyfrom_rev;
|
||||
const char *copyfrom_path;
|
||||
const char *copyfrom_url;
|
||||
|
||||
void *file_baton;
|
||||
const char *base_checksum;
|
||||
|
||||
/* (const char *name) -> (svn_prop_t *) */
|
||||
apr_hash_t *prop_changes;
|
||||
|
||||
struct revision_baton *rb;
|
||||
};
|
||||
|
||||
@ -316,16 +335,7 @@ renumber_mergeinfo_revs(svn_string_t **final_val,
|
||||
subpool, subpool));
|
||||
}
|
||||
|
||||
SVN_ERR(svn_mergeinfo_sort(final_mergeinfo, subpool));
|
||||
|
||||
/* Mergeinfo revision sources for r0 and r1 are invalid; you can't merge r0
|
||||
or r1. However, svndumpfilter can be abused to produce r1 merge source
|
||||
revs. So if we encounter any, then strip them out, no need to put them
|
||||
into the load target. */
|
||||
SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(&final_mergeinfo,
|
||||
final_mergeinfo,
|
||||
1, 0, FALSE,
|
||||
subpool, subpool));
|
||||
SVN_ERR(svn_mergeinfo__canonicalize_ranges(final_mergeinfo, subpool));
|
||||
|
||||
SVN_ERR(svn_mergeinfo_to_string(final_val, final_mergeinfo, pool));
|
||||
svn_pool_destroy(subpool);
|
||||
@ -550,6 +560,7 @@ new_revision_record(void **revision_baton,
|
||||
pb = parse_baton;
|
||||
rb->pool = svn_pool_create(pool);
|
||||
rb->pb = pb;
|
||||
rb->db = NULL;
|
||||
|
||||
for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
|
||||
{
|
||||
@ -601,6 +612,47 @@ uuid_record(const char *uuid,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Push information about another directory onto the linked list RB->db.
|
||||
*
|
||||
* CHILD_BATON is the baton returned by the commit editor. RELPATH is the
|
||||
* repository-relative path of this directory. IS_ADDED is true iff this
|
||||
* directory is being added (with or without history). If added with
|
||||
* history then COPYFROM_PATH/COPYFROM_REV are the copyfrom source, else
|
||||
* are NULL/SVN_INVALID_REVNUM.
|
||||
*/
|
||||
static void
|
||||
push_directory(struct revision_baton *rb,
|
||||
void *child_baton,
|
||||
const char *relpath,
|
||||
svn_boolean_t is_added,
|
||||
const char *copyfrom_path,
|
||||
svn_revnum_t copyfrom_rev)
|
||||
{
|
||||
struct directory_baton *child_db = apr_pcalloc(rb->pool, sizeof (*child_db));
|
||||
|
||||
SVN_ERR_ASSERT_NO_RETURN(
|
||||
is_added || (copyfrom_path == NULL && copyfrom_rev == SVN_INVALID_REVNUM));
|
||||
|
||||
/* If this node is an existing (not newly added) child of a copied node,
|
||||
calculate where it was copied from. */
|
||||
if (!is_added
|
||||
&& ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
|
||||
{
|
||||
const char *name = svn_relpath_basename(relpath, NULL);
|
||||
|
||||
copyfrom_path = svn_relpath_join(rb->db->copyfrom_path, name,
|
||||
rb->pool);
|
||||
copyfrom_rev = rb->db->copyfrom_rev;
|
||||
}
|
||||
|
||||
child_db->baton = child_baton;
|
||||
child_db->relpath = relpath;
|
||||
child_db->copyfrom_path = copyfrom_path;
|
||||
child_db->copyfrom_rev = copyfrom_rev;
|
||||
child_db->parent = rb->db;
|
||||
rb->db = child_db;
|
||||
}
|
||||
|
||||
static svn_error_t *
|
||||
new_node_record(void **node_baton,
|
||||
apr_hash_t *headers,
|
||||
@ -611,17 +663,17 @@ new_node_record(void **node_baton,
|
||||
const struct svn_delta_editor_t *commit_editor = rb->pb->commit_editor;
|
||||
void *commit_edit_baton = rb->pb->commit_edit_baton;
|
||||
struct node_baton *nb;
|
||||
struct directory_baton *child_db;
|
||||
apr_hash_index_t *hi;
|
||||
void *child_baton;
|
||||
char *relpath_compose;
|
||||
const char *nb_dirname;
|
||||
|
||||
nb = apr_pcalloc(rb->pool, sizeof(*nb));
|
||||
nb->rb = rb;
|
||||
|
||||
nb->is_added = FALSE;
|
||||
nb->copyfrom_path = NULL;
|
||||
nb->copyfrom_url = NULL;
|
||||
nb->copyfrom_rev = SVN_INVALID_REVNUM;
|
||||
nb->prop_changes = apr_hash_make(rb->pool);
|
||||
|
||||
/* If the creation of commit_editor is pending, create it now and
|
||||
open_root on it; also create a top-level directory baton. */
|
||||
@ -654,13 +706,9 @@ new_node_record(void **node_baton,
|
||||
|
||||
LDR_DBG(("Opened root %p\n", child_baton));
|
||||
|
||||
/* child_db corresponds to the root directory baton here */
|
||||
child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
|
||||
child_db->baton = child_baton;
|
||||
child_db->depth = 0;
|
||||
child_db->relpath = "";
|
||||
child_db->parent = NULL;
|
||||
rb->db = child_db;
|
||||
/* child_baton corresponds to the root directory baton here */
|
||||
push_directory(rb, child_baton, "", TRUE /*is_added*/,
|
||||
NULL, SVN_INVALID_REVNUM);
|
||||
}
|
||||
|
||||
for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi))
|
||||
@ -730,7 +778,7 @@ new_node_record(void **node_baton,
|
||||
|
||||
for (i = 0; i < residual_open_path->nelts; i ++)
|
||||
{
|
||||
relpath_compose =
|
||||
char *relpath_compose =
|
||||
svn_relpath_join(rb->db->relpath,
|
||||
APR_ARRAY_IDX(residual_open_path, i, const char *),
|
||||
rb->pool);
|
||||
@ -739,12 +787,8 @@ new_node_record(void **node_baton,
|
||||
rb->rev - rb->rev_offset - 1,
|
||||
rb->pool, &child_baton));
|
||||
LDR_DBG(("Opened dir %p\n", child_baton));
|
||||
child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
|
||||
child_db->baton = child_baton;
|
||||
child_db->depth = rb->db->depth + 1;
|
||||
child_db->relpath = relpath_compose;
|
||||
child_db->parent = rb->db;
|
||||
rb->db = child_db;
|
||||
push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/,
|
||||
NULL, SVN_INVALID_REVNUM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -772,7 +816,7 @@ new_node_record(void **node_baton,
|
||||
if (rb->pb->parent_dir)
|
||||
nb->copyfrom_path = svn_relpath_join(rb->pb->parent_dir,
|
||||
nb->copyfrom_path, rb->pool);
|
||||
nb->copyfrom_path = svn_path_url_add_component2(rb->pb->root_url,
|
||||
nb->copyfrom_url = svn_path_url_add_component2(rb->pb->root_url,
|
||||
nb->copyfrom_path,
|
||||
rb->pool);
|
||||
}
|
||||
@ -783,18 +827,20 @@ new_node_record(void **node_baton,
|
||||
case svn_node_action_delete:
|
||||
case svn_node_action_replace:
|
||||
LDR_DBG(("Deleting entry %s in %p\n", nb->path, rb->db->baton));
|
||||
SVN_ERR(commit_editor->delete_entry(nb->path, rb->rev - rb->rev_offset,
|
||||
SVN_ERR(commit_editor->delete_entry(nb->path,
|
||||
rb->rev - rb->rev_offset - 1,
|
||||
rb->db->baton, rb->pool));
|
||||
if (nb->action == svn_node_action_delete)
|
||||
break;
|
||||
else
|
||||
/* FALL THROUGH */;
|
||||
case svn_node_action_add:
|
||||
nb->is_added = TRUE;
|
||||
switch (nb->kind)
|
||||
{
|
||||
case svn_node_file:
|
||||
SVN_ERR(commit_editor->add_file(nb->path, rb->db->baton,
|
||||
nb->copyfrom_path,
|
||||
nb->copyfrom_url,
|
||||
nb->copyfrom_rev,
|
||||
rb->pool, &(nb->file_baton)));
|
||||
LDR_DBG(("Added file %s to dir %p as %p\n",
|
||||
@ -802,17 +848,13 @@ new_node_record(void **node_baton,
|
||||
break;
|
||||
case svn_node_dir:
|
||||
SVN_ERR(commit_editor->add_directory(nb->path, rb->db->baton,
|
||||
nb->copyfrom_path,
|
||||
nb->copyfrom_url,
|
||||
nb->copyfrom_rev,
|
||||
rb->pool, &child_baton));
|
||||
LDR_DBG(("Added dir %s to dir %p as %p\n",
|
||||
nb->path, rb->db->baton, child_baton));
|
||||
child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
|
||||
child_db->baton = child_baton;
|
||||
child_db->depth = rb->db->depth + 1;
|
||||
child_db->relpath = apr_pstrdup(rb->pool, nb->path);
|
||||
child_db->parent = rb->db;
|
||||
rb->db = child_db;
|
||||
push_directory(rb, child_baton, nb->path, TRUE /*is_added*/,
|
||||
nb->copyfrom_path, nb->copyfrom_rev);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -830,12 +872,8 @@ new_node_record(void **node_baton,
|
||||
SVN_ERR(commit_editor->open_directory(nb->path, rb->db->baton,
|
||||
rb->rev - rb->rev_offset - 1,
|
||||
rb->pool, &child_baton));
|
||||
child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
|
||||
child_db->baton = child_baton;
|
||||
child_db->depth = rb->db->depth + 1;
|
||||
child_db->relpath = apr_pstrdup(rb->pool, nb->path);
|
||||
child_db->parent = rb->db;
|
||||
rb->db = child_db;
|
||||
push_directory(rb, child_baton, nb->path, FALSE /*is_added*/,
|
||||
NULL, SVN_INVALID_REVNUM);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -887,8 +925,8 @@ set_node_property(void *baton,
|
||||
const svn_string_t *value)
|
||||
{
|
||||
struct node_baton *nb = baton;
|
||||
const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
|
||||
apr_pool_t *pool = nb->rb->pool;
|
||||
svn_prop_t *prop;
|
||||
|
||||
if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
|
||||
{
|
||||
@ -938,21 +976,11 @@ set_node_property(void *baton,
|
||||
|
||||
SVN_ERR(svn_repos__validate_prop(name, value, pool));
|
||||
|
||||
switch (nb->kind)
|
||||
{
|
||||
case svn_node_file:
|
||||
LDR_DBG(("Applying properties on %p\n", nb->file_baton));
|
||||
SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
|
||||
value, pool));
|
||||
break;
|
||||
case svn_node_dir:
|
||||
LDR_DBG(("Applying properties on %p\n", nb->rb->db->baton));
|
||||
SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
|
||||
value, pool));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
prop = apr_palloc(nb->rb->pool, sizeof (*prop));
|
||||
prop->name = apr_pstrdup(pool, name);
|
||||
prop->value = value ? svn_string_dup(value, pool) : NULL;
|
||||
svn_hash_sets(nb->prop_changes, prop->name, prop);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
@ -961,44 +989,84 @@ delete_node_property(void *baton,
|
||||
const char *name)
|
||||
{
|
||||
struct node_baton *nb = baton;
|
||||
const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
|
||||
apr_pool_t *pool = nb->rb->pool;
|
||||
svn_prop_t *prop;
|
||||
|
||||
SVN_ERR(svn_repos__validate_prop(name, NULL, pool));
|
||||
|
||||
if (nb->kind == svn_node_file)
|
||||
SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
|
||||
NULL, pool));
|
||||
else
|
||||
SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
|
||||
NULL, pool));
|
||||
prop = apr_palloc(pool, sizeof (*prop));
|
||||
prop->name = apr_pstrdup(pool, name);
|
||||
prop->value = NULL;
|
||||
svn_hash_sets(nb->prop_changes, prop->name, prop);
|
||||
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Delete all the properties of the node, if any.
|
||||
*
|
||||
* The commit editor doesn't have a method to delete a node's properties
|
||||
* without knowing what they are, so we have to first find out what
|
||||
* properties the node would have had. If it's copied (explicitly or
|
||||
* implicitly), we look at the copy source. If it's only being changed,
|
||||
* we look at the node's current path in the head revision.
|
||||
*/
|
||||
static svn_error_t *
|
||||
remove_node_props(void *baton)
|
||||
{
|
||||
struct node_baton *nb = baton;
|
||||
struct revision_baton *rb = nb->rb;
|
||||
apr_pool_t *pool = nb->rb->pool;
|
||||
apr_hash_index_t *hi;
|
||||
apr_hash_t *props;
|
||||
const char *orig_path;
|
||||
svn_revnum_t orig_rev;
|
||||
|
||||
/* Find the path and revision that has the node's original properties */
|
||||
if (ARE_VALID_COPY_ARGS(nb->copyfrom_path, nb->copyfrom_rev))
|
||||
{
|
||||
LDR_DBG(("using nb->copyfrom %s@%ld", nb->copyfrom_path, nb->copyfrom_rev));
|
||||
orig_path = nb->copyfrom_path;
|
||||
orig_rev = nb->copyfrom_rev;
|
||||
}
|
||||
else if (!nb->is_added
|
||||
&& ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
|
||||
{
|
||||
/* If this is a dir, then it's described by rb->db;
|
||||
if this is a file, then it's a child of the dir in rb->db. */
|
||||
LDR_DBG(("using rb->db->copyfrom (k=%d) %s@%ld",
|
||||
nb->kind, rb->db->copyfrom_path, rb->db->copyfrom_rev));
|
||||
orig_path = (nb->kind == svn_node_dir)
|
||||
? rb->db->copyfrom_path
|
||||
: svn_relpath_join(rb->db->copyfrom_path,
|
||||
svn_relpath_basename(nb->path, NULL),
|
||||
rb->pool);
|
||||
orig_rev = rb->db->copyfrom_rev;
|
||||
}
|
||||
else
|
||||
{
|
||||
LDR_DBG(("using self.path@head %s@%ld", nb->path, SVN_INVALID_REVNUM));
|
||||
/* ### Should we query at a known, fixed, "head" revision number
|
||||
instead of passing SVN_INVALID_REVNUM and getting a moving target? */
|
||||
orig_path = nb->path;
|
||||
orig_rev = SVN_INVALID_REVNUM;
|
||||
}
|
||||
LDR_DBG(("Trying %s@%ld", orig_path, orig_rev));
|
||||
|
||||
if ((nb->action == svn_node_action_add
|
||||
|| nb->action == svn_node_action_replace)
|
||||
&& ! SVN_IS_VALID_REVNUM(nb->copyfrom_rev))
|
||||
&& ! ARE_VALID_COPY_ARGS(orig_path, orig_rev))
|
||||
/* Add-without-history; no "old" properties to worry about. */
|
||||
return SVN_NO_ERROR;
|
||||
|
||||
if (nb->kind == svn_node_file)
|
||||
{
|
||||
SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session, nb->path,
|
||||
SVN_INVALID_REVNUM, NULL, NULL, &props, pool));
|
||||
SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session,
|
||||
orig_path, orig_rev, NULL, NULL, &props, pool));
|
||||
}
|
||||
else /* nb->kind == svn_node_dir */
|
||||
{
|
||||
SVN_ERR(svn_ra_get_dir2(nb->rb->pb->aux_session, NULL, NULL, &props,
|
||||
nb->path, SVN_INVALID_REVNUM, 0, pool));
|
||||
orig_path, orig_rev, 0, pool));
|
||||
}
|
||||
|
||||
for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
|
||||
@ -1052,6 +1120,29 @@ close_node(void *baton)
|
||||
{
|
||||
struct node_baton *nb = baton;
|
||||
const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
|
||||
apr_pool_t *pool = nb->rb->pool;
|
||||
apr_hash_index_t *hi;
|
||||
|
||||
for (hi = apr_hash_first(pool, nb->prop_changes);
|
||||
hi; hi = apr_hash_next(hi))
|
||||
{
|
||||
const char *name = svn__apr_hash_index_key(hi);
|
||||
svn_prop_t *prop = svn__apr_hash_index_val(hi);
|
||||
|
||||
switch (nb->kind)
|
||||
{
|
||||
case svn_node_file:
|
||||
SVN_ERR(commit_editor->change_file_prop(nb->file_baton,
|
||||
name, prop->value, pool));
|
||||
break;
|
||||
case svn_node_dir:
|
||||
SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton,
|
||||
name, prop->value, pool));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pass a file node closure through to the editor *unless* we
|
||||
deleted the file (which doesn't require us to open it). */
|
||||
|
@ -1710,6 +1710,11 @@ static svn_error_t *get_dir(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
|
||||
&ab, root, full_path,
|
||||
pool));
|
||||
|
||||
/* Fetch the directories' entries before starting the response, to allow
|
||||
proper error handling in cases like when FULL_PATH doesn't exist */
|
||||
if (want_contents)
|
||||
SVN_CMD_ERR(svn_fs_dir_entries(&entries, root, full_path, pool));
|
||||
|
||||
/* Begin response ... */
|
||||
SVN_ERR(svn_ra_svn__write_tuple(conn, pool, "w(r(!", "success", rev));
|
||||
SVN_ERR(svn_ra_svn__write_proplist(conn, pool, props));
|
||||
@ -1721,8 +1726,6 @@ static svn_error_t *get_dir(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
|
||||
/* Use epoch for a placeholder for a missing date. */
|
||||
const char *missing_date = svn_time_to_cstring(0, pool);
|
||||
|
||||
SVN_CMD_ERR(svn_fs_dir_entries(&entries, root, full_path, pool));
|
||||
|
||||
/* Transform the hash table's FS entries into dirents. This probably
|
||||
* belongs in libsvn_repos. */
|
||||
subpool = svn_pool_create(pool);
|
||||
@ -2465,9 +2468,30 @@ static svn_error_t *get_location_segments(svn_ra_svn_conn_t *conn,
|
||||
|
||||
abs_path = svn_fspath__join(b->fs_path->data, relative_path, pool);
|
||||
|
||||
if (SVN_IS_VALID_REVNUM(start_rev)
|
||||
&& SVN_IS_VALID_REVNUM(end_rev)
|
||||
&& (end_rev > start_rev))
|
||||
SVN_ERR(trivial_auth_request(conn, pool, b));
|
||||
SVN_ERR(log_command(baton, conn, pool, "%s",
|
||||
svn_log__get_location_segments(abs_path, peg_revision,
|
||||
start_rev, end_rev,
|
||||
pool)));
|
||||
|
||||
/* No START_REV or PEG_REVISION? We'll use HEAD. */
|
||||
if (!SVN_IS_VALID_REVNUM(start_rev) || !SVN_IS_VALID_REVNUM(peg_revision))
|
||||
{
|
||||
svn_revnum_t youngest;
|
||||
|
||||
SVN_CMD_ERR(svn_fs_youngest_rev(&youngest, b->fs, pool));
|
||||
|
||||
if (!SVN_IS_VALID_REVNUM(start_rev))
|
||||
start_rev = youngest;
|
||||
if (!SVN_IS_VALID_REVNUM(peg_revision))
|
||||
peg_revision = youngest;
|
||||
}
|
||||
|
||||
/* No END_REV? We'll use 0. */
|
||||
if (!SVN_IS_VALID_REVNUM(end_rev))
|
||||
end_rev = 0;
|
||||
|
||||
if (end_rev > start_rev)
|
||||
{
|
||||
err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
|
||||
"Get-location-segments end revision must not be "
|
||||
@ -2475,9 +2499,7 @@ static svn_error_t *get_location_segments(svn_ra_svn_conn_t *conn,
|
||||
return log_fail_and_flush(err, b, conn, pool);
|
||||
}
|
||||
|
||||
if (SVN_IS_VALID_REVNUM(peg_revision)
|
||||
&& SVN_IS_VALID_REVNUM(start_rev)
|
||||
&& (start_rev > peg_revision))
|
||||
if (start_rev > peg_revision)
|
||||
{
|
||||
err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
|
||||
"Get-location-segments start revision must not "
|
||||
@ -2485,12 +2507,6 @@ static svn_error_t *get_location_segments(svn_ra_svn_conn_t *conn,
|
||||
return log_fail_and_flush(err, b, conn, pool);
|
||||
}
|
||||
|
||||
SVN_ERR(trivial_auth_request(conn, pool, b));
|
||||
SVN_ERR(log_command(baton, conn, pool, "%s",
|
||||
svn_log__get_location_segments(abs_path, peg_revision,
|
||||
start_rev, end_rev,
|
||||
pool)));
|
||||
|
||||
/* All the parameters are fine - let's perform the query against the
|
||||
* repository. */
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "svn_subst.h"
|
||||
#include "svn_string.h"
|
||||
|
||||
#include "private/svn_string_private.h"
|
||||
|
||||
#include "sync.h"
|
||||
|
||||
#include "svn_private_config.h"
|
||||
@ -83,6 +85,92 @@ normalize_string(const svn_string_t **str,
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
/* Remove r0 references from the mergeinfo string *STR.
|
||||
*
|
||||
* r0 was never a valid mergeinfo reference and cannot be committed with
|
||||
* recent servers, but can be committed through a server older than 1.6.18
|
||||
* for HTTP or older than 1.6.17 for the other protocols. See issue #4476
|
||||
* "Mergeinfo containing r0 makes svnsync and dump and load fail".
|
||||
*
|
||||
* Set *WAS_CHANGED to TRUE if *STR was changed, otherwise to FALSE.
|
||||
*/
|
||||
static svn_error_t *
|
||||
remove_r0_mergeinfo(const svn_string_t **str,
|
||||
svn_boolean_t *was_changed,
|
||||
apr_pool_t *result_pool,
|
||||
apr_pool_t *scratch_pool)
|
||||
{
|
||||
svn_stringbuf_t *new_str = svn_stringbuf_create_empty(result_pool);
|
||||
apr_array_header_t *lines;
|
||||
int i;
|
||||
|
||||
SVN_ERR_ASSERT(*str && (*str)->data);
|
||||
|
||||
*was_changed = FALSE;
|
||||
|
||||
/* for each line */
|
||||
lines = svn_cstring_split((*str)->data, "\n", FALSE, scratch_pool);
|
||||
|
||||
for (i = 0; i < lines->nelts; i++)
|
||||
{
|
||||
char *line = APR_ARRAY_IDX(lines, i, char *);
|
||||
char *colon;
|
||||
char *rangelist;
|
||||
|
||||
/* split at the last colon */
|
||||
colon = strrchr(line, ':');
|
||||
|
||||
if (! colon)
|
||||
return svn_error_createf(SVN_ERR_MERGEINFO_PARSE_ERROR, NULL,
|
||||
_("Missing colon in svn:mergeinfo "
|
||||
"property"));
|
||||
|
||||
rangelist = colon + 1;
|
||||
|
||||
/* remove r0 */
|
||||
if (colon[1] == '0')
|
||||
{
|
||||
if (strncmp(rangelist, "0*,", 3) == 0)
|
||||
{
|
||||
rangelist += 3;
|
||||
}
|
||||
else if (strcmp(rangelist, "0*") == 0
|
||||
|| strncmp(rangelist, "0,", 2) == 0
|
||||
|| strncmp(rangelist, "0-1*", 4) == 0
|
||||
|| strncmp(rangelist, "0-1,", 4) == 0
|
||||
|| strcmp(rangelist, "0-1") == 0)
|
||||
{
|
||||
rangelist += 2;
|
||||
}
|
||||
else if (strcmp(rangelist, "0") == 0)
|
||||
{
|
||||
rangelist += 1;
|
||||
}
|
||||
else if (strncmp(rangelist, "0-", 2) == 0)
|
||||
{
|
||||
rangelist[0] = '1';
|
||||
}
|
||||
}
|
||||
|
||||
/* reassemble */
|
||||
if (rangelist[0])
|
||||
{
|
||||
if (new_str->len)
|
||||
svn_stringbuf_appendbyte(new_str, '\n');
|
||||
svn_stringbuf_appendbytes(new_str, line, colon + 1 - line);
|
||||
svn_stringbuf_appendcstr(new_str, rangelist);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp((*str)->data, new_str->data) != 0)
|
||||
{
|
||||
*was_changed = TRUE;
|
||||
}
|
||||
|
||||
*str = svn_stringbuf__morph_into_string(new_str);
|
||||
return SVN_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* Normalize the encoding and line ending style of the values of properties
|
||||
* in REV_PROPS that "need translation" (according to
|
||||
@ -153,6 +241,7 @@ typedef struct edit_baton_t {
|
||||
svn_boolean_t got_textdeltas;
|
||||
svn_revnum_t base_revision;
|
||||
svn_boolean_t quiet;
|
||||
svn_boolean_t mergeinfo_tweaked; /* Did we tweak svn:mergeinfo? */
|
||||
svn_boolean_t strip_mergeinfo; /* Are we stripping svn:mergeinfo? */
|
||||
svn_boolean_t migrate_svnmerge; /* Are we converting svnmerge.py data? */
|
||||
svn_boolean_t mergeinfo_stripped; /* Did we strip svn:mergeinfo? */
|
||||
@ -414,8 +503,19 @@ change_file_prop(void *file_baton,
|
||||
if (svn_prop_needs_translation(name))
|
||||
{
|
||||
svn_boolean_t was_normalized;
|
||||
svn_boolean_t mergeinfo_tweaked = FALSE;
|
||||
|
||||
/* Normalize encoding to UTF-8, and EOL style to LF. */
|
||||
SVN_ERR(normalize_string(&value, &was_normalized,
|
||||
eb->source_prop_encoding, pool, pool));
|
||||
/* Correct malformed mergeinfo. */
|
||||
if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
|
||||
{
|
||||
SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
|
||||
pool, pool));
|
||||
if (mergeinfo_tweaked)
|
||||
eb->mergeinfo_tweaked = TRUE;
|
||||
}
|
||||
if (was_normalized)
|
||||
(*(eb->normalized_node_props_counter))++;
|
||||
}
|
||||
@ -513,8 +613,19 @@ change_dir_prop(void *dir_baton,
|
||||
if (svn_prop_needs_translation(name))
|
||||
{
|
||||
svn_boolean_t was_normalized;
|
||||
svn_boolean_t mergeinfo_tweaked = FALSE;
|
||||
|
||||
/* Normalize encoding to UTF-8, and EOL style to LF. */
|
||||
SVN_ERR(normalize_string(&value, &was_normalized, eb->source_prop_encoding,
|
||||
pool, pool));
|
||||
/* Maybe adjust svn:mergeinfo. */
|
||||
if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
|
||||
{
|
||||
SVN_ERR(remove_r0_mergeinfo(&value, &mergeinfo_tweaked,
|
||||
pool, pool));
|
||||
if (mergeinfo_tweaked)
|
||||
eb->mergeinfo_tweaked = TRUE;
|
||||
}
|
||||
if (was_normalized)
|
||||
(*(eb->normalized_node_props_counter))++;
|
||||
}
|
||||
@ -548,6 +659,10 @@ close_edit(void *edit_baton,
|
||||
{
|
||||
if (eb->got_textdeltas)
|
||||
SVN_ERR(svn_cmdline_printf(pool, "\n"));
|
||||
if (eb->mergeinfo_tweaked)
|
||||
SVN_ERR(svn_cmdline_printf(pool,
|
||||
"NOTE: Adjusted Subversion mergeinfo in "
|
||||
"this revision.\n"));
|
||||
if (eb->mergeinfo_stripped)
|
||||
SVN_ERR(svn_cmdline_printf(pool,
|
||||
"NOTE: Dropped Subversion mergeinfo "
|
||||
|
@ -25,7 +25,7 @@
|
||||
"""
|
||||
|
||||
# $HeadURL: http://svn.apache.org/repos/asf/subversion/branches/1.8.x/win-tests.py $
|
||||
# $LastChangedRevision: 1492044 $
|
||||
# $LastChangedRevision: 1692801 $
|
||||
|
||||
import os, sys, subprocess
|
||||
import filecmp
|
||||
@ -481,6 +481,7 @@ def __init__(self, abs_httpd_dir, abs_objdir, abs_builddir, httpd_port,
|
||||
self.httpd_config = os.path.join(self.root, 'httpd.conf')
|
||||
self.httpd_users = os.path.join(self.root, 'users')
|
||||
self.httpd_mime_types = os.path.join(self.root, 'mime.types')
|
||||
self.httpd_groups = os.path.join(self.root, 'groups')
|
||||
self.abs_builddir = abs_builddir
|
||||
self.abs_objdir = abs_objdir
|
||||
self.service_name = 'svn-test-httpd-' + str(httpd_port)
|
||||
@ -494,6 +495,7 @@ def __init__(self, abs_httpd_dir, abs_objdir, abs_builddir, httpd_port,
|
||||
create_target_dir(self.root_dir)
|
||||
|
||||
self._create_users_file()
|
||||
self._create_groups_file()
|
||||
self._create_mime_types_file()
|
||||
self._create_dontdothat_file()
|
||||
|
||||
@ -540,6 +542,8 @@ def __init__(self, abs_httpd_dir, abs_objdir, abs_builddir, httpd_port,
|
||||
if self.httpd_ver >= 2.2:
|
||||
fp.write(self._sys_module('auth_basic_module', 'mod_auth_basic.so'))
|
||||
fp.write(self._sys_module('authn_file_module', 'mod_authn_file.so'))
|
||||
fp.write(self._sys_module('authz_groupfile_module', 'mod_authz_groupfile.so'))
|
||||
fp.write(self._sys_module('authz_host_module', 'mod_authz_host.so'))
|
||||
else:
|
||||
fp.write(self._sys_module('auth_module', 'mod_auth.so'))
|
||||
fp.write(self._sys_module('alias_module', 'mod_alias.so'))
|
||||
@ -562,6 +566,7 @@ def __init__(self, abs_httpd_dir, abs_objdir, abs_builddir, httpd_port,
|
||||
# Define two locations for repositories
|
||||
fp.write(self._svn_repo('repositories'))
|
||||
fp.write(self._svn_repo('local_tmp'))
|
||||
fp.write(self._svn_authz_repo())
|
||||
|
||||
# And two redirects for the redirect tests
|
||||
fp.write('RedirectMatch permanent ^/svn-test-work/repositories/'
|
||||
@ -592,6 +597,17 @@ def _create_users_file(self):
|
||||
'jrandom', 'rayjandom'])
|
||||
os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp', self.httpd_users,
|
||||
'jconstant', 'rayjandom'])
|
||||
os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp', self.httpd_users,
|
||||
'JRANDOM', 'rayjandom'])
|
||||
os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp', self.httpd_users,
|
||||
'JCONSTANT', 'rayjandom'])
|
||||
|
||||
def _create_groups_file(self):
|
||||
"Create groups for mod_authz_svn tests"
|
||||
fp = open(self.httpd_groups, 'w')
|
||||
fp.write('random: jrandom\n')
|
||||
fp.write('constant: jconstant\n')
|
||||
fp.close()
|
||||
|
||||
def _create_mime_types_file(self):
|
||||
"Create empty mime.types file"
|
||||
@ -652,6 +668,153 @@ def _svn_repo(self, name):
|
||||
' DontDoThatConfigFile ' + self._quote(self.dontdothat_file) + '\n' \
|
||||
'</Location>\n'
|
||||
|
||||
def _svn_authz_repo(self):
|
||||
local_tmp = os.path.join(self.abs_builddir,
|
||||
CMDLINE_TEST_SCRIPT_NATIVE_PATH,
|
||||
'svn-test-work', 'local_tmp')
|
||||
return \
|
||||
'<Location /authz-test-work/anon>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' <IfModule mod_authz_core.c>' + '\n' \
|
||||
' Require all granted' + '\n' \
|
||||
' </IfModule>' + '\n' \
|
||||
' <IfModule !mod_authz_core.c>' + '\n' \
|
||||
' Allow from all' + '\n' \
|
||||
' </IfModule>' + '\n' \
|
||||
' SVNPathAuthz ' + self.path_authz_option + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/mixed>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' Satisfy Any' + '\n' \
|
||||
' SVNPathAuthz ' + self.path_authz_option + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/mixed-noauthwhenanon>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' AuthzSVNNoAuthWhenAnonymousAllowed On' + '\n' \
|
||||
' SVNPathAuthz On' + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/authn>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' SVNPathAuthz ' + self.path_authz_option + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/authn-anonoff>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' AuthzSVNAnonymous Off' + '\n' \
|
||||
' SVNPathAuthz On' + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/authn-lcuser>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' AuthzForceUsernameCase Lower' + '\n' \
|
||||
' SVNPathAuthz ' + self.path_authz_option + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/authn-lcuser>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' AuthzForceUsernameCase Lower' + '\n' \
|
||||
' SVNPathAuthz ' + self.path_authz_option + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/authn-group>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' AuthGroupFile ' + self._quote(self.httpd_groups) + '\n' \
|
||||
' Require group random' + '\n' \
|
||||
' AuthzSVNAuthoritative Off' + '\n' \
|
||||
' SVNPathAuthz On' + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<IfModule mod_authz_core.c>' + '\n' \
|
||||
'<Location /authz-test-work/sallrany>' + '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' AuthzSendForbiddenOnFailure On' + '\n' \
|
||||
' Satisfy All' + '\n' \
|
||||
' <RequireAny>' + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' Require expr req(\'ALLOW\') == \'1\'' + '\n' \
|
||||
' </RequireAny>' + '\n' \
|
||||
' SVNPathAuthz ' + self.path_authz_option + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'<Location /authz-test-work/sallrall>'+ '\n' \
|
||||
' DAV svn' + '\n' \
|
||||
' SVNParentPath ' + local_tmp + '\n' \
|
||||
' AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
|
||||
' SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
|
||||
' SVNListParentPath On' + '\n' \
|
||||
' AuthType Basic' + '\n' \
|
||||
' AuthName "Subversion Repository"' + '\n' \
|
||||
' AuthUserFile ' + self._quote(self.httpd_users) + '\n' \
|
||||
' AuthzSendForbiddenOnFailure On' + '\n' \
|
||||
' Satisfy All' + '\n' \
|
||||
' <RequireAll>' + '\n' \
|
||||
' Require valid-user' + '\n' \
|
||||
' Require expr req(\'ALLOW\') == \'1\'' + '\n' \
|
||||
' </RequireAll>' + '\n' \
|
||||
' SVNPathAuthz ' + self.path_authz_option + '\n' \
|
||||
'</Location>' + '\n' \
|
||||
'</IfModule>' + '\n' \
|
||||
|
||||
def start(self):
|
||||
if self.service:
|
||||
self._start_service()
|
||||
@ -786,6 +949,10 @@ def _stop_daemon(self):
|
||||
log_file = os.path.join(abs_builddir, log)
|
||||
fail_log_file = os.path.join(abs_builddir, faillog)
|
||||
|
||||
if run_httpd:
|
||||
httpd_version = "%.1f" % daemon.httpd_ver
|
||||
else:
|
||||
httpd_version = None
|
||||
th = run_tests.TestHarness(abs_srcdir, abs_builddir,
|
||||
log_file,
|
||||
fail_log_file,
|
||||
@ -795,6 +962,7 @@ def _stop_daemon(self):
|
||||
fsfs_sharding, fsfs_packing,
|
||||
list_tests, svn_bin, mode_filter,
|
||||
milestone_filter,
|
||||
httpd_version=httpd_version,
|
||||
set_log_level=log_level, ssl_cert=ssl_cert)
|
||||
old_cwd = os.getcwd()
|
||||
try:
|
||||
|
@ -105,7 +105,7 @@
|
||||
#define PACKAGE_NAME "subversion"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "subversion 1.8.10"
|
||||
#define PACKAGE_STRING "subversion 1.8.14"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "subversion"
|
||||
@ -114,11 +114,14 @@
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.8.10"
|
||||
#define PACKAGE_VERSION "1.8.14"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Defined to allow building against httpd 2.4 with broken auth */
|
||||
/* #undef SVN_ALLOW_BROKEN_HTTPD_AUTH */
|
||||
|
||||
/* Define to the Python/C API format character suitable for apr_int64_t */
|
||||
#define SVN_APR_INT64_T_PYCFMT "l"
|
||||
|
||||
@ -129,10 +132,10 @@
|
||||
#define SVN_BINDIR "/usr/bin"
|
||||
|
||||
/* Defined to the config.guess name of the build system */
|
||||
#define SVN_BUILD_HOST "bikeshed-malachite-topaz-amber-freebsd"
|
||||
#define SVN_BUILD_HOST "bikeshed-rgb-freebsd"
|
||||
|
||||
/* Defined to the config.guess name of the build target */
|
||||
#define SVN_BUILD_TARGET "bikeshed-malachite-topaz-amber-freebsd"
|
||||
#define SVN_BUILD_TARGET "bikeshed-rgb-freebsd"
|
||||
|
||||
/* The path of a default editor for the client. */
|
||||
/* #undef SVN_CLIENT_EDITOR */
|
||||
@ -153,7 +156,7 @@
|
||||
#define SVN_FS_WANT_DB_PATCH 14
|
||||
|
||||
/* Define if compiler provides atomic builtins */
|
||||
#define SVN_HAS_ATOMIC_BUILTINS 0
|
||||
/* #undef SVN_HAS_ATOMIC_BUILTINS */
|
||||
|
||||
/* Is GNOME Keyring support enabled? */
|
||||
/* #undef SVN_HAVE_GNOME_KEYRING */
|
||||
|
Loading…
Reference in New Issue
Block a user