Author: rhuijben
Date: Sun Apr 20 14:46:42 2014
New Revision: 1588772

URL: http://svn.apache.org/r1588772
Log:
Implement an initial fix for issue #4480. As noted in the code this patch
might make this code report out of date in a few cases where we should allow
a commit, but this is much safer than not reporting out of date where we
should.

As far as I can tell this check matches how we do things in the repos/fs
commit api, so I hope somebody with more knowledge of these apis can
confirm that this is the right fix to close issue #4480.

* subversion/mod_dav_svn/repos.c
  (do_out_of_date_check): Implement an additional out of date check for
    directory changes to catch the issue #4480 problem.

* subversion/tests/cmdline/commit_tests.py
  (commit_mergeinfo_ood): Remove XFail marker.

Modified:
    subversion/trunk/subversion/mod_dav_svn/repos.c
    subversion/trunk/subversion/tests/cmdline/commit_tests.py

Modified: subversion/trunk/subversion/mod_dav_svn/repos.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/repos.c?rev=1588772&r1=1588771&r2=1588772&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/repos.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/repos.c Sun Apr 20 14:46:42 2014
@@ -1791,18 +1791,113 @@ do_out_of_date_check(dav_resource_combin
                                 "Could not get created rev of "
                                 "resource", r->pool);
 
-  if (comb->priv.version_name < created_rev)
+  if (SVN_IS_VALID_REVNUM(created_rev))
     {
-      serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
-                               comb->res.collection
-                                ? "Directory '%s' is out of date"
-                                : (comb->res.exists
-                                    ? "File '%s' is out of date"
-                                    : "'%s' is out of date"),
-                               comb->priv.repos_path);
-      return dav_svn__convert_err(serr, HTTP_CONFLICT,
-                                  "Attempting to modify out-of-date resource.",
+      if (comb->priv.version_name < created_rev)
+        {
+          serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
+                                   comb->res.collection
+                                    ? "Directory '%s' is out of date"
+                                    : (comb->res.exists
+                                        ? "File '%s' is out of date"
+                                        : "'%s' is out of date"),
+                                   comb->priv.repos_path);
+          return dav_svn__convert_err(serr, HTTP_CONFLICT,
+                                      "Attempting to modify out-of-date 
resource.",
+                                      r->pool);
+        }
+    }
+  else if (SVN_IS_VALID_REVNUM(comb->priv.version_name)
+           && comb->res.collection)
+    {
+      /* Issue #4480: With HTTPv2 we can receive the first change for a
+         directory after it has been made mutable, because one of its
+         descendants was changed before changing the directory.
+
+         We have to check if whatever the node is in HEAD is equivalent
+         to what it was in the provided BASE revision.
+
+         If the node was copied, we would process it before its decendants
+         and we already performed quite a few checks when making it mutable
+         via its descendant, so what we should really check here is if the
+         properties changed since the BASE version.
+
+         ### I think svn_fs_node_relation() checks for more changes than we
+             should check for here. Needs further review. But it looks like\
+             this check matches the checks in the libsvn_fs commit editor.
+
+             For now I would say reporting out of date in a few too many
+             cases is safer than not reporting out of date when we should.
+       */
+      svn_revnum_t youngest;
+      svn_fs_root_t *youngest_root;
+      svn_fs_root_t *rev_root;
+      svn_fs_node_relation_t node_relation;
+
+      serr = svn_fs_youngest_rev(&youngest, comb->res.info->repos->fs,
+                                 r->pool);
+      if (serr != NULL)
+        {
+          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                      "Could not determine the youngest "
+                                      "revision for verification against "
+                                      "the baseline being checked out",
+                                      r->pool);
+        }
+
+      if (comb->priv.version_name == youngest)
+        return NULL; /* Easy out: we commit against HEAD */
+
+      serr = svn_fs_revision_root(&youngest_root, comb->res.info->repos->fs,
+                                  youngest, r->pool);
+
+      if (serr != NULL)
+        {
+          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                      "Could not open youngest revision root "
+                                      "for verification against the base "
+                                      "revision", r->pool);
+        }
+
+      serr = svn_fs_revision_root(&rev_root, comb->res.info->repos->fs,
+                                  comb->priv.version_name, r->pool);
+
+      if (serr != NULL)
+        {
+          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                      "Could not open the base revision"
+                                      "for verification against the youngest "
+                                      "revision", r->pool);
+        }
+
+      serr = svn_fs_node_relation(&node_relation, rev_root,
+                                  comb->priv.repos_path,
+                                  youngest_root,
+                                  comb->priv.repos_path,
                                   r->pool);
+
+      svn_fs_close_root(rev_root);
+      svn_fs_close_root(youngest_root);
+
+      if (serr != NULL)
+        {
+          /* ### correct HTTP error? */
+          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                      "Unable to fetch the node revision id "
+                                      "of the version resource within the "
+                                      "revision",
+                                      r->pool);
+        }
+
+      if (node_relation != svn_fs_node_same)
+        {
+          serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
+                                   "Directory '%s' is out of date",
+                                   comb->priv.repos_path);
+          return dav_svn__convert_err(serr, HTTP_CONFLICT,
+                                      "Attempting to modify out-of-date 
resource.",
+                                      r->pool);
+        }
     }
 
   return NULL;

Modified: subversion/trunk/subversion/tests/cmdline/commit_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/commit_tests.py?rev=1588772&r1=1588771&r2=1588772&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/commit_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/commit_tests.py Sun Apr 20 
14:46:42 2014
@@ -3072,7 +3072,6 @@ def commit_deep_deleted(sbox):
                                         sbox.ospath('A'))
 
 @Issue(4480)
-@XFail(svntest.main.is_ra_type_dav)
 def commit_mergeinfo_ood(sbox):
   "commit of mergeinfo that should cause out of date"
 


Reply via email to