You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2015/07/28 13:18:39 UTC

svn commit: r1693068 [2/2] - in /subversion/branches/1.7.x-issue4340-repos: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ subversion/bindings/swig/include/ subversion/include/ subversion/libsvn_client/ subversion/libsvn_fs_fs/ ...

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/svnrdump/load_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/svnrdump/load_editor.c?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/svnrdump/load_editor.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/svnrdump/load_editor.c Tue Jul 28 11:18:37 2015
@@ -41,6 +41,8 @@
 
 #define SVNRDUMP_PROP_LOCK SVN_PROP_PREFIX "rdump-lock"
 
+#define ARE_VALID_COPY_ARGS(p,r) ((p) && SVN_IS_VALID_REVNUM(r))
+
 #if 0
 #define LDR_DBG(x) SVN_DBG(x)
 #else
@@ -102,6 +104,15 @@ struct directory_baton
   void *baton;
   const char *relpath;
   int depth;
+
+  /* The copy-from source of this directory, no matter whether it is
+     copied explicitly (the root node of a copy) or implicitly (being an
+     existing child of a copied directory). For a node that is newly
+     added (without history), even inside a copied parent, these are
+     NULL and SVN_INVALID_REVNUM. */
+  const char *copyfrom_path;
+  svn_revnum_t copyfrom_rev;
+
   struct directory_baton *parent;
 };
 
@@ -115,12 +126,20 @@ struct node_baton
   svn_node_kind_t kind;
   enum svn_node_action action;
 
+  /* Is this directory explicitly added? If not, then it already existed
+     or is a child of a copy. */
+  svn_boolean_t is_added;
+
   svn_revnum_t copyfrom_rev;
   const char *copyfrom_path;
+  const char *copyfrom_url;
 
   void *file_baton;
   const char *base_checksum;
 
+  /* (const char *name) -> (svn_prop_t *) */
+  apr_hash_t *prop_changes;
+
   struct revision_baton *rb;
 };
 
