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 2012/10/21 04:00:47 UTC

svn commit: r1400556 [9/29] - in /subversion/branches/ev2-export: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/hudson/ contrib/client-side/emacs/ contrib/client-side/svn-push/ contrib/client-side/svnmerge/ contrib/hook-s...

Modified: subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.c Sun Oct 21 02:00:31 2012
@@ -1087,7 +1087,6 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
     }
   else /* ! svn_path_is_url() */
     {
-      /* Acquire return values. */
       SVN_ERR(svn_client__get_wc_or_repos_mergeinfo_catalog(
         mergeinfo_catalog, NULL, NULL, include_descendants, FALSE,
         ignore_invalid_mergeinfo, svn_mergeinfo_inherited,
@@ -1259,7 +1258,7 @@ struct filter_log_entry_baton_t
   /* A rangelist describing all the revisions potentially merged or
      potentially eligible for merging (see FILTERING_MERGED) based on
      the target's explicit or inherited mergeinfo. */
-  const apr_array_header_t *rangelist;
+  const svn_rangelist_t *rangelist;
 
   /* The wrapped svn_log_entry_receiver_t callback and baton which
      filter_log_entry_with_rangelist() is acting as a filter for. */
@@ -1291,7 +1290,7 @@ filter_log_entry_with_rangelist(void *ba
                                 apr_pool_t *pool)
 {
   struct filter_log_entry_baton_t *fleb = baton;
-  apr_array_header_t *intersection, *this_rangelist;
+  svn_rangelist_t *intersection, *this_rangelist;
 
   if (fleb->ctx->cancel_func)
     SVN_ERR(fleb->ctx->cancel_func(fleb->ctx->cancel_baton));
@@ -1332,7 +1331,7 @@ filter_log_entry_with_rangelist(void *ba
     {
       apr_hash_index_t *hi;
       svn_boolean_t all_subtrees_have_this_rev = TRUE;
-      apr_array_header_t *this_rev_rangelist =
+      svn_rangelist_t *this_rev_rangelist =
         svn_rangelist__initialize(log_entry->revision - 1,
                                   log_entry->revision, TRUE, pool);
       apr_pool_t *iterpool = svn_pool_create(pool);
@@ -1405,7 +1404,7 @@ filter_log_entry_with_rangelist(void *ba
           if (ancestor_is_self /* Explicit mergeinfo on TARGET_PATH_AFFECTED */
               && (change->action != 'M'))
             {
-              apr_array_header_t *rangelist = apr_hash_get(
+              svn_rangelist_t *rangelist = apr_hash_get(
                 nearest_ancestor_mergeinfo, path, APR_HASH_KEY_STRING);
               svn_merge_range_t *youngest_range = APR_ARRAY_IDX(
                 rangelist, rangelist->nelts - 1, svn_merge_range_t *);
@@ -1424,7 +1423,7 @@ filter_log_entry_with_rangelist(void *ba
                    hi2 = apr_hash_next(hi2))
                 {
                   const char *mergeinfo_path = svn__apr_hash_index_key(hi2);
-                  apr_array_header_t *rangelist = svn__apr_hash_index_val(hi2);
+                  svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi2);
 
                   /* Does the mergeinfo for PATH reflect if
                      LOG_ENTRY->REVISION was previously merged
@@ -1498,7 +1497,7 @@ static svn_error_t *
 logs_for_mergeinfo_rangelist(const char *source_url,
                              const apr_array_header_t *merge_source_fspaths,
                              svn_boolean_t filtering_merged,
-                             const apr_array_header_t *rangelist,
+                             const svn_rangelist_t *rangelist,
                              svn_mergeinfo_catalog_t target_mergeinfo_catalog,
                              const char *target_fspath,
                              svn_boolean_t discover_changed_paths,
@@ -1573,6 +1572,44 @@ logs_for_mergeinfo_rangelist(const char 
 
   return SVN_NO_ERROR;
 }
+
+/* Set *OUT_MERGEINFO to a shallow copy of MERGEINFO with each source path
+   converted to a (URI-encoded) URL based on REPOS_ROOT_URL. *OUT_MERGEINFO
+   is declared as 'apr_hash_t *' because its key do not obey the rules of
+   'svn_mergeinfo_t'.
+
+   Allocate *OUT_MERGEINFO and the new keys in RESULT_POOL.  Use
+   SCRATCH_POOL for any temporary allocations. */
+static svn_error_t *
+mergeinfo_relpaths_to_urls(apr_hash_t **out_mergeinfo,
+                           svn_mergeinfo_t mergeinfo,
+                           const char *repos_root_url,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  *out_mergeinfo = NULL;
+  if (mergeinfo)
+    {
+      apr_hash_index_t *hi;
+      apr_hash_t *full_path_mergeinfo = apr_hash_make(result_pool);
+
+      for (hi = apr_hash_first(scratch_pool, mergeinfo);
+           hi; hi = apr_hash_next(hi))
+        {
+          const char *key = svn__apr_hash_index_key(hi);
+          void *val = svn__apr_hash_index_val(hi);
+
+          apr_hash_set(full_path_mergeinfo,
+                       svn_path_url_add_component2(repos_root_url, key + 1,
+                                                   result_pool),
+                       APR_HASH_KEY_STRING, val);
+        }
+      *out_mergeinfo = full_path_mergeinfo;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 /*** Public APIs ***/
 
@@ -1615,8 +1652,8 @@ svn_client_mergeinfo_get_merged(apr_hash
       mergeinfo = NULL;
     }
 
-  SVN_ERR(svn_mergeinfo__relpaths_to_urls(mergeinfo_p, mergeinfo,
-                                          repos_root, pool, pool));
+  SVN_ERR(mergeinfo_relpaths_to_urls(mergeinfo_p, mergeinfo,
+                                     repos_root, pool, pool));
   return SVN_NO_ERROR;
 }
 
@@ -1649,8 +1686,8 @@ svn_client_mergeinfo_log2(svn_boolean_t 
 
   svn_mergeinfo_t source_history;
   svn_mergeinfo_t target_history;
-  apr_array_header_t *master_noninheritable_rangelist;
-  apr_array_header_t *master_inheritable_rangelist;
+  svn_rangelist_t *master_noninheritable_rangelist;
+  svn_rangelist_t *master_inheritable_rangelist;
   apr_array_header_t *merge_source_fspaths =
     apr_array_make(scratch_pool, 1, sizeof(const char *));
   apr_hash_index_t *hi_catalog;
@@ -1730,7 +1767,10 @@ svn_client_mergeinfo_log2(svn_boolean_t 
         }
     }
 
-  /* Open RA sessions to the repository for the source and target.
+  /* Fetch the location history as mergeinfo, for the source branch
+   * (between the given start and end revisions), and, if we're finding
+   * merged revisions, then also for the entire target branch.
+   *
    * ### TODO: As the source and target must be in the same repository, we
    * should share a single session, tracking the two URLs separately. */
   {
@@ -1885,7 +1925,7 @@ svn_client_mergeinfo_log2(svn_boolean_t 
         {
           /* The inheritable rangelist merged from SUBTREE_SOURCE_HISTORY
              to SUBTREE_PATH. */
-          apr_array_header_t *subtree_merged_rangelist =
+          svn_rangelist_t *subtree_merged_rangelist =
             apr_array_make(scratch_pool, 1, sizeof(svn_merge_range_t *));
 
           SVN_ERR(svn_rangelist__merge_many(master_inheritable_rangelist,
@@ -1922,9 +1962,9 @@ svn_client_mergeinfo_log2(svn_boolean_t 
            hi;
            hi = apr_hash_next(hi))
         {
-          apr_array_header_t *deleted_rangelist;
-          apr_array_header_t *added_rangelist;
-          apr_array_header_t *subtree_merged_rangelist =
+          svn_rangelist_t *deleted_rangelist;
+          svn_rangelist_t *added_rangelist;
+          svn_rangelist_t *subtree_merged_rangelist =
             svn__apr_hash_index_val(hi);
 
           svn_pool_clear(iterpool);
@@ -1960,7 +2000,7 @@ svn_client_mergeinfo_log2(svn_boolean_t 
   else
     {
       /* Create the starting rangelist for what might be eligible. */
-      apr_array_header_t *source_master_rangelist =
+      svn_rangelist_t *source_master_rangelist =
         apr_array_make(scratch_pool, 1, sizeof(svn_merge_range_t *));
 
       SVN_ERR(svn_rangelist__merge_many(source_master_rangelist,
@@ -1997,7 +2037,7 @@ svn_client_mergeinfo_log2(svn_boolean_t 
         = APR_ARRAY_IDX(master_inheritable_rangelist,
                         master_inheritable_rangelist->nelts - 1,
                         svn_merge_range_t *);
-      apr_array_header_t *youngest_rangelist =
+      svn_rangelist_t *youngest_rangelist =
         svn_rangelist__initialize(youngest_range->end - 1,
                                   youngest_range->end,
                                   youngest_range->inheritable,
@@ -2008,9 +2048,9 @@ svn_client_mergeinfo_log2(svn_boolean_t 
            hi = apr_hash_next(hi))
         {
           const char *key = svn__apr_hash_index_key(hi);
-          apr_array_header_t *subtree_merged_rangelist =
+          svn_rangelist_t *subtree_merged_rangelist =
             svn__apr_hash_index_val(hi);
-          apr_array_header_t *intersecting_rangelist;
+          svn_rangelist_t *intersecting_rangelist;
 
           svn_pool_clear(iterpool);
           SVN_ERR(svn_rangelist_intersect(&intersecting_rangelist,

Modified: subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.h?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/mergeinfo.h Sun Oct 21 02:00:31 2012
@@ -65,7 +65,7 @@ typedef struct svn_client__merge_path_t
      with the youngest start revisions come first.  In both the forward and
      reverse merge cases the ranges should never overlap.  This rangelist
      may be empty but should never be NULL unless ABSENT is true. */
-  apr_array_header_t *remaining_ranges;
+  svn_rangelist_t *remaining_ranges;
 
   svn_mergeinfo_t pre_merge_mergeinfo;  /* Explicit or inherited mergeinfo
                                            on ABSPATH prior to a merge.
@@ -300,7 +300,7 @@ svn_client__get_wc_or_repos_mergeinfo_ca
    If HAS_REV_ZERO_HISTORY is not NULL, then set *HAS_REV_ZERO_HISTORY to
    TRUE if the natural history includes revision 0, else to FALSE.
 
-   RA_SESSION is an open RA session to the repository in which URL lives;
+   RA_SESSION is an open RA session to the repository of PATHREV;
    it may be temporarily reparented by this function.
 */
 svn_error_t *

Modified: subversion/branches/ev2-export/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/prop_commands.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/prop_commands.c Sun Oct 21 02:00:31 2012
@@ -38,6 +38,7 @@
 #include "svn_pools.h"
 #include "svn_props.h"
 #include "svn_hash.h"
+#include "svn_sorts.h"
 
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
@@ -576,21 +577,28 @@ pristine_or_working_props(apr_hash_t **p
 
 /* Helper for the remote case of svn_client_propget.
  *
- * Get the value of property PROPNAME in REVNUM, using RA_LIB and
- * SESSION.  Store the value ('svn_string_t *') in PROPS, under the
- * path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *').
+ * If PROPS is not null, then get the value of property PROPNAME in REVNUM,
+   using RA_LIB and SESSION.  Store the value ('svn_string_t *') in PROPS,
+   under the path key "TARGET_PREFIX/TARGET_RELATIVE" ('const char *').
+ *
+ * If INHERITED_PROPS is not null, then set *INHERITED_PROPS to a
+ * depth-first ordered array of svn_prop_inherited_item_t * structures
+ * representing the PROPNAME properties inherited by the target.  If
+ * INHERITABLE_PROPS in not null and no inheritable properties are found,
+ * then set *INHERITED_PROPS to an empty array.
  *
  * Recurse according to DEPTH, similarly to svn_client_propget3().
  *
  * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE".
  * Yes, caller passes this; it makes the recursion more efficient :-).
  *
- * Allocate the keys and values in PERM_POOL, but do all temporary
- * work in WORK_POOL.  The two pools can be the same; recursive
- * calls may use a different WORK_POOL, however.
+ * Allocate PROPS and *INHERITED_PROPS in RESULT_POOL, but do all temporary
+ * work in SCRATCH_POOL.  The two pools can be the same; recursive
+ * calls may use a different SCRATCH_POOL, however.
  */
 static svn_error_t *
 remote_propget(apr_hash_t *props,
+               apr_array_header_t **inherited_props,
                const char *propname,
                const char *target_prefix,
                const char *target_relative,
@@ -598,26 +606,27 @@ remote_propget(apr_hash_t *props,
                svn_revnum_t revnum,
                svn_ra_session_t *ra_session,
                svn_depth_t depth,
-               apr_pool_t *perm_pool,
-               apr_pool_t *work_pool)
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   apr_hash_t *dirents;
-  apr_hash_t *prop_hash;
+  apr_hash_t *prop_hash = NULL;
   const svn_string_t *val;
   const char *target_full_url =
-    svn_path_url_add_component2(target_prefix, target_relative, work_pool);
+    svn_path_url_add_component2(target_prefix, target_relative,
+                                scratch_pool);
 
   if (kind == svn_node_dir)
     {
       SVN_ERR(svn_ra_get_dir2(ra_session,
                               (depth >= svn_depth_files ? &dirents : NULL),
                               NULL, &prop_hash, target_relative, revnum,
-                              SVN_DIRENT_KIND, work_pool));
+                              SVN_DIRENT_KIND, scratch_pool));
     }
   else if (kind == svn_node_file)
     {
       SVN_ERR(svn_ra_get_file(ra_session, target_relative, revnum,
-                              NULL, NULL, &prop_hash, work_pool));
+                              NULL, NULL, &prop_hash, scratch_pool));
     }
   else if (kind == svn_node_none)
     {
@@ -632,10 +641,52 @@ remote_propget(apr_hash_t *props,
                                target_full_url);
     }
 
-  if ((val = apr_hash_get(prop_hash, propname, APR_HASH_KEY_STRING)))
+  if (inherited_props)
+    {
+      /* We will filter out all but PROPNAME later, making a final copy
+         in RESULT_POOL, so pass SCRATCH_POOL for both pools. */
+      SVN_ERR(svn_ra_get_inherited_props(ra_session, inherited_props,
+                                         target_relative, revnum,
+                                         scratch_pool, scratch_pool));
+    }
+
+  /* Make a copy of any inherited PROPNAME properties in RESULT_POOL. */
+  if (inherited_props)
+    {
+      int i;
+      apr_array_header_t *final_iprops =
+        apr_array_make(result_pool, 1, sizeof(svn_prop_inherited_item_t *));
+
+      for (i = 0; i < (*inherited_props)->nelts; i++)
+        {
+          svn_prop_inherited_item_t *iprop =
+            APR_ARRAY_IDX((*inherited_props), i, svn_prop_inherited_item_t *);
+          svn_string_t *iprop_val = apr_hash_get(iprop->prop_hash, propname,
+                                                 APR_HASH_KEY_STRING);
+
+          if (iprop_val)
+            {
+              svn_prop_inherited_item_t *new_iprop =
+                apr_palloc(result_pool, sizeof(*new_iprop));
+              new_iprop->path_or_url =
+                apr_pstrdup(result_pool, iprop->path_or_url);
+              new_iprop->prop_hash = apr_hash_make(result_pool);
+              apr_hash_set(new_iprop->prop_hash,
+                           apr_pstrdup(result_pool, propname),
+                           APR_HASH_KEY_STRING,
+                           svn_string_dup(iprop_val, result_pool));
+              APR_ARRAY_PUSH(final_iprops, svn_prop_inherited_item_t *) =
+                new_iprop;
+            }
+        }
+      *inherited_props = final_iprops;
+    }
+
+  if (prop_hash
+      && (val = apr_hash_get(prop_hash, propname, APR_HASH_KEY_STRING)))
     {
-      apr_hash_set(props, apr_pstrdup(perm_pool, target_full_url),
-                   APR_HASH_KEY_STRING, svn_string_dup(val, perm_pool));
+      apr_hash_set(props, apr_pstrdup(result_pool, target_full_url),
+                   APR_HASH_KEY_STRING, svn_string_dup(val, result_pool));
     }
 
   if (depth >= svn_depth_files
@@ -643,9 +694,9 @@ remote_propget(apr_hash_t *props,
       && apr_hash_count(dirents) > 0)
     {
       apr_hash_index_t *hi;
-      apr_pool_t *iterpool = svn_pool_create(work_pool);
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-      for (hi = apr_hash_first(work_pool, dirents);
+      for (hi = apr_hash_first(scratch_pool, dirents);
            hi;
            hi = apr_hash_next(hi))
         {
@@ -665,7 +716,7 @@ remote_propget(apr_hash_t *props,
           new_target_relative = svn_relpath_join(target_relative, this_name,
                                                  iterpool);
 
-          SVN_ERR(remote_propget(props,
+          SVN_ERR(remote_propget(props, NULL,
                                  propname,
                                  target_prefix,
                                  new_target_relative,
@@ -673,7 +724,7 @@ remote_propget(apr_hash_t *props,
                                  revnum,
                                  ra_session,
                                  depth_below_here,
-                                 perm_pool, iterpool));
+                                 result_pool, iterpool));
         }
 
       svn_pool_destroy(iterpool);
@@ -774,7 +825,8 @@ get_prop_from_wc(apr_hash_t **props,
 
 /* Note: this implementation is very similar to svn_client_proplist. */
 svn_error_t *
-svn_client_propget4(apr_hash_t **props,
+svn_client_propget5(apr_hash_t **props,
+                    apr_array_header_t **inherited_props,
                     const char *propname,
                     const char *target,
                     const svn_opt_revision_t *peg_revision,
@@ -787,6 +839,8 @@ svn_client_propget4(apr_hash_t **props,
                     apr_pool_t *scratch_pool)
 {
   svn_revnum_t revnum;
+  svn_boolean_t local_explicit_props;
+  svn_boolean_t local_iprops;
 
   SVN_ERR(error_if_wcprop_name(propname));
   if (!svn_path_is_url(target))
@@ -796,9 +850,19 @@ svn_client_propget4(apr_hash_t **props,
                                                         target);
   revision = svn_cl__rev_default_to_peg(revision, peg_revision);
 
-  if (! svn_path_is_url(target)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
+  local_explicit_props =
+    (! svn_path_is_url(target)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind));
+
+  local_iprops =
+    (local_explicit_props
+     && (peg_revision->kind == svn_opt_revision_working
+         || peg_revision->kind == svn_opt_revision_unspecified )
+     && (revision->kind == svn_opt_revision_working
+         || revision->kind == svn_opt_revision_unspecified ));
+
+  if (local_explicit_props)
     {
       svn_node_kind_t kind;
       svn_boolean_t pristine;
@@ -832,30 +896,120 @@ svn_client_propget4(apr_hash_t **props,
       else if (err)
         return svn_error_trace(err);
 
+      if (inherited_props && local_iprops)
+        SVN_ERR(svn_wc__get_iprops(inherited_props, ctx->wc_ctx,
+                                   target, propname,
+                                   scratch_pool, scratch_pool));
+
       SVN_ERR(get_prop_from_wc(props, propname, target,
                                pristine, kind,
                                depth, changelists, ctx, scratch_pool,
                                result_pool));
     }
-  else
+
+  if ((inherited_props && !local_iprops)
+      || !local_explicit_props)
     {
-      svn_client__pathrev_t *loc;
       svn_ra_session_t *ra_session;
       svn_node_kind_t kind;
+      svn_opt_revision_t new_operative_rev;
+      svn_opt_revision_t new_peg_rev;
+
+      /* Peg or operative revisions may be WC specific for
+         TARGET's explicit props, but still require us to
+         contact the repository for the inherited properties. */
+      if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)
+          || SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+        {
+          svn_revnum_t origin_rev;
+          const char *repos_relpath;
+          const char *repos_root_url;
+          const char *repos_uuid;
+          const char *local_abspath;
+          const char *copy_root_abspath;
+          svn_boolean_t is_copy;
+
+          SVN_ERR(svn_dirent_get_absolute(&local_abspath, target,
+                                          scratch_pool));
+
+          if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+            {
+              SVN_ERR(svn_wc__node_get_origin(&is_copy,
+                                              &origin_rev,
+                                              &repos_relpath,
+                                              &repos_root_url,
+                                              &repos_uuid,
+                                              &copy_root_abspath,
+                                              ctx->wc_ctx,
+                                              local_abspath,
+                                              FALSE, /* scan_deleted */
+                                              result_pool,
+                                              scratch_pool));
+              if (repos_relpath)
+                {
+                  target = svn_path_url_add_component2(repos_root_url,
+                                                       repos_relpath,
+                                                       scratch_pool);
+                  if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+                    {
+                      svn_revnum_t resolved_peg_rev;
+
+                      SVN_ERR(svn_client__get_revision_number(
+                        &resolved_peg_rev, NULL, ctx->wc_ctx,
+                        local_abspath, NULL, peg_revision, scratch_pool));
+                      new_peg_rev.kind = svn_opt_revision_number;
+                      new_peg_rev.value.number = resolved_peg_rev;
+                      peg_revision = &new_peg_rev;
+                    }
+
+                  if (SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+                    {
+                      svn_revnum_t resolved_operative_rev;
+
+                      SVN_ERR(svn_client__get_revision_number(
+                        &resolved_operative_rev, NULL, ctx->wc_ctx,
+                        local_abspath, NULL, revision, scratch_pool));
+                      new_operative_rev.kind = svn_opt_revision_number;
+                      new_operative_rev.value.number = resolved_operative_rev;
+                      revision = &new_operative_rev;
+                    }
+                }
+              else
+                {
+                  /* TARGET doesn't exist in the repository, so there are
+                     obviously not inherited props to be found there. */
+                  local_iprops = TRUE;
+                  *inherited_props = apr_array_make(
+                    result_pool, 0, sizeof(svn_prop_inherited_item_t *));
+                }
+            }
+        }
 
-      /* Get an RA plugin for this filesystem object. */
-      SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
-                                                target, NULL,
-                                                peg_revision,
-                                                revision, ctx, scratch_pool));
-
-      SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, scratch_pool));
-
-      *props = apr_hash_make(result_pool);
-      SVN_ERR(remote_propget(*props, propname, loc->url, "",
-                             kind, loc->rev, ra_session,
-                             depth, result_pool, scratch_pool));
-      revnum = loc->rev;
+      /* Do we still have anything to ask the repository about? */
+      if (!local_explicit_props || !local_iprops)
+        {
+          svn_client__pathrev_t *loc;
+
+          /* Get an RA plugin for this filesystem object. */
+          SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
+                                                    target, NULL,
+                                                    peg_revision,
+                                                    revision, ctx,
+                                                    scratch_pool));
+
+          SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind,
+                                    scratch_pool));
+
+          if (!local_explicit_props)
+            *props = apr_hash_make(result_pool);
+
+          SVN_ERR(remote_propget(!local_explicit_props ? *props : NULL,
+                                 !local_iprops ? inherited_props : NULL,
+                                 propname, loc->url, "",
+                                 kind, loc->rev, ra_session,
+                                 depth, result_pool, scratch_pool));
+          revnum = loc->rev;
+        }
     }
 
   if (actual_revnum)
@@ -889,19 +1043,24 @@ svn_client_revprop_get(const char *propn
 }
 
 
-/* Call RECEIVER for the given PATH and PROP_HASH.
+/* Call RECEIVER for the given PATH and its PROP_HASH and/or
+ * INHERITED_PROPERTIES.
  *
- * If PROP_HASH is null or has zero count, do nothing.
+ * If PROP_HASH is null or has zero count or INHERITED_PROPERTIES is null,
+ * then do nothing.
  */
 static svn_error_t*
 call_receiver(const char *path,
               apr_hash_t *prop_hash,
-              svn_proplist_receiver_t receiver,
+              apr_array_header_t *inherited_properties,
+              svn_proplist_receiver2_t receiver,
               void *receiver_baton,
-              apr_pool_t *pool)
+              apr_pool_t *scratch_pool)
 {
-  if (prop_hash && apr_hash_count(prop_hash))
-    SVN_ERR(receiver(receiver_baton, path, prop_hash, pool));
+  if ((prop_hash && apr_hash_count(prop_hash))
+      || inherited_properties)
+    SVN_ERR(receiver(receiver_baton, path, prop_hash, inherited_properties,
+                     scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -909,20 +1068,23 @@ call_receiver(const char *path,
 
 /* Helper for the remote case of svn_client_proplist.
  *
- * Push a new 'svn_client_proplist_item_t *' item onto PROPLIST,
- * containing the properties for "TARGET_PREFIX/TARGET_RELATIVE" in
- * REVNUM, obtained using RA_LIB and SESSION.  The item->node_name
- * will be "TARGET_PREFIX/TARGET_RELATIVE", and the value will be a
- * hash mapping 'const char *' property names onto 'svn_string_t *'
- * property values.
+ * If GET_EXPLICIT_PROPS is true, then call RECEIVER for paths at or under
+ * "TARGET_PREFIX/TARGET_RELATIVE@REVNUM" (obtained using RA_SESSION) which
+ * have regular properties.  If GET_TARGET_INHERITED_PROPS is true, then send
+ * the target's inherited properties to the callback.
  *
- * Allocate the new item and its contents in POOL.
- * Do all looping, recursion, and temporary work in SCRATCHPOOL.
+ * The 'path' and keys for 'prop_hash' and 'inherited_prop' arguments to
+ * RECEIVER are all URLs.
+ * 
+ * RESULT_POOL is used to allocated the 'path', 'prop_hash', and
+ * 'inherited_prop' arguments to RECEIVER.  SCRATCH_POOL is used for all
+ * other (temporary) allocations.
  *
  * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE".
  *
  * If the target is a directory, only fetch properties for the files
- * and directories at depth DEPTH.
+ * and directories at depth DEPTH.  DEPTH has not effect on inherited
+ * properties.
  */
 static svn_error_t *
 remote_proplist(const char *target_prefix,
@@ -930,29 +1092,36 @@ remote_proplist(const char *target_prefi
                 svn_node_kind_t kind,
                 svn_revnum_t revnum,
                 svn_ra_session_t *ra_session,
+                svn_boolean_t get_explicit_props,
+                svn_boolean_t get_target_inherited_props,
                 svn_depth_t depth,
-                svn_proplist_receiver_t receiver,
+                svn_proplist_receiver2_t receiver,
                 void *receiver_baton,
-                apr_pool_t *pool,
-                apr_pool_t *scratchpool)
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
 {
   apr_hash_t *dirents;
-  apr_hash_t *prop_hash, *final_hash;
+  apr_hash_t *prop_hash = NULL;
+  apr_hash_t *final_hash = NULL;
   apr_hash_index_t *hi;
   const char *target_full_url =
-    svn_path_url_add_component2(target_prefix, target_relative, scratchpool);
+    svn_path_url_add_component2(target_prefix, target_relative, scratch_pool);
+  apr_array_header_t *inherited_props;
 
+  /* Note that we pass only the SCRATCH_POOL to svn_ra_get[dir*|file*] because
+     we'll be filtering out non-regular properties from PROP_HASH before we
+     return. */
   if (kind == svn_node_dir)
     {
       SVN_ERR(svn_ra_get_dir2(ra_session,
                               (depth > svn_depth_empty) ? &dirents : NULL,
                               NULL, &prop_hash, target_relative, revnum,
-                              SVN_DIRENT_KIND, scratchpool));
+                              SVN_DIRENT_KIND, scratch_pool));
     }
   else if (kind == svn_node_file)
     {
       SVN_ERR(svn_ra_get_file(ra_session, target_relative, revnum,
-                              NULL, NULL, &prop_hash, scratchpool));
+                              NULL, NULL, &prop_hash, scratch_pool));
     }
   else
     {
@@ -961,38 +1130,50 @@ remote_proplist(const char *target_prefi
                                target_full_url);
     }
 
-  /* Filter out non-regular properties, since the RA layer returns all
-     kinds.  Copy regular properties keys/vals from the prop_hash
-     allocated in SCRATCHPOOL to the "final" hash allocated in POOL. */
-  final_hash = apr_hash_make(pool);
-  for (hi = apr_hash_first(scratchpool, prop_hash);
-       hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *name = svn__apr_hash_index_key(hi);
-      apr_ssize_t klen = svn__apr_hash_index_klen(hi);
-      svn_string_t *value = svn__apr_hash_index_val(hi);
-      svn_prop_kind_t prop_kind;
-
-      prop_kind = svn_property_kind2(name);
+  if (get_target_inherited_props)
+    SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
+                                       target_relative, revnum,
+                                       result_pool, scratch_pool));
+  else
+    inherited_props = NULL;
 
-      if (prop_kind == svn_prop_regular_kind)
+  if (get_explicit_props)
+    {
+      /* Filter out non-regular properties, since the RA layer returns all
+         kinds.  Copy regular properties keys/vals from the prop_hash
+         allocated in SCRATCH_POOL to the "final" hash allocated in
+         RESULT_POOL. */
+      final_hash = apr_hash_make(result_pool);
+      for (hi = apr_hash_first(scratch_pool, prop_hash);
+           hi;
+           hi = apr_hash_next(hi))
         {
-          name = apr_pstrdup(pool, name);
-          value = svn_string_dup(value, pool);
-          apr_hash_set(final_hash, name, klen, value);
-        }
+          const char *name = svn__apr_hash_index_key(hi);
+          apr_ssize_t klen = svn__apr_hash_index_klen(hi);
+          svn_string_t *value = svn__apr_hash_index_val(hi);
+          svn_prop_kind_t prop_kind;
+
+          prop_kind = svn_property_kind2(name);
+
+          if (prop_kind == svn_prop_regular_kind)
+            {
+              name = apr_pstrdup(result_pool, name);
+              value = svn_string_dup(value, result_pool);
+              apr_hash_set(final_hash, name, klen, value);
+            }
+        }  
     }
 
-  SVN_ERR(call_receiver(target_full_url, final_hash, receiver, receiver_baton,
-                        pool));
+  SVN_ERR(call_receiver(target_full_url, final_hash, inherited_props,
+                        receiver, receiver_baton, result_pool));
 
   if (depth > svn_depth_empty
+      && get_explicit_props
       && (kind == svn_node_dir) && (apr_hash_count(dirents) > 0))
     {
-      apr_pool_t *subpool = svn_pool_create(scratchpool);
+      apr_pool_t *subpool = svn_pool_create(scratch_pool);
 
-      for (hi = apr_hash_first(scratchpool, dirents);
+      for (hi = apr_hash_first(scratch_pool, dirents);
            hi;
            hi = apr_hash_next(hi))
         {
@@ -1018,10 +1199,12 @@ remote_proplist(const char *target_prefi
                                       this_ent->kind,
                                       revnum,
                                       ra_session,
+                                      TRUE,
+                                      FALSE,
                                       depth_below_here,
                                       receiver,
                                       receiver_baton,
-                                      pool,
+                                      result_pool,
                                       subpool));
             }
         }
@@ -1037,7 +1220,7 @@ remote_proplist(const char *target_prefi
 struct recursive_proplist_receiver_baton
 {
   svn_wc_context_t *wc_ctx;  /* Working copy context. */
-  svn_proplist_receiver_t wrapped_receiver;  /* Proplist receiver to call. */
+  svn_proplist_receiver2_t wrapped_receiver;  /* Proplist receiver to call. */
   void *wrapped_receiver_baton;    /* Baton for the proplist receiver. */
 
   /* Anchor, anchor_abspath pair for converting to relative paths */
@@ -1068,114 +1251,275 @@ recursive_proplist_receiver(void *baton,
     path = local_abspath;
 
   return svn_error_trace(b->wrapped_receiver(b->wrapped_receiver_baton,
-                                             path, props, scratch_pool));
+                                             path, props, NULL,
+                                             scratch_pool));
 }
 
-svn_error_t *
-svn_client_proplist3(const char *path_or_url,
-                     const svn_opt_revision_t *peg_revision,
-                     const svn_opt_revision_t *revision,
-                     svn_depth_t depth,
-                     const apr_array_header_t *changelists,
-                     svn_proplist_receiver_t receiver,
-                     void *receiver_baton,
-                     svn_client_ctx_t *ctx,
-                     apr_pool_t *pool)
+/* Helper for svn_client_proplist4 when retrieving properties and/or
+   inherited properties from the repository.  Except as noted below,
+   all arguments are as per svn_client_proplist4.
+   
+   GET_EXPLICIT_PROPS controls if explicit props are retrieved. */
+static svn_error_t *
+get_remote_props(const char *path_or_url,
+                 const svn_opt_revision_t *peg_revision,
+                 const svn_opt_revision_t *revision,
+                 svn_depth_t depth,
+                 svn_boolean_t get_explicit_props,
+                 svn_boolean_t get_target_inherited_props,
+                 svn_proplist_receiver2_t receiver,
+                 void *receiver_baton,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
 {
-  peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision,
-                                                        path_or_url);
-  revision = svn_cl__rev_default_to_peg(revision, peg_revision);
+  svn_ra_session_t *ra_session;
+  svn_node_kind_t kind;
+  svn_opt_revision_t new_operative_rev;
+  svn_opt_revision_t new_peg_rev;
+  svn_client__pathrev_t *loc;
+
+  /* Peg or operative revisions may be WC specific for
+     PATH_OR_URL's explicit props, but still require us to
+     contact the repository for the inherited properties. */
+  if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind)
+      || SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+    {
+      svn_revnum_t origin_rev;
+      const char *repos_relpath;
+      const char *repos_root_url;
+      const char *repos_uuid;
+      const char *local_abspath;
+      const char *copy_root_abspath;
+      svn_boolean_t is_copy;
 
-  if (depth == svn_depth_unknown)
-    depth = svn_depth_empty;
+      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url,
+                                      scratch_pool));
 
-  if (! svn_path_is_url(path_or_url)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
-      && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind))
-    {
-      svn_boolean_t pristine;
-      svn_node_kind_t kind;
-      apr_hash_t *changelist_hash = NULL;
-      const char *local_abspath;
+      if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+        {
+          SVN_ERR(svn_wc__node_get_origin(&is_copy,
+                                          &origin_rev,
+                                          &repos_relpath,
+                                          &repos_root_url,
+                                          &repos_uuid,
+                                          &copy_root_abspath,
+                                          ctx->wc_ctx,
+                                          local_abspath,
+                                          FALSE, /* scan_deleted */
+                                          result_pool,
+                                          scratch_pool));
+          if (repos_relpath)
+            {
+              path_or_url =
+                svn_path_url_add_component2(repos_root_url,
+                                            repos_relpath,
+                                            scratch_pool);
+              if (SVN_CLIENT__REVKIND_NEEDS_WC(peg_revision->kind))
+                {
+                  svn_revnum_t resolved_peg_rev;
+
+                  SVN_ERR(svn_client__get_revision_number(&resolved_peg_rev,
+                                                          NULL, ctx->wc_ctx,
+                                                          local_abspath, NULL,
+                                                          peg_revision,
+                                                          scratch_pool));
+                  new_peg_rev.kind = svn_opt_revision_number;
+                  new_peg_rev.value.number = resolved_peg_rev;
+                  peg_revision = &new_peg_rev;
+                }
+
+              if (SVN_CLIENT__REVKIND_NEEDS_WC(revision->kind))
+                {
+                  svn_revnum_t resolved_operative_rev;
+
+                  SVN_ERR(svn_client__get_revision_number(
+                    &resolved_operative_rev,
+                    NULL, ctx->wc_ctx,
+                    local_abspath, NULL,
+                    revision,
+                    scratch_pool));
+                  new_operative_rev.kind = svn_opt_revision_number;
+                  new_operative_rev.value.number = resolved_operative_rev;
+                  revision = &new_operative_rev;
+                }
+            }
+          else
+            {
+                  /* PATH_OR_URL doesn't exist in the repository, so there are
+                     obviously not inherited props to be found there. If we
+                     aren't looking for explicit props then we're done. */
+                  if (!get_explicit_props)
+                    return SVN_NO_ERROR;
+            }
+        }
+    }
 
-      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url, pool));
+  /* Get an RA session for this URL. */
+  SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
+                                            path_or_url, NULL,
+                                            peg_revision,
+                                            revision, ctx,
+                                            result_pool));
+
+  SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind,
+                            result_pool));
+
+  SVN_ERR(remote_proplist(loc->url, "", kind, loc->rev, ra_session,
+                          get_explicit_props,
+                          get_target_inherited_props,
+                          depth, receiver, receiver_baton,
+                          result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
 
-      pristine = ((revision->kind == svn_opt_revision_committed)
-                  || (revision->kind == svn_opt_revision_base));
+/* Helper for svn_client_proplist4 when retrieving properties and
+   possibly inherited properties from the WC.  All arguments are as
+   per svn_client_proplist4. */
+static svn_error_t *
+get_local_props(const char *path_or_url,
+                const svn_opt_revision_t *revision,
+                svn_depth_t depth,
+                const apr_array_header_t *changelists,
+                svn_boolean_t get_target_inherited_props,
+                svn_proplist_receiver2_t receiver,
+                void *receiver_baton,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  svn_boolean_t pristine;
+  svn_node_kind_t kind;
+  apr_hash_t *changelist_hash = NULL;
+  const char *local_abspath;
 
-      SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, local_abspath, FALSE,
-                               pool));
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url,
+                                  scratch_pool));
 
-      if (kind == svn_node_unknown || kind == svn_node_none)
-        {
-          /* svn uses SVN_ERR_UNVERSIONED_RESOURCE as warning only
-             for this function. */
-          return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
-                                   _("'%s' is not under version control"),
-                                   svn_dirent_local_style(local_abspath,
-                                                          pool));
-        }
+  pristine = ((revision->kind == svn_opt_revision_committed)
+              || (revision->kind == svn_opt_revision_base));
 
-      if (changelists && changelists->nelts)
-        SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash,
-                                           changelists, pool));
+  SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, local_abspath, FALSE,
+                           scratch_pool));
 
-      /* Fetch, recursively or not. */
-      if (kind == svn_node_dir)
-        {
-          struct recursive_proplist_receiver_baton rb;
+  if (kind == svn_node_unknown || kind == svn_node_none)
+    {
+      /* svn uses SVN_ERR_UNVERSIONED_RESOURCE as warning only
+         for this function. */
+      return svn_error_createf(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
+                               _("'%s' is not under version control"),
+                               svn_dirent_local_style(local_abspath,
+                                                      scratch_pool));
+    }
+
+  if (get_target_inherited_props)
+    {
+      apr_array_header_t *iprops;
 
-          rb.wc_ctx = ctx->wc_ctx;
-          rb.wrapped_receiver = receiver;
-          rb.wrapped_receiver_baton = receiver_baton;
+      SVN_ERR(svn_wc__get_iprops(&iprops, ctx->wc_ctx, local_abspath,
+                                 NULL, scratch_pool, scratch_pool));
+      SVN_ERR(call_receiver(path_or_url, NULL, iprops, receiver,
+                            receiver_baton, scratch_pool));
+    }
 
-          if (strcmp(path_or_url, local_abspath) != 0)
-            {
-              rb.anchor = path_or_url;
-              rb.anchor_abspath = local_abspath;
-            }
-          else
-            {
-              rb.anchor = NULL;
-              rb.anchor_abspath = NULL;
-            }
+  if (changelists && changelists->nelts)
+    SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash,
+                                       changelists, scratch_pool));
 
-          SVN_ERR(svn_wc__prop_list_recursive(ctx->wc_ctx, local_abspath, NULL,
-                                              depth, pristine, changelists,
-                                              recursive_proplist_receiver, &rb,
-                                              ctx->cancel_func,
-                                              ctx->cancel_baton, pool));
+  /* Fetch, recursively or not. */
+  if (kind == svn_node_dir)
+    {
+      struct recursive_proplist_receiver_baton rb;
+
+      rb.wc_ctx = ctx->wc_ctx;
+      rb.wrapped_receiver = receiver;
+      rb.wrapped_receiver_baton = receiver_baton;
+
+      if (strcmp(path_or_url, local_abspath) != 0)
+        {
+          rb.anchor = path_or_url;
+          rb.anchor_abspath = local_abspath;
         }
-      else if (svn_wc__changelist_match(ctx->wc_ctx, local_abspath,
-                                        changelist_hash, pool))
+      else
         {
-          apr_hash_t *hash;
+          rb.anchor = NULL;
+          rb.anchor_abspath = NULL;
+        }
 
-          SVN_ERR(pristine_or_working_props(&hash, ctx->wc_ctx, local_abspath,
-                                            pristine, pool, pool));
-          SVN_ERR(call_receiver(path_or_url, hash,
-                                receiver, receiver_baton, pool));
+      SVN_ERR(svn_wc__prop_list_recursive(ctx->wc_ctx, local_abspath, NULL,
+                                          depth, pristine, changelists,
+                                          recursive_proplist_receiver, &rb,
+                                          ctx->cancel_func,
+                                          ctx->cancel_baton, result_pool));
+    }
+  else if (svn_wc__changelist_match(ctx->wc_ctx, local_abspath,
+                                    changelist_hash, scratch_pool))
+    {
+      apr_hash_t *hash;
+
+      SVN_ERR(pristine_or_working_props(&hash, ctx->wc_ctx, local_abspath,
+                                        pristine, result_pool,
+                                        scratch_pool));
+      SVN_ERR(call_receiver(path_or_url, hash, NULL,
+                            receiver, receiver_baton, scratch_pool));
 
-        }
     }
-  else /* remote target */
-    {
-      svn_ra_session_t *ra_session;
-      svn_node_kind_t kind;
-      apr_pool_t *subpool = svn_pool_create(pool);
-      svn_client__pathrev_t *loc;
+  return SVN_NO_ERROR;
+}
 
-      /* Get an RA session for this URL. */
-      SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
-                                                path_or_url, NULL,
-                                                peg_revision,
-                                                revision, ctx, pool));
+svn_error_t *
+svn_client_proplist4(const char *path_or_url,
+                     const svn_opt_revision_t *peg_revision,
+                     const svn_opt_revision_t *revision,
+                     svn_depth_t depth,
+                     const apr_array_header_t *changelists,
+                     svn_boolean_t get_target_inherited_props,
+                     svn_proplist_receiver2_t receiver,
+                     void *receiver_baton,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  svn_boolean_t local_explicit_props;
+  svn_boolean_t local_iprops;
 
-      SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, pool));
+  peg_revision = svn_cl__rev_default_to_head_or_working(peg_revision,
+                                                        path_or_url);
+  revision = svn_cl__rev_default_to_peg(revision, peg_revision);
 
-      SVN_ERR(remote_proplist(loc->url, "", kind, loc->rev, ra_session, depth,
-                              receiver, receiver_baton, pool, subpool));
-      svn_pool_destroy(subpool);
+  if (depth == svn_depth_unknown)
+    depth = svn_depth_empty;
+
+  /* Are explicit props available locally? */
+  local_explicit_props =
+    (! svn_path_is_url(path_or_url)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(peg_revision->kind)
+     && SVN_CLIENT__REVKIND_IS_LOCAL_TO_WC(revision->kind));
+
+  /* If we want iprops are they avaiable locally? */
+  local_iprops =
+    (get_target_inherited_props /* We want iprops */
+     && local_explicit_props /* No local explicit props means no local iprops. */
+     && (peg_revision->kind == svn_opt_revision_working
+         || peg_revision->kind == svn_opt_revision_unspecified )
+     && (revision->kind == svn_opt_revision_working
+         || revision->kind == svn_opt_revision_unspecified ));
+
+  if ((get_target_inherited_props && !local_iprops)
+      || !local_explicit_props)
+    {
+      SVN_ERR(get_remote_props(path_or_url, peg_revision, revision, depth,
+                               !local_explicit_props,
+                               (get_target_inherited_props && !local_iprops),
+                               receiver, receiver_baton, ctx, result_pool,
+                               scratch_pool));
+    }
+
+  if (local_explicit_props)
+    {
+      SVN_ERR(get_local_props(path_or_url, revision, depth, changelists,
+                              local_iprops, receiver, receiver_baton, ctx,
+                              result_pool, scratch_pool));
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ev2-export/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/ra.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/ra.c Sun Oct 21 02:00:31 2012
@@ -581,6 +581,7 @@ svn_client__repos_location_segments(apr_
 {
   struct gls_receiver_baton_t gls_receiver_baton;
   const char *old_session_url;
+  svn_error_t *err;
 
   *segments = apr_array_make(pool, 8, sizeof(svn_location_segment_t *));
   gls_receiver_baton.segments = *segments;
@@ -588,11 +589,12 @@ svn_client__repos_location_segments(apr_
   gls_receiver_baton.pool = pool;
   SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
                                             url, pool));
-  SVN_ERR(svn_ra_get_location_segments(ra_session, "", peg_revision,
-                                       start_revision, end_revision,
-                                       gls_receiver, &gls_receiver_baton,
-                                       pool));
-  SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
+  err = svn_ra_get_location_segments(ra_session, "", peg_revision,
+                                     start_revision, end_revision,
+                                     gls_receiver, &gls_receiver_baton,
+                                     pool);
+  SVN_ERR(svn_error_compose_create(
+            err, svn_ra_reparent(ra_session, old_session_url, pool)));
   qsort((*segments)->elts, (*segments)->nelts,
         (*segments)->elt_size, compare_segments);
   return SVN_NO_ERROR;
@@ -689,14 +691,16 @@ svn_client__repos_location(svn_client__p
 {
   const char *old_session_url;
   const char *op_url;
+  svn_error_t *err;
 
   SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
                                             peg_loc->url, scratch_pool));
-  SVN_ERR(repos_locations(&op_url, NULL, ra_session,
-                          peg_loc->url, peg_loc->rev,
-                          op_revnum, SVN_INVALID_REVNUM,
-                          result_pool, scratch_pool));
-  SVN_ERR(svn_ra_reparent(ra_session, old_session_url, scratch_pool));
+  err = repos_locations(&op_url, NULL, ra_session,
+                        peg_loc->url, peg_loc->rev,
+                        op_revnum, SVN_INVALID_REVNUM,
+                        result_pool, scratch_pool);
+  SVN_ERR(svn_error_compose_create(
+            err, svn_ra_reparent(ra_session, old_session_url, scratch_pool)));
 
   *op_loc_p = svn_client__pathrev_create(peg_loc->repos_root_url,
                                          peg_loc->repos_uuid,
@@ -896,8 +900,8 @@ svn_client__get_youngest_common_ancestor
     {
       const char *path = svn__apr_hash_index_key(hi);
       apr_ssize_t path_len = svn__apr_hash_index_klen(hi);
-      apr_array_header_t *ranges1 = svn__apr_hash_index_val(hi);
-      apr_array_header_t *ranges2, *common;
+      svn_rangelist_t *ranges1 = svn__apr_hash_index_val(hi);
+      svn_rangelist_t *ranges2, *common;
 
       ranges2 = apr_hash_get(history2, path, path_len);
       if (ranges2)

Modified: subversion/branches/ev2-export/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/relocate.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/relocate.c Sun Oct 21 02:00:31 2012
@@ -139,7 +139,6 @@ relocate_externals(const char *local_abs
                    apr_array_header_t *ext_desc,
                    const char *old_parent_repos_root_url,
                    const char *new_parent_repos_root_url,
-                   svn_boolean_t ignore_externals,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *scratch_pool)
 {
@@ -199,7 +198,7 @@ relocate_externals(const char *local_abs
         SVN_ERR(svn_client_relocate2(target_abspath,
                                      old_parent_repos_root_url,
                                      new_parent_repos_root_url,
-                                     ignore_externals, ctx, iterpool));
+                                     FALSE, ctx, iterpool));
     }
 
   svn_pool_destroy(iterpool);
@@ -281,8 +280,7 @@ svn_client_relocate2(const char *wcroot_
                                                   iterpool));
       if (ext_desc->nelts)
         SVN_ERR(relocate_externals(this_abspath, ext_desc, old_repos_root_url,
-                                   new_repos_root_url, ignore_externals, ctx,
-                                   iterpool));
+                                   new_repos_root_url, ctx, iterpool));
     }
 
   svn_pool_destroy(iterpool);

Modified: subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/repos_diff.c Sun Oct 21 02:00:31 2012
@@ -1151,6 +1151,13 @@ close_directory(void *dir_baton,
           const char *deleted_path = svn__apr_hash_index_key(hi);
           deleted_path_notify_t *dpn = svn__apr_hash_index_val(hi);
 
+          /* Ignore paths which are not children of b->path.  (There
+             should be none due to editor ordering constraints, but
+             ra_serf drops the ball here -- see issue #3802 for
+             details.) */
+          if (! svn_relpath_skip_ancestor(b->path, deleted_path))
+            continue;
+
           notify = svn_wc_create_notify(deleted_path, dpn->action, pool);
           notify->kind = dpn->kind;
           notify->content_state = notify->prop_state = dpn->state;

Modified: subversion/branches/ev2-export/subversion/libsvn_client/revisions.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/revisions.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/revisions.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/revisions.c Sun Oct 21 02:00:31 2012
@@ -96,7 +96,7 @@ svn_client__get_revision_number(svn_revn
                                            scratch_pool, scratch_pool);
 
         /* Return the same error as older code did (before and at r935091).
-           At least svn_client_proplist3 promises SVN_ERR_ENTRY_NOT_FOUND. */
+           At least svn_client_proplist4 promises SVN_ERR_ENTRY_NOT_FOUND. */
         if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
           {
             svn_error_clear(err);

Modified: subversion/branches/ev2-export/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/switch.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/switch.c Sun Oct 21 02:00:31 2012
@@ -79,6 +79,8 @@ switch_internal(svn_revnum_t *result_rev
   svn_revnum_t revnum;
   svn_error_t *err = SVN_NO_ERROR;
   const char *diff3_cmd;
+  apr_hash_t *wcroot_iprops;
+  apr_array_header_t *inherited_props;
   svn_boolean_t use_commit_times;
   svn_boolean_t sleep_here = FALSE;
   svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
@@ -218,6 +220,62 @@ switch_internal(svn_revnum_t *result_rev
                                  svn_dirent_dirname(local_abspath, pool));
     }
 
+  wcroot_iprops = apr_hash_make(pool);
+  
+  /* Will the base of LOCAL_ABSPATH require an iprop cache post-switch?
+     If we are switching LOCAL_ABSPATH to the root of the repository then
+     we don't need to cache inherited properties.  In all other cases we
+     *might* need to cache iprops. */
+  if (strcmp(switch_loc->repos_root_url, switch_loc->url) != 0)
+    {
+      svn_boolean_t wc_root;
+      svn_boolean_t needs_iprop_cache = TRUE;
+
+      SVN_ERR(svn_wc__strictly_is_wc_root(&wc_root,
+                                          ctx->wc_ctx,
+                                          local_abspath,
+                                          pool));
+
+      /* Switching the WC root to anything but the repos root means
+         we need an iprop cache. */ 
+      if (!wc_root)
+        {
+          /* We know we are switching a subtree to something other than the
+             repos root, but if we are unswitching that subtree we don't
+             need an iprops cache. */
+          const char *target_parent_url;
+          const char *unswitched_url;
+
+          /* Calculate the URL LOCAL_ABSPATH would have if it was unswitched
+             relative to its parent. */
+          SVN_ERR(svn_wc__node_get_url(&target_parent_url, ctx->wc_ctx,
+                                       svn_dirent_dirname(local_abspath,
+                                                          pool),
+                                       pool, pool));
+          unswitched_url = svn_path_url_add_component2(
+            target_parent_url,
+            svn_dirent_basename(local_abspath, pool),
+            pool);
+
+          /* If LOCAL_ABSPATH will be unswitched relative to its parent, then
+             it doesn't need an iprop cache.  Note: It doesn't matter if
+             LOCAL_ABSPATH is withing a switched subtree, only if it's the
+             *root* of a switched subtree.*/
+          if (strcmp(unswitched_url, switch_loc->url) == 0)
+            needs_iprop_cache = FALSE;
+      }
+
+
+      if (needs_iprop_cache)
+        {
+          SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
+                                             "", switch_loc->rev, pool,
+                                             pool));
+          apr_hash_set(wcroot_iprops, local_abspath, APR_HASH_KEY_STRING,
+                       inherited_props);
+        }
+    }
+
   SVN_ERR(svn_ra_reparent(ra_session, anchor_url, pool));
 
   /* Fetch the switch (update) editor.  If REVISION is invalid, that's
@@ -226,13 +284,13 @@ switch_internal(svn_revnum_t *result_rev
                                 SVN_RA_CAPABILITY_DEPTH, pool));
 
   dfb.ra_session = ra_session;
-  SVN_ERR(svn_ra_get_session_url(ra_session, &dfb.anchor_url, pool));
+  dfb.anchor_url = anchor_url;
   dfb.target_revision = switch_loc->rev;
 
   SVN_ERR(svn_wc__get_switch_editor(&switch_editor, &switch_edit_baton,
                                     &revnum, ctx->wc_ctx, anchor_abspath,
-                                    target, switch_loc->url, use_commit_times,
-                                    depth,
+                                    target, switch_loc->url, wcroot_iprops,
+                                    use_commit_times, depth,
                                     depth_is_sticky, allow_unver_obstructions,
                                     server_supports_depth,
                                     diff3_cmd, preserved_exts,

Modified: subversion/branches/ev2-export/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/update.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/update.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/update.c Sun Oct 21 02:00:31 2012
@@ -201,6 +201,8 @@ update_internal(svn_revnum_t *result_rev
   svn_boolean_t *use_sleep = timestamp_sleep ? timestamp_sleep : &sleep_here;
   svn_boolean_t clean_checkout = FALSE;
   const char *diff3_cmd;
+  apr_hash_t *wcroot_iprops;
+  svn_opt_revision_t opt_rev;
   svn_ra_session_t *ra_session;
   const char *preserved_exts_str;
   apr_array_header_t *preserved_exts;
@@ -211,6 +213,9 @@ update_internal(svn_revnum_t *result_rev
                                                  SVN_CONFIG_CATEGORY_CONFIG,
                                                  APR_HASH_KEY_STRING) : NULL;
 
+  if (result_rev)
+    *result_rev = SVN_INVALID_REVNUM;
+
   /* An unknown depth can't be sticky. */
   if (depth == svn_depth_unknown)
     depth_is_sticky = FALSE;
@@ -350,10 +355,18 @@ update_internal(svn_revnum_t *result_rev
       anchor_loc->url = corrected_url;
     }
 
+  /* Resolve unspecified REVISION now, because we need to retrieve the
+     correct inherited props prior to the editor drive and we need to
+     use the same value of HEAD for both. */
+  opt_rev.kind = revision->kind;
+  opt_rev.value = revision->value;
+  if (opt_rev.kind == svn_opt_revision_unspecified)
+    opt_rev.kind = svn_opt_revision_head;
+
   /* ### todo: shouldn't svn_client__get_revision_number be able
      to take a URL as easily as a local path?  */
   SVN_ERR(svn_client__get_revision_number(&revnum, NULL, ctx->wc_ctx,
-                                          local_abspath, ra_session, revision,
+                                          local_abspath, ra_session, &opt_rev,
                                           pool));
 
   SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
@@ -363,12 +376,31 @@ update_internal(svn_revnum_t *result_rev
   dfb.target_revision = revnum;
   dfb.anchor_url = anchor_loc->url;
 
+  err = svn_client__get_inheritable_props(&wcroot_iprops, local_abspath,
+                                          revnum, depth, ra_session, ctx,
+                                          pool, pool);
+
+  /* We might be trying to update to a non-existant path-rev. */
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          err = NULL;
+        }
+      else
+        {
+          return svn_error_trace(err);
+        }
+    }
+
   /* Fetch the update editor.  If REVISION is invalid, that's okay;
      the RA driver will call editor->set_target_revision later on. */
   SVN_ERR(svn_wc__get_update_editor(&update_editor, &update_edit_baton,
                                     &revnum, ctx->wc_ctx, anchor_abspath,
-                                    target, use_commit_times, depth,
-                                    depth_is_sticky, allow_unver_obstructions,
+                                    target, wcroot_iprops, use_commit_times,
+                                    depth, depth_is_sticky,
+                                    allow_unver_obstructions,
                                     adds_as_modification,
                                     server_supports_depth,
                                     clean_checkout,

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/compat.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/compat.c Sun Oct 21 02:00:31 2012
@@ -1637,9 +1637,12 @@ apply_change(void **dir_baton,
                                                        change->copyfrom_path,
                                                        scratch_pool);
           else
-            /* ### prefix with "/" ?  */
             copyfrom_url = change->copyfrom_path;
 
+          /* Make this an FS path by prepending "/" */
+          if (copyfrom_url[0] != '/')
+            copyfrom_url = apr_pstrcat(scratch_pool, "/", copyfrom_url, NULL);
+
           copyfrom_rev = change->copyfrom_rev;
         }
 

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/editor.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/editor.c Sun Oct 21 02:00:31 2012
@@ -77,23 +77,23 @@ struct svn_editor_t
 #define END_CALLBACK(editor) ((editor)->within_callback = FALSE)
 
 /* Marker to indicate no further changes are allowed on this node.  */
-static const int marker_done;
+static const int marker_done = 0;
 #define MARKER_DONE (&marker_done)
 
 /* Marker indicating that add_* may be called for this path, or that it
    can be the destination of a copy or move. For copy/move, the path
    will switch to MARKER_ALLOW_ALTER, to enable further tweaks.  */
-static const int marker_allow_add;
+static const int marker_allow_add = 0;
 #define MARKER_ALLOW_ADD (&marker_allow_add)
 
 /* Marker indicating that alter_* may be called for this path.  */
-static const int marker_allow_alter;
+static const int marker_allow_alter = 0;
 #define MARKER_ALLOW_ALTER (&marker_allow_alter)
 
 /* Just like MARKER_DONE, but also indicates that the node was created
    via add_directory(). This allows us to verify that the CHILDREN param
    was comprehensive.  */
-static const int marker_added_dir;
+static const int marker_added_dir = 0;
 #define MARKER_ADDED_DIR (&marker_added_dir)
 
 #define MARK_FINISHED(editor) ((editor)->finished = TRUE)

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/svndiff.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/svndiff.c Sun Oct 21 02:00:31 2012
@@ -186,18 +186,86 @@ zlib_encode(const char *data,
 }
 
 static svn_error_t *
+send_simple_insertion_window(svn_txdelta_window_t *window,
+                             struct encoder_baton *eb)
+{
+  unsigned char headers[4 + 5 * MAX_ENCODED_INT_LEN + MAX_INSTRUCTION_LEN];
+  unsigned char ibuf[MAX_INSTRUCTION_LEN];
+  unsigned char *header_current;
+  apr_size_t header_len;
+  apr_size_t ip_len, i;
+  apr_size_t len = window->new_data->len;
+
+  /* there is only one target copy op. It must span the whole window */
+  assert(window->ops[0].action_code == svn_txdelta_new);
+  assert(window->ops[0].length == window->tview_len);
+  assert(window->ops[0].offset == 0);
+
+  /* write stream header if necessary */
+  if (eb->header_done == FALSE)
+    {
+      eb->header_done = TRUE;
+      headers[0] = 'S';
+      headers[1] = 'V';
+      headers[2] = 'N';
+      headers[3] = (unsigned char)eb->version;
+      header_current = headers + 4;
+    }
+  else
+    {
+      header_current = headers;
+    }
+    
+  /* Encode the action code and length.  */
+  if (window->tview_len >> 6 == 0)
+    {
+      ibuf[0] = (unsigned char)(window->tview_len + (0x2 << 6));
+      ip_len = 1;
+    }
+  else
+    {
+      ibuf[0] = (0x2 << 6);
+      ip_len = encode_int(ibuf + 1, window->tview_len) - ibuf;
+    }
+
+  /* encode the window header.  */
+  header_current[0] = 0;  /* source offset == 0 */
+  header_current[1] = 0;  /* source length == 0 */
+  header_current = encode_int(header_current + 2, window->tview_len);
+  header_current[0] = (unsigned char)ip_len;  /* 1 instruction */
+  header_current = encode_int(&header_current[1], len);
+
+  /* append instructions (1 to a handful of bytes) */
+  for (i = 0; i < ip_len; ++i)
+    header_current[i] = ibuf[i];
+
+  header_len = header_current - headers + ip_len;
+    
+  /* Write out the window.  */
+  SVN_ERR(svn_stream_write(eb->output, (const char *)headers, &header_len));
+  if (len)
+    SVN_ERR(svn_stream_write(eb->output, window->new_data->data, &len));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 window_handler(svn_txdelta_window_t *window, void *baton)
 {
   struct encoder_baton *eb = baton;
-  apr_pool_t *pool = svn_pool_create(eb->pool);
-  svn_stringbuf_t *instructions = svn_stringbuf_create_empty(pool);
-  svn_stringbuf_t *i1 = svn_stringbuf_create_empty(pool);
-  svn_stringbuf_t *header = svn_stringbuf_create_empty(pool);
+  apr_pool_t *pool;
+  svn_stringbuf_t *instructions;
+  svn_stringbuf_t *i1;
+  svn_stringbuf_t *header;
   const svn_string_t *newdata;
   unsigned char ibuf[MAX_INSTRUCTION_LEN], *ip;
   const svn_txdelta_op_t *op;
   apr_size_t len;
 
+  /* use specialized code if there is no source */
+  if (window && !window->src_ops && window->num_ops == 1 && !eb->version)
+    return svn_error_trace(send_simple_insertion_window(window, eb));
+
   /* Make sure we write the header.  */
   if (eb->header_done == FALSE)
     {
@@ -229,6 +297,12 @@ window_handler(svn_txdelta_window_t *win
       return svn_stream_close(output);
     }
 
+  /* create the necessary data buffers */
+  pool = svn_pool_create(eb->pool);
+  instructions = svn_stringbuf_create_empty(pool);
+  i1 = svn_stringbuf_create_empty(pool);
+  header = svn_stringbuf_create_empty(pool);
+
   /* Encode the instructions.  */
   for (op = window->ops; op < window->ops + window->num_ops; op++)
     {
@@ -450,7 +524,7 @@ decode_size(apr_size_t *val,
  */
 static svn_error_t *
 zlib_decode(const unsigned char *in, apr_size_t inLen, svn_stringbuf_t *out,
-            apr_size_t limit, svn_boolean_t copyless_allowed)
+            apr_size_t limit)
 {
   apr_size_t len;
   const unsigned char *oldplace = in;
@@ -469,22 +543,10 @@ zlib_decode(const unsigned char *in, apr
   inLen -= (in - oldplace);
   if (inLen == len)
     {
-      if (copyless_allowed)
-        {
-          /* "in" is no longer used but the memory remains allocated for
-           * at least as long as "out" will be used by the caller.
-           */
-          out->data = (char *)in;
-          out->len = len;
-          out->blocksize = len; /* sic! */
-        }
-      else
-        {
-          svn_stringbuf_ensure(out, len);
-          memcpy(out->data, in, len);
-          out->data[len] = 0;
-          out->len = len;
-        }
+      svn_stringbuf_ensure(out, len);
+      memcpy(out->data, in, len);
+      out->data[len] = 0;
+      out->len = len;
 
       return SVN_NO_ERROR;
     }
@@ -661,9 +723,9 @@ decode_window(svn_txdelta_window_t *wind
       /* these may in fact simply return references to insend */
 
       SVN_ERR(zlib_decode(insend, newlen, ndout,
-                          SVN_DELTA_WINDOW_SIZE, TRUE));
+                          SVN_DELTA_WINDOW_SIZE));
       SVN_ERR(zlib_decode(data, insend - data, instout,
-                          MAX_INSTRUCTION_SECTION_LEN, TRUE));
+                          MAX_INSTRUCTION_SECTION_LEN));
 
       newlen = ndout->len;
       data = (unsigned char *)instout->data;
@@ -1008,8 +1070,7 @@ svn__compress(svn_string_t *in,
               svn_stringbuf_t *out,
               int compression_level)
 {
-  return zlib_encode(in->data, in->len, out,
-                     compression_level);
+  return zlib_encode(in->data, in->len, out, compression_level);
 }
 
 svn_error_t *
@@ -1017,6 +1078,5 @@ svn__decompress(svn_string_t *in,
                 svn_stringbuf_t *out,
                 apr_size_t limit)
 {
-  return zlib_decode((const unsigned char*)in->data, in->len, out, limit,
-                     FALSE);
+  return zlib_decode((const unsigned char*)in->data, in->len, out, limit);
 }

Modified: subversion/branches/ev2-export/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_delta/text_delta.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_delta/text_delta.c Sun Oct 21 02:00:31 2012
@@ -998,3 +998,42 @@ svn_error_t *svn_txdelta_send_txstream(s
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_txdelta_send_contents(const unsigned char *contents,
+                          apr_size_t len,
+                          svn_txdelta_window_handler_t handler,
+                          void *handler_baton,
+                          apr_pool_t *pool)
+{
+  svn_string_t new_data;
+  svn_txdelta_op_t op = { svn_txdelta_new, 0, 0 };
+  svn_txdelta_window_t window = { 0, 0, 0, 1, 0 };
+  window.ops = &op;
+  window.new_data = &new_data;
+
+  /* send CONTENT as a series of max-sized windows */
+  while (len > 0)
+    {
+      /* stuff next chunk into the window */
+      window.tview_len = len < SVN_DELTA_WINDOW_SIZE
+                       ? len
+                       : SVN_DELTA_WINDOW_SIZE;
+      op.length = window.tview_len;
+      new_data.len = window.tview_len;
+      new_data.data = (const char*)contents;
+
+      /* update remaining */
+      contents += window.tview_len;
+      len -= window.tview_len;
+
+      /* shove it at the handler */
+      SVN_ERR((*handler)(&window, handler_baton));
+    }
+
+  /* indicate end of stream */
+  SVN_ERR((*handler)(NULL, handler_baton));
+
+  return SVN_NO_ERROR;
+}
+

Modified: subversion/branches/ev2-export/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_diff/diff_file.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_diff/diff_file.c Sun Oct 21 02:00:31 2012
@@ -340,30 +340,17 @@ is_one_at_eof(struct file_info file[], a
 /* Quickly determine whether there is a eol char in CHUNK.
  * (mainly copy-n-paste from eol.c#svn_eol__find_eol_start).
  */
-#if SVN_UNALIGNED_ACCESS_IS_OK
-#if APR_SIZEOF_VOIDP == 8
-#  define LOWER_7BITS_SET 0x7f7f7f7f7f7f7f7f
-#  define BIT_7_SET       0x8080808080808080
-#  define R_MASK          0x0a0a0a0a0a0a0a0a
-#  define N_MASK          0x0d0d0d0d0d0d0d0d
-#else
-#  define LOWER_7BITS_SET 0x7f7f7f7f
-#  define BIT_7_SET       0x80808080
-#  define R_MASK          0x0a0a0a0a
-#  define N_MASK          0x0d0d0d0d
-#endif
-#endif
 
 #if SVN_UNALIGNED_ACCESS_IS_OK
 static svn_boolean_t contains_eol(apr_uintptr_t chunk)
 {
-  apr_uintptr_t r_test = chunk ^ R_MASK;
-  apr_uintptr_t n_test = chunk ^ N_MASK;
+  apr_uintptr_t r_test = chunk ^ SVN__R_MASK;
+  apr_uintptr_t n_test = chunk ^ SVN__N_MASK;
 
-  r_test |= (r_test & LOWER_7BITS_SET) + LOWER_7BITS_SET;
-  n_test |= (n_test & LOWER_7BITS_SET) + LOWER_7BITS_SET;
+  r_test |= (r_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
+  n_test |= (n_test & SVN__LOWER_7BITS_SET) + SVN__LOWER_7BITS_SET;
 
-  return (r_test & n_test & BIT_7_SET) != BIT_7_SET;
+  return (r_test & n_test & SVN__BIT_7_SET) != SVN__BIT_7_SET;
 }
 #endif
 

Modified: subversion/branches/ev2-export/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_diff/parse-diff.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_diff/parse-diff.c Sun Oct 21 02:00:31 2012
@@ -595,7 +595,6 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                     original_end = hunk_text_end;
                   if (modified_end == 0)
                     modified_end = hunk_text_end;
-                  break;
                 }
 
               SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &pos, iterpool));
@@ -1284,8 +1283,7 @@ svn_diff_parse_next_patch(svn_patch_t **
       /* Run the state machine. */
       for (i = 0; i < (sizeof(transitions) / sizeof(transitions[0])); i++)
         {
-          if (line->len > strlen(transitions[i].expected_input)
-              && starts_with(line->data, transitions[i].expected_input)
+          if (starts_with(line->data, transitions[i].expected_input)
               && state == transitions[i].required_state)
             {
               SVN_ERR(transitions[i].fn(&state, line->data, *patch,
@@ -1302,19 +1300,24 @@ svn_diff_parse_next_patch(svn_patch_t **
         }
       else if (state == state_git_tree_seen && line_after_tree_header_read)
         {
-          /* We have a valid diff header for a patch with only tree changes.
-           * Rewind to the start of the line just read, so subsequent calls
-           * to this function don't end up skipping the line -- it may
-           * contain a patch. */
-          SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &last_line,
-                                   scratch_pool));
-          break;
+          /* git patches can contain an index line after the file mode line */
+          if (!starts_with(line->data, "index "))
+          {
+            /* We have a valid diff header for a patch with only tree changes.
+             * Rewind to the start of the line just read, so subsequent calls
+             * to this function don't end up skipping the line -- it may
+             * contain a patch. */
+            SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &last_line,
+                    scratch_pool));
+            break;
+          }
         }
       else if (state == state_git_tree_seen)
         {
           line_after_tree_header_read = TRUE;
         }
-      else if (! valid_header_line && state != state_start)
+      else if (! valid_header_line && state != state_start
+               && !starts_with(line->data, "index "))
         {
           /* We've encountered an invalid diff header.
            *

Modified: subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c?rev=1400556&r1=1400555&r2=1400556&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_fs/fs-loader.c Sun Oct 21 02:00:31 2012
@@ -28,6 +28,7 @@
 #include <apr_md5.h>
 #include <apr_thread_mutex.h>
 #include <apr_uuid.h>
+#include <apr_strings.h>
 
 #include "svn_ctype.h"
 #include "svn_types.h"
@@ -65,27 +66,37 @@ svn_mutex__t *common_pool_lock;
 
 /* --- Utility functions for the loader --- */
 
-static const struct fs_type_defn {
+struct fs_type_defn {
   const char *fs_type;
   const char *fsap_name;
   fs_init_func_t initfunc;
-} fs_modules[] = {
+  struct fs_type_defn *next;
+};
+
+static struct fs_type_defn base_defn =
   {
     SVN_FS_TYPE_BDB, "base",
 #ifdef SVN_LIBSVN_FS_LINKS_FS_BASE
-    svn_fs_base__init
+    svn_fs_base__init,
+#else
+    NULL,
 #endif
-  },
+    NULL
+  };
 
+static struct fs_type_defn fsfs_defn =
   {
     SVN_FS_TYPE_FSFS, "fs",
 #ifdef SVN_LIBSVN_FS_LINKS_FS_FS
-    svn_fs_fs__init
+    svn_fs_fs__init,
+#else
+    NULL,
 #endif
-  },
+    &base_defn
+  };
+
+static struct fs_type_defn *fs_modules = &fsfs_defn;
 
-  { NULL }
-};
 
 static svn_error_t *
 load_module(fs_init_func_t *initfunc, const char *name, apr_pool_t *pool)
@@ -99,6 +110,15 @@ load_module(fs_init_func_t *initfunc, co
     const char *libname;
     const char *funcname;
     apr_status_t status;
+    const char *p;
+
+    /* Demand a simple alphanumeric name so that the generated DSO
+       name is sensible. */
+    for (p = name; *p; ++p)
+      if (!svn_ctype_isalnum(*p))
+        return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
+                                 _("Invalid name for FS type '%s'"),
+                                 name);
 
     libname = apr_psprintf(pool, "libsvn_fs_%s-%d.so.0",
                            name, SVN_VER_MAJOR);
@@ -173,21 +193,77 @@ get_library_vtable_direct(fs_library_vta
   return SVN_NO_ERROR;
 }
 
+#if defined(SVN_USE_DSO) && APR_HAS_DSO
+/* Return *FST for the third party FS_TYPE */
+static svn_error_t *
+get_or_allocate_third(struct fs_type_defn **fst,
+                      const char *fs_type)
+{
+  while (*fst)
+    {
+      if (strcmp(fs_type, (*fst)->fs_type) == 0)
+        return SVN_NO_ERROR;
+      fst = &(*fst)->next;
+    }
+
+  *fst = apr_palloc(common_pool, sizeof(struct fs_type_defn));
+  (*fst)->fs_type = apr_pstrdup(common_pool, fs_type);
+  (*fst)->fsap_name = (*fst)->fs_type;
+  (*fst)->initfunc = NULL;
+  (*fst)->next = NULL;
+
+  return SVN_NO_ERROR;
+}
+#endif
+
 /* Fetch a library vtable by FS type. */
 static svn_error_t *
 get_library_vtable(fs_library_vtable_t **vtable, const char *fs_type,
                    apr_pool_t *pool)
 {
-  const struct fs_type_defn *fst;
+  struct fs_type_defn **fst = &fs_modules;
+  svn_boolean_t known = FALSE;
 
-  for (fst = fs_modules; fst->fs_type; fst++)
+  /* There are two FS module definitions known at compile time.  We
+     want to check these without any locking overhead even when
+     dynamic third party modules are enabled.  The third party modules
+     cannot be checked until the lock is held.  */
+  if (strcmp(fs_type, (*fst)->fs_type) == 0)
+    known = TRUE;
+  else
     {
-      if (strcmp(fs_type, fst->fs_type) == 0)
-        return get_library_vtable_direct(vtable, fst, pool);
+      fst = &(*fst)->next;
+      if (strcmp(fs_type, (*fst)->fs_type) == 0)
+        known = TRUE;
     }
 
-  return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
-                           _("Unknown FS type '%s'"), fs_type);
+#if defined(SVN_USE_DSO) && APR_HAS_DSO
+  /* Third party FS modules that are unknown at compile time.
+     
+     A third party FS is identified by the file fs-type containing a
+     third party name, say "foo".  The loader will load the DSO with
+     the name "libsvn_fs_foo" and use the entry point with the name
+     "svn_fs_foo__init".
+
+     Note: the BDB and FSFS modules don't follow this naming scheme
+     and this allows them to be used to test the third party loader.
+     Change the content of fs-type to "base" in a BDB filesystem or to
+     "fs" in an FSFS filesystem and they will be loaded as third party
+     modules. */
+  if (!known)
+    {
+      fst = &(*fst)->next;
+      if (!common_pool)  /* Best-effort init, see get_library_vtable_direct. */
+        SVN_ERR(svn_fs_initialize(NULL));
+      SVN_MUTEX__WITH_LOCK(common_pool_lock,
+                           get_or_allocate_third(fst, fs_type));
+      known = TRUE;
+    }
+#endif
+  if (!known)
+    return svn_error_createf(SVN_ERR_FS_UNKNOWN_FS_TYPE, NULL,
+                             _("Unknown FS type '%s'"), fs_type);
+  return get_library_vtable_direct(vtable, *fst, pool);
 }
 
 svn_error_t *
@@ -525,7 +601,8 @@ svn_fs_pack(const char *path,
 
   SVN_MUTEX__WITH_LOCK(common_pool_lock,
                        vtable->pack_fs(fs, path, notify_func, notify_baton,
-                                       cancel_func, cancel_baton, pool));
+                                       cancel_func, cancel_baton, pool,
+                                       common_pool));
   return SVN_NO_ERROR;
 }
 
@@ -547,6 +624,17 @@ svn_fs_recover(const char *path,
                                          pool));
 }
 
+svn_error_t *
+svn_fs_freeze(svn_fs_t *fs,
+              svn_error_t *(*freeze_body)(void *baton, apr_pool_t *pool),
+              void *baton,
+              apr_pool_t *pool)
+{
+  SVN_ERR(fs->vtable->freeze(fs, freeze_body, baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* --- Berkeley-specific functions --- */
 
@@ -594,8 +682,8 @@ svn_error_t *
 svn_fs_hotcopy_berkeley(const char *src_path, const char *dest_path,
                         svn_boolean_t clean_logs, apr_pool_t *pool)
 {
-  return svn_error_trace(svn_fs_hotcopy(src_path, dest_path, clean_logs,
-                                        pool));
+  return svn_error_trace(svn_fs_hotcopy2(src_path, dest_path, clean_logs,
+                                         FALSE, NULL, NULL, pool));
 }
 
 svn_error_t *
@@ -1116,6 +1204,27 @@ svn_fs_file_contents(svn_stream_t **cont
 }
 
 svn_error_t *
+svn_fs_try_process_file_contents(svn_boolean_t *success,
+                                 svn_fs_root_t *root,
+                                 const char *path,
+                                 svn_fs_process_contents_func_t processor,
+                                 void* baton,
+                                 apr_pool_t *pool)
+{
+  /* if the FS doesn't implement this function, report a "failed" attempt */
+  if (root->vtable->try_process_file_contents == NULL)
+    {
+      *success = FALSE;
+      return SVN_NO_ERROR;
+    }
+
+  return svn_error_trace(root->vtable->try_process_file_contents(
+                         success,
+                         root, path,
+                         processor, baton, pool));
+}
+
+svn_error_t *
 svn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
 {
   SVN_ERR(svn_fs__path_valid(path, pool));
@@ -1414,11 +1523,11 @@ svn_error_t *
 svn_fs_print_modules(svn_stringbuf_t *output,
                      apr_pool_t *pool)
 {
-  const struct fs_type_defn *defn;
+  const struct fs_type_defn *defn = fs_modules;
   fs_library_vtable_t *vtable;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
-  for (defn = fs_modules; defn->fs_type != NULL; ++defn)
+  while (defn)
     {
       char *line;
       svn_error_t *err;
@@ -1431,6 +1540,7 @@ svn_fs_print_modules(svn_stringbuf_t *ou
           if (err->apr_err == SVN_ERR_FS_UNKNOWN_FS_TYPE)
             {
               svn_error_clear(err);
+              defn = defn->next;
               continue;
             }
           else
@@ -1440,6 +1550,7 @@ svn_fs_print_modules(svn_stringbuf_t *ou
       line = apr_psprintf(iterpool, "* fs_%s : %s\n",
                           defn->fsap_name, vtable->get_description());
       svn_stringbuf_appendcstr(output, line);
+      defn = defn->next;
     }
 
   svn_pool_destroy(iterpool);