You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/09/24 16:02:52 UTC

svn commit: r1000876 [1/4] - in /subversion/branches/object-model: ./ build/ notes/ notes/http-and-webdav/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_diff/ subversion/libsvn_fs/ subversion/libsvn_ra/ sub...

Author: hwright
Date: Fri Sep 24 14:02:50 2010
New Revision: 1000876

URL: http://svn.apache.org/viewvc?rev=1000876&view=rev
Log:
On the object-model branch:
Bring up-to-date with trunk.

Added:
    subversion/branches/object-model/subversion/tests/cmdline/atomic-ra-revprop-change.c
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/atomic-ra-revprop-change.c
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/copy-bad-line-endings.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/copy-bad-line-endings.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/copy-bad-line-endings.expected.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/copy-bad-line-endings.expected.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/repo-with-copy-of-root-dir.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/repo-with-copy-of-root-dir.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/tag-trunk-with-file.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/tag-trunk-with-file.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/tag-trunk-with-file2.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/tag-trunk-with-file2.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/trunk-A-changes.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/trunk-A-changes.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/trunk-A-changes.expected.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/trunk-A-changes.expected.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/trunk-only.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/trunk-only.dump
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests_data/trunk-only.expected.dump
      - copied unchanged from r1000870, subversion/trunk/subversion/tests/cmdline/svnrdump_tests_data/trunk-only.expected.dump
Modified:
    subversion/branches/object-model/   (props changed)
    subversion/branches/object-model/build.conf
    subversion/branches/object-model/build/transform_libtool_scripts.sh
    subversion/branches/object-model/notes/http-and-webdav/webdav-protocol
    subversion/branches/object-model/notes/subversion-design.html
    subversion/branches/object-model/subversion/include/mod_dav_svn.h
    subversion/branches/object-model/subversion/include/private/svn_dav_protocol.h
    subversion/branches/object-model/subversion/include/svn_client.h
    subversion/branches/object-model/subversion/include/svn_dav.h
    subversion/branches/object-model/subversion/include/svn_error.h
    subversion/branches/object-model/subversion/include/svn_error_codes.h
    subversion/branches/object-model/subversion/include/svn_fs.h
    subversion/branches/object-model/subversion/include/svn_ra.h
    subversion/branches/object-model/subversion/include/svn_ra_svn.h
    subversion/branches/object-model/subversion/include/svn_repos.h
    subversion/branches/object-model/subversion/include/svn_wc.h
    subversion/branches/object-model/subversion/libsvn_client/deprecated.c
    subversion/branches/object-model/subversion/libsvn_client/externals.c
    subversion/branches/object-model/subversion/libsvn_client/prop_commands.c
    subversion/branches/object-model/subversion/libsvn_client/relocate.c
    subversion/branches/object-model/subversion/libsvn_diff/parse-diff.c
    subversion/branches/object-model/subversion/libsvn_fs/access.c
    subversion/branches/object-model/subversion/libsvn_ra/deprecated.c
    subversion/branches/object-model/subversion/libsvn_ra/ra_loader.c
    subversion/branches/object-model/subversion/libsvn_ra/ra_loader.h
    subversion/branches/object-model/subversion/libsvn_ra/wrapper_template.h
    subversion/branches/object-model/subversion/libsvn_ra_local/ra_plugin.c
    subversion/branches/object-model/subversion/libsvn_ra_neon/commit.c
    subversion/branches/object-model/subversion/libsvn_ra_neon/fetch.c
    subversion/branches/object-model/subversion/libsvn_ra_neon/options.c
    subversion/branches/object-model/subversion/libsvn_ra_neon/props.c
    subversion/branches/object-model/subversion/libsvn_ra_neon/ra_neon.h
    subversion/branches/object-model/subversion/libsvn_ra_neon/util.c
    subversion/branches/object-model/subversion/libsvn_ra_serf/commit.c
    subversion/branches/object-model/subversion/libsvn_ra_serf/options.c
    subversion/branches/object-model/subversion/libsvn_ra_serf/ra_serf.h
    subversion/branches/object-model/subversion/libsvn_ra_serf/replay.c
    subversion/branches/object-model/subversion/libsvn_ra_serf/util.c
    subversion/branches/object-model/subversion/libsvn_ra_svn/client.c
    subversion/branches/object-model/subversion/libsvn_ra_svn/protocol
    subversion/branches/object-model/subversion/libsvn_repos/deprecated.c
    subversion/branches/object-model/subversion/libsvn_repos/fs-wrap.c
    subversion/branches/object-model/subversion/libsvn_subr/error.c
    subversion/branches/object-model/subversion/libsvn_subr/sqlite.c
    subversion/branches/object-model/subversion/libsvn_subr/svn_string.c
    subversion/branches/object-model/subversion/libsvn_wc/copy.c
    subversion/branches/object-model/subversion/libsvn_wc/deprecated.c
    subversion/branches/object-model/subversion/libsvn_wc/entries.c
    subversion/branches/object-model/subversion/libsvn_wc/relocate.c
    subversion/branches/object-model/subversion/libsvn_wc/wc-queries.sql
    subversion/branches/object-model/subversion/libsvn_wc/wc_db.c
    subversion/branches/object-model/subversion/libsvn_wc/wc_db.h
    subversion/branches/object-model/subversion/mod_dav_svn/authz.c
    subversion/branches/object-model/subversion/mod_dav_svn/deadprops.c
    subversion/branches/object-model/subversion/mod_dav_svn/mod_dav_svn.c
    subversion/branches/object-model/subversion/mod_dav_svn/repos.c
    subversion/branches/object-model/subversion/mod_dav_svn/util.c
    subversion/branches/object-model/subversion/mod_dav_svn/version.c
    subversion/branches/object-model/subversion/svn/main.c
    subversion/branches/object-model/subversion/svn/switch-cmd.c
    subversion/branches/object-model/subversion/svnrdump/dump_editor.c
    subversion/branches/object-model/subversion/svnrdump/dump_editor.h
    subversion/branches/object-model/subversion/svnrdump/load_editor.c
    subversion/branches/object-model/subversion/svnrdump/svnrdump.c
    subversion/branches/object-model/subversion/svnserve/cyrus_auth.c
    subversion/branches/object-model/subversion/svnserve/serve.c
    subversion/branches/object-model/subversion/svnsync/main.c
    subversion/branches/object-model/subversion/tests/cmdline/   (props changed)
    subversion/branches/object-model/subversion/tests/cmdline/prop_tests.py
    subversion/branches/object-model/subversion/tests/cmdline/svnrdump_tests.py
    subversion/branches/object-model/subversion/tests/cmdline/svntest/actions.py
    subversion/branches/object-model/subversion/tests/cmdline/svntest/main.py
    subversion/branches/object-model/subversion/tests/cmdline/svntest/wc.py
    subversion/branches/object-model/subversion/tests/cmdline/switch_tests.py
    subversion/branches/object-model/subversion/tests/libsvn_subr/cache-test.c
    subversion/branches/object-model/subversion/tests/libsvn_subr/target-test.c
    subversion/branches/object-model/subversion/tests/libsvn_wc/db-test.c
    subversion/branches/object-model/tools/client-side/svnmucc/svnmucc.c

Propchange: subversion/branches/object-model/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Sep 24 14:02:50 2010
@@ -1,4 +1,5 @@
 /subversion/branches/1.5.x-r30215:870312
+/subversion/branches/atomic-revprop:965046-1000689
 /subversion/branches/bdb-reverse-deltas:872050-872529
 /subversion/branches/diff-callbacks3:870059-870761
 /subversion/branches/dont-save-plaintext-passwords-by-default:870728-871118
@@ -37,4 +38,4 @@
 /subversion/branches/tc_url_rev:874351-874483
 /subversion/branches/tree-conflicts:868291-873154
 /subversion/branches/tree-conflicts-notify:873926-874008
-/subversion/trunk:997486-999302
+/subversion/trunk:997486-1000870

Modified: subversion/branches/object-model/build.conf
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/build.conf?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/build.conf (original)
+++ subversion/branches/object-model/build.conf Fri Sep 24 14:02:50 2010
@@ -1021,6 +1021,15 @@ install = test
 libs = libsvn_wc libsvn_subr apriconv apr
 testing = skip
 
+[atomic-ra-revprop-change]
+type = exe
+path = subversion/tests/cmdline
+sources = atomic-ra-revprop-change.c
+install = test
+libs = libsvn_ra libsvn_subr apriconv apr
+testing = skip
+
+
 
 # ----------------------------------------------------------------------------
 #
@@ -1122,7 +1131,7 @@ libs = __ALL__
        diff-diff3-test
        ra-local-test
        svndiff-test vdelta-test
-       entries-dump
+       entries-dump atomic-ra-revprop-change
        diff-test diff3-test diff4-test
        client-test
        tree-conflict-data-test db-test pristine-store-test entries-compat-test

Modified: subversion/branches/object-model/build/transform_libtool_scripts.sh
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/build/transform_libtool_scripts.sh?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/build/transform_libtool_scripts.sh (original)
+++ subversion/branches/object-model/build/transform_libtool_scripts.sh Fri Sep 24 14:02:50 2010
@@ -57,17 +57,20 @@ svnserve="$delta $fs $ra_svn $repos $sub
 svnsync="$auth_gnome_keyring $auth_kwallet $delta $ra $subr"
 svnversion="$subr $wc"
 entries_dump="$subr $wc"
+atomic_ra_revprop_change="$subr $ra"
 
 # Variable 'executables' containing names of variables corresponding to executables
-executables="svn svnadmin svndumpfilter svnlook svnserve svnsync svnversion entries_dump"
+executables="svn svnadmin svndumpfilter svnlook svnserve svnsync svnversion entries_dump atomic_ra_revprop_change"
 
 for executable in $executables; do
   # Set variables containing paths of executables
-  if [ "$executable" != entries_dump ]; then
-    eval "${executable}_path=subversion/$executable/$executable"
-  else
+  eval "${executable}_path=subversion/$executable/$executable"
+  if [ "$executable" = entries_dump ]; then
     eval "${executable}_path=subversion/tests/cmdline/entries-dump"
   fi
+  if [ "$executable" = atomic_ra_revprop_change ]; then
+    eval "${executable}_path=subversion/tests/cmdline/atomic-ra-revprop-change"
+  fi
   # Delete duplicates in dependencies of executables
   executable_dependencies="$(echo -n $(for x in $(eval echo "\$$executable"); do echo $x; done | sort -u))"
   eval "$executable=\$executable_dependencies"

Modified: subversion/branches/object-model/notes/http-and-webdav/webdav-protocol
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/notes/http-and-webdav/webdav-protocol?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/notes/http-and-webdav/webdav-protocol (original)
+++ subversion/branches/object-model/notes/http-and-webdav/webdav-protocol Fri Sep 24 14:02:50 2010
@@ -177,6 +177,42 @@ Response:
   
   ...svn-svndiff stream that can be passed to svn_txdelta_parse_svndiff...
 
+PROPPATCH
+=========
+
+We extend PROPPATCH as follows.  To pass OLD_VALUE_P (as in
+svn_ra_change_rev_prop2()), any propchange which is accompanied by a non-NULL
+OLD_VALUE_P goes within the <D:set><D:prop> tag (and never within the
+<D:remove><D:prop> tag --- even if it is a propdel).  Consequently, in
+mod_dav_svn it would land in db_store() and not db_remove().
+
+The property tag (in the C: or S: namespace) always contains the propval in its
+cdata (potentially base64-encoded).  The extension is as follows:
+
+* The property tag grows a V:absent attribute, to represent that the property
+  is being removed (i.e., a propdel routed to <D:set><D:prop>).
+
+* A <V:old-value> tag may be nested within the property tag.  The nested tag
+  supports the same V:absent and V:encoding attributed as the parent (property)
+  tag.
+
+* To preserve SVN_ERR_FS_PROP_BASEVALUE_MISMATCH (which is part of
+  the API promise), the <D:status>HTTP/1.1 500 (status)</D:status>
+  part of the "207 Multi-Status" response is used.  We transmit in
+  it a "412 Precondition Failed" response, which ra_neon and ra_serf
+  then special-case to interpret SVN_ERR_FS_PROP_BASEVALUE_MISMATCH.
+
+  Someday we will marshal complete svn_error_t chains over the wire
+  in ra_dav, just like ra_svn does (see svn_ra_svn__handle_failure_status()),
+  or at least will preserve the outer apr_err code in more cases.  In the 
+  meantime, using 412 allows us to preserve the SVN_ERR_FS_PROP_BASEVALUE_MISMATCH
+  error code, which is required for implementing svn_ra_change_rev_prop2().
+
+Historical note: we route propdels via <D:set>/db_store() because the mod_dav
+API for db_remove() was insufficient.  See this thread:
+http://mid.gmane.org/4C531CFB.2010202@collab.net
+
+
 Custom REPORTs
 ==============
 

Modified: subversion/branches/object-model/notes/subversion-design.html
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/notes/subversion-design.html?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/notes/subversion-design.html (original)
+++ subversion/branches/object-model/notes/subversion-design.html Fri Sep 24 14:02:50 2010
@@ -2255,7 +2255,7 @@ write/Makefile:6
 
     <p>For a detailed description of exactly how Greg Stein
       <em class="email">gstein@lyra.org</em> is mapping the WebDAV DeltaV spec to
-      Subversion, see his paper: <a href="http://svn.apache.org/repos/asf/subversion/trunk/www/webdav-usage.html">http://svn.apache.org/repos/asf/subversion/trunk/www/webdav-usage.html</a>
+      Subversion, see his paper: <a href="http://svn.apache.org/repos/asf/subversion/trunk/notes/http-and-webdav/webdav-usage.html">http://svn.apache.org/repos/asf/subversion/trunk/notes/http-and-webdav/webdav-usage.html</a>
     </p>
 
     <p>For more information on WebDAV and the DeltaV extensions, see

Modified: subversion/branches/object-model/subversion/include/mod_dav_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/mod_dav_svn.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/mod_dav_svn.h (original)
+++ subversion/branches/object-model/subversion/include/mod_dav_svn.h Fri Sep 24 14:02:50 2010
@@ -48,8 +48,10 @@ extern "C" {
 
    Three special substrings of the uri are returned for convenience:
 
-   * REPOS_NAME:      The single path component that is the directory
-                      which contains the repository.
+   * REPOS_BASENAME:  The single path component that is the directory
+                      which contains the repository.  (Don't confuse
+                      this with the "repository name" as optionally
+                      defined via the SVNReposName directive!)
 
    * RELATIVE_PATH:   The remaining imaginary path components.
 
@@ -68,7 +70,7 @@ extern "C" {
    ROOT_PATH of '/svn/repos'.  But either way, we would get back:
 
      * CLEANED_URI:    /svn/repos/proj1/!svn/blah/13/A/B/alpha
-     * REPOS_NAME:     proj1
+     * REPOS_BASENAME: proj1
      * RELATIVE_PATH:  /!svn/blah/13/A/B/alpha
      * REPOS_PATH:     A/B/alpha
      * TRAILING_SLASH: FALSE
@@ -78,7 +80,7 @@ AP_MODULE_DECLARE(dav_error *) dav_svn_s
                                                  const char *root_path,
                                                  const char **cleaned_uri,
                                                  int *trailing_slash,
-                                                 const char **repos_name,
+                                                 const char **repos_basename,
                                                  const char **relative_path,
                                                  const char **repos_path);
 

Modified: subversion/branches/object-model/subversion/include/private/svn_dav_protocol.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/private/svn_dav_protocol.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/private/svn_dav_protocol.h (original)
+++ subversion/branches/object-model/subversion/include/private/svn_dav_protocol.h Fri Sep 24 14:02:50 2010
@@ -46,6 +46,17 @@ extern "C" {
 #define SVN_DAV__INCLUDE_DESCENDANTS "include-descendants"
 #define SVN_DAV__VERSION_NAME "version-name"
 
+/** Names of XML elements attributes and tags for svn_ra_change_rev_prop2()'s
+    extension of PROPPATCH.  */
+#define SVN_DAV__OLD_VALUE "old-value"
+#define SVN_DAV__OLD_VALUE__ABSENT "absent"
+
+/** Helper typedef for svn_ra_change_rev_prop2() implementation. */
+typedef struct svn_dav__two_props_t {
+  const svn_string_t *const *old_value_p;
+  const svn_string_t *new_value;
+} svn_dav__two_props_t;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/object-model/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_client.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_client.h (original)
+++ subversion/branches/object-model/subversion/include/svn_client.h Fri Sep 24 14:02:50 2010
@@ -3418,17 +3418,34 @@ svn_client_upgrade(const char *dir,
  */
 
 /**
- * Modify a working copy directory @a dir, changing any
- * repository URLs that begin with @a from to begin with @a to instead,
- * recursing into subdirectories if @a recurse is TRUE.
+ * Recursively modify a working copy rooted at @a wcroot_dir, changing any
+ * repository URLs that begin with @a from to begin with @a to instead.
  *
- * @param dir Working copy directory
+ * @param wcroot_dir Working copy root directory
  * @param from Original URL
  * @param to New URL
- * @param recurse Whether to recurse
  * @param ctx svn_client_ctx_t
  * @param pool The pool from which to perform memory allocations
+ *
+ * @since New in 1.7
+ */
+svn_error_t *
+svn_client_relocate2(const char *wcroot_dir,
+                     const char *from,
+                     const char *to,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *pool);
+
+/**
+ * Similar to svn_client_relocate2().
+ *
+ * @note As of the 1.7 API, @a dir is required to be a working copy
+ * root directory, and @a recurse is required to be TRUE.
+ *
+ * @deprecated Provided for limited backwards compatibility with the
+ * 1.6 API.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_client_relocate(const char *dir,
                     const char *from,
@@ -3437,7 +3454,6 @@ svn_client_relocate(const char *dir,
                     svn_client_ctx_t *ctx,
                     apr_pool_t *pool);
 
-
 /** @} */
 
 /**
@@ -4100,6 +4116,12 @@ svn_client_propset(const char *propname,
  * new value.  (To check that an old value is still non-existent, set
  * @a original_propval->data to NULL, and @a original_propval->len is
  * ignored.)
+ * If the server advertises #SVN_RA_CAPABILITY_ATOMIC_REVPROPS, the
+ * check of @a original_propval is done atomically.
+ *
+ * Note: the representation of "property is not set" in @a
+ * original_propval differs from the representation in other APIs
+ * (such as svn_fs_change_rev_prop2() and svn_ra_change_rev_prop2()).
  *
  * If @a force is TRUE, allow newlines in the author property.
  *

Modified: subversion/branches/object-model/subversion/include/svn_dav.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_dav.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_dav.h (original)
+++ subversion/branches/object-model/subversion/include/svn_dav.h Fri Sep 24 14:02:50 2010
@@ -243,6 +243,12 @@ extern "C" {
 #define SVN_DAV_NS_DAV_SVN_LOG_REVPROPS SVN_DAV_PROP_NS_DAV "svn/log-revprops"
 
 /** Presence of this in a DAV header in an OPTIONS response indicates
+ * that the transmitter (in this case, the server) knows how to enforce
+ * old-value atomicity in PROPPATCH (for editing revprops). */
+#define SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS\
+            SVN_DAV_PROP_NS_DAV "svn/atomic-revprops"
+
+/** Presence of this in a DAV header in an OPTIONS response indicates
  * that the transmitter (in this case, the server) knows how to handle
  * a replay of a directory in the repository (not root). */
 #define SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY\

Modified: subversion/branches/object-model/subversion/include/svn_error.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_error.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_error.h (original)
+++ subversion/branches/object-model/subversion/include/svn_error.h Fri Sep 24 14:02:50 2010
@@ -193,6 +193,15 @@ svn_error_compose(svn_error_t *chain,
 svn_error_t *
 svn_error_root_cause(svn_error_t *err);
 
+/** Return TRUE if @a err's chain contains the error code @a apr_err.
+ *
+ * If @a err is #SVN_NO_ERROR, return FALSE.
+ *
+ * @since New in 1.7.
+ */
+svn_boolean_t
+svn_error_has_cause(svn_error_t *err, apr_status_t apr_err);
+
 /** Create a new error that is a deep copy of @a err and return it.
  *
  * @since New in 1.2.

Modified: subversion/branches/object-model/subversion/include/svn_error_codes.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_error_codes.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_error_codes.h (original)
+++ subversion/branches/object-model/subversion/include/svn_error_codes.h Fri Sep 24 14:02:50 2010
@@ -1334,12 +1334,12 @@ SVN_ERROR_START
              SVN_ERR_MISC_CATEGORY_START + 32,
              "Unsupported schema found in SQLite db")
 
-/** @since New in 1.7. */
+  /** @since New in 1.7. */
   SVN_ERRDEF(SVN_ERR_SQLITE_BUSY,
              SVN_ERR_MISC_CATEGORY_START + 33,
              "The SQLite db is busy")
 
-/** @since New in 1.7. */
+  /** @since New in 1.7. */
   SVN_ERRDEF(SVN_ERR_SQLITE_RESETTING_FOR_ROLLBACK,
              SVN_ERR_MISC_CATEGORY_START + 34,
              "SQLite busy at transaction rollback; "

Modified: subversion/branches/object-model/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_fs.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_fs.h (original)
+++ subversion/branches/object-model/subversion/include/svn_fs.h Fri Sep 24 14:02:50 2010
@@ -1894,10 +1894,11 @@ svn_fs_revision_proplist(apr_hash_t **ta
  * - @a fs is a filesystem, and @a rev is the revision in that filesystem
  *   whose property should change.
  * - @a name is the name of the property to change.
- * - if @a old_value_p is not @c NULL, then @a *old_value_p is the expected old
- *   value of the property, and changing the value will fail with error
- *   #SVN_ERR_FS_PROP_BASEVALUE_MISMATCH if the present value of the property
- *   is not @a *old_value_p.  (This is an atomic test-and-set).
+ * - if @a old_value_p is not @c NULL, then changing the property will fail with
+ *   error #SVN_ERR_FS_PROP_BASEVALUE_MISMATCH if the present value of the
+ *   property is not @a *old_value_p.  (This is an atomic test-and-set).
+ *   @a *old_value_p may be @c NULL, representing that the property must be not
+ *   already set.
  * - @a value is the new value of the property, or zero if the property should
  *   be removed altogether.
  *

Modified: subversion/branches/object-model/subversion/include/svn_ra.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_ra.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_ra.h (original)
+++ subversion/branches/object-model/subversion/include/svn_ra.h Fri Sep 24 14:02:50 2010
@@ -746,12 +746,40 @@ svn_ra_get_dated_revision(svn_ra_session
  *
  * If @a value is @c NULL, delete the named revision property.
  *
+ * If the server advertises the #SVN_RA_CAPABILITY_ATOMIC_REVPROPS capability
+ * and @a old_value_p is not @c NULL, then changing the property will fail with
+ * an error chain that contains #SVN_ERR_FS_PROP_BASEVALUE_MISMATCH if the
+ * present value of the property is not @a *old_value_p.  (This is an atomic
+ * test-and-set).
+ * @a *old_value_p may be @c NULL, representing that the property must be not
+ * already set.
+ *
+ * If the capability is not advertised, then @a old_value_p MUST be @c NULL.
+ *
  * Please note that properties attached to revisions are @em unversioned.
  *
  * Use @a pool for memory allocation.
  *
+ * @see svn_fs_change_rev_prop2(), svn_error_has_cause().
+ *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_ra_change_rev_prop2(svn_ra_session_t *session,
+                        svn_revnum_t rev,
+                        const char *name,
+                        const svn_string_t *const *old_value_p,
+                        const svn_string_t *value,
+                        apr_pool_t *pool);
+
+/**
+ * Similar to svn_ra_change_rev_prop2(), but with @a old_value_p set
+ * to @c NULL.
+ *
  * @since New in 1.2.
+ * @deprecated Provided for backward compatibility with the 1.6 API.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_ra_change_rev_prop(svn_ra_session_t *session,
                        svn_revnum_t rev,
@@ -1913,6 +1941,14 @@ svn_ra_has_capability(svn_ra_session_t *
  */
 #define SVN_RA_CAPABILITY_COMMIT_REVPROPS "commit-revprops"
 
+/**
+ * The capability of specifying (and atomically verifying) expected
+ * preexisting values when modifying revprops.
+ *
+ * @since New in 1.7.
+ */
+#define SVN_RA_CAPABILITY_ATOMIC_REVPROPS "atomic-revprops"
+
 /*       *** PLEASE READ THIS IF YOU ADD A NEW CAPABILITY ***
  *
  * RA layers generally fetch all capabilities when asked about any

Modified: subversion/branches/object-model/subversion/include/svn_ra_svn.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_ra_svn.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_ra_svn.h (original)
+++ subversion/branches/object-model/subversion/include/svn_ra_svn.h Fri Sep 24 14:02:50 2010
@@ -60,6 +60,8 @@ extern "C" {
 #define SVN_RA_SVN_CAP_LOG_REVPROPS "log-revprops"
 /* maps to SVN_RA_CAPABILITY_PARTIAL_REPLAY */
 #define SVN_RA_SVN_CAP_PARTIAL_REPLAY "partial-replay"
+/* maps to SVN_RA_CAPABILITY_ATOMIC_REVPROPS */
+#define SVN_RA_SVN_CAP_ATOMIC_REVPROPS "atomic-revprops"
 
 /** ra_svn passes @c svn_dirent_t fields over the wire as a list of
  * words, these are the values used to represent each field.

Modified: subversion/branches/object-model/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_repos.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_repos.h (original)
+++ subversion/branches/object-model/subversion/include/svn_repos.h Fri Sep 24 14:02:50 2010
@@ -1994,28 +1994,55 @@ svn_repos_fs_get_locks(apr_hash_t **lock
 /** @} */
 
 /**
- * Like svn_fs_change_rev_prop(), but validate the name and value of the
+ * Like svn_fs_change_rev_prop2(), but validate the name and value of the
  * property and invoke the @a repos's pre- and post-revprop-change hooks
  * around the change as specified by @a use_pre_revprop_change_hook and
  * @a use_post_revprop_change_hook (respectively).
  *
  * @a rev is the revision whose property to change, @a name is the
  * name of the property, and @a new_value is the new value of the
- * property.   @a author is the authenticated username of the person
+ * property.   If @a old_value_p is not @c NULL, then @a *old_value_p
+ * is the expected current (preexisting) value of the property (or @c NULL
+ * for "unset").  @a author is the authenticated username of the person
  * changing the property value, or NULL if not available.
  *
  * If @a authz_read_func is non-NULL, then use it (with @a
  * authz_read_baton) to validate the changed-paths associated with @a
  * rev.  If the revision contains any unreadable changed paths, then
- * return SVN_ERR_AUTHZ_UNREADABLE.
+ * return #SVN_ERR_AUTHZ_UNREADABLE.
  *
  * Validate @a name and @a new_value like the same way
  * svn_repos_fs_change_node_prop() does.
  *
  * Use @a pool for temporary allocations.
  *
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_repos_fs_change_rev_prop4(svn_repos_t *repos,
+                              svn_revnum_t rev,
+                              const char *author,
+                              const char *name,
+                              const svn_string_t *const *old_value_p,
+                              const svn_string_t *new_value,
+                              svn_boolean_t
+                              use_pre_revprop_change_hook,
+                              svn_boolean_t
+                              use_post_revprop_change_hook,
+                              svn_repos_authz_func_t
+                              authz_read_func,
+                              void *authz_read_baton,
+                              apr_pool_t *pool);
+
+/**
+ * Similar to svn_repos_fs_change_rev_prop4(), but with @a old_value_p always
+ * set to @c NULL.  (In other words, it is similar to
+ * svn_fs_change_rev_prop().)
+ *
+ * @deprecated Provided for backward compatibility with the 1.6 API.
  * @since New in 1.5.
  */
+SVN_DEPRECATED
 svn_error_t *
 svn_repos_fs_change_rev_prop3(svn_repos_t *repos,
                               svn_revnum_t rev,

Modified: subversion/branches/object-model/subversion/include/svn_wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/include/svn_wc.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/include/svn_wc.h (original)
+++ subversion/branches/object-model/subversion/include/svn_wc.h Fri Sep 24 14:02:50 2010
@@ -6791,13 +6791,13 @@ typedef svn_error_t *(*svn_wc_relocation
                                                       const char *uuid,
                                                       const char *url);
 
-/** Change repository references at @a local_abspath and all it's children.
- * The pre-change URL should be @a from, and the post-change URL will be
- * @a to.  @a validator (and its baton, @a validator_baton), will be called
- * for the newly generated base URL and calculated repo root.
+/** Recursively change repository references at @a wcroot_abspath
+ * (which is the root directory of a working copy).  The pre-change
+ * URL should be @a from, and the post-change URL will be @a to.  @a
+ * validator (and its baton, @a validator_baton), will be called for
+ * the newly generated base URL and calculated repo root.
  *
- * If @a recurse is @c FALSE, none of the children of @a local_abspath will
- * be changed.  @a wc_ctx is an working copy context.
+ * @a wc_ctx is an working copy context.
  *
  * @a scratch_pool will be used for temporary allocations.
  *
@@ -6805,10 +6805,9 @@ typedef svn_error_t *(*svn_wc_relocation
  */
 svn_error_t *
 svn_wc_relocate4(svn_wc_context_t *wc_ctx,
-                 const char *local_abspath,
+                 const char *wcroot_abspath,
                  const char *from,
                  const char *to,
-                 svn_boolean_t recurse,
                  svn_wc_relocation_validator3_t validator,
                  void *validator_baton,
                  apr_pool_t *scratch_pool);
@@ -6816,8 +6815,12 @@ svn_wc_relocate4(svn_wc_context_t *wc_ct
 /** Similar to svn_wc_relocate4(), but with a #svn_wc_adm_access_t /
  * relative path parameter pair.
  *
+ * @note As of the 1.7 API, @a path is required to be a working copy
+ * root directory, and @a recurse is required to be TRUE.
+ *
  * @since New in 1.5.
- * @deprecated Provided for backwards compatibility with the 1.6 API.
+ * @deprecated Provided for limited backwards compatibility with the
+ * 1.6 API.
  */
 SVN_DEPRECATED
 svn_error_t *

Modified: subversion/branches/object-model/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_client/deprecated.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/object-model/subversion/libsvn_client/deprecated.c Fri Sep 24 14:02:50 2010
@@ -2039,3 +2039,18 @@ svn_client_mergeinfo_log_eligible(const 
                                   svn_depth_empty, revprops, ctx,
                                   pool);
 }
+
+/*** From relocate.c ***/
+svn_error_t *
+svn_client_relocate(const char *path,
+                    const char *from,
+                    const char *to,
+                    svn_boolean_t recurse,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *pool)
+{
+  if (! recurse)
+    svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, 0,
+                     _("Non-recursive relocation not supported"));
+  return svn_client_relocate2(path, from, to, ctx, pool);
+}

Modified: subversion/branches/object-model/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_client/externals.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/object-model/subversion/libsvn_client/externals.c Fri Sep 24 14:02:50 2010
@@ -229,8 +229,8 @@ switch_dir_external(const char *path,
                   SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root,
                                                  subpool));
 
-                  err = svn_client_relocate(path, repos_root_url, repos_root,
-                                            TRUE, ctx, subpool);
+                  err = svn_client_relocate2(path, repos_root_url, repos_root,
+                                             ctx, subpool);
                   /* If the relocation failed because the new URL points
                      to another repository, then we need to relegate and
                      check out a new WC. */

Modified: subversion/branches/object-model/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_client/prop_commands.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/object-model/subversion/libsvn_client/prop_commands.c Fri Sep 24 14:02:50 2010
@@ -450,6 +450,53 @@ svn_client_propset4(const char *propname
     }
 }
 
+static svn_error_t *
+check_and_set_revprop(svn_revnum_t *set_rev,
+                      svn_ra_session_t *ra_session,
+                      const char *propname,
+                      const svn_string_t *original_propval,
+                      const svn_string_t *propval,
+                      apr_pool_t *pool)
+{
+  if (original_propval)
+    {
+      /* Ensure old value hasn't changed behind our back. */
+      svn_string_t *current;
+      SVN_ERR(svn_ra_rev_prop(ra_session, *set_rev, propname, &current, pool));
+
+      if (original_propval->data && (! current))
+        {
+          return svn_error_createf(
+                  SVN_ERR_RA_OUT_OF_DATE, NULL,
+                  _("revprop '%s' in r%ld is unexpectedly absent "
+                    "in repository (maybe someone else deleted it?)"),
+                  propname, *set_rev);
+        }
+      else if (original_propval->data
+               && (! svn_string_compare(original_propval, current)))
+        {
+          return svn_error_createf(
+                  SVN_ERR_RA_OUT_OF_DATE, NULL,
+                  _("revprop '%s' in r%ld has unexpected value "
+                    "in repository (maybe someone else changed it?)"),
+                  propname, *set_rev);
+        }
+      else if ((! original_propval->data) && current)
+        {
+          return svn_error_createf(
+                  SVN_ERR_RA_OUT_OF_DATE, NULL,
+                  _("revprop '%s' in r%ld is unexpectedly present "
+                    "in repository (maybe someone else set it?)"),
+                  propname, *set_rev);
+        }
+    }
+
+  SVN_ERR(svn_ra_change_rev_prop2(ra_session, *set_rev, propname, 
+                                  NULL, propval, pool));
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_client_revprop_set2(const char *propname,
                         const svn_string_t *propval,
@@ -462,6 +509,7 @@ svn_client_revprop_set2(const char *prop
                         apr_pool_t *pool)
 {
   svn_ra_session_t *ra_session;
+  svn_boolean_t be_atomic;
 
   if ((strcmp(propname, SVN_PROP_REVISION_AUTHOR) == 0)
       && propval
@@ -485,42 +533,31 @@ svn_client_revprop_set2(const char *prop
   SVN_ERR(svn_client__get_revision_number(set_rev, NULL, ctx->wc_ctx, NULL,
                                           ra_session, revision, pool));
 
-  if (original_propval)
-    {
-      /* Ensure old value hasn't changed behind our back. */
-      svn_string_t *current;
-      SVN_ERR(svn_ra_rev_prop(ra_session, *set_rev, propname, &current, pool));
+  SVN_ERR(svn_ra_has_capability(ra_session, &be_atomic,
+                                SVN_RA_CAPABILITY_ATOMIC_REVPROPS, pool));
+  if (be_atomic)
+    {
+      /* Convert ORIGINAL_PROPVAL to an OLD_VALUE_P. */
+      const svn_string_t *const *old_value_p;
+      const svn_string_t *unset = NULL;
+
+      if (original_propval == NULL)
+      	old_value_p = NULL;
+      else if (original_propval->data == NULL)
+      	old_value_p = &unset;
+      else
+      	old_value_p = &original_propval;
 
-      if (original_propval->data && (! current))
-        {
-          return svn_error_createf(
-                  SVN_ERR_RA_OUT_OF_DATE, NULL,
-                  _("revprop '%s' in r%ld is unexpectedly absent "
-                    "in repository (maybe someone else deleted it?)"),
-                  propname, *set_rev);
-        }
-      else if (original_propval->data
-               && (! svn_string_compare(original_propval, current)))
-        {
-          return svn_error_createf(
-                  SVN_ERR_RA_OUT_OF_DATE, NULL,
-                  _("revprop '%s' in r%ld has unexpected value "
-                    "in repository (maybe someone else changed it?)"),
-                  propname, *set_rev);
-        }
-      else if ((! original_propval->data) && current)
-        {
-          return svn_error_createf(
-                  SVN_ERR_RA_OUT_OF_DATE, NULL,
-                  _("revprop '%s' in r%ld is unexpectedly present "
-                    "in repository (maybe someone else set it?)"),
-                  propname, *set_rev);
-        }
+      /* The actual RA call. */
+      SVN_ERR(svn_ra_change_rev_prop2(ra_session, *set_rev, propname, 
+                                      old_value_p, propval, pool));
+    }
+  else
+    {
+      /* The actual RA call. */
+      SVN_ERR(check_and_set_revprop(set_rev, ra_session, propname,
+                                    original_propval, propval, pool));
     }
-
-  /* The actual RA call. */
-  SVN_ERR(svn_ra_change_rev_prop(ra_session, *set_rev, propname, propval,
-                                 pool));
 
   if (ctx->notify_func2)
     {

Modified: subversion/branches/object-model/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_client/relocate.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/object-model/subversion/libsvn_client/relocate.c Fri Sep 24 14:02:50 2010
@@ -126,24 +126,23 @@ validator_func(void *baton,
 }
 
 svn_error_t *
-svn_client_relocate(const char *path,
-                    const char *from,
-                    const char *to,
-                    svn_boolean_t recurse,
-                    svn_client_ctx_t *ctx,
-                    apr_pool_t *pool)
+svn_client_relocate2(const char *wcroot_dir,
+                     const char *from,
+                     const char *to,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *pool)
 {
   struct validator_baton_t vb;
   const char *local_abspath;
 
-  /* Now, populate our validator callback baton, and call the relocate code. */
+  /* Populate our validator callback baton, and call the relocate code. */
   vb.ctx = ctx;
-  vb.path = path;
+  vb.path = wcroot_dir;
   vb.url_uuids = apr_array_make(pool, 1, sizeof(struct url_uuid_t));
   vb.pool = pool;
 
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
-  SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from, to, recurse,
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, wcroot_dir, pool));
+  SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from, to,
                            validator_func, &vb, pool));
 
   return SVN_NO_ERROR;

Modified: subversion/branches/object-model/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_diff/parse-diff.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/object-model/subversion/libsvn_diff/parse-diff.c Fri Sep 24 14:02:50 2010
@@ -752,8 +752,8 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
 static int
 compare_hunks(const void *a, const void *b)
 {
-  const svn_diff_hunk_t *ha = *((const svn_diff_hunk_t **)a);
-  const svn_diff_hunk_t *hb = *((const svn_diff_hunk_t **)b);
+  const svn_diff_hunk_t *ha = *((const svn_diff_hunk_t *const *)a);
+  const svn_diff_hunk_t *hb = *((const svn_diff_hunk_t *const *)b);
 
   if (ha->original_start < hb->original_start)
     return -1;

Modified: subversion/branches/object-model/subversion/libsvn_fs/access.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_fs/access.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_fs/access.c (original)
+++ subversion/branches/object-model/subversion/libsvn_fs/access.c Fri Sep 24 14:02:50 2010
@@ -87,7 +87,7 @@ svn_fs_access_add_lock_token2(svn_fs_acc
                               const char *token)
 {
   apr_hash_set(access_ctx->lock_tokens,
-               token, APR_HASH_KEY_STRING, (void *) path);
+               token, APR_HASH_KEY_STRING, path);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/object-model/subversion/libsvn_ra/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra/deprecated.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra/deprecated.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra/deprecated.c Fri Sep 24 14:02:50 2010
@@ -196,6 +196,15 @@ svn_error_t *svn_ra_open(svn_ra_session_
                       config, pool);
 }
 
+svn_error_t *svn_ra_change_rev_prop(svn_ra_session_t *session,
+                                    svn_revnum_t rev,
+                                    const char *name,
+                                    const svn_string_t *value,
+                                    apr_pool_t *pool)
+{
+  return svn_ra_change_rev_prop2(session, rev, name, NULL, value, pool);
+}
+
 svn_error_t *svn_ra_get_commit_editor2(svn_ra_session_t *session,
                                        const svn_delta_editor_t **editor,
                                        void **edit_baton,

Modified: subversion/branches/object-model/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra/ra_loader.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra/ra_loader.c Fri Sep 24 14:02:50 2010
@@ -612,14 +612,37 @@ svn_error_t *svn_ra_get_dated_revision(s
   return session->vtable->get_dated_revision(session, revision, tm, pool);
 }
 
-svn_error_t *svn_ra_change_rev_prop(svn_ra_session_t *session,
-                                    svn_revnum_t rev,
-                                    const char *name,
-                                    const svn_string_t *value,
-                                    apr_pool_t *pool)
+svn_error_t *svn_ra_change_rev_prop2(svn_ra_session_t *session,
+                                     svn_revnum_t rev,
+                                     const char *name,
+                                     const svn_string_t *const *old_value_p,
+                                     const svn_string_t *value,
+                                     apr_pool_t *pool)
 {
   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(rev));
-  return session->vtable->change_rev_prop(session, rev, name, value, pool);
+
+  /* If an old value was specified, make sure the server supports
+   * specifying it. */
+  if (old_value_p)
+    {
+      svn_boolean_t has_atomic_revprops;
+
+      SVN_ERR(svn_ra_has_capability(session, &has_atomic_revprops,
+                                    SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                    pool));
+
+      if (!has_atomic_revprops)
+        /* API violation.  (Should be an ASSERT, but gstein talked me
+         * out of it.) */
+        return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                                 _("Specifying 'old_value_p' is not allowed when "
+                                   "the '%s' capability is not advertised, and "
+                                   "could indicate a bug in your client"),
+                                   SVN_RA_CAPABILITY_ATOMIC_REVPROPS);
+    }
+
+  return session->vtable->change_rev_prop(session, rev, name,
+                                          old_value_p, value, pool);
 }
 
 svn_error_t *svn_ra_rev_proplist(svn_ra_session_t *session,

Modified: subversion/branches/object-model/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra/ra_loader.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/object-model/subversion/libsvn_ra/ra_loader.h Fri Sep 24 14:02:50 2010
@@ -77,6 +77,7 @@ typedef struct svn_ra__vtable_t {
   svn_error_t *(*change_rev_prop)(svn_ra_session_t *session,
                                   svn_revnum_t rev,
                                   const char *name,
+                                  const svn_string_t *const *old_value_p,
                                   const svn_string_t *value,
                                   apr_pool_t *pool);
 

Modified: subversion/branches/object-model/subversion/libsvn_ra/wrapper_template.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra/wrapper_template.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra/wrapper_template.h (original)
+++ subversion/branches/object-model/subversion/libsvn_ra/wrapper_template.h Fri Sep 24 14:02:50 2010
@@ -127,7 +127,7 @@ static svn_error_t *compat_change_rev_pr
                                            const svn_string_t *value,
                                            apr_pool_t *pool)
 {
-  return VTBL.change_rev_prop(session_baton, rev, propname, value, pool);
+  return VTBL.change_rev_prop(session_baton, rev, propname, NULL, value, pool);
 }
 
 static svn_error_t *compat_rev_proplist(void *session_baton,

Modified: subversion/branches/object-model/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_local/ra_plugin.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_local/ra_plugin.c Fri Sep 24 14:02:50 2010
@@ -563,14 +563,16 @@ static svn_error_t *
 svn_ra_local__change_rev_prop(svn_ra_session_t *session,
                               svn_revnum_t rev,
                               const char *name,
+                              const svn_string_t *const *old_value_p,
                               const svn_string_t *value,
                               apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
+
   SVN_ERR(get_username(session, pool));
-  return svn_repos_fs_change_rev_prop3(sess->repos, rev, sess->username,
-                                       name, value, TRUE, TRUE, NULL, NULL,
-                                       pool);
+  return svn_repos_fs_change_rev_prop4(sess->repos, rev, sess->username,
+                                       name, old_value_p, value, TRUE, TRUE,
+                                       NULL, NULL, pool);
 }
 
 static svn_error_t *
@@ -1389,7 +1391,8 @@ svn_ra_local__has_capability(svn_ra_sess
   if (strcmp(capability, SVN_RA_CAPABILITY_DEPTH) == 0
       || strcmp(capability, SVN_RA_CAPABILITY_LOG_REVPROPS) == 0
       || strcmp(capability, SVN_RA_CAPABILITY_PARTIAL_REPLAY) == 0
-      || strcmp(capability, SVN_RA_CAPABILITY_COMMIT_REVPROPS) == 0)
+      || strcmp(capability, SVN_RA_CAPABILITY_COMMIT_REVPROPS) == 0
+      || strcmp(capability, SVN_RA_CAPABILITY_ATOMIC_REVPROPS) == 0)
     {
       *has = TRUE;
     }

Modified: subversion/branches/object-model/subversion/libsvn_ra_neon/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_neon/commit.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_neon/commit.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_neon/commit.c Fri Sep 24 14:02:50 2010
@@ -616,7 +616,8 @@ static svn_error_t * do_proppatch(svn_ra
     }
 
   return svn_ra_neon__do_proppatch(ras, url, rb->prop_changes,
-                                   rb->prop_deletes, extra_headers, pool);
+                                   rb->prop_deletes, NULL, extra_headers,
+                                   pool);
 }
 
 
@@ -1416,7 +1417,7 @@ static svn_error_t * apply_revprops(comm
     return err;
 
   return svn_ra_neon__do_proppatch(cc->ras, vcc_rsrc.wr_url, revprop_table,
-                                   NULL, NULL, pool);
+                                   NULL, NULL, NULL, pool);
 }
 
 svn_error_t * svn_ra_neon__get_commit_editor(svn_ra_session_t *session,

Modified: subversion/branches/object-model/subversion/libsvn_ra_neon/fetch.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_neon/fetch.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_neon/fetch.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_neon/fetch.c Fri Sep 24 14:02:50 2010
@@ -1122,6 +1122,7 @@ svn_error_t *svn_ra_neon__get_latest_rev
 svn_error_t *svn_ra_neon__change_rev_prop(svn_ra_session_t *session,
                                           svn_revnum_t rev,
                                           const char *name,
+                                          const svn_string_t *const *old_value_p,
                                           const svn_string_t *value,
                                           apr_pool_t *pool)
 {
@@ -1130,12 +1131,24 @@ svn_error_t *svn_ra_neon__change_rev_pro
   svn_error_t *err;
   apr_hash_t *prop_changes = NULL;
   apr_array_header_t *prop_deletes = NULL;
+  apr_hash_t *prop_old_values = NULL;
   static const ne_propname wanted_props[] =
     {
       { "DAV:", "auto-version" },
       { NULL }
     };
 
+  if (old_value_p)
+    {
+      svn_boolean_t capable;
+      SVN_ERR(svn_ra_neon__has_capability(session, &capable,
+                                          SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                          pool));
+
+      /* How did you get past the same check in svn_ra_change_rev_prop2()? */
+      SVN_ERR_ASSERT(capable);
+    }
+
   /* Main objective: do a PROPPATCH (allprops) on a baseline object */
 
   /* ### A Word From Our Sponsor:  see issue #916.
@@ -1165,19 +1178,33 @@ svn_error_t *svn_ra_neon__change_rev_pro
          to attempt the PROPPATCH if the deltaV server is going to do
          auto-versioning and create a new baseline! */
 
-  if (value)
+  if (old_value_p)
     {
-      prop_changes = apr_hash_make(pool);
-      apr_hash_set(prop_changes, name, APR_HASH_KEY_STRING, value);
+      svn_dav__two_props_t *both_values;
+
+      both_values = apr_palloc(pool, sizeof(*both_values));
+      both_values->old_value_p = old_value_p;
+      both_values->new_value = value;
+
+      prop_old_values = apr_hash_make(pool);
+      apr_hash_set(prop_old_values, name, APR_HASH_KEY_STRING, both_values);
     }
   else
     {
-      prop_deletes = apr_array_make(pool, 1, sizeof(const char *));
-      APR_ARRAY_PUSH(prop_deletes, const char *) = name;
+      if (value)
+        {
+          prop_changes = apr_hash_make(pool);
+          apr_hash_set(prop_changes, name, APR_HASH_KEY_STRING, value);
+        }
+      else
+        {
+          prop_deletes = apr_array_make(pool, 1, sizeof(const char *));
+          APR_ARRAY_PUSH(prop_deletes, const char *) = name;
+        }
     }
 
   err = svn_ra_neon__do_proppatch(ras, baseline->url, prop_changes,
-                                  prop_deletes, NULL, pool);
+                                  prop_deletes, prop_old_values, NULL, pool);
   if (err)
     return
       svn_error_create

Modified: subversion/branches/object-model/subversion/libsvn_ra_neon/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_neon/options.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_neon/options.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_neon/options.c Fri Sep 24 14:02:50 2010
@@ -152,6 +152,8 @@ parse_capabilities(ne_request *req,
                APR_HASH_KEY_STRING, capability_no);
   apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
                APR_HASH_KEY_STRING, capability_no);
+  apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+               APR_HASH_KEY_STRING, capability_no);
 
   /* Then find out which ones are supported. */
   val = ne_get_response_header(req, "dav");
@@ -199,6 +201,10 @@ parse_capabilities(ne_request *req,
         apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
                      APR_HASH_KEY_STRING, capability_yes);
 
+      if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS, vals))
+        apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                     APR_HASH_KEY_STRING, capability_yes);
+
       if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY,
                                       vals))
         apr_hash_set(ras->capabilities, SVN_RA_CAPABILITY_PARTIAL_REPLAY,

Modified: subversion/branches/object-model/subversion/libsvn_ra_neon/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_neon/props.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_neon/props.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_neon/props.c Fri Sep 24 14:02:50 2010
@@ -1075,12 +1075,14 @@ get_encoding_and_cdata(const char **enco
 static svn_error_t *
 append_setprop(svn_stringbuf_t *body,
                const char *name,
+               const svn_string_t *const *old_value_p,
                const svn_string_t *value,
                apr_pool_t *pool)
 {
   const char *encoding;
   const char *xml_safe;
   const char *xml_tag_name;
+  const char *old_value_tag;
 
   /* Map property names to namespaces */
 #define NSLEN (sizeof(SVN_PROP_PREFIX) - 1)
@@ -1094,11 +1096,45 @@ append_setprop(svn_stringbuf_t *body,
       xml_tag_name = apr_pstrcat(pool, "C:", name, NULL);
     }
 
-  SVN_ERR(get_encoding_and_cdata(&encoding, &xml_safe, value, pool));
+  if (old_value_p)
+    {
+      if (*old_value_p)
+        {
+          const char *encoding2;
+          const char *xml_safe2;
+          SVN_ERR(get_encoding_and_cdata(&encoding2, &xml_safe2,
+                                         *old_value_p, pool));
+          old_value_tag = apr_psprintf(pool, "<%s %s>%s</%s>",
+                                       "V:" SVN_DAV__OLD_VALUE, encoding2,
+                                       xml_safe2, "V:" SVN_DAV__OLD_VALUE);
+        }
+      else
+        {
+#define OLD_VALUE_ABSENT_TAG \
+          "<" "V:" SVN_DAV__OLD_VALUE \
+              " V:" SVN_DAV__OLD_VALUE__ABSENT "=\"1\" " \
+          "/>"
+          old_value_tag = OLD_VALUE_ABSENT_TAG;
+        }
+    }
+  else
+    {
+      old_value_tag = "";
+    }
+
+  if (old_value_p && !value)
+    {
+      encoding = "V:" SVN_DAV__OLD_VALUE__ABSENT "=\"1\"" ;
+      xml_safe = "";
+    }
+  else
+    {
+      SVN_ERR(get_encoding_and_cdata(&encoding, &xml_safe, value, pool));
+    }
 
   svn_stringbuf_appendcstr(body,
-                           apr_psprintf(pool,"<%s %s>%s</%s>",
-                                        xml_tag_name, encoding,
+                           apr_psprintf(pool,"<%s %s>%s%s</%s>",
+                                        xml_tag_name, encoding, old_value_tag,
                                         xml_safe, xml_tag_name));
   return SVN_NO_ERROR;
 }
@@ -1109,6 +1145,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
                           const char *url,
                           apr_hash_t *prop_changes,
                           const apr_array_header_t *prop_deletes,
+                          apr_hash_t *prop_old_values,
                           apr_hash_t *extra_headers,
                           apr_pool_t *pool)
 {
@@ -1118,7 +1155,8 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
 
   /* just punt if there are no changes to make. */
   if ((prop_changes == NULL || (! apr_hash_count(prop_changes)))
-      && (prop_deletes == NULL || prop_deletes->nelts == 0))
+      && (prop_deletes == NULL || prop_deletes->nelts == 0)
+      && (prop_old_values == NULL || (! apr_hash_count(prop_old_values))))
     return SVN_NO_ERROR;
 
   /* easier to roll our own PROPPATCH here than use ne_proppatch(), which
@@ -1130,6 +1168,22 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
      SVN_DAV_PROP_NS_CUSTOM "\" xmlns:S=\""
      SVN_DAV_PROP_NS_SVN "\">" DEBUG_CR, pool);
 
+  /* Handle property changes/deletions with expected old values. */
+  if (prop_old_values)
+    {
+      apr_hash_index_t *hi;
+      svn_stringbuf_appendcstr(body, "<D:set><D:prop>");
+      for (hi = apr_hash_first(pool, prop_old_values); hi; hi = apr_hash_next(hi))
+        {
+          const char *name = svn__apr_hash_index_key(hi);
+          svn_dav__two_props_t *both_values = svn__apr_hash_index_val(hi);
+          svn_pool_clear(subpool);
+          SVN_ERR(append_setprop(body, name, both_values->old_value_p,
+                                 both_values->new_value, subpool));
+        }
+      svn_stringbuf_appendcstr(body, "</D:prop></D:set>");
+    }
+
   /* Handle property changes. */
   if (prop_changes)
     {
@@ -1141,7 +1195,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
           void *val;
           svn_pool_clear(subpool);
           apr_hash_this(hi, &key, NULL, &val);
-          SVN_ERR(append_setprop(body, key, val, subpool));
+          SVN_ERR(append_setprop(body, key, NULL, val, subpool));
         }
       svn_stringbuf_appendcstr(body, "</D:prop></D:set>");
     }
@@ -1155,7 +1209,7 @@ svn_ra_neon__do_proppatch(svn_ra_neon__s
         {
           const char *name = APR_ARRAY_IDX(prop_deletes, n, const char *);
           svn_pool_clear(subpool);
-          SVN_ERR(append_setprop(body, name, NULL, subpool));
+          SVN_ERR(append_setprop(body, name, NULL, NULL, subpool));
         }
       svn_stringbuf_appendcstr(body, "</D:prop></D:remove>");
     }

Modified: subversion/branches/object-model/subversion/libsvn_ra_neon/ra_neon.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_neon/ra_neon.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_neon/ra_neon.h (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_neon/ra_neon.h Fri Sep 24 14:02:50 2010
@@ -254,6 +254,7 @@ svn_error_t *svn_ra_neon__get_dated_revi
 svn_error_t *svn_ra_neon__change_rev_prop(svn_ra_session_t *session,
                                           svn_revnum_t rev,
                                           const char *name,
+                                          const svn_string_t *const *old_value_p,
                                           const svn_string_t *value,
                                           apr_pool_t *pool);
 
@@ -575,12 +576,15 @@ svn_error_t *svn_ra_neon__get_vcc(const 
 /* Issue a PROPPATCH request on URL, transmitting PROP_CHANGES (a hash
    of const svn_string_t * values keyed on Subversion user-visible
    property names) and PROP_DELETES (an array of property names to
-   delete).  Send any extra request headers in EXTRA_HEADERS. Use POOL
-   for all allocations.  */
+   delete). PROP_OLD_VALUES is a hash of Subversion user-visible property
+   names mapped to svn_dav__two_props_t * values. Send any extra
+   request headers in EXTRA_HEADERS. Use POOL for all allocations.
+ */
 svn_error_t *svn_ra_neon__do_proppatch(svn_ra_neon__session_t *ras,
                                        const char *url,
                                        apr_hash_t *prop_changes,
                                        const apr_array_header_t *prop_deletes,
+                                       apr_hash_t *prop_old_values,
                                        apr_hash_t *extra_headers,
                                        apr_pool_t *pool);
 

Modified: subversion/branches/object-model/subversion/libsvn_ra_neon/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_neon/util.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_neon/util.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_neon/util.c Fri Sep 24 14:02:50 2010
@@ -167,6 +167,7 @@ typedef struct
   svn_ra_neon__request_t *req;
   svn_stringbuf_t *description;
   svn_boolean_t contains_error;
+  svn_boolean_t contains_precondition_error;
 } multistatus_baton_t;
 
 /* Implements svn_ra_neon__startelm_cb_t. */
@@ -231,6 +232,9 @@ end_207_element(void *baton, int state,
             return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                     _("The request response contained at least "
                                       "one error"));
+          else if (b->contains_precondition_error) 
+            return svn_error_create(SVN_ERR_FS_PROP_BASEVALUE_MISMATCH, NULL,
+                                    b->description->data);
           else
             return svn_error_create(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                     b->description->data);
@@ -260,6 +264,10 @@ end_207_element(void *baton, int state,
             else
               b->propstat_has_error = (status.klass != 2);
 
+            /* Handle "412 Precondition Failed" specially */
+            if (status.code == 412)
+              b->contains_precondition_error = TRUE;
+
             free(status.reason_phrase);
           }
         else

Modified: subversion/branches/object-model/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_serf/commit.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_serf/commit.c Fri Sep 24 14:02:50 2010
@@ -109,6 +109,10 @@ typedef struct {
   apr_hash_t *changed_props;
   apr_hash_t *removed_props;
 
+  /* Same, for the old value (*old_value_p). */
+  apr_hash_t *previous_changed_props;
+  apr_hash_t *previous_removed_props;
+
   /* In HTTP v2, this is the file/directory version we think we're changing. */
   svn_revnum_t base_revision;
 
@@ -639,16 +643,17 @@ checkout_file(file_context_t *file)
 /* Helper function for proppatch_walker() below. */
 static svn_error_t *
 get_encoding_and_cdata(const char **encoding_p,
-                       serf_bucket_t **cdata_bkt_p,
+                       const svn_string_t **encoded_value_p,
                        serf_bucket_alloc_t *alloc,
                        const svn_string_t *value,
                        apr_pool_t *pool)
 {
-  const char *encoding;
-  const char *cdata;
-  apr_size_t len; /* of cdata */
-
-  SVN_ERR_ASSERT(value);
+  if (value == NULL)
+    {
+      *encoding_p = NULL;
+      *encoded_value_p = NULL;
+      return SVN_NO_ERROR;
+    }
 
   /* If a property is XML-safe, XML-encode it.  Else, base64-encode
      it. */
@@ -656,23 +661,72 @@ get_encoding_and_cdata(const char **enco
     {
       svn_stringbuf_t *xml_esc = NULL;
       svn_xml_escape_cdata_string(&xml_esc, value, pool);
-      encoding = NULL;
-      cdata = xml_esc->data;
-      len = xml_esc->len;
+      *encoding_p = NULL;
+      *encoded_value_p = svn_string_create_from_buf(xml_esc, pool);
     }
   else
     {
-      const svn_string_t *base64ed = svn_base64_encode_string2(value, TRUE,
-                                                               pool);
-      encoding = "base64";
-      cdata = base64ed->data;
-      len = base64ed->len;
+      *encoding_p = "base64";
+      *encoded_value_p = svn_base64_encode_string2(value, TRUE, pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+typedef struct walker_baton_t {
+  serf_bucket_t *body_bkt;
+  apr_hash_t *previous_changed_props;
+  apr_hash_t *previous_removed_props;
+  const char *path;
+
+  /* Hack, since change_rev_prop(old_value_p != NULL, value = NULL) uses D:set
+     rather than D:remove...  (see notes/http-and-webdav/webdav-protocol) */
+  enum {
+    filter_all_props,
+    filter_props_with_old_value,
+    filter_props_without_old_value
+  } filter;
+
+  /* Is the property being deleted? */
+  svn_boolean_t deleting;
+} walker_baton_t;
+
+static svn_error_t *
+derive_old_val(const svn_string_t *const *   *old_val_p_p,
+               walker_baton_t *wb,
+               const char *ns,
+               const char *name,
+               apr_pool_t *pool)
+{
+  const svn_string_t *const *old_val_p;
+
+  old_val_p = NULL;
+
+  if (wb->previous_changed_props)
+    {
+      const svn_string_t *old_val;
+      old_val = svn_ra_serf__get_prop_string(wb->previous_changed_props,
+                                             wb->path, ns, name);
+      if (old_val)
+        {
+          old_val_p = apr_pcalloc(pool, sizeof(*old_val_p));
+          *(const svn_string_t **)old_val_p = svn_string_dup(old_val, pool);
+        }
     }
 
-  /* ENCODING, CDATA, and LEN are now set. */
+  if (wb->previous_removed_props)
+    {
+      const svn_string_t *old_val;
+      old_val = svn_ra_serf__get_prop_string(wb->previous_removed_props,
+                                             wb->path, ns, name);
+      if (old_val)
+        {
+          old_val_p = apr_pcalloc(pool, sizeof(*old_val_p));
+          *(const svn_string_t **)old_val_p = NULL;
+        }
+    }
 
-  *encoding_p = encoding;
-  *cdata_bkt_p = SERF_BUCKET_SIMPLE_STRING_LEN(cdata, len, alloc);
+  *old_val_p_p = old_val_p;
   return SVN_NO_ERROR;
 }
 
@@ -683,10 +737,13 @@ proppatch_walker(void *baton,
                  const svn_string_t *val,
                  apr_pool_t *pool)
 {
-  serf_bucket_t *body_bkt = baton;
+  walker_baton_t *wb = baton;
+  serf_bucket_t *body_bkt = wb->body_bkt;
   serf_bucket_t *cdata_bkt;
   serf_bucket_alloc_t *alloc;
   const char *encoding;
+  const svn_string_t *const *old_val_p;
+  const svn_string_t *encoded_value;
   char *prop_name;
 
   /* Use the namespace prefix instead of adding the xmlns attribute to support
@@ -697,14 +754,82 @@ proppatch_walker(void *baton,
     prop_name = apr_pstrcat(pool, "C:", name, NULL);
   name_len = strlen(prop_name);
 
+  SVN_ERR(derive_old_val(&old_val_p, wb, ns, name, pool));
+
+  /* Jump through hoops to work with D:remove and its val = (""-for-NULL)
+   * representation. */
+  if (wb->filter != filter_all_props)
+    {
+      if (wb->filter == filter_props_with_old_value && ! old_val_p)
+      	return SVN_NO_ERROR;
+      if (wb->filter == filter_props_without_old_value && old_val_p)
+      	return SVN_NO_ERROR;
+    }
+  if (wb->deleting)
+    val = NULL;
+
   alloc = body_bkt->allocator;
 
-  SVN_ERR(get_encoding_and_cdata(&encoding, &cdata_bkt, alloc, val, pool));
+  SVN_ERR(get_encoding_and_cdata(&encoding, &encoded_value, alloc, val, pool));
+  if (encoded_value)
+    {
+      cdata_bkt = SERF_BUCKET_SIMPLE_STRING_LEN(encoded_value->data,
+                                                encoded_value->len,
+                                                alloc);
+    }
+  else
+    {
+      cdata_bkt = NULL;
+    }
 
-  svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
-                                    "V:encoding", encoding,
-                                    NULL);
-  serf_bucket_aggregate_append(body_bkt, cdata_bkt);
+  if (cdata_bkt)
+    svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
+                                      "V:encoding", encoding,
+                                      NULL);
+  else
+    svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, prop_name,
+                                      "V:" SVN_DAV__OLD_VALUE__ABSENT, "1",
+                                      NULL);
+
+  if (old_val_p)
+    {
+      const char *encoding2;
+      const svn_string_t *encoded_value2;
+      serf_bucket_t *cdata_bkt2;
+
+      SVN_ERR(get_encoding_and_cdata(&encoding2, &encoded_value2,
+                                     alloc, *old_val_p, pool));
+
+      if (encoded_value2)
+        {
+          cdata_bkt2 = SERF_BUCKET_SIMPLE_STRING_LEN(encoded_value2->data,
+                                                     encoded_value2->len,
+                                                     alloc);
+        }
+      else
+        {
+          cdata_bkt2 = NULL;
+        }
+
+      if (cdata_bkt2)
+        svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
+                                          "V:" SVN_DAV__OLD_VALUE,
+                                          "V:encoding", encoding2,
+                                          NULL);
+      else
+        svn_ra_serf__add_open_tag_buckets(body_bkt, alloc,
+                                          "V:" SVN_DAV__OLD_VALUE,
+                                          "V:" SVN_DAV__OLD_VALUE__ABSENT, "1",
+                                          NULL);
+
+      if (cdata_bkt2)
+        serf_bucket_aggregate_append(body_bkt, cdata_bkt2);
+
+      svn_ra_serf__add_close_tag_buckets(body_bkt, alloc,
+                                         "V:" SVN_DAV__OLD_VALUE);
+    }
+  if (cdata_bkt)
+    serf_bucket_aggregate_append(body_bkt, cdata_bkt);
   svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, prop_name);
 
   return SVN_NO_ERROR;
@@ -753,6 +878,7 @@ create_proppatch_body(serf_bucket_t **bk
 {
   proppatch_context_t *ctx = baton;
   serf_bucket_t *body_bkt;
+  walker_baton_t *wb;
 
   body_bkt = serf_bucket_aggregate_create(alloc);
 
@@ -764,14 +890,37 @@ create_proppatch_body(serf_bucket_t **bk
                                     "xmlns:S", SVN_DAV_PROP_NS_SVN,
                                     NULL);
 
+  wb = apr_pcalloc(pool, sizeof(*wb));
+  wb->body_bkt = body_bkt;
+  wb->previous_changed_props = ctx->previous_changed_props;
+  wb->previous_removed_props = ctx->previous_removed_props;
+  wb->path = ctx->path;
+
   if (apr_hash_count(ctx->changed_props) > 0)
     {
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:set", NULL);
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:prop", NULL);
 
+      wb->filter = filter_all_props;
+      wb->deleting = FALSE;
       SVN_ERR(svn_ra_serf__walk_all_props(ctx->changed_props, ctx->path,
                                           SVN_INVALID_REVNUM,
-                                          proppatch_walker, body_bkt, pool));
+                                          proppatch_walker, wb, pool));
+
+      svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
+      svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:set");
+    }
+
+  if (apr_hash_count(ctx->removed_props) > 0)
+    {
+      svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:set", NULL);
+      svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:prop", NULL);
+
+      wb->filter = filter_props_with_old_value;
+      wb->deleting = TRUE;
+      SVN_ERR(svn_ra_serf__walk_all_props(ctx->removed_props, ctx->path,
+                                          SVN_INVALID_REVNUM,
+                                          proppatch_walker, wb, pool));
 
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:set");
@@ -782,9 +931,11 @@ create_proppatch_body(serf_bucket_t **bk
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:remove", NULL);
       svn_ra_serf__add_open_tag_buckets(body_bkt, alloc, "D:prop", NULL);
 
+      wb->filter = filter_props_without_old_value;
+      wb->deleting = TRUE;
       SVN_ERR(svn_ra_serf__walk_all_props(ctx->removed_props, ctx->path,
                                           SVN_INVALID_REVNUM,
-                                          proppatch_walker, body_bkt, pool));
+                                          proppatch_walker, wb, pool));
 
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:prop");
       svn_ra_serf__add_close_tag_buckets(body_bkt, alloc, "D:remove");
@@ -2208,6 +2359,7 @@ svn_error_t *
 svn_ra_serf__change_rev_prop(svn_ra_session_t *ra_session,
                              svn_revnum_t rev,
                              const char *name,
+                             const svn_string_t *const *old_value_p,
                              const svn_string_t *value,
                              apr_pool_t *pool)
 {
@@ -2219,6 +2371,17 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
   apr_hash_t *props;
   svn_error_t *err;
 
+  if (old_value_p)
+    {
+      svn_boolean_t capable;
+      SVN_ERR(svn_ra_serf__has_capability(ra_session, &capable,
+                                          SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                                          pool));
+
+      /* How did you get past the same check in svn_ra_change_rev_prop2()? */
+      SVN_ERR_ASSERT(capable);
+    }
+
   commit = apr_pcalloc(pool, sizeof(*commit));
 
   commit->pool = pool;
@@ -2265,8 +2428,28 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
   proppatch_ctx->path = proppatch_target;
   proppatch_ctx->changed_props = apr_hash_make(proppatch_ctx->pool);
   proppatch_ctx->removed_props = apr_hash_make(proppatch_ctx->pool);
+  if (old_value_p)
+    {
+      proppatch_ctx->previous_changed_props = apr_hash_make(proppatch_ctx->pool);
+      proppatch_ctx->previous_removed_props = apr_hash_make(proppatch_ctx->pool);
+    }
   proppatch_ctx->base_revision = SVN_INVALID_REVNUM;
 
+  if (old_value_p && *old_value_p)
+    {
+      svn_ra_serf__set_prop(proppatch_ctx->previous_changed_props,
+                            proppatch_ctx->path,
+                            ns, name, *old_value_p, proppatch_ctx->pool);
+    }
+  else if (old_value_p)
+    {
+      svn_string_t *dummy_value = svn_string_create("", proppatch_ctx->pool);
+
+      svn_ra_serf__set_prop(proppatch_ctx->previous_removed_props,
+                            proppatch_ctx->path,
+                            ns, name, dummy_value, proppatch_ctx->pool);
+    }
+
   if (value)
     {
       svn_ra_serf__set_prop(proppatch_ctx->changed_props, proppatch_ctx->path,

Modified: subversion/branches/object-model/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_serf/options.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_serf/options.c Fri Sep 24 14:02:50 2010
@@ -313,6 +313,13 @@ capabilities_headers_iterator_callback(v
                        SVN_RA_CAPABILITY_LOG_REVPROPS,
                        APR_HASH_KEY_STRING, capability_yes);
         }
+      if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS,
+                                      vals))
+        {
+          apr_hash_set(orc->session->capabilities,
+                       SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+                       APR_HASH_KEY_STRING, capability_yes);
+        }
       if (svn_cstring_match_glob_list(SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY, vals))
         {
           apr_hash_set(orc->session->capabilities,
@@ -404,6 +411,8 @@ options_response_handler(serf_request_t 
                APR_HASH_KEY_STRING, capability_no);
   apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_LOG_REVPROPS,
                APR_HASH_KEY_STRING, capability_no);
+  apr_hash_set(orc->session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
+               APR_HASH_KEY_STRING, capability_no);
 
   /* Then see which ones we can discover. */
   serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback, orc);

Modified: subversion/branches/object-model/subversion/libsvn_ra_serf/ra_serf.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_serf/ra_serf.h?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_serf/ra_serf.h (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_serf/ra_serf.h Fri Sep 24 14:02:50 2010
@@ -673,6 +673,9 @@ typedef struct svn_ra_serf__server_error
   /* Have we seen an error tag? */
   svn_boolean_t in_error;
 
+  /* Have we seen a HTTP "412 Precondition Failed" error? */
+  svn_boolean_t contains_precondition_error;
+
   /* Should we be collecting the XML cdata? */
   svn_boolean_t collect_cdata;
 
@@ -1322,6 +1325,7 @@ svn_error_t *
 svn_ra_serf__change_rev_prop(svn_ra_session_t *session,
                              svn_revnum_t rev,
                              const char *name,
+                             const svn_string_t *const *old_value_p,
                              const svn_string_t *value,
                              apr_pool_t *pool);
 

Modified: subversion/branches/object-model/subversion/libsvn_ra_serf/replay.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_serf/replay.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_serf/replay.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_serf/replay.c Fri Sep 24 14:02:50 2010
@@ -118,6 +118,10 @@ typedef struct replay_context_t {
   /* Cached report target url */
   const char *report_target;
 
+  /* Target and revision to fetch revision properties on */
+  const char *revprop_target;
+  svn_revnum_t revprop_rev;
+
   /* Revision properties for this revision. */
   apr_hash_t *revs_props;
   apr_hash_t *props;
@@ -190,8 +194,8 @@ start_replay(svn_ra_serf__xml_parser_t *
       /* Create a pool for the commit editor. */
       ctx->dst_rev_pool = svn_pool_create(ctx->src_rev_pool);
       ctx->props = apr_hash_make(ctx->dst_rev_pool);
-      SVN_ERR(svn_ra_serf__walk_all_props(ctx->revs_props, ctx->report_target,
-                                          ctx->revision,
+      SVN_ERR(svn_ra_serf__walk_all_props(ctx->revs_props, ctx->revprop_target,
+                                          ctx->revprop_rev,
                                           svn_ra_serf__set_bare_props,
                                           ctx->props, ctx->dst_rev_pool));
       if (ctx->revstart_func)
@@ -758,10 +762,25 @@ svn_ra_serf__replay_range(svn_ra_session
           /* Request all properties of a certain revision. */
           replay_ctx->report_target = report_target;
           replay_ctx->revs_props = apr_hash_make(replay_ctx->src_rev_pool);
+
+          if (SVN_RA_SERF__HAVE_HTTPV2_SUPPORT(session))
+           {
+             replay_ctx->revprop_target = apr_psprintf(pool, "%s/%ld",
+                                                       session->rev_stub, rev);
+             replay_ctx->revprop_rev = SVN_INVALID_REVNUM;
+            }
+          else
+            {
+              replay_ctx->revprop_target = report_target;
+              replay_ctx->revprop_rev = rev;
+            }
+
           SVN_ERR(svn_ra_serf__deliver_props(&prop_ctx,
                                              replay_ctx->revs_props, session,
-                                             session->conns[0], report_target,
-                                             rev,  "0", all_props,
+                                             session->conns[0],
+                                             replay_ctx->revprop_target,
+                                             replay_ctx->revprop_rev,
+                                             "0", all_props,
                                              TRUE, NULL,
                                              replay_ctx->src_rev_pool));
 

Modified: subversion/branches/object-model/subversion/libsvn_ra_serf/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_ra_serf/util.c?rev=1000876&r1=1000875&r2=1000876&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_ra_serf/util.c (original)
+++ subversion/branches/object-model/subversion/libsvn_ra_serf/util.c Fri Sep 24 14:02:50 2010
@@ -836,6 +836,7 @@ svn_ra_serf__handle_discard_body(serf_re
             {
               server_err->error = svn_error_create(APR_SUCCESS, NULL, NULL);
               server_err->has_xml_response = TRUE;
+              server_err->contains_precondition_error = FALSE;
               server_err->cdata = svn_stringbuf_create("", pool);
               server_err->collect_cdata = FALSE;
               server_err->parser.pool = server_err->error->pool;
@@ -945,6 +946,34 @@ svn_ra_serf__handle_status_only(serf_req
   return svn_error_return(err);
 }
 
+/* Given a string like "HTTP/1.1 500 (status)" in BUF, parse out the numeric
+   status code into *STATUS_CODE_OUT.  Ignores leading whitespace. */
+static svn_error_t *
+parse_dav_status(int *status_code_out, svn_stringbuf_t *buf,
+                 apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  const char *token;
+  char *tok_status;
+  svn_stringbuf_t *temp_buf = svn_stringbuf_dup(buf, scratch_pool);
+
+  svn_stringbuf_strip_whitespace(temp_buf);
+  token = apr_strtok(temp_buf->data, " \t\r\n", &tok_status);
+  if (token)
+    token = apr_strtok(NULL, " \t\r\n", &tok_status);
+  if (!token)
+    return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+                             "Malformed DAV:status CDATA '%s'",
+                             buf->data);
+  err = svn_cstring_atoi(status_code_out, token);
+  if (err)
+    return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, err,
+                             "Malformed DAV:status CDATA '%s'",
+                             buf->data);
+
+  return SVN_NO_ERROR;
+}
+
 /*
  * Expat callback invoked on a start element tag for a 207 response.
  */
@@ -968,6 +997,14 @@ start_207(svn_ra_serf__xml_parser_t *par
       svn_stringbuf_setempty(ctx->cdata);
       ctx->collect_cdata = TRUE;
     }
+  else if (ctx->in_error &&
+           strcmp(name.namespace, "DAV:") == 0 &&
+           strcmp(name.name, "status") == 0)
+    {
+      /* Start collecting cdata. */
+      svn_stringbuf_setempty(ctx->cdata);
+      ctx->collect_cdata = TRUE;
+    }
 
   return SVN_NO_ERROR;
 }
@@ -993,7 +1030,22 @@ end_207(svn_ra_serf__xml_parser_t *parse
       ctx->collect_cdata = FALSE;
       ctx->error->message = apr_pstrmemdup(ctx->error->pool, ctx->cdata->data,
                                            ctx->cdata->len);
-      ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
+      if (ctx->contains_precondition_error)
+        ctx->error->apr_err = SVN_ERR_FS_PROP_BASEVALUE_MISMATCH;
+      else
+        ctx->error->apr_err = SVN_ERR_RA_DAV_REQUEST_FAILED;
+    }
+  else if (ctx->in_error &&
+           strcmp(name.namespace, "DAV:") == 0 &&
+           strcmp(name.name, "status") == 0)
+    {
+      int status_code;
+
+      ctx->collect_cdata = FALSE;
+
+      SVN_ERR(parse_dav_status(&status_code, ctx->cdata, parser->pool));
+      if (status_code == 412)
+        ctx->contains_precondition_error = TRUE;
     }
 
   return SVN_NO_ERROR;
@@ -1044,6 +1096,7 @@ svn_ra_serf__handle_multistatus_only(ser
         {
           server_err->error = svn_error_create(APR_SUCCESS, NULL, NULL);
           server_err->has_xml_response = TRUE;
+          server_err->contains_precondition_error = FALSE;
           server_err->cdata = svn_stringbuf_create("", pool);
           server_err->collect_cdata = FALSE;
           server_err->parser.pool = server_err->error->pool;