@@ -436,6 +455,7 @@ new_revision_record(void **revision_bato
   pb = parse_baton;
   rb->pool = svn_pool_create(pool);
   rb->pb = pb;
+  rb->db = NULL;
 
   for (hi = apr_hash_first(pool, headers); hi; hi = apr_hash_next(hi))
     {
@@ -479,6 +499,47 @@ uuid_record(const char *uuid,
   return SVN_NO_ERROR;
 }
 
+/* Push information about another directory onto the linked list RB->db.
+ *
+ * CHILD_BATON is the baton returned by the commit editor. RELPATH is the
+ * repository-relative path of this directory. IS_ADDED is true iff this
+ * directory is being added (with or without history). If added with
+ * history then COPYFROM_PATH/COPYFROM_REV are the copyfrom source, else
+ * are NULL/SVN_INVALID_REVNUM.
+ */
+static void
+push_directory(struct revision_baton *rb,
+               void *child_baton,
+               const char *relpath,
+               svn_boolean_t is_added,
+               const char *copyfrom_path,
+               svn_revnum_t copyfrom_rev)
+{
+  struct directory_baton *child_db = apr_pcalloc(rb->pool, sizeof (*child_db));
+
+  SVN_ERR_ASSERT_NO_RETURN(
+    is_added || (copyfrom_path == NULL && copyfrom_rev == SVN_INVALID_REVNUM));
+
+  /* If this node is an existing (not newly added) child of a copied node,
+     calculate where it was copied from. */
+  if (!is_added
+      && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
+    {
+      const char *name = svn_relpath_basename(relpath, NULL);
+
+      copyfrom_path = svn_relpath_join(rb->db->copyfrom_path, name,
+                                       rb->pool);
+      copyfrom_rev = rb->db->copyfrom_rev;
+    }
+
+  child_db->baton = child_baton;
+  child_db->relpath = relpath;
+  child_db->copyfrom_path = copyfrom_path;
+  child_db->copyfrom_rev = copyfrom_rev;
+  child_db->parent = rb->db;
+  rb->db = child_db;
+}
+
 static svn_error_t *
 new_node_record(void **node_baton,
                 apr_hash_t *headers,
@@ -489,17 +550,17 @@ new_node_record(void **node_baton,
   const struct svn_delta_editor_t *commit_editor = rb->pb->commit_editor;
   void *commit_edit_baton = rb->pb->commit_edit_baton;
   struct node_baton *nb;
-  struct directory_baton *child_db;
   apr_hash_index_t *hi;
   void *child_baton;
-  char *relpath_compose;
   const char *nb_dirname;
 
   nb = apr_pcalloc(rb->pool, sizeof(*nb));
   nb->rb = rb;
-
+  nb->is_added = FALSE;
   nb->copyfrom_path = NULL;
+  nb->copyfrom_url = NULL;
   nb->copyfrom_rev = SVN_INVALID_REVNUM;
+  nb->prop_changes = apr_hash_make(rb->pool);
 
   /* If the creation of commit_editor is pending, create it now and
      open_root on it; also create a top-level directory baton. */
@@ -532,13 +593,9 @@ new_node_record(void **node_baton,
 
       LDR_DBG(("Opened root %p\n", child_baton));
 
-      /* child_db corresponds to the root directory baton here */
-      child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-      child_db->baton = child_baton;
-      child_db->depth = 0;
-      child_db->relpath = "";
-      child_db->parent = NULL;
-      rb->db = child_db;
+      /* child_baton corresponds to the root directory baton here */
+      push_directory(rb, child_baton, "", TRUE /*is_added*/,
+                     NULL, SVN_INVALID_REVNUM);
     }
 
   for (hi = apr_hash_first(rb->pool, headers); hi; hi = apr_hash_next(hi))
@@ -607,7 +664,7 @@ new_node_record(void **node_baton,
 
       for (i = 0; i < residual_open_path->nelts; i ++)
         {
-          relpath_compose =
+          char *relpath_compose =
             svn_relpath_join(rb->db->relpath,
                              APR_ARRAY_IDX(residual_open_path, i, const char *),
                              rb->pool);
@@ -616,12 +673,8 @@ new_node_record(void **node_baton,
                                                 rb->rev - rb->rev_offset - 1,
                                                 rb->pool, &child_baton));
           LDR_DBG(("Opened dir %p\n", child_baton));
-          child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-          child_db->baton = child_baton;
-          child_db->depth = rb->db->depth + 1;
-          child_db->relpath = relpath_compose;
-          child_db->parent = rb->db;
-          rb->db = child_db;
+          push_directory(rb, child_baton, relpath_compose, TRUE /*is_added*/,
+                         NULL, SVN_INVALID_REVNUM);
         }
     }
 
@@ -649,7 +702,7 @@ new_node_record(void **node_baton,
       if (rb->pb->parent_dir)
         nb->copyfrom_path = svn_relpath_join(rb->pb->parent_dir,
                                              nb->copyfrom_path, rb->pool);
-      nb->copyfrom_path = svn_path_url_add_component2(rb->pb->root_url,
+      nb->copyfrom_url = svn_path_url_add_component2(rb->pb->root_url,
                                                       nb->copyfrom_path,
                                                       rb->pool);
     }
@@ -667,11 +720,12 @@ new_node_record(void **node_baton,
       else
         /* FALL THROUGH */;
     case svn_node_action_add:
+      nb->is_added = TRUE;
       switch (nb->kind)
         {
         case svn_node_file:
           SVN_ERR(commit_editor->add_file(nb->path, rb->db->baton,
-                                          nb->copyfrom_path,
+                                          nb->copyfrom_url,
                                           nb->copyfrom_rev,
                                           rb->pool, &(nb->file_baton)));
           LDR_DBG(("Added file %s to dir %p as %p\n",
@@ -679,17 +733,13 @@ new_node_record(void **node_baton,
           break;
         case svn_node_dir:
           SVN_ERR(commit_editor->add_directory(nb->path, rb->db->baton,
-                                               nb->copyfrom_path,
+                                               nb->copyfrom_url,
                                                nb->copyfrom_rev,
                                                rb->pool, &child_baton));
           LDR_DBG(("Added dir %s to dir %p as %p\n",
                    nb->path, rb->db->baton, child_baton));
-          child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-          child_db->baton = child_baton;
-          child_db->depth = rb->db->depth + 1;
-          child_db->relpath = apr_pstrdup(rb->pool, nb->path);
-          child_db->parent = rb->db;
-          rb->db = child_db;
+          push_directory(rb, child_baton, nb->path, TRUE /*is_added*/,
+                         nb->copyfrom_path, nb->copyfrom_rev);
           break;
         default:
           break;
@@ -707,12 +757,8 @@ new_node_record(void **node_baton,
           SVN_ERR(commit_editor->open_directory(nb->path, rb->db->baton,
                                                 rb->rev - rb->rev_offset - 1,
                                                 rb->pool, &child_baton));
-          child_db = apr_pcalloc(rb->pool, sizeof(*child_db));
-          child_db->baton = child_baton;
-          child_db->depth = rb->db->depth + 1;
-          child_db->relpath = apr_pstrdup(rb->pool, nb->path);
-          child_db->parent = rb->db;
-          rb->db = child_db;
+          push_directory(rb, child_baton, nb->path, FALSE /*is_added*/,
+                         NULL, SVN_INVALID_REVNUM);
           break;
         }
       break;
@@ -763,8 +809,8 @@ set_node_property(void *baton,
                   const svn_string_t *value)
 {
   struct node_baton *nb = baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
+  svn_prop_t *prop;
 
   if (value && strcmp(name, SVN_PROP_MERGEINFO) == 0)
     {
@@ -814,21 +860,11 @@ set_node_property(void *baton,
 
   SVN_ERR(svn_repos__validate_prop(name, value, pool));
 
-  switch (nb->kind)
-    {
-    case svn_node_file:
-      LDR_DBG(("Applying properties on %p\n", nb->file_baton));
-      SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
-                                              value, pool));
-      break;
-    case svn_node_dir:
-      LDR_DBG(("Applying properties on %p\n", nb->rb->db->baton));
-      SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
-                                             value, pool));
-      break;
-    default:
-      break;
-    }
+  prop = apr_palloc(nb->rb->pool, sizeof (*prop));
+  prop->name = apr_pstrdup(pool, name);
+  prop->value = value ? svn_string_dup(value, pool) : NULL;
+  apr_hash_set(nb->prop_changes, prop->name, APR_HASH_KEY_STRING, prop);
+
   return SVN_NO_ERROR;
 }
 
@@ -837,44 +873,84 @@ delete_node_property(void *baton,
                      const char *name)
 {
   struct node_baton *nb = baton;
-  const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
   apr_pool_t *pool = nb->rb->pool;
+  svn_prop_t *prop;
 
   SVN_ERR(svn_repos__validate_prop(name, NULL, pool));
 
-  if (nb->kind == svn_node_file)
-    SVN_ERR(commit_editor->change_file_prop(nb->file_baton, name,
-                                            NULL, pool));
-  else
-    SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton, name,
-                                           NULL, pool));
+  prop = apr_palloc(pool, sizeof (*prop));
+  prop->name = apr_pstrdup(pool, name);
+  prop->value = NULL;
+  apr_hash_set(nb->prop_changes, prop->name, APR_HASH_KEY_STRING, prop);
 
   return SVN_NO_ERROR;
 }
 
+/* Delete all the properties of the node, if any.
+ *
+ * The commit editor doesn't have a method to delete a node's properties
+ * without knowing what they are, so we have to first find out what
+ * properties the node would have had. If it's copied (explicitly or
+ * implicitly), we look at the copy source. If it's only being changed,
+ * we look at the node's current path in the head revision.
+ */
 static svn_error_t *
 remove_node_props(void *baton)
 {
   struct node_baton *nb = baton;
+  struct revision_baton *rb = nb->rb;
   apr_pool_t *pool = nb->rb->pool;
   apr_hash_index_t *hi;
   apr_hash_t *props;
+  const char *orig_path;
+  svn_revnum_t orig_rev;
+
+  /* Find the path and revision that has the node's original properties */
+  if (ARE_VALID_COPY_ARGS(nb->copyfrom_path, nb->copyfrom_rev))
+    {
+      LDR_DBG(("using nb->copyfrom  %s@%ld", nb->copyfrom_path, nb->copyfrom_rev));
+      orig_path = nb->copyfrom_path;
+      orig_rev = nb->copyfrom_rev;
+    }
+  else if (!nb->is_added
+           && ARE_VALID_COPY_ARGS(rb->db->copyfrom_path, rb->db->copyfrom_rev))
+    {
+      /* If this is a dir, then it's described by rb->db;
+         if this is a file, then it's a child of the dir in rb->db. */
+      LDR_DBG(("using rb->db->copyfrom (k=%d) %s@%ld",
+                 nb->kind, rb->db->copyfrom_path, rb->db->copyfrom_rev));
+      orig_path = (nb->kind == svn_node_dir)
+                    ? rb->db->copyfrom_path
+                    : svn_relpath_join(rb->db->copyfrom_path,
+                                       svn_relpath_basename(nb->path, NULL),
+                                       rb->pool);
+      orig_rev = rb->db->copyfrom_rev;
+    }
+  else
+    {
+      LDR_DBG(("using self.path@head  %s@%ld", nb->path, SVN_INVALID_REVNUM));
+      /* ### Should we query at a known, fixed, "head" revision number
+         instead of passing SVN_INVALID_REVNUM and getting a moving target? */
+      orig_path = nb->path;
+      orig_rev = SVN_INVALID_REVNUM;
+    }
+  LDR_DBG(("Trying %s@%ld", orig_path, orig_rev));
 
   if ((nb->action == svn_node_action_add
             || nb->action == svn_node_action_replace)
-      && ! SVN_IS_VALID_REVNUM(nb->copyfrom_rev))
+      && ! ARE_VALID_COPY_ARGS(orig_path, orig_rev))
     /* Add-without-history; no "old" properties to worry about. */
     return SVN_NO_ERROR;
 
   if (nb->kind == svn_node_file)
     {
-      SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session, nb->path,
-                              SVN_INVALID_REVNUM, NULL, NULL, &props, pool));
+      SVN_ERR(svn_ra_get_file(nb->rb->pb->aux_session,
+                              orig_path, orig_rev, NULL, NULL, &props, pool));
     }
   else  /* nb->kind == svn_node_dir */
     {
       SVN_ERR(svn_ra_get_dir2(nb->rb->pb->aux_session, NULL, NULL, &props,
-                              nb->path, SVN_INVALID_REVNUM, 0, pool));
+                              orig_path, orig_rev, 0, pool));
     }
 
   for (hi = apr_hash_first(pool, props); hi; hi = apr_hash_next(hi))
@@ -928,6 +1004,29 @@ close_node(void *baton)
 {
   struct node_baton *nb = baton;
   const struct svn_delta_editor_t *commit_editor = nb->rb->pb->commit_editor;
+  apr_pool_t *pool = nb->rb->pool;
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(pool, nb->prop_changes);
+       hi; hi = apr_hash_next(hi))
+    {
+      const char *name = svn__apr_hash_index_key(hi);
+      svn_prop_t *prop = svn__apr_hash_index_val(hi);
+
+      switch (nb->kind)
+        {
+        case svn_node_file:
+          SVN_ERR(commit_editor->change_file_prop(nb->file_baton,
+                                                  name, prop->value, pool));
+          break;
+        case svn_node_dir:
+          SVN_ERR(commit_editor->change_dir_prop(nb->rb->db->baton,
+                                                 name, prop->value, pool));
+          break;
+        default:
+          break;
+        }
+    }
 
   /* Pass a file node closure through to the editor *unless* we
      deleted the file (which doesn't require us to open it). */

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/svnserve/serve.c?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/svnserve/serve.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/svnserve/serve.c Tue Jul 28 11:18:37 2015
@@ -2266,9 +2266,30 @@ static svn_error_t *get_location_segment
 
   abs_path = svn_fspath__join(b->fs_path->data, relative_path, pool);
 
-  if (SVN_IS_VALID_REVNUM(start_rev)
-      && SVN_IS_VALID_REVNUM(end_rev)
-      && (end_rev > start_rev))
+  SVN_ERR(trivial_auth_request(conn, pool, b));
+  SVN_ERR(log_command(baton, conn, pool, "%s",
+                      svn_log__get_location_segments(abs_path, peg_revision,
+                                                     start_rev, end_rev,
+                                                     pool)));
+
+  /* No START_REV or PEG_REVISION?  We'll use HEAD. */
+  if (!SVN_IS_VALID_REVNUM(start_rev) || !SVN_IS_VALID_REVNUM(peg_revision))
+    {
+      svn_revnum_t youngest;
+
+      SVN_CMD_ERR(svn_fs_youngest_rev(&youngest, b->fs, pool));
+
+      if (!SVN_IS_VALID_REVNUM(start_rev))
+        start_rev = youngest;
+      if (!SVN_IS_VALID_REVNUM(peg_revision))
+        peg_revision = youngest;
+    }
+
+  /* No END_REV?  We'll use 0. */
+  if (!SVN_IS_VALID_REVNUM(end_rev))
+    end_rev = 0;
+
+  if (end_rev > start_rev)
     {
       err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
                               "Get-location-segments end revision must not be "
@@ -2276,9 +2297,7 @@ static svn_error_t *get_location_segment
       return log_fail_and_flush(err, b, conn, pool);
     }
 
-  if (SVN_IS_VALID_REVNUM(peg_revision)
-      && SVN_IS_VALID_REVNUM(start_rev)
-      && (start_rev > peg_revision))
+  if (start_rev > peg_revision)
     {
       err = svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,
                               "Get-location-segments start revision must not "
@@ -2286,12 +2305,6 @@ static svn_error_t *get_location_segment
       return log_fail_and_flush(err, b, conn, pool);
     }
 
-  SVN_ERR(trivial_auth_request(conn, pool, b));
-  SVN_ERR(log_command(baton, conn, pool, "%s",
-                      svn_log__get_location_segments(abs_path, peg_revision,
-                                                     start_rev, end_rev,
-                                                     pool)));
-
   /* All the parameters are fine - let's perform the query against the
    * repository. */
 

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/README
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/README?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/README (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/README Tue Jul 28 11:18:37 2015
@@ -83,6 +83,133 @@ paths adjusted appropriately:
      Require valid-user
    </Location>
 
+   <Location /authz-test-work/anon>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     # This may seem unnecessary but granting access to everyone here is necessary
+     # to exercise a bug with httpd 2.3.x+.  The "Require all granted" syntax is
+     # new to 2.3.x+ which we can detect with the mod_authz_core.c module
+     # signature.  Use the "Allow from all" syntax with older versions for symmetry.
+     <IfModule mod_authz_core.c>
+       Require all granted
+     </IfModule>
+     <IfModule !mod_authz_core.c>
+       Allow from all
+     </IfMOdule>
+   </Location>
+   <Location /authz-test-work/mixed>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     AuthType          Basic
+     AuthName          "Subversion Repository"
+     AuthUserFile /usr/local/apache2/conf/users
+     Require           valid-user
+     Satisfy Any
+   </Location>
+   <Location /authz-test-work/mixed-noauthwhenanon>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     AuthType          Basic
+     AuthName          "Subversion Repository"
+     AuthUserFile /usr/local/apache2/conf/users
+     Require           valid-user
+     AuthzSVNNoAuthWhenAnonymousAllowed On
+   </Location>
+   <Location /authz-test-work/authn>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     AuthType          Basic
+     AuthName          "Subversion Repository"
+     AuthUserFile /usr/local/apache2/conf/users
+     Require           valid-user
+   </Location>
+   <Location /authz-test-work/authn-anonoff>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     AuthType          Basic
+     AuthName          "Subversion Repository"
+     AuthUserFile /usr/local/apache2/conf/users
+     Require           valid-user
+     AuthzSVNAnonymous Off
+   </Location>
+   <Location /authz-test-work/authn-lcuser>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     AuthType          Basic
+     AuthName          "Subversion Repository"
+     AuthUserFile /usr/local/apache2/conf/users
+     Require           valid-user
+     AuthzForceUsernameCase Lower
+   </Location>
+   <Location /authz-test-work/authn-lcuser>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     AuthType          Basic
+     AuthName          "Subversion Repository"
+     AuthUserFile /usr/local/apache2/conf/users
+     Require           valid-user
+     AuthzForceUsernameCase Lower
+   </Location>
+   <Location /authz-test-work/authn-group>
+     DAV               svn
+     SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+     AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+     SVNListParentPath On
+     AuthType          Basic
+     AuthName          "Subversion Repository"
+     AuthUserFile /usr/local/apache2/conf/users
+     AuthGroupFile /usr/local/apache2/conf/groups
+     Require           group random
+     AuthzSVNAuthoritative Off
+   </Location>
+   <IfModule mod_authz_core.c>
+     <Location /authz-test-work/sallrany>
+       DAV               svn
+       SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+       AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+       SVNListParentPath On
+       AuthType          Basic
+       AuthName          "Subversion Repository"
+       AuthUserFile /usr/local/apache2/conf/users
+       AuthzSendForbiddenOnFailure On
+       Satisfy All
+       <RequireAny>
+         Require valid-user
+         Require expr req('ALLOW') == '1'
+       </RequireAny>
+     </Location>
+     <Location /authz-test-work/sallrall>
+       DAV               svn
+       SVNParentPath /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/local_tmp
+       AuthzSVNAccessFile /home/yourusernamehere/projects/svn/subversion/tests/cmdline/svn-test-work/authz
+       SVNListParentPath On
+       AuthType          Basic
+       AuthName          "Subversion Repository"
+       AuthUserFile /usr/local/apache2/conf/users
+       AuthzSendForbiddenOnFailure On
+       Satisfy All
+       <RequireAll>
+         Require valid-user
+         Require expr req('ALLOW') == '1'
+       </RequireAll>
+     </Location>
+   </IfModule>
+
+
    RedirectMatch permanent ^/svn-test-work/repositories/REDIRECT-PERM-(.*)$ /svn-test-work/repositories/$1
    RedirectMatch           ^/svn-test-work/repositories/REDIRECT-TEMP-(.*)$ /svn-test-work/repositories/$1
 
@@ -101,6 +228,15 @@ just drop the following 2-line snippet i
 ----------------------------
 jrandom:xCGl35kV9oWCY
 jconstant:xCGl35kV9oWCY
+JRANDOM:xCGl35kV9oWCY
+JCONSTANT:xCGl35kV9oWCY
+----------------------------
+
+and these lines into the
+/usr/local/apache/conf/groups file:
+----------------------------
+random: jrandom
+constant: jconstant
 ----------------------------
 
 Now, (re)start Apache and run the tests over mod_dav_svn.
@@ -138,6 +274,8 @@ Note [1]: It would be quite too much to
           ----------------------------
           jrandom:$apr1$3p1.....$FQW6RceW5QhJ2blWDQgKn0
           jconstant:$apr1$jp1.....$Usrqji1c9H6AbOxOGAzzb0
+          JRANDOM:$apr1$3p1.....$FQW6RceW5QhJ2blWDQgKn0
+          JCONSTANT:$apr1$jp1.....$Usrqji1c9H6AbOxOGAzzb0
           ----------------------------
 
 

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/authz_tests.py?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/authz_tests.py (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/authz_tests.py Tue Jul 28 11:18:37 2015
@@ -608,8 +608,10 @@ def authz_log_and_tracing_test(sbox):
 
   ## cat
 
+  expected_err2 = ".*svn: E195012: Unable to find repository location.*"
+
   # now see if we can look at the older version of rho
-  svntest.actions.run_and_verify_svn(None, None, expected_err,
+  svntest.actions.run_and_verify_svn(None, None, expected_err2,
                                      'cat', '-r', '2', D_url+'/rho')
 
   if sbox.repo_url.startswith('http'):
@@ -626,10 +628,11 @@ def authz_log_and_tracing_test(sbox):
   svntest.actions.run_and_verify_svn(None, None, expected_err,
                                      'diff', '-r', 'HEAD', G_url+'/rho')
 
-  svntest.actions.run_and_verify_svn(None, None, expected_err,
+  # diff treats the unreadable path as indicating an add so no error
+  svntest.actions.run_and_verify_svn(None, None, [],
                                      'diff', '-r', '2', D_url+'/rho')
 
-  svntest.actions.run_and_verify_svn(None, None, expected_err,
+  svntest.actions.run_and_verify_svn(None, None, [],
                                      'diff', '-r', '2:4', D_url+'/rho')
 
 # test whether read access is correctly granted and denied

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/copy_tests.py?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/copy_tests.py Tue Jul 28 11:18:37 2015
@@ -5476,6 +5476,18 @@ def copy_deleted_dir(sbox):
                                      'cp', sbox.ospath('A/D'),
                                      sbox.ospath('new_D'))
 
+def resurrect_at_root(sbox):
+   "resurrect directory at root"
+   sbox.build(create_wc=False)
+
+   svntest.actions.run_and_verify_svn(None, None, [], 'rm',
+                                      sbox.repo_url + '/A',
+                                      '-m', '')
+
+   svntest.actions.run_and_verify_svn(None, None, [], 'cp',
+                                      sbox.repo_url + '/A/D/H@1',
+                                      sbox.repo_url + '/A', '-m', '')
+
 ########################################################################
 # Run the tests
 
@@ -5586,6 +5598,7 @@ test_list = [ None,
               case_only_rename,
               copy_and_move_conflicts,
               copy_deleted_dir,
+              resurrect_at_root,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/davautocheck.sh
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/davautocheck.sh?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/davautocheck.sh (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/davautocheck.sh Tue Jul 28 11:18:37 2015
@@ -248,8 +248,6 @@ LOAD_MOD_AUTHN_CORE="$(get_loadmodule_co
     || fail "Authn_Core module not found."
 LOAD_MOD_AUTHZ_CORE="$(get_loadmodule_config mod_authz_core)" \
     || fail "Authz_Core module not found."
-LOAD_MOD_AUTHZ_HOST="$(get_loadmodule_config mod_authz_host)" \
-    || fail "Authz_Host module not found."
 LOAD_MOD_UNIXD=$(get_loadmodule_config mod_unixd) \
     || fail "UnixD module not found"
 }
@@ -257,6 +255,10 @@ LOAD_MOD_AUTHN_FILE="$(get_loadmodule_co
     || fail "Authn_File module not found."
 LOAD_MOD_AUTHZ_USER="$(get_loadmodule_config mod_authz_user)" \
     || fail "Authz_User module not found."
+LOAD_MOD_AUTHZ_GROUPFILE="$(get_loadmodule_config mod_authz_groupfile)" \
+    || fail "Authz_GroupFile module not found."
+LOAD_MOD_AUTHZ_HOST="$(get_loadmodule_config mod_authz_host)" \
+    || fail "Authz_Host module not found."
 }
 if [ ${APACHE_MPM:+set} ]; then
     LOAD_MOD_MPM=$(get_loadmodule_config mod_mpm_$APACHE_MPM) \
@@ -272,6 +274,7 @@ HTTPD_ERROR_LOG="$HTTPD_ROOT/error_log"
 HTTPD_MIME_TYPES="$HTTPD_ROOT/mime.types"
 BASE_URL="http://localhost:$HTTPD_PORT"
 HTTPD_USERS="$HTTPD_ROOT/users"
+HTTPD_GROUPS="$HTTPD_ROOT/groups"
 
 mkdir "$HTTPD_ROOT" \
   || fail "couldn't create temporary directory '$HTTPD_ROOT'"
@@ -281,6 +284,14 @@ say "Using directory '$HTTPD_ROOT'..."
 say "Adding users for lock authentication"
 $HTPASSWD -bc $HTTPD_USERS jrandom   rayjandom
 $HTPASSWD -b  $HTTPD_USERS jconstant rayjandom
+$HTPASSWD -b  $HTTPD_USERS JRANDOM   rayjandom
+$HTPASSWD -b  $HTTPD_USERS JCONSTANT rayjandom
+ 
+say "Adding groups for mod_authz_svn tests"
+cat > "$HTTPD_GROUPS" <<__EOF__
+random: jrandom
+constant: jconstant
+__EOF__
 
 touch $HTTPD_MIME_TYPES
 
@@ -297,7 +308,9 @@ $LOAD_MOD_AUTHN_CORE
 $LOAD_MOD_AUTHN_FILE
 $LOAD_MOD_AUTHZ_CORE
 $LOAD_MOD_AUTHZ_USER
+$LOAD_MOD_AUTHZ_GROUPFILE
 $LOAD_MOD_AUTHZ_HOST
+$LOAD_MOD_ACCESS_COMPAT
 LoadModule          authz_svn_module "$MOD_AUTHZ_SVN"
 
 __EOF__
@@ -309,9 +322,17 @@ User                $(id -un)
 Group               $(id -gn)
 __EOF__
 else
+HTTPD_LOCK="$HTTPD_ROOT/lock"
+mkdir "$HTTPD_LOCK" \
+  || fail "couldn't create lock directory '$HTTPD_LOCK'"
   cat >> "$HTTPD_CFG" <<__EOF__
-# TODO: maybe uncomment this for prefork,worker MPMs only?
-# Mutex file:lock mpm-accept
+# worker and prefork MUST have a mpm-accept lockfile in 2.3.0+
+<IfModule worker.c>
+  Mutex "file:$HTTPD_LOCK" mpm-accept
+</IfModule>
+<IfModule prefork.c>
+  Mutex "file:$HTTPD_LOCK" mpm-accept
+</IfModule>
 __EOF__
 fi
 
@@ -369,6 +390,151 @@ CustomLog           "$HTTPD_ROOT/ops" "%
   SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
   ${SVN_PATH_AUTHZ_LINE}
 </Location>
+<Location /authz-test-work/anon>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  # This may seem unnecessary but granting access to everyone here is necessary
+  # to exercise a bug with httpd 2.3.x+.  The "Require all granted" syntax is
+  # new to 2.3.x+ which we can detect with the mod_authz_core.c module
+  # signature.  Use the "Allow from all" syntax with older versions for symmetry.
+  <IfModule mod_authz_core.c>
+    Require all granted
+  </IfModule>
+  <IfModule !mod_authz_core.c>
+    Allow from all
+  </IfMOdule>
+  ${SVN_PATH_AUTHZ_LINE}
+</Location>
+<Location /authz-test-work/mixed>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  AuthType          Basic
+  AuthName          "Subversion Repository"
+  AuthUserFile      $HTTPD_USERS
+  Require           valid-user
+  Satisfy Any
+  ${SVN_PATH_AUTHZ_LINE}
+</Location>
+<Location /authz-test-work/mixed-noauthwhenanon>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  AuthType          Basic
+  AuthName          "Subversion Repository"
+  AuthUserFile      $HTTPD_USERS
+  Require           valid-user
+  AuthzSVNNoAuthWhenAnonymousAllowed On
+  SVNPathAuthz On
+</Location>
+<Location /authz-test-work/authn>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  AuthType          Basic
+  AuthName          "Subversion Repository"
+  AuthUserFile      $HTTPD_USERS
+  Require           valid-user
+  ${SVN_PATH_AUTHZ_LINE}
+</Location>
+<Location /authz-test-work/authn-anonoff>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  AuthType          Basic
+  AuthName          "Subversion Repository"
+  AuthUserFile      $HTTPD_USERS
+  Require           valid-user
+  AuthzSVNAnonymous Off
+  SVNPathAuthz On
+</Location>
+<Location /authz-test-work/authn-lcuser>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  AuthType          Basic
+  AuthName          "Subversion Repository"
+  AuthUserFile      $HTTPD_USERS
+  Require           valid-user
+  AuthzForceUsernameCase Lower
+  ${SVN_PATH_AUTHZ_LINE}
+</Location>
+<Location /authz-test-work/authn-lcuser>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  AuthType          Basic
+  AuthName          "Subversion Repository"
+  AuthUserFile      $HTTPD_USERS
+  Require           valid-user
+  AuthzForceUsernameCase Lower
+  ${SVN_PATH_AUTHZ_LINE}
+</Location>
+<Location /authz-test-work/authn-group>
+  DAV               svn
+  SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+  AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+  SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+  SVNListParentPath On
+  AuthType          Basic
+  AuthName          "Subversion Repository"
+  AuthUserFile      $HTTPD_USERS
+  AuthGroupFile     $HTTPD_GROUPS
+  Require           group random
+  AuthzSVNAuthoritative Off
+  SVNPathAuthz On
+</Location>
+<IfModule mod_authz_core.c>
+  <Location /authz-test-work/sallrany>
+    DAV               svn
+    SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+    AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+    SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+    SVNListParentPath On
+    AuthType          Basic
+    AuthName          "Subversion Repository"
+    AuthUserFile      $HTTPD_USERS
+    AuthzSendForbiddenOnFailure On
+    Satisfy All
+    <RequireAny>
+      Require valid-user
+      Require expr req('ALLOW') == '1'
+    </RequireAny>
+    ${SVN_PATH_AUTHZ_LINE}
+  </Location>
+  <Location /authz-test-work/sallrall>
+    DAV               svn
+    SVNParentPath     "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/local_tmp"
+    AuthzSVNAccessFile "$ABS_BUILDDIR/subversion/tests/cmdline/svn-test-work/authz"
+    SVNAdvertiseV2Protocol ${ADVERTISE_V2_PROTOCOL}
+    SVNListParentPath On
+    AuthType          Basic
+    AuthName          "Subversion Repository"
+    AuthUserFile      $HTTPD_USERS
+    AuthzSendForbiddenOnFailure On
+    Satisfy All
+    <RequireAll>
+      Require valid-user
+      Require expr req('ALLOW') == '1'
+    </RequireAll>
+    ${SVN_PATH_AUTHZ_LINE}
+  </Location>
+</IfModule>
 RedirectMatch permanent ^/svn-test-work/repositories/REDIRECT-PERM-(.*)\$ /svn-test-work/repositories/\$1
 RedirectMatch           ^/svn-test-work/repositories/REDIRECT-TEMP-(.*)\$ /svn-test-work/repositories/\$1
 __EOF__

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/patch_tests.py?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/patch_tests.py Tue Jul 28 11:18:37 2015
@@ -4070,6 +4070,243 @@ def patch_git_with_index_line(sbox):
                                        1, # check-props
                                        1) # dry-run
 
+@XFail()
+@Issue(4533)
+def patch_hunk_avoid_reorder(sbox):
+  """avoid reordering hunks"""
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_append('A/mu',
+                     'AA\n' 'BB\n' 'CC\n' 'DD\n' 'EE\n' 'FF\n'
+                     'TT\n' 'UU\n' 'VV\n' 'WW\n' 'XX\n' 'YY\n'
+                     'GG\n' 'HH\n' 'II\n' 'JJ\n' 'KK\n' 'LL\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     'MM\n' 'NN\n' 'OO\n' 'PP\n' 'QQ\n' 'RR\n'
+                     'SS\n' 'TT\n' 'UU\n' 'VV\n' 'WW\n' 'XX\n'
+                     'YY\n' 'ZZ\n', truncate=True)
+  sbox.simple_commit()
+
+  # two hunks, first matches at offset +18, second matches at both -13
+  # and +18 but we want the second match as it is after the first
+  unidiff_patch = [
+    "Index: A/mu\n"
+    "===================================================================\n",
+    "--- A/mu\t(revision 1)\n",
+    "+++ A/mu\t(working copy)\n",
+    "@@ -13,6 +13,7 @@\n",
+    " MM\n",
+    " NN\n",
+    " OO\n",
+    "+11111\n",
+    " PP\n",
+    " QQ\n",
+    " RR\n",
+    "@@ -20,6 +20,7 @@\n",
+    " TT\n",
+    " UU\n",
+    " VV\n",
+    "+22222\n",
+    " WW\n",
+    " XX\n",
+    " YY\n",
+    ]
+
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  expected_output = [
+    'U         %s\n' % sbox.ospath('A/mu'),
+    '>         applied hunk @@ -13,6 +13,7 @@ with offset 18\n',
+    '>         applied hunk @@ -20,6 +20,7 @@ with offset 18\n'
+    ]
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/mu', contents=
+                     'AA\n' 'BB\n' 'CC\n' 'DD\n' 'EE\n' 'FF\n'
+                     'TT\n' 'UU\n' 'VV\n' 'WW\n' 'XX\n' 'YY\n'
+                     'GG\n' 'HH\n' 'II\n' 'JJ\n' 'KK\n' 'LL\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     'MM\n' 'NN\n' 'OO\n' '11111\n' 'PP\n' 'QQ\n' 'RR\n'
+                     'SS\n' 'TT\n' 'UU\n' 'VV\n' '22222\n' 'WW\n' 'XX\n'
+                     'YY\n' 'ZZ\n')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status='M ', wc_rev=2)
+  expected_skip = wc.State('', { })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+
+  sbox.simple_revert('A/mu')
+
+  # change patch so second hunk matches at both -14 and +17, we still
+  # want the second match
+  unidiff_patch = [
+    "Index: A/mu\n"
+    "===================================================================\n",
+    "--- A/mu\t(revision 1)\n",
+    "+++ A/mu\t(working copy)\n",
+    "@@ -13,6 +13,7 @@\n",
+    " MM\n",
+    " NN\n",
+    " OO\n",
+    "+11111\n",
+    " PP\n",
+    " QQ\n",
+    " RR\n",
+    "@@ -21,6 +21,7 @@\n",
+    " TT\n",
+    " UU\n",
+    " VV\n",
+    "+22222\n",
+    " WW\n",
+    " XX\n",
+    " YY\n",
+    ]
+
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  expected_output = [
+    'U         %s\n' % sbox.ospath('A/mu'),
+    '>         applied hunk @@ -13,6 +13,7 @@ with offset 18\n',
+    '>         applied hunk @@ -21,6 +21,7 @@ with offset 17\n'
+    ]
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/mu', contents=
+                     'AA\n' 'BB\n' 'CC\n' 'DD\n' 'EE\n' 'FF\n'
+                     'TT\n' 'UU\n' 'VV\n' 'WW\n' 'XX\n' 'YY\n'
+                     'GG\n' 'HH\n' 'II\n' 'JJ\n' 'KK\n' 'LL\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     'MM\n' 'NN\n' 'OO\n' '11111\n' 'PP\n' 'QQ\n' 'RR\n'
+                     'SS\n' 'TT\n' 'UU\n' 'VV\n' '22222\n' 'WW\n' 'XX\n'
+                     'YY\n' 'ZZ\n')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status='M ', wc_rev=2)
+  expected_skip = wc.State('', { })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+
+  sbox.simple_revert('A/mu')
+
+  # change patch so second hunk matches at both -12 and +19, we still
+  # want the second match
+  unidiff_patch = [
+    "Index: A/mu\n"
+    "===================================================================\n",
+    "--- A/mu\t(revision 1)\n",
+    "+++ A/mu\t(working copy)\n",
+    "@@ -13,6 +13,7 @@\n",
+    " MM\n",
+    " NN\n",
+    " OO\n",
+    "+11111\n",
+    " PP\n",
+    " QQ\n",
+    " RR\n",
+    "@@ -19,6 +19,7 @@\n",
+    " TT\n",
+    " UU\n",
+    " VV\n",
+    "+22222\n",
+    " WW\n",
+    " XX\n",
+    " YY\n",
+    ]
+
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  expected_output = [
+    'U         %s\n' % sbox.ospath('A/mu'),
+    '>         applied hunk @@ -13,6 +13,7 @@ with offset 18\n',
+    '>         applied hunk @@ -19,6 +19,7 @@ with offset 19\n'
+    ]
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/mu', contents=
+                     'AA\n' 'BB\n' 'CC\n' 'DD\n' 'EE\n' 'FF\n'
+                     'TT\n' 'UU\n' 'VV\n' 'WW\n' 'XX\n' 'YY\n'
+                     'GG\n' 'HH\n' 'II\n' 'JJ\n' 'KK\n' 'LL\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     '33333\n' '33333\n' '33333\n'
+                     'MM\n' 'NN\n' 'OO\n' '11111\n' 'PP\n' 'QQ\n' 'RR\n'
+                     'SS\n' 'TT\n' 'UU\n' 'VV\n' '22222\n' 'WW\n' 'XX\n'
+                     'YY\n' 'ZZ\n')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status='M ', wc_rev=2)
+  expected_skip = wc.State('', { })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+
+@Issue(4533)
+def patch_hunk_reorder(sbox):
+  """hunks that reorder"""
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_append('A/mu',
+                     'AA\n' 'BB\n' 'CC\n' 'DD\n' 'EE\n' 'FF\n' 'GG\n'
+                     'HH\n' 'II\n' 'JJ\n' 'KK\n' 'LL\n' 'MM\n' 'NN\n',
+                     truncate=True)
+  sbox.simple_commit()
+
+  # Two hunks match in opposite order
+  unidiff_patch = [
+    "Index: A/mu\n"
+    "===================================================================\n",
+    "--- A/mu\t(revision 1)\n",
+    "+++ A/mu\t(working copy)\n",
+    "@@ -2,6 +2,7 @@\n",
+    " II\n",
+    " JJ\n",
+    " KK\n",
+    "+11111\n",
+    " LL\n",
+    " MM\n",
+    " NN\n",
+    "@@ -9,6 +10,7 @@\n",
+    " BB\n",
+    " CC\n",
+    " DD\n",
+    "+22222\n",
+    " EE\n",
+    " FF\n",
+    " GG\n",
+    ]
+
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  expected_output = [
+    'U         %s\n' % sbox.ospath('A/mu'),
+    '>         applied hunk @@ -9,6 +10,7 @@ with offset -7\n',
+    '>         applied hunk @@ -2,6 +2,7 @@ with offset 7\n',
+    ]
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('A/mu', contents=
+                     'AA\n' 'BB\n' 'CC\n' 'DD\n' '22222\n' 'EE\n' 'FF\n' 'GG\n'
+                     'HH\n' 'II\n' 'JJ\n' 'KK\n' '11111\n' 'LL\n' 'MM\n' 'NN\n')
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/mu', status='M ', wc_rev=2)
+  expected_skip = wc.State('', { })
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output, expected_disk,
+                                       expected_status, expected_skip)
+
 ########################################################################
 #Run the tests
 
@@ -4114,6 +4351,8 @@ test_list = [ None,
               patch_target_no_eol_at_eof,
               patch_add_and_delete,
               patch_git_with_index_line,
+              patch_hunk_avoid_reorder,
+              patch_hunk_reorder,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svnrdump_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svnrdump_tests.py?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svnrdump_tests.py (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svnrdump_tests.py Tue Jul 28 11:18:37 2015
@@ -762,6 +762,151 @@ def svnrdump_load_partial_incremental_du
                                           svntest.verify.AnyOutput,
                                           [], 0, 'load', sbox.repo_url)
 
+#----------------------------------------------------------------------
+
+# Regression test for issue 4551 "svnrdump load commits wrong properties,
+# or fails, on a non-deltas dumpfile". In this test, the copy source does
+# not exist and the failure mode is to error out.
+@Issue(4551)
+def load_non_deltas_copy_with_props(sbox):
+  "load non-deltas copy with props"
+  sbox.build()
+
+  # Case (1): Copies that do not replace anything: the copy target path
+  # at (new rev - 1) does not exist
+
+  # Set properties on each node to be copied
+  sbox.simple_propset('p', 'v', 'A/mu', 'A/B', 'A/B/E')
+  sbox.simple_propset('q', 'v', 'A/mu', 'A/B', 'A/B/E')
+  sbox.simple_commit()
+  sbox.simple_update()  # avoid mixed-rev
+
+  # Do the copies
+  sbox.simple_copy('A/mu@2', 'A/mu_COPY')
+  sbox.simple_copy('A/B@2', 'A/B_COPY')
+  # Also add new nodes inside the copied dir, to test more code paths
+  sbox.simple_copy('A/B/E@2', 'A/B_COPY/copied')
+  sbox.simple_mkdir('A/B_COPY/added')
+  sbox.simple_copy('A/B/E@2', 'A/B_COPY/added/copied')
+  # On each copied node, delete a prop
+  sbox.simple_propdel('p', 'A/mu_COPY', 'A/B_COPY', 'A/B_COPY/E',
+                           'A/B_COPY/copied', 'A/B_COPY/added/copied')
+
+  sbox.simple_commit()
+
+  # Dump with 'svnadmin' (non-deltas mode)
+  dumpfile = svntest.actions.run_and_verify_dump(sbox.repo_dir, deltas=False)
+
+  # Load with 'svnrdump'. This used to throw an error:
+  # svnrdump: E160013: File not found: revision 2, path '/A/B_COPY'
+  new_repo_dir, new_repo_url = sbox.add_repo_path('new_repo')
+  svntest.main.create_repos(new_repo_dir)
+  svntest.actions.enable_revprop_changes(new_repo_dir)
+  svntest.actions.run_and_verify_svnrdump(dumpfile,
+                                          svntest.verify.AnyOutput,
+                                          [], 0, 'load', new_repo_url)
+
+  # Check that property 'p' really was deleted on each copied node
+  for tgt_path in ['A/mu_COPY', 'A/B_COPY', 'A/B_COPY/E',
+                   'A/B_COPY/copied', 'A/B_COPY/added/copied']:
+    tgt_url = new_repo_url + '/' + tgt_path
+    _, out, _ = svntest.main.run_svn(None, 'proplist', tgt_url)
+    expected = ["Properties on '%s':" % (tgt_url,),
+                'q']
+    actual = map(str.strip, out)
+    svntest.verify.compare_and_display_lines(None, 'PROPS', expected, actual)
+
+# Regression test for issue 4551 "svnrdump load commits wrong properties,
+# or fails, on a non-deltas dumpfile". In this test, the copy source does
+# exist and the failure mode is to fail to delete a property.
+@Issue(4551)
+def load_non_deltas_replace_copy_with_props(sbox):
+  "load non-deltas replace&copy with props"
+  sbox.build()
+
+  # Case (2): Copies that replace something: the copy target path
+  # at (new rev - 1) exists and has no property named 'p'
+
+  # Set props on the copy source nodes (a file, a dir, a child of the dir)
+  sbox.simple_propset('p', 'v', 'A/mu', 'A/B', 'A/B/E')
+  sbox.simple_propset('q', 'v', 'A/mu', 'A/B', 'A/B/E')
+  sbox.simple_commit()
+  sbox.simple_update()  # avoid mixed-rev
+
+  # Do the copies, replacing something
+  sbox.simple_rm('A/D/gamma', 'A/C')
+  sbox.simple_copy('A/mu@2', 'A/D/gamma')
+  sbox.simple_copy('A/B@2', 'A/C')
+  # On the copy, delete a prop that wasn't present on the node that it replaced
+  sbox.simple_propdel('p', 'A/D/gamma', 'A/C', 'A/C/E')
+
+  sbox.simple_commit()
+
+  # Dump with 'svnadmin' (non-deltas mode)
+  dumpfile = svntest.actions.run_and_verify_dump(sbox.repo_dir, deltas=False)
+
+  # Load with 'svnrdump'
+  new_repo_dir, new_repo_url = sbox.add_repo_path('new_repo')
+  svntest.main.create_repos(new_repo_dir)
+  svntest.actions.enable_revprop_changes(new_repo_dir)
+  svntest.actions.run_and_verify_svnrdump(dumpfile,
+                                          svntest.verify.AnyOutput,
+                                          [], 0, 'load', new_repo_url)
+
+  # Check that property 'p' really was deleted on each copied node
+  # This used to fail, finding that property 'p' was still present
+  for tgt_path in ['A/D/gamma', 'A/C', 'A/C/E']:
+    tgt_url = new_repo_url + '/' + tgt_path
+    _, out, _ = svntest.main.run_svn(None, 'proplist', tgt_url)
+    expected = ["Properties on '%s':" % (tgt_url,),
+                'q']
+    actual = map(str.strip, out)
+    svntest.verify.compare_and_display_lines(None, 'PROPS', expected, actual)
+
+# Regression test for issue 4551 "svnrdump load commits wrong properties,
+# or fails, on a non-deltas dumpfile". In this test, a node's props are
+# modified, and the failure mode is that RA-serf would end up deleting
+# properties that should remain on the node.
+@Issue(4551)
+def load_non_deltas_with_props(sbox):
+  "load non-deltas with props"
+  sbox.build()
+
+  # Case (3): A node's props are modified, and at least one of its previous
+  # props remains after the modification. svnrdump made two prop mod method
+  # calls for the same property (delete, then set). RA-serf's commit editor
+  # didn't expect this and performed the deletes after the non-deletes, and
+  # so ended up deleting a property that should not be deleted.
+
+  # Set properties on each node to be modified
+  sbox.simple_propset('p', 'v', 'A/mu')
+  sbox.simple_propset('q', 'v', 'A/mu', 'A/B')
+  sbox.simple_commit()
+
+  # Do the modifications: a different kind of mod on each node
+  sbox.simple_propdel('p', 'A/mu')
+  sbox.simple_propset('q', 'v2', 'A/B')
+  sbox.simple_commit()
+
+  # Dump with 'svnadmin' (non-deltas mode)
+  dumpfile = svntest.actions.run_and_verify_dump(sbox.repo_dir, deltas=False)
+
+  # Load with 'svnrdump'
+  new_repo_dir, new_repo_url = sbox.add_repo_path('new_repo')
+  svntest.main.create_repos(new_repo_dir)
+  svntest.actions.enable_revprop_changes(new_repo_dir)
+  svntest.actions.run_and_verify_svnrdump(dumpfile,
+                                          svntest.verify.AnyOutput,
+                                          [], 0, 'load', new_repo_url)
+
+  # Check that property 'q' remains on each modified node
+  for tgt_path in ['A/mu', 'A/B']:
+    tgt_url = new_repo_url + '/' + tgt_path
+    _, out, _ = svntest.main.run_svn(None, 'proplist', tgt_url)
+    expected = ["Properties on '%s':" % (tgt_url,),
+                'q']
+    actual = map(str.strip, out)
+    svntest.verify.compare_and_display_lines(None, 'PROPS', expected, actual)
   ########################################################################
 # Run the tests
 
@@ -813,6 +958,9 @@ test_list = [ None,
               reflect_dropped_renumbered_revs,
               dont_drop_valid_mergeinfo_during_incremental_svnrdump_loads,
               svnrdump_load_partial_incremental_dump,
+              load_non_deltas_copy_with_props,
+              load_non_deltas_replace_copy_with_props,
+              load_non_deltas_with_props,
              ]
 
 if __name__ == '__main__':

Propchange: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svntest/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Jul 28 11:18:37 2015
@@ -1,6 +1,6 @@
 /subversion/1.7.x-issue4059/subversion/tests/cmdline/svntest:1239661-1239744
 /subversion/branches/1.5.x-r30215/subversion/tests/cmdline/svntest:870312
-/subversion/branches/1.7.x/subversion/tests/cmdline/svntest:1480943-1645438
+/subversion/branches/1.7.x/subversion/tests/cmdline/svntest:1480943-1693067
 /subversion/branches/1.7.x-JavaHL-pools/subversion/tests/cmdline/svntest:1158684-1158722
 /subversion/branches/1.7.x-gssapi-solaris10/subversion/tests/cmdline/svntest:1453164-1515067
 /subversion/branches/1.7.x-issue3888/subversion/tests/cmdline/svntest:1148937-1149162

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svntest/main.py?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/cmdline/svntest/main.py Tue Jul 28 11:18:37 2015
@@ -1148,6 +1148,30 @@ def server_enforces_date_syntax():
 def server_has_atomic_revprop():
   return options.server_minor_version >= 7
 
+
+# https://issues.apache.org/bugzilla/show_bug.cgi?id=56480
+# https://issues.apache.org/bugzilla/show_bug.cgi?id=55397
+__mod_dav_url_quoting_broken_versions = frozenset([
+    '2.2.27',
+    '2.2.26',
+    '2.2.25',
+    '2.4.9',
+    '2.4.8',
+    '2.4.7',
+    '2.4.6',
+    '2.4.5',
+])
+def is_mod_dav_url_quoting_broken():
+    if is_ra_type_dav():
+        return (options.httpd_version in __mod_dav_url_quoting_broken_versions)
+    return None
+
+def is_httpd_authz_provider_enabled():
+    if is_ra_type_dav():
+      v = options.httpd_version.split('.')
+      return (v[0] == '2' and int(v[1]) >= 3) or int(v[0]) > 2
+    return None
+
 ######################################################################
 
 
@@ -1194,6 +1218,8 @@ class TestSpawningThread(threading.Threa
       args.append('--mode-filter=' + options.mode_filter)
     if options.milestone_filter:
       args.append('--milestone-filter=' + options.milestone_filter)
+    if options.httpd_version:
+      args.append('--httpd-version=' + options.httpd_version)
 
     result, stdout_lines, stderr_lines = spawn_process(command, 0, 0, None,
                                                        *args)
@@ -1361,6 +1387,36 @@ class TestRunner:
       sandbox.cleanup_test_paths()
     return exit_code
 
+
+# https://issues.apache.org/bugzilla/show_bug.cgi?id=56480
+# https://issues.apache.org/bugzilla/show_bug.cgi?id=55397
+__mod_dav_url_quoting_broken_versions = frozenset([
+    '2.2.27',
+    '2.2.26',
+    '2.2.25',
+    '2.4.9',
+    '2.4.8',
+    '2.4.7',
+    '2.4.6',
+    '2.4.5',
+])
+def is_mod_dav_url_quoting_broken():
+    if is_ra_type_dav():
+        return (options.httpd_version in __mod_dav_url_quoting_broken_versions)
+    return None
+
+def is_httpd_authz_provider_enabled():
+    if is_ra_type_dav():
+      v = options.httpd_version.split('.')
+      return (v[0] == '2' and int(v[1]) >= 3) or int(v[0]) > 2
+    return None
+
+def is_httpd_authz_provider_enabled():
+    if is_ra_type_dav():
+      v = options.httpd_version.split('.')
+      return (v[0] == '2' and int(v[1]) >= 3) or int(v[0]) > 2
+    return None
+
 ######################################################################
 # Main testing functions
 

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_repos/repos-test.c?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_repos/repos-test.c Tue Jul 28 11:18:37 2015
@@ -2684,6 +2684,246 @@ test_dump_r0_mergeinfo(const svn_test_op
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+mkdir_delete_copy(svn_repos_t *repos,
+                  const char *src,
+                  const char *dst,
+                  apr_pool_t *pool)
+{
+  svn_fs_t *fs = svn_repos_fs(repos);
+  svn_revnum_t youngest_rev;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root, *rev_root;
+
+  SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
+  
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "A/T", pool));
+  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_delete(txn_root, "A/T", pool));
+  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_revision_root(&rev_root, fs, youngest_rev - 1, pool));
+  SVN_ERR(svn_fs_copy(rev_root, src, txn_root, dst, pool));
+  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+
+  return SVN_NO_ERROR;
+}
+
+struct authz_read_baton_t {
+  apr_hash_t *paths;
+  apr_pool_t *pool;
+  const char *deny;
+};
+
+static svn_error_t *
+authz_read_func(svn_boolean_t *allowed,
+                svn_fs_root_t *root,
+                const char *path,
+                void *baton,
+                apr_pool_t *pool)
+{
+  struct authz_read_baton_t *b = baton;
+
+  if (b->deny && !strcmp(b->deny, path))
+    *allowed = FALSE;
+  else
+    *allowed = TRUE;
+
+  apr_hash_set(b->paths, apr_pstrdup(b->pool, path), APR_HASH_KEY_STRING,
+               (void*)1);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+verify_locations(apr_hash_t *actual,
+                 apr_hash_t *expected,
+                 apr_hash_t *checked,
+                 apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(pool, expected); hi; hi = apr_hash_next(hi))
+    {
+      const svn_revnum_t *rev = svn__apr_hash_index_key(hi);
+      const char *path = apr_hash_get(actual, rev, sizeof(svn_revnum_t));
+
+      if (!path)
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "expected %s for %d found (null)",
+                                 (char*)svn__apr_hash_index_val(hi),
+                                 (int)*rev);
+      else if (strcmp(path, svn__apr_hash_index_val(hi)))
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "expected %s for %d found %s",
+                                 (char*)svn__apr_hash_index_val(hi),
+                                 (int)*rev, path);
+
+    }
+
+  for (hi = apr_hash_first(pool, actual); hi; hi = apr_hash_next(hi))
+    {
+      const svn_revnum_t *rev = svn__apr_hash_index_key(hi);
+      const char *path = apr_hash_get(expected, rev, sizeof(svn_revnum_t));
+
+      if (!path)
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "found %s for %d expected (null)",
+                                 (char*)svn__apr_hash_index_val(hi),
+                                 (int)*rev);
+      else if (strcmp(path, svn__apr_hash_index_val(hi)))
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "found %s for %d expected %s",
+                                 (char*)svn__apr_hash_index_val(hi),
+                                 (int)*rev, path);
+
+      if (!apr_hash_get(checked, path, APR_HASH_KEY_STRING))
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "did not check %s", path);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static void
+set_expected(apr_hash_t *expected,
+             svn_revnum_t rev,
+             const char *path,
+             apr_pool_t *pool)
+{
+  svn_revnum_t *rp = apr_palloc(pool, sizeof(svn_revnum_t));
+  *rp = rev;
+  apr_hash_set(expected, rp, sizeof(svn_revnum_t), path);
+}
+
+static svn_error_t *
+trace_node_locations_authz(const svn_test_opts_t *opts,
+                           apr_pool_t *pool)
+{
+  svn_repos_t *repos;
+  svn_fs_t *fs;
+  svn_revnum_t youngest_rev = 0;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  struct authz_read_baton_t arb;
+  apr_array_header_t *revs = apr_array_make(pool, 10, sizeof(svn_revnum_t));
+  apr_hash_t *locations;
+  apr_hash_t *expected = apr_hash_make(pool);
+  int i;
+
+  /* Create test repository. */
+  SVN_ERR(svn_test__create_repos(&repos, "test-repo-trace-node-locations-authz",
+                                 opts, pool));
+  fs = svn_repos_fs(repos);
+
+  /* r1 create A */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, youngest_rev, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_dir(txn_root, "A", pool));
+  SVN_ERR(svn_fs_make_file(txn_root, "A/f", pool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "A/f", "foobar", pool));
+  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+
+  /* r4 copy A to B */
+  SVN_ERR(mkdir_delete_copy(repos, "A", "B", pool));
+
+  /* r7 copy B to C */
+  SVN_ERR(mkdir_delete_copy(repos, "B", "C", pool));
+
+  /* r10 copy C to D */
+  SVN_ERR(mkdir_delete_copy(repos, "C", "D", pool));
+
+  SVN_ERR(svn_fs_youngest_rev(&youngest_rev, fs, pool));
+  SVN_ERR_ASSERT(youngest_rev == 10);
+
+  arb.paths = apr_hash_make(pool);
+  arb.pool = pool;
+  arb.deny = NULL;
+
+  apr_array_clear(revs);
+  for (i = 0; i <= youngest_rev; ++i)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = i;
+  set_expected(expected, 10, "/D/f", pool);
+  set_expected(expected, 8, "/C/f", pool);
+  set_expected(expected, 7, "/C/f", pool);
+  set_expected(expected, 5, "/B/f", pool);
+  set_expected(expected, 4, "/B/f", pool);
+  set_expected(expected, 2, "/A/f", pool);
+  set_expected(expected, 1, "/A/f", pool);
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  apr_array_clear(revs);
+  for (i = 1; i <= youngest_rev; ++i)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = i;
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  apr_array_clear(revs);
+  for (i = 2; i <= youngest_rev; ++i)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = i;
+  set_expected(expected, 1, NULL, pool);
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  apr_array_clear(revs);
+  for (i = 3; i <= youngest_rev; ++i)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = i;
+  set_expected(expected, 2, NULL, pool);
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  apr_array_clear(revs);
+  for (i = 6; i <= youngest_rev; ++i)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = i;
+  set_expected(expected, 5, NULL, pool);
+  set_expected(expected, 4, NULL, pool);
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  arb.deny = "/B/f";
+  apr_array_clear(revs);
+  for (i = 0; i <= youngest_rev; ++i)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = i;
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  apr_array_clear(revs);
+  for (i = 6; i <= youngest_rev; ++i)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = i;
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  APR_ARRAY_PUSH(revs, svn_revnum_t) = 0;
+  apr_hash_clear(arb.paths);
+  SVN_ERR(svn_repos_trace_node_locations(fs, &locations, "D/f", 10, revs,
+                                         authz_read_func, &arb, pool));
+  SVN_ERR(verify_locations(locations, expected, arb.paths, pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* The test table.  */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -2723,5 +2963,7 @@ struct svn_test_descriptor_t test_funcs[
                        "test dumping with r0 mergeinfo"),
     SVN_TEST_OPTS_PASS(filename_with_control_chars,
                        "test filenames with control characters"),
+    SVN_TEST_OPTS_PASS(trace_node_locations_authz,
+                       "authz for svn_repos_trace_node_locations"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_subr/config-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_subr/config-test.c?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_subr/config-test.c (original)
+++ subversion/branches/1.7.x-issue4340-repos/subversion/tests/libsvn_subr/config-test.c Tue Jul 28 11:18:37 2015
@@ -231,6 +231,32 @@ test_has_section(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_expand(const svn_test_opts_t *opts,
+            apr_pool_t *pool)
+{
+  svn_config_t *cfg;
+  const char *cfg_file, *val;
+
+  if (!srcdir)
+    SVN_ERR(init_params(pool));
+
+  cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL);
+  SVN_ERR(svn_config_read2(&cfg, cfg_file, TRUE, FALSE, pool));
+
+  /* Get expanded "g" which requires expanding "c". */
+  svn_config_get(cfg, &val, "section1", "g", NULL);
+
+  /* Get expanded "c". */
+  svn_config_get(cfg, &val, "section1", "c", NULL);
+
+  /* With pool debugging enabled this ensures that the expanded value 
+     of "c" was not created in a temporary pool when expanding "g". */
+  SVN_TEST_STRING_ASSERT(val, "bar");
+
+  return SVN_NO_ERROR;
+}
+
 /*
    ====================================================================
    If you add a new test to this file, update this array.
@@ -248,5 +274,7 @@ struct svn_test_descriptor_t test_funcs[
                    "test svn_config boolean conversion"),
     SVN_TEST_PASS2(test_has_section,
                    "test svn_config_has_section"),
+    SVN_TEST_OPTS_PASS(test_expand,
+                       "test variable expansion"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/1.7.x-issue4340-repos/win-tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/1.7.x-issue4340-repos/win-tests.py?rev=1693068&r1=1693067&r2=1693068&view=diff
==============================================================================
--- subversion/branches/1.7.x-issue4340-repos/win-tests.py (original)
+++ subversion/branches/1.7.x-issue4340-repos/win-tests.py Tue Jul 28 11:18:37 2015
@@ -466,6 +466,7 @@ class Httpd:
     self.httpd_config = os.path.join(self.root, 'httpd.conf')
     self.httpd_users = os.path.join(self.root, 'users')
     self.httpd_mime_types = os.path.join(self.root, 'mime.types')
+    self.httpd_groups = os.path.join(self.root, 'groups')
     self.abs_builddir = abs_builddir
     self.abs_objdir = abs_objdir
     self.service_name = 'svn-test-httpd-' + str(httpd_port)
@@ -479,6 +480,7 @@ class Httpd:
     create_target_dir(self.root_dir)
 
     self._create_users_file()
+    self._create_groups_file()
     self._create_mime_types_file()
 
     # Determine version.
@@ -520,6 +522,8 @@ class Httpd:
     if self.httpd_ver >= 2.2:
       fp.write(self._sys_module('auth_basic_module', 'mod_auth_basic.so'))
       fp.write(self._sys_module('authn_file_module', 'mod_authn_file.so'))
+      fp.write(self._sys_module('authz_groupfile_module', 'mod_authz_groupfile.so'))
+      fp.write(self._sys_module('authz_host_module', 'mod_authz_host.so'))
     else:
       fp.write(self._sys_module('auth_module', 'mod_auth.so'))
     fp.write(self._sys_module('alias_module', 'mod_alias.so'))
@@ -533,6 +537,7 @@ class Httpd:
     # Define two locations for repositories
     fp.write(self._svn_repo('repositories'))
     fp.write(self._svn_repo('local_tmp'))
+    fp.write(self._svn_authz_repo())
 
     # And two redirects for the redirect tests
     fp.write('RedirectMatch permanent ^/svn-test-work/repositories/'
@@ -562,6 +567,17 @@ class Httpd:
                                     'jrandom', 'rayjandom'])
     os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-mb',  self.httpd_users,
                                     'jconstant', 'rayjandom'])
+    os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp',  self.httpd_users,
+                                    'JRANDOM', 'rayjandom'])
+    os.spawnv(os.P_WAIT, htpasswd, ['htpasswd.exe', '-bp',  self.httpd_users,
+                                    'JCONSTANT', 'rayjandom'])
+
+  def _create_groups_file(self):
+    "Create groups for mod_authz_svn tests"
+    fp = open(self.httpd_groups, 'w')
+    fp.write('random: jrandom\n')
+    fp.write('constant: jconstant\n')
+    fp.close()
 
   def _create_mime_types_file(self):
     "Create empty mime.types file"
@@ -595,6 +611,153 @@ class Httpd:
       '  Require         valid-user\n' \
       '</Location>\n'
 
+  def _svn_authz_repo(self):
+    local_tmp = os.path.join(self.abs_builddir,
+                             CMDLINE_TEST_SCRIPT_NATIVE_PATH,
+                             'svn-test-work', 'local_tmp')
+    return \
+      '<Location /authz-test-work/anon>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  <IfModule mod_authz_core.c>' + '\n' \
+      '    Require all granted' + '\n' \
+      '  </IfModule>' + '\n' \
+      '  <IfModule !mod_authz_core.c>' + '\n' \
+      '    Allow from all' + '\n' \
+      '  </IfModule>' + '\n' \
+      '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/mixed>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  Require           valid-user' + '\n' \
+      '  Satisfy Any' + '\n' \
+      '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/mixed-noauthwhenanon>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  Require           valid-user' + '\n' \
+      '  AuthzSVNNoAuthWhenAnonymousAllowed On' + '\n' \
+      '  SVNPathAuthz On' + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/authn>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  Require           valid-user' + '\n' \
+      '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/authn-anonoff>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  Require           valid-user' + '\n' \
+      '  AuthzSVNAnonymous Off' + '\n' \
+      '  SVNPathAuthz On' + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/authn-lcuser>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  Require           valid-user' + '\n' \
+      '  AuthzForceUsernameCase Lower' + '\n' \
+      '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/authn-lcuser>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  Require           valid-user' + '\n' \
+      '  AuthzForceUsernameCase Lower' + '\n' \
+      '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/authn-group>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  AuthGroupFile    ' + self._quote(self.httpd_groups) + '\n' \
+      '  Require           group random' + '\n' \
+      '  AuthzSVNAuthoritative Off' + '\n' \
+      '  SVNPathAuthz On' + '\n' \
+      '</Location>' + '\n' \
+      '<IfModule mod_authz_core.c>' + '\n' \
+      '<Location /authz-test-work/sallrany>' + '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  AuthzSendForbiddenOnFailure On' + '\n' \
+      '  Satisfy All' + '\n' \
+      '  <RequireAny>' + '\n' \
+      '    Require valid-user' + '\n' \
+      '    Require expr req(\'ALLOW\') == \'1\'' + '\n' \
+      '  </RequireAny>' + '\n' \
+      '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '</Location>' + '\n' \
+      '<Location /authz-test-work/sallrall>'+ '\n' \
+      '  DAV               svn' + '\n' \
+      '  SVNParentPath     ' + local_tmp + '\n' \
+      '  AuthzSVNAccessFile ' + self._quote(self.authz_file) + '\n' \
+      '  SVNAdvertiseV2Protocol ' + self.httpv2_option + '\n' \
+      '  SVNListParentPath On' + '\n' \
+      '  AuthType          Basic' + '\n' \
+      '  AuthName          "Subversion Repository"' + '\n' \
+      '  AuthUserFile    ' + self._quote(self.httpd_users) + '\n' \
+      '  AuthzSendForbiddenOnFailure On' + '\n' \
+      '  Satisfy All' + '\n' \
+      '  <RequireAll>' + '\n' \
+      '    Require valid-user' + '\n' \
+      '    Require expr req(\'ALLOW\') == \'1\'' + '\n' \
+      '  </RequireAll>' + '\n' \
+      '  SVNPathAuthz ' + self.path_authz_option + '\n' \
+      '</Location>' + '\n' \
+      '</IfModule>' + '\n' \
+
   def start(self):
     if self.service:
       self._start_service()
@@ -728,6 +891,10 @@ if not test_javahl:
     log_file = os.path.join(abs_builddir, log)
     fail_log_file = os.path.join(abs_builddir, faillog)
 
+  if run_httpd:
+    httpd_version = "%.1f" % daemon.httpd_ver
+  else:
+    httpd_version = None
   th = run_tests.TestHarness(abs_srcdir, abs_builddir,
                              log_file,
                              fail_log_file,
@@ -736,7 +903,8 @@ if not test_javahl:
                              cleanup, enable_sasl, parallel, config_file,
                              fsfs_sharding, fsfs_packing,
                              list_tests, svn_bin, mode_filter,
-                             milestone_filter)
+                             milestone_filter,
+                             httpd_version=httpd_version)
   old_cwd = os.getcwd()
   try:
     os.chdir(abs_builddir)