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

svn commit: r1044548 [7/39] - in /subversion/branches/ignore-mergeinfo: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/ contrib/hook-scripts/ contrib/server-side/ notes/api-errata/ notes/api-erra...

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

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/relocate.c Sat Dec 11 00:15:55 2010
@@ -125,15 +125,91 @@ validator_func(void *baton,
   return SVN_NO_ERROR;
 }
 
+
+/* Examing the array of svn_wc_external_item2_t's EXT_DESC (parsed
+   from the svn:externals property set on LOCAL_ABSPATH) and determine
+   if the external working copies described by such should be
+   relocated as a side-effect of the relocation of their parent
+   working copy (from OLD_PARENT_REPOS_ROOT_URL to
+   NEW_PARENT_REPOS_ROOT_URL).  If so, attempt said relocation.  */
+static svn_error_t *
+relocate_externals(const char *local_abspath,
+                   apr_array_header_t *ext_desc,
+                   const char *old_parent_repos_root_url,
+                   const char *new_parent_repos_root_url,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *scratch_pool)
+{
+  const char *url;
+  apr_pool_t *iterpool;
+  int i;
+
+  SVN_ERR(svn_client_url_from_path2(&url, local_abspath, ctx,
+                                    scratch_pool, scratch_pool));
+
+  /* Parse an externals definition into an array of external items. */
+
+  iterpool = svn_pool_create(scratch_pool);
+
+  for (i = 0; i < ext_desc->nelts; i++)
+    {
+      svn_wc_external_item2_t *ext_item =
+        APR_ARRAY_IDX(ext_desc, i, svn_wc_external_item2_t *);
+      const char *target_repos_root_url;
+      const char *target_abspath;
+      
+      svn_pool_clear(iterpool);
+
+      /* If this external isn't pulled in via a relative URL, ignore
+         it.  There's no sense in relocating a working copy only to
+         have the next 'svn update' try to point it back to another
+         location. */
+      if (! ((strncmp("../", ext_item->url, 3) == 0) ||
+             (strncmp("^/", ext_item->url, 2) == 0)))
+        continue;
+
+      /* If the external working copy's not-yet-relocated repos root
+         URL matches the primary working copy's pre-relocated
+         repository root URL, try to relocate that external, too.
+         You might wonder why this check is needed, given that we're
+         already limiting ourselves to externals pulled via URLs
+         relative to their primary working copy.  Well, it's because
+         you can use "../" to "crawl up" above one repository's URL
+         space and down into another one.  */
+      SVN_ERR(svn_dirent_get_absolute(&target_abspath,
+                                      svn_dirent_join(local_abspath,
+                                                      ext_item->target_dir,
+                                                      iterpool),
+                                      iterpool));
+      SVN_ERR(svn_client_root_url_from_path(&target_repos_root_url,
+                                            target_abspath, ctx, iterpool));
+
+      if (strcmp(target_repos_root_url, old_parent_repos_root_url) == 0)
+        SVN_ERR(svn_client_relocate2(target_abspath,
+                                     old_parent_repos_root_url,
+                                     new_parent_repos_root_url,
+                                     TRUE, ctx, iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_client_relocate2(const char *wcroot_dir,
-                     const char *from,
-                     const char *to,
+                     const char *from_prefix,
+                     const char *to_prefix,
+                     svn_boolean_t ignore_externals,
                      svn_client_ctx_t *ctx,
                      apr_pool_t *pool)
 {
   struct validator_baton_t vb;
   const char *local_abspath;
+  apr_hash_t *externals_hash = NULL;
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool = NULL;
+  const char *old_repos_root_url, *new_repos_root_url;
 
   /* Populate our validator callback baton, and call the relocate code. */
   vb.ctx = ctx;
@@ -141,9 +217,61 @@ svn_client_relocate2(const char *wcroot_
   vb.url_uuids = apr_array_make(pool, 1, sizeof(struct url_uuid_t));
   vb.pool = pool;
 
+  if (svn_path_is_url(wcroot_dir))
+    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                             _("'%s' is not a local path"),
+                             wcroot_dir);
+
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, wcroot_dir, pool));
-  SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from, to,
+
+  /* If we're ignoring externals, just relocate and get outta here. */
+  if (ignore_externals)
+    {
+      return svn_error_return(svn_wc_relocate4(ctx->wc_ctx, local_abspath,
+                                               from_prefix, to_prefix,
+                                               validator_func, &vb, pool));
+    }
+
+  /* Fetch our current root URL. */
+  SVN_ERR(svn_client_root_url_from_path(&old_repos_root_url, local_abspath,
+                                        ctx, pool));
+
+  /* Perform the relocation. */
+  SVN_ERR(svn_wc_relocate4(ctx->wc_ctx, local_abspath, from_prefix, to_prefix,
                            validator_func, &vb, pool));
 
+  /* Now fetch new current root URL. */
+  SVN_ERR(svn_client_root_url_from_path(&new_repos_root_url, local_abspath,
+                                        ctx, pool));
+
+
+  /* Relocate externals, too (if any). */
+  SVN_ERR(svn_client__crawl_for_externals(&externals_hash, local_abspath,
+                                          svn_depth_infinity, ctx, pool, pool));
+  if (! apr_hash_count(externals_hash))
+    return SVN_NO_ERROR;
+
+  iterpool = svn_pool_create(pool);
+
+  for (hi = apr_hash_first(pool, externals_hash);
+       hi != NULL;
+       hi = apr_hash_next(hi))
+    {
+      const char *this_abspath = svn__apr_hash_index_key(hi);
+      const svn_string_t *pval = svn__apr_hash_index_val(hi);
+      apr_array_header_t *ext_desc;
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(svn_wc_parse_externals_description3(&ext_desc, this_abspath,
+                                                  pval->data, FALSE,
+                                                  iterpool));
+      if (ext_desc->nelts)
+        SVN_ERR(relocate_externals(this_abspath, ext_desc, old_repos_root_url,
+                                   new_repos_root_url, ctx, iterpool));
+    }
+    
+  svn_pool_destroy(iterpool);
+
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff.c Sat Dec 11 00:15:55 2010
@@ -521,7 +521,7 @@ diff_deleted_dir(const char *dir,
                                 mimetype1, mimetype2,
                                 b->pristine_props,
                                 b->edit_baton->diff_cmd_baton,
-                                pool));
+                                iterpool));
         }
  
       if (dirent->kind == svn_node_dir)
@@ -1060,7 +1060,8 @@ close_directory(void *dir_baton,
     return SVN_NO_ERROR;
 
   if (eb->dry_run)
-    svn_hash__clear(svn_client__dry_run_deletions(eb->diff_cmd_baton), pool);
+    SVN_ERR(svn_hash__clear(svn_client__dry_run_deletions(eb->diff_cmd_baton),
+                            pool));
 
   err = get_dir_abspath(&local_dir_abspath, eb->wc_ctx, b->wcpath,
                         FALSE, b->pool);
@@ -1244,7 +1245,7 @@ absent_directory(const char *path,
       svn_wc_notify_t *notify
         = svn_wc_create_notify(svn_dirent_join(pb->wcpath,
                                                svn_relpath_basename(path,
-                                                                    pool),
+                                                                    NULL),
                                                pool),
                                svn_wc_notify_skip, pool);
       notify->kind = svn_node_dir;

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/repos_diff_summarize.c Sat Dec 11 00:15:55 2010
@@ -196,7 +196,7 @@ diff_deleted_dir(const char *dir,
                                 &kind,
                                 iterpool));
 
-      sum = apr_pcalloc(pool, sizeof(*sum));
+      sum = apr_pcalloc(iterpool, sizeof(*sum));
       sum->summarize_kind = svn_client_diff_summarize_kind_deleted;
       sum->path = path;
       sum->node_kind = kind;

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/resolved.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/resolved.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/resolved.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/resolved.c Sat Dec 11 00:15:55 2010
@@ -36,6 +36,7 @@
 #include "client.h"
 #include "private/svn_wc_private.h"
 
+#include "svn_private_config.h"
 
 /*** Code. ***/
 
@@ -48,6 +49,10 @@ svn_client_resolve(const char *path,
 {
   const char *local_abspath;
 
+  if (svn_path_is_url(path))
+    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                             _("'%s' is not a local path"), path);
+
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
 
   SVN_ERR(svn_wc_resolved_conflict5(ctx->wc_ctx, local_abspath,

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/revert.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/revert.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/revert.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/revert.c Sat Dec 11 00:15:55 2010
@@ -27,6 +27,7 @@
 
 /*** Includes. ***/
 
+#include "svn_path.h"
 #include "svn_wc.h"
 #include "svn_client.h"
 #include "svn_dirent_uri.h"
@@ -37,6 +38,7 @@
 #include "client.h"
 #include "private/svn_wc_private.h"
 
+#include "svn_private_config.h"
 
 
 /*** Code. ***/
@@ -121,6 +123,17 @@ svn_client_revert2(const apr_array_heade
   svn_boolean_t use_commit_times;
   struct revert_with_write_lock_baton baton;
 
+  /* Don't even attempt to modify the working copy if any of the
+   * targets look like URLs. URLs are invalid input. */
+  for (i = 0; i < paths->nelts; i++)
+    {
+      const char *path = APR_ARRAY_IDX(paths, i, const char *);
+
+      if (svn_path_is_url(path))
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                 _("'%s' is not a local path"), path);
+    }
+  
   cfg = ctx->config ? apr_hash_get(ctx->config, SVN_CONFIG_CATEGORY_CONFIG,
                                    APR_HASH_KEY_STRING) : NULL;
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/status.c Sat Dec 11 00:15:55 2010
@@ -32,6 +32,7 @@
 #include "svn_pools.h"
 #include "client.h"
 
+#include "svn_path.h"
 #include "svn_dirent_uri.h"
 #include "svn_delta.h"
 #include "svn_client.h"
@@ -306,7 +307,11 @@ svn_client_status5(svn_revnum_t *result_
   apr_hash_t *ignored_props;
   svn_error_t *err;
   apr_hash_t *changelist_hash = NULL;
-  struct svn_cl__externals_store externals_store = { NULL };
+  struct svn_client__external_func_baton_t externals_store = { NULL };
+
+  if (svn_path_is_url(path))
+    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                             _("'%s' is not a local path"), path);
 
   if (changelists && changelists->nelts)
     SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelists, pool));
@@ -408,7 +413,7 @@ svn_client_status5(svn_revnum_t *result_
 
   if (!ignore_externals)
     {
-      externals_store.pool = pool;
+      externals_store.result_pool = pool;
       externals_store.externals_new = apr_hash_make(pool);
     }
 
@@ -444,10 +449,10 @@ svn_client_status5(svn_revnum_t *result_
                                     dir_abspath, target_basename,
                                     depth, get_all,
                                     no_ignore, ignores, tweak_status, &sb,
-                                    ignore_externals ? NULL
-                                                     : svn_cl__store_externals,
-                                    ignore_externals ? NULL
-                                                     : &externals_store,
+                                    ignore_externals
+                                        ? NULL
+                                        : svn_client__external_info_gatherer,
+                                    ignore_externals ? NULL : &externals_store,
                                     ctx->cancel_func, ctx->cancel_baton,
                                     pool, pool));
 
@@ -568,10 +573,10 @@ svn_client_status5(svn_revnum_t *result_
       err = svn_wc_walk_status(ctx->wc_ctx, target_abspath,
                                depth, get_all, no_ignore, ignores,
                                tweak_status, &sb,
-                               ignore_externals ? NULL
-                                                : svn_cl__store_externals,
-                               ignore_externals ? NULL
-                                                : &externals_store,
+                               ignore_externals
+                                   ? NULL
+                                   : svn_client__external_info_gatherer,
+                               ignore_externals ? NULL : &externals_store,
                                ctx->cancel_func, ctx->cancel_baton,
                                pool);
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/switch.c Sat Dec 11 00:15:55 2010
@@ -329,6 +329,11 @@ svn_client_switch2(svn_revnum_t *result_
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool)
 {
+  if (svn_path_is_url(path))
+    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                             _("'%s' is not a local path"),
+                             path);
+
   return svn_client__switch_internal(result_rev, path, switch_url,
                                      peg_revision, revision, depth,
                                      depth_is_sticky, NULL, ignore_externals,

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/update.c Sat Dec 11 00:15:55 2010
@@ -44,7 +44,18 @@
 
 /*** Code. ***/
 
-
+/* This is a helper for svn_client__update_internal(), which see for
+   an explanation of most of these parameters.  Some stuff that's
+   unique is as follows:
+
+   ANCHOR_ABSPATH is the local absolute path of the update anchor.
+   This is typically either the same as LOCAL_ABSPATH, or the
+   immediate parent of LOCAL_ABSPATH.
+
+   If NOTIFY_SUMMARY is set (and there's a notification hander in
+   CTX), transmit the final update summary upon successful
+   completion of the update.
+*/
 static svn_error_t *
 update_internal(svn_revnum_t *result_rev,
                 const char *local_abspath,
@@ -56,6 +67,7 @@ update_internal(svn_revnum_t *result_rev
                 svn_boolean_t allow_unver_obstructions,
                 svn_boolean_t *timestamp_sleep,
                 svn_boolean_t innerupdate,
+                svn_boolean_t notify_summary,
                 svn_client_ctx_t *ctx,
                 apr_pool_t *pool)
 {
@@ -144,6 +156,20 @@ update_internal(svn_revnum_t *result_rev
     ? svn_cstring_split(preserved_exts_str, "\n\r\t\v ", FALSE, pool)
     : NULL;
 
+  /* Let everyone know we're starting a real update (unless we're
+     asked not to). */
+  if (ctx->notify_func2 && notify_summary)
+    {
+      svn_wc_notify_t *notify
+        = svn_wc_create_notify(local_abspath, svn_wc_notify_update_started,
+                               pool);
+      notify->kind = svn_node_none;
+      notify->content_state = notify->prop_state
+        = svn_wc_notify_state_inapplicable;
+      notify->lock_state = svn_wc_notify_lock_state_inapplicable;
+      (*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
+    }
+
   /* Open an RA session for the URL */
   SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
                                                anchor_url,
@@ -154,8 +180,8 @@ update_internal(svn_revnum_t *result_rev
      relocate our working copy first. */
   if (corrected_url)
     {
-      SVN_ERR(svn_client_relocate(anchor_abspath, anchor_url, corrected_url,
-                                  TRUE, ctx, pool));
+      SVN_ERR(svn_client_relocate2(anchor_abspath, anchor_url, corrected_url,
+                                   TRUE, ctx, pool));
       anchor_url = corrected_url;
     }
 
@@ -235,8 +261,8 @@ update_internal(svn_revnum_t *result_rev
   if (sleep_here)
     svn_io_sleep_for_timestamps(local_abspath, pool);
 
-  /* Let everyone know we're finished here. */
-  if (ctx->notify_func2)
+  /* Let everyone know we're finished here (unless we're asked not to). */
+  if (ctx->notify_func2 && notify_summary)
     {
       svn_wc_notify_t *notify
         = svn_wc_create_notify(local_abspath, svn_wc_notify_update_completed,
@@ -266,44 +292,99 @@ svn_client__update_internal(svn_revnum_t
                             svn_boolean_t allow_unver_obstructions,
                             svn_boolean_t *timestamp_sleep,
                             svn_boolean_t innerupdate,
+                            svn_boolean_t make_parents,
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool)
 {
-  const char *anchor_abspath;
+  const char *anchor_abspath, *lockroot_abspath;
   svn_error_t *err;
+  svn_opt_revision_t peg_revision = *((svn_opt_revision_t *)revision);
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  SVN_ERR_ASSERT(! (innerupdate && make_parents));
 
-  if (!innerupdate)
-    SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
-                                       ctx->wc_ctx, local_abspath, TRUE,
-                                       pool, pool));
+  if (make_parents)
+    {
+      int i;
+      const char *parent_abspath = local_abspath;
+      apr_array_header_t *missing_parents = 
+        apr_array_make(pool, 4, sizeof(const char *));
+
+      while (1)
+        {
+          /* Try to lock.  If we can't lock because our target (or its
+             parent) isn't a working copy, we'll try to walk up the
+             tree to find a working copy, remembering this path's
+             parent as one we need to flesh out.  */
+          err = svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
+                                           parent_abspath, !innerupdate,
+                                           pool, pool);
+          if (!err)
+            break;
+          if ((err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
+              || svn_dirent_is_root(parent_abspath, strlen(parent_abspath)))
+            return err;
+          svn_error_clear(err);
+
+          /* Remember the parent of our update target as a missing
+             parent. */
+          parent_abspath = svn_dirent_dirname(parent_abspath, pool);
+          APR_ARRAY_PUSH(missing_parents, const char *) = parent_abspath;
+        }
+
+      /* Run 'svn up --depth=empty' (effectively) on the missing
+         parents, if any. */
+      anchor_abspath = lockroot_abspath;
+      for (i = missing_parents->nelts - 1; i >= 0; i--)
+        {
+          const char *missing_parent =
+            APR_ARRAY_IDX(missing_parents, i, const char *);
+          err = update_internal(result_rev, missing_parent, anchor_abspath,
+                                &peg_revision, svn_depth_empty, FALSE,
+                                ignore_externals, allow_unver_obstructions,
+                                timestamp_sleep, innerupdate, FALSE,
+                                ctx, pool);
+          if (err)
+            goto cleanup;
+          anchor_abspath = missing_parent;
+
+          /* If we successfully updated a missing parent, let's re-use
+             the returned revision number for future updates for the
+             sake of consistency. */
+          peg_revision.kind = svn_opt_revision_number;
+          peg_revision.value.number = *result_rev;
+        }
+    }
   else
-    SVN_ERR(svn_wc__acquire_write_lock(&anchor_abspath,
-                                       ctx->wc_ctx, local_abspath, FALSE,
-                                       pool, pool));
+    {
+      SVN_ERR(svn_wc__acquire_write_lock(&lockroot_abspath, ctx->wc_ctx,
+                                         local_abspath, !innerupdate,
+                                         pool, pool));
+      anchor_abspath = lockroot_abspath;
+    }
 
   err = update_internal(result_rev, local_abspath, anchor_abspath,
-                         revision, depth, depth_is_sticky,
-                         ignore_externals, allow_unver_obstructions,
-                         timestamp_sleep, innerupdate, ctx, pool);
-
+                        &peg_revision, depth, depth_is_sticky,
+                        ignore_externals, allow_unver_obstructions,
+                        timestamp_sleep, innerupdate, TRUE, ctx, pool);
+ cleanup:
   err = svn_error_compose_create(
             err,
-            svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool));
+            svn_wc__release_write_lock(ctx->wc_ctx, lockroot_abspath, pool));
 
   return svn_error_return(err);
 }
 
 
 svn_error_t *
-svn_client_update3(apr_array_header_t **result_revs,
+svn_client_update4(apr_array_header_t **result_revs,
                    const apr_array_header_t *paths,
                    const svn_opt_revision_t *revision,
                    svn_depth_t depth,
                    svn_boolean_t depth_is_sticky,
                    svn_boolean_t ignore_externals,
                    svn_boolean_t allow_unver_obstructions,
+                   svn_boolean_t make_parents,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool)
 {
@@ -316,10 +397,19 @@ svn_client_update3(apr_array_header_t **
 
   for (i = 0; i < paths->nelts; ++i)
     {
+      path = APR_ARRAY_IDX(paths, i, const char *);
+
+      if (svn_path_is_url(path))
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                 _("'%s' is not a local path"), path);
+    }
+
+  for (i = 0; i < paths->nelts; ++i)
+    {
       svn_boolean_t sleep;
-      svn_boolean_t skipped = FALSE;
       svn_error_t *err = SVN_NO_ERROR;
       svn_revnum_t result_rev;
+      const char *local_abspath;
       path = APR_ARRAY_IDX(paths, i, const char *);
 
       svn_pool_clear(subpool);
@@ -327,56 +417,30 @@ svn_client_update3(apr_array_header_t **
       if (ctx->cancel_func && (err = ctx->cancel_func(ctx->cancel_baton)))
         break;
 
-      if (svn_path_is_url(path))
-        {
-          skipped = TRUE;
-        }
-      else
-        {
-          const char *local_abspath;
-
-          SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool));
-          err = svn_client__update_internal(&result_rev, local_abspath,
-                                            revision, depth, depth_is_sticky,
-                                            ignore_externals,
-                                            allow_unver_obstructions,
-                                            &sleep, FALSE, ctx, subpool);
-
-          if (err && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
-            {
-              return svn_error_return(err);
-            }
+      SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, subpool));
+      err = svn_client__update_internal(&result_rev, local_abspath,
+                                        revision, depth, depth_is_sticky,
+                                        ignore_externals,
+                                        allow_unver_obstructions,
+                                        &sleep, FALSE, make_parents,
+                                        ctx, subpool);
 
-          if (err)
-            {
-              /* SVN_ERR_WC_NOT_WORKING_COPY: it's not versioned */
-              svn_error_clear(err);
-              skipped = TRUE;
-            }
+      if (err && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
+        {
+          return svn_error_return(err);
         }
 
-      if (skipped)
+      if (err)
         {
+          /* SVN_ERR_WC_NOT_WORKING_COPY: it's not versioned */
+          svn_error_clear(err);
           result_rev = SVN_INVALID_REVNUM;
           if (ctx->notify_func2)
             {
               svn_wc_notify_t *notify;
-
-              if (svn_path_is_url(path))
-                {
-                  /* For some historic reason this user error is supported,
-                     and must provide correct notifications. */
-                  notify = svn_wc_create_notify_url(path,
-                                                    svn_wc_notify_skip,
-                                                    subpool);
-                }
-              else
-                {
-                  notify = svn_wc_create_notify(path,
-                                                svn_wc_notify_skip,
-                                                subpool);
-                }
-
+              notify = svn_wc_create_notify(path,
+                                            svn_wc_notify_skip,
+                                            subpool);
               (*ctx->notify_func2)(ctx->notify_baton2, notify, subpool);
             }
         }

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_client/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_client/util.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_client/util.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_client/util.c Sat Dec 11 00:15:55 2010
@@ -34,6 +34,7 @@
 #include "svn_wc.h"
 #include "svn_client.h"
 
+#include "private/svn_client_private.h"
 #include "private/svn_wc_private.h"
 
 #include "client.h"
@@ -218,7 +219,9 @@ svn_client__path_relative_to_root(const 
         }
       rel_url = svn_path_uri_decode(rel_url, result_pool);
       *rel_path = include_leading_slash
-                    ? apr_pstrcat(result_pool, "/", rel_url, NULL) : rel_url;
+                    ? apr_pstrcat(result_pool, "/", rel_url,
+                                  (char *)NULL)
+                    : rel_url;
     }
 
   return SVN_NO_ERROR;
@@ -318,3 +321,25 @@ svn_cl__rev_default_to_peg(const svn_opt
     return peg_revision;
   return revision;
 }
+
+svn_error_t *
+svn_client__assert_homogeneous_target_type(const apr_array_header_t *targets)
+{
+  svn_boolean_t wc_present = FALSE, url_present = FALSE;
+  int i;
+
+  for (i = 0; i < targets->nelts; ++i)
+    {
+      const char *target = APR_ARRAY_IDX(targets, i, const char *);
+      if (! svn_path_is_url(target))
+        wc_present = TRUE;
+      else
+        url_present = TRUE;
+      if (url_present && wc_present)
+        return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                                 _("Cannot mix repository and working copy "
+                                   "targets"));
+    }
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/path_driver.c Sat Dec 11 00:15:55 2010
@@ -194,7 +194,9 @@ svn_delta_path_driver(const svn_delta_ed
            current one.  For the first iteration, this is just the
            empty string. ***/
       if (i > 0)
-        common = svn_relpath_get_longest_ancestor(last_path, path, iterpool);
+        common = (last_path[0] == '/')
+          ? svn_fspath__get_longest_ancestor(last_path, path, iterpool)
+          : svn_relpath_get_longest_ancestor(last_path, path, iterpool);
       common_len = strlen(common);
 
       /*** Step B - Close any directories between the last path and
@@ -215,7 +217,7 @@ svn_delta_path_driver(const svn_delta_ed
       /*** Step C - Open any directories between the common ancestor
            and the parent of the current path. ***/
       if (*path == '/')
-        svn_uri_split(&pdir, &bname, path, iterpool);
+        svn_fspath__split(&pdir, &bname, path, iterpool);
       else
         svn_relpath_split(&pdir, &bname, path, iterpool);
       if (strlen(pdir) > common_len)

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_delta/svndiff.c Sat Dec 11 00:15:55 2010
@@ -352,10 +352,13 @@ struct decode_baton
 };
 
 
-/* Decode an svndiff-encoded integer into VAL and return a pointer to
+/* Decode an svndiff-encoded integer into *VAL and return a pointer to
    the byte after the integer.  The bytes to be decoded live in the
-   range [P..END-1].  See the comment for encode_int earlier in this
-   file for more detail on the encoding format.  */
+   range [P..END-1].  If these bytes do not contain a whole encoded
+   integer, return NULL; in this case *VAL is undefined.
+
+   See the comment for encode_int() earlier in this file for more detail on
+   the encoding format.  */
 static const unsigned char *
 decode_file_offset(svn_filesize_t *val,
                    const unsigned char *p,
@@ -381,7 +384,6 @@ decode_file_offset(svn_filesize_t *val,
       }
     }
 
-  *val = temp;
   return NULL;
 }
 
@@ -409,7 +411,6 @@ decode_size(apr_size_t *val,
       }
     }
 
-  *val = temp;
   return NULL;
 }
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/diff_file.c Sat Dec 11 00:15:55 2010
@@ -67,21 +67,26 @@ typedef struct svn_diff__file_token_t
 typedef struct svn_diff__file_baton_t
 {
   const svn_diff_file_options_t *options;
-  const char *path[4];
 
-  apr_file_t *file[4];
-  apr_off_t size[4];
+  struct file_info {
+    const char *path;  /* path to this file, absolute or relative to CWD */
 
-  int chunk[4];
-  char *buffer[4];
-  char *curp[4];
-  char *endp[4];
+    /* All the following fields are active while this datasource is open */
+    apr_file_t *file;  /* handle of this file */
+    apr_off_t size;    /* total raw size in bytes of this file */
+
+    /* The current chunk: CHUNK_SIZE bytes except for the last chunk. */
+    int chunk;     /* the current chunk number, zero-based */
+    char *buffer;  /* a buffer containing the current chunk */
+    char *curp;    /* current position in the current chunk */
+    char *endp;    /* next memory address after the current chunk */
+
+    svn_diff__normalize_state_t normalize_state;
+  } files[4];
 
   /* List of free tokens that may be reused. */
   svn_diff__file_token_t *tokens;
 
-  svn_diff__normalize_state_t normalize_state[4];
-
   apr_pool_t *pool;
 } svn_diff__file_baton_t;
 
@@ -198,26 +203,30 @@ map_or_read_file(apr_file_t **file,
 }
 
 
-/* Implements svn_diff_fns_t::datasource_open */
+/* Let FILE stand for the file_info struct element of BATON->files that is
+ * indexed by DATASOURCE.  BATON's type is (svn_diff__file_baton_t *).
+ *
+ * Open the file at FILE.path; initialize FILE.file, FILE.size, FILE.buffer,
+ * FILE.curp and FILE.endp; allocate a buffer and read the first chunk.
+ *
+ * Implements svn_diff_fns_t::datasource_open. */
 static svn_error_t *
 datasource_open(void *baton, svn_diff_datasource_e datasource)
 {
   svn_diff__file_baton_t *file_baton = baton;
-  int idx;
+  struct file_info *file = &file_baton->files[datasource_to_index(datasource)];
   apr_finfo_t finfo;
   apr_off_t length;
   char *curp;
   char *endp;
 
-  idx = datasource_to_index(datasource);
-
-  SVN_ERR(svn_io_file_open(&file_baton->file[idx], file_baton->path[idx],
+  SVN_ERR(svn_io_file_open(&file->file, file->path,
                            APR_READ, APR_OS_DEFAULT, file_baton->pool));
 
   SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE,
-                               file_baton->file[idx], file_baton->pool));
+                               file->file, file_baton->pool));
 
-  file_baton->size[idx] = finfo.size;
+  file->size = finfo.size;
   length = finfo.size > CHUNK_SIZE ? CHUNK_SIZE : finfo.size;
 
   if (length == 0)
@@ -226,10 +235,10 @@ datasource_open(void *baton, svn_diff_da
   endp = curp = apr_palloc(file_baton->pool, (apr_size_t) length);
   endp += length;
 
-  file_baton->buffer[idx] = file_baton->curp[idx] = curp;
-  file_baton->endp[idx] = endp;
+  file->buffer = file->curp = curp;
+  file->endp = endp;
 
-  return read_chunk(file_baton->file[idx], file_baton->path[idx],
+  return read_chunk(file->file, file->path,
                     curp, length, 0, file_baton->pool);
 }
 
@@ -252,7 +261,7 @@ datasource_get_next_token(apr_uint32_t *
 {
   svn_diff__file_baton_t *file_baton = baton;
   svn_diff__file_token_t *file_token;
-  int idx;
+  struct file_info *file = &file_baton->files[datasource_to_index(datasource)];
   char *endp;
   char *curp;
   char *eol;
@@ -264,15 +273,13 @@ datasource_get_next_token(apr_uint32_t *
 
   *token = NULL;
 
-  idx = datasource_to_index(datasource);
-
-  curp = file_baton->curp[idx];
-  endp = file_baton->endp[idx];
+  curp = file->curp;
+  endp = file->endp;
 
-  last_chunk = offset_to_chunk(file_baton->size[idx]);
+  last_chunk = offset_to_chunk(file->size);
 
   if (curp == endp
-      && last_chunk == file_baton->chunk[idx])
+      && last_chunk == file->chunk)
     {
       return SVN_NO_ERROR;
     }
@@ -289,8 +296,8 @@ datasource_get_next_token(apr_uint32_t *
     }
 
   file_token->datasource = datasource;
-  file_token->offset = chunk_to_offset(file_baton->chunk[idx])
-                       + (curp - file_baton->buffer[idx]);
+  file_token->offset = chunk_to_offset(file->chunk)
+                       + (curp - file->buffer);
   file_token->raw_length = 0;
   file_token->length = 0;
 
@@ -311,7 +318,7 @@ datasource_get_next_token(apr_uint32_t *
             }
         }
 
-      if (file_baton->chunk[idx] == last_chunk)
+      if (file->chunk == last_chunk)
         {
           eol = endp;
           break;
@@ -320,21 +327,21 @@ datasource_get_next_token(apr_uint32_t *
       length = endp - curp;
       file_token->raw_length += length;
       svn_diff__normalize_buffer(&curp, &length,
-                                 &file_baton->normalize_state[idx],
+                                 &file->normalize_state,
                                  curp, file_baton->options);
       file_token->length += length;
       h = svn_diff__adler32(h, curp, length);
 
-      curp = endp = file_baton->buffer[idx];
-      file_baton->chunk[idx]++;
-      length = file_baton->chunk[idx] == last_chunk ?
-        offset_in_chunk(file_baton->size[idx]) : CHUNK_SIZE;
+      curp = endp = file->buffer;
+      file->chunk++;
+      length = file->chunk == last_chunk ?
+        offset_in_chunk(file->size) : CHUNK_SIZE;
       endp += length;
-      file_baton->endp[idx] = endp;
+      file->endp = endp;
 
-      SVN_ERR(read_chunk(file_baton->file[idx], file_baton->path[idx],
+      SVN_ERR(read_chunk(file->file, file->path,
                          curp, length,
-                         chunk_to_offset(file_baton->chunk[idx]),
+                         chunk_to_offset(file->chunk),
                          file_baton->pool));
 
       /* If the last chunk ended in a CR, we're done. */
@@ -349,7 +356,7 @@ datasource_get_next_token(apr_uint32_t *
 
   length = eol - curp;
   file_token->raw_length += length;
-  file_baton->curp[idx] = eol;
+  file->curp = eol;
 
   /* If the file length is exactly a multiple of CHUNK_SIZE, we will end up
    * with a spurious empty token.  Avoid returning it.
@@ -360,7 +367,7 @@ datasource_get_next_token(apr_uint32_t *
     {
       char *c = curp;
       svn_diff__normalize_buffer(&c, &length,
-                                 &file_baton->normalize_state[idx],
+                                 &file->normalize_state,
                                  curp, file_baton->options);
 
       file_token->norm_offset = file_token->offset;
@@ -388,13 +395,12 @@ token_compare(void *baton, void *token1,
   char buffer[2][COMPARE_CHUNK_SIZE];
   char *bufp[2];
   apr_off_t offset[2];
-  int idx[2];
+  struct file_info *file[2];
   apr_off_t length[2];
   apr_off_t total_length;
   /* How much is left to read of each token from the file. */
   apr_off_t raw_length[2];
   int i;
-  int chunk[2];
   svn_diff__normalize_state_t state[2];
 
   file_token[0] = token1;
@@ -420,17 +426,18 @@ token_compare(void *baton, void *token1,
 
   for (i = 0; i < 2; ++i)
     {
-      idx[i] = datasource_to_index(file_token[i]->datasource);
+      int idx = datasource_to_index(file_token[i]->datasource);
+
+      file[i] = &file_baton->files[idx];
       offset[i] = file_token[i]->norm_offset;
-      chunk[i] = file_baton->chunk[idx[i]];
       state[i] = svn_diff__normalize_state_normal;
 
-      if (offset_to_chunk(offset[i]) == chunk[i])
+      if (offset_to_chunk(offset[i]) == file[i]->chunk)
         {
           /* If the start of the token is in memory, the entire token is
            * in memory.
            */
-          bufp[i] = file_baton->buffer[idx[i]];
+          bufp[i] = file[i]->buffer;
           bufp[i] += offset_in_chunk(offset[i]);
 
           length[i] = total_length;
@@ -458,15 +465,15 @@ token_compare(void *baton, void *token1,
                                          NULL,
                                          _("The file '%s' changed unexpectedly"
                                            " during diff"),
-                                         file_baton->path[idx[i]]);
+                                         file[i]->path);
 
               /* Read a chunk from disk into a buffer */
               bufp[i] = buffer[i];
               length[i] = raw_length[i] > COMPARE_CHUNK_SIZE ?
                 COMPARE_CHUNK_SIZE : raw_length[i];
 
-              SVN_ERR(read_chunk(file_baton->file[idx[i]],
-                                 file_baton->path[idx[i]],
+              SVN_ERR(read_chunk(file[i]->file,
+                                 file[i]->path,
                                  bufp[i], length[i], offset[i],
                                  file_baton->pool));
               offset[i] += length[i];
@@ -555,12 +562,42 @@ svn_diff_file_options_create(apr_pool_t 
   return apr_pcalloc(pool, sizeof(svn_diff_file_options_t));
 }
 
+/* A baton for use with opt_parsing_error_func(). */
+struct opt_parsing_error_baton_t
+{
+  svn_error_t *err;
+  apr_pool_t *pool;
+};
+
+/* Store an error message from apr_getopt_long().  Set BATON->err to a new
+ * error with a message generated from FMT and the remaining arguments.
+ * Implements apr_getopt_err_fn_t. */
+static void
+opt_parsing_error_func(void *baton,
+                       const char *fmt, ...)
+{
+  struct opt_parsing_error_baton_t *b = baton;
+  const char *message;
+  va_list ap;
+
+  va_start(ap, fmt);
+  message = apr_pvsprintf(b->pool, fmt, ap);
+  va_end(ap);
+
+  /* Skip leading ": " (if present, which it always is in known cases). */
+  if (strncmp(message, ": ", 2) == 0)
+    message += 2;
+
+  b->err = svn_error_create(SVN_ERR_INVALID_DIFF_OPTION, NULL, message);
+}
+
 svn_error_t *
 svn_diff_file_options_parse(svn_diff_file_options_t *options,
                             const apr_array_header_t *args,
                             apr_pool_t *pool)
 {
   apr_getopt_t *os;
+  struct opt_parsing_error_baton_t opt_parsing_error_baton = { NULL, pool };
   /* Make room for each option (starting at index 1) plus trailing NULL. */
   const char **argv = apr_palloc(pool, sizeof(char*) * (args->nelts + 2));
 
@@ -569,8 +606,12 @@ svn_diff_file_options_parse(svn_diff_fil
   argv[args->nelts + 1] = NULL;
 
   apr_getopt_init(&os, pool, args->nelts + 1, argv);
-  /* No printing of error messages, please! */
-  os->errfn = NULL;
+
+  /* Capture any error message from apr_getopt_long().  This will typically
+   * say which option is wrong, which we would not otherwise know. */
+  os->errfn = opt_parsing_error_func;
+  os->errarg = &opt_parsing_error_baton;
+
   while (1)
     {
       const char *opt_arg;
@@ -580,7 +621,13 @@ svn_diff_file_options_parse(svn_diff_fil
       if (APR_STATUS_IS_EOF(err))
         break;
       if (err)
-        return svn_error_wrap_apr(err, _("Error parsing diff options"));
+        /* Wrap apr_getopt_long()'s error message.  Its doc string implies
+         * it always will produce one, but never mind if it doesn't.  Avoid
+         * using the message associated with the return code ERR, because
+         * it refers to the "command line" which may be misleading here. */
+        return svn_error_create(SVN_ERR_INVALID_DIFF_OPTION,
+                                opt_parsing_error_baton.err,
+                                _("Error in options to internal diff"));
 
       switch (opt_id)
         {
@@ -623,8 +670,8 @@ svn_diff_file_diff_2(svn_diff_t **diff,
 
   memset(&baton, 0, sizeof(baton));
   baton.options = options;
-  baton.path[0] = original;
-  baton.path[1] = modified;
+  baton.files[0].path = original;
+  baton.files[1].path = modified;
   baton.pool = svn_pool_create(pool);
 
   SVN_ERR(svn_diff_diff(diff, &baton, &svn_diff__file_vtable, pool));
@@ -645,9 +692,9 @@ svn_diff_file_diff3_2(svn_diff_t **diff,
 
   memset(&baton, 0, sizeof(baton));
   baton.options = options;
-  baton.path[0] = original;
-  baton.path[1] = modified;
-  baton.path[2] = latest;
+  baton.files[0].path = original;
+  baton.files[1].path = modified;
+  baton.files[2].path = latest;
   baton.pool = svn_pool_create(pool);
 
   SVN_ERR(svn_diff_diff3(diff, &baton, &svn_diff__file_vtable, pool));
@@ -669,10 +716,10 @@ svn_diff_file_diff4_2(svn_diff_t **diff,
 
   memset(&baton, 0, sizeof(baton));
   baton.options = options;
-  baton.path[0] = original;
-  baton.path[1] = modified;
-  baton.path[2] = latest;
-  baton.path[3] = ancestor;
+  baton.files[0].path = original;
+  baton.files[1].path = modified;
+  baton.files[2].path = latest;
+  baton.files[3].path = ancestor;
   baton.pool = svn_pool_create(pool);
 
   SVN_ERR(svn_diff_diff4(diff, &baton, &svn_diff__file_vtable, pool));
@@ -1130,11 +1177,11 @@ svn_diff_file_output_unified3(svn_stream
                               apr_pool_t *pool)
 {
   svn_diff__file_output_baton_t baton;
-  int i;
 
   if (svn_diff_contains_diffs(diff))
     {
       const char **c;
+      int i;
 
       memset(&baton, 0, sizeof(baton));
       baton.output_stream = output_stream;
@@ -1161,42 +1208,44 @@ svn_diff_file_output_unified3(svn_stream
       SVN_ERR(svn_utf_cstring_from_utf8_ex2(&baton.insert_str, "+",
                                             header_encoding, pool));
 
-  if (relative_to_dir)
-    {
-      /* Possibly adjust the "original" and "modified" paths shown in
-         the output (see issue #2723). */
-      const char *child_path;
-
-      if (! original_header)
-        {
-          child_path = svn_dirent_is_child(relative_to_dir,
-                                           original_path, pool);
-          if (child_path)
-            original_path = child_path;
-          else
-            return svn_error_createf(
-                               SVN_ERR_BAD_RELATIVE_PATH, NULL,
-                               _("Path '%s' must be an immediate child of "
-                                 "the directory '%s'"),
-                               svn_dirent_local_style(original_path, pool),
-                               svn_dirent_local_style(relative_to_dir, pool));
-        }
-
-      if (! modified_header)
-        {
-          child_path = svn_dirent_is_child(relative_to_dir,
-                                           modified_path, pool);
-          if (child_path)
-            modified_path = child_path;
-          else
-            return svn_error_createf(
-                               SVN_ERR_BAD_RELATIVE_PATH, NULL,
-                               _("Path '%s' must be an immediate child of "
-                                 "the directory '%s'"),
-                               svn_dirent_local_style(modified_path, pool),
-                               svn_dirent_local_style(relative_to_dir, pool));
+      if (relative_to_dir)
+        {
+          /* Possibly adjust the "original" and "modified" paths shown in
+             the output (see issue #2723). */
+          const char *child_path;
+
+          if (! original_header)
+            {
+              child_path = svn_dirent_is_child(relative_to_dir,
+                                               original_path, pool);
+              if (child_path)
+                original_path = child_path;
+              else
+                return svn_error_createf(
+                                   SVN_ERR_BAD_RELATIVE_PATH, NULL,
+                                   _("Path '%s' must be an immediate child of "
+                                     "the directory '%s'"),
+                                   svn_dirent_local_style(original_path, pool),
+                                   svn_dirent_local_style(relative_to_dir,
+                                                          pool));
+            }
+
+          if (! modified_header)
+            {
+              child_path = svn_dirent_is_child(relative_to_dir,
+                                               modified_path, pool);
+              if (child_path)
+                modified_path = child_path;
+              else
+                return svn_error_createf(
+                                   SVN_ERR_BAD_RELATIVE_PATH, NULL,
+                                   _("Path '%s' must be an immediate child of "
+                                     "the directory '%s'"),
+                                   svn_dirent_local_style(modified_path, pool),
+                                   svn_dirent_local_style(relative_to_dir,
+                                                          pool));
+            }
         }
-    }
 
       for (i = 0; i < 2; i++)
         {

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_diff/parse-diff.c Sat Dec 11 00:15:55 2010
@@ -28,6 +28,7 @@
 #include "svn_error.h"
 #include "svn_io.h"
 #include "svn_pools.h"
+#include "svn_props.h"
 #include "svn_string.h"
 #include "svn_utf.h"
 #include "svn_dirent_uri.h"
@@ -150,7 +151,7 @@ parse_range(svn_linenum_t *start, svn_li
 {
   char *comma;
 
-  if (strlen(range) == 0)
+  if (*range == 0)
     return FALSE;
 
   comma = strstr(range, ",");
@@ -189,6 +190,7 @@ parse_hunk_header(const char *header, sv
                   const char *atat, apr_pool_t *pool)
 {
   const char *p;
+  const char *start;
   svn_stringbuf_t *range;
 
   p = header + strlen(atat);
@@ -201,16 +203,18 @@ parse_hunk_header(const char *header, sv
     return FALSE;
   /* OK, this may be worth allocating some memory for... */
   range = svn_stringbuf_create_ensure(31, pool);
-  p++;
+  start = ++p;
   while (*p && *p != ' ')
     {
-      svn_stringbuf_appendbyte(range, *p);
       p++;
     }
+
   if (*p != ' ')
     /* No no no... */
     return FALSE;
 
+  svn_stringbuf_appendbytes(range, start, p - start);
+
   /* Try to parse the first range. */
   if (! parse_range(&hunk->original_start, &hunk->original_length, range->data))
     return FALSE;
@@ -222,16 +226,17 @@ parse_hunk_header(const char *header, sv
     /* Eeek! */
     return FALSE;
   /* OK, this may be worth copying... */
-  p++;
+  start = ++p;
   while (*p && *p != ' ')
     {
-      svn_stringbuf_appendbyte(range, *p);
       p++;
     }
   if (*p != ' ')
     /* No no no... */
     return FALSE;
 
+  svn_stringbuf_appendbytes(range, start, p - start);
+
   /* Check for trailing @@ */
   p++;
   if (! starts_with(p, atat))
@@ -477,19 +482,24 @@ svn_diff_hunk_readline_diff_text(const s
   return SVN_NO_ERROR;
 }
 
-/* Parse PROP_NAME from HEADER as the part after the INDICATOR line. */
+/* Parse *PROP_NAME from HEADER as the part after the INDICATOR line.
+ * Allocate *PROP_NAME in RESULT_POOL.
+ * Set *PROP_NAME to NULL if no valid property name was found. */
 static svn_error_t *
 parse_prop_name(const char **prop_name, const char *header, 
                 const char *indicator, apr_pool_t *result_pool)
 {
-  /* ### This can fail if the filename cannot be represented in the current
-   * ### locale's encoding. */
   SVN_ERR(svn_utf_cstring_to_utf8(prop_name,
                                   header + strlen(indicator),
                                   result_pool));
-
-  /* ### Are we guarenteed that there are no trailing or leading
-   * ### whitespaces in the name? */
+  if (**prop_name == '\0')
+    *prop_name = NULL;
+  else if (! svn_prop_name_is_valid(*prop_name))
+    {
+      svn_stringbuf_t *buf = svn_stringbuf_create(*prop_name, result_pool);
+      svn_stringbuf_strip_whitespace(buf);
+      *prop_name = (svn_prop_name_is_valid(buf->data) ? buf->data : NULL);
+    }
 
   return SVN_NO_ERROR;
 }
@@ -674,20 +684,23 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
           else if (starts_with(line->data, "Added: "))
             {
               SVN_ERR(parse_prop_name(prop_name, line->data, "Added: ",
-                                      result_pool));
-              *prop_operation = svn_diff_op_added;
+                                      result_pool));  
+              if (*prop_name)
+                *prop_operation = svn_diff_op_added;
             }
           else if (starts_with(line->data, "Deleted: "))
             {
               SVN_ERR(parse_prop_name(prop_name, line->data, "Deleted: ",
                                       result_pool));
-              *prop_operation = svn_diff_op_deleted;
+              if (*prop_name)
+                *prop_operation = svn_diff_op_deleted;
             }
           else if (starts_with(line->data, "Modified: "))
             {
               SVN_ERR(parse_prop_name(prop_name, line->data, "Modified: ",
                                       result_pool));
-              *prop_operation = svn_diff_op_modified;
+              if (*prop_name)
+                *prop_operation = svn_diff_op_modified;
             }
           else if (starts_with(line->data, minus)
                    || starts_with(line->data, "diff --git "))
@@ -1027,7 +1040,7 @@ git_move_from(enum parse_state *new_stat
   return SVN_NO_ERROR;
 }
 
-/* Parse the 'rename to ' line fo a git extended unidiff. */
+/* Parse the 'rename to ' line of a git extended unidiff. */
 static svn_error_t *
 git_move_to(enum parse_state *new_state, const char *line, svn_patch_t *patch,
             apr_pool_t *result_pool, apr_pool_t *scratch_pool)
@@ -1262,6 +1275,8 @@ svn_diff_parse_next_patch(svn_patch_t **
       const char *prop_name;
       svn_diff_operation_kind_t prop_operation;
 
+      last_prop_name = NULL;
+
       /* Parse hunks. */
       (*patch)->hunks = apr_array_make(result_pool, 10,
                                        sizeof(svn_diff_hunk_t *));

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.c Sat Dec 11 00:15:55 2010
@@ -684,7 +684,15 @@ svn_fs_commit_txn(const char **conflict_
   SVN_ERR(txn->vtable->commit(conflict_p, new_rev, txn, pool));
 
 #ifdef PACK_AFTER_EVERY_COMMIT
-  SVN_ERR(svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool));
+  {
+    svn_error_t *err = svn_fs_pack(fs_path, NULL, NULL, NULL, NULL, pool);
+    if (err && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
+      /* Pre-1.6 filesystem. */
+      svn_error_clear(err);
+    else if (err)
+      /* Real error. */
+      return svn_error_return(err);
+  }
 #endif
 
   return SVN_NO_ERROR;
@@ -991,6 +999,22 @@ svn_fs_closest_copy(svn_fs_root_t **root
 }
 
 svn_error_t *
+svn_fs_get_mergeinfo2(svn_mergeinfo_catalog_t *catalog,
+                      svn_fs_root_t *root,
+                      const apr_array_header_t *paths,
+                      svn_mergeinfo_inheritance_t inherit,
+                      svn_boolean_t validate_inherited_mergeinfo,
+                      svn_boolean_t include_descendants,
+                      apr_pool_t *pool)
+{
+  return svn_error_return(root->vtable->get_mergeinfo(catalog, root, paths,
+                                                      inherit,
+                                                      validate_inherited_mergeinfo,
+                                                      include_descendants,
+                                                      pool));
+}
+
+svn_error_t *
 svn_fs_get_mergeinfo(svn_mergeinfo_catalog_t *catalog,
                      svn_fs_root_t *root,
                      const apr_array_header_t *paths,
@@ -998,10 +1022,24 @@ svn_fs_get_mergeinfo(svn_mergeinfo_catal
                      svn_boolean_t include_descendants,
                      apr_pool_t *pool)
 {
-  return svn_error_return(root->vtable->get_mergeinfo(catalog, root, paths,
-                                                      inherit,
-                                                      include_descendants,
-                                                      pool));
+  return svn_error_return(svn_fs_get_mergeinfo2(catalog, root, paths,
+                                                inherit,
+                                                FALSE,
+                                                include_descendants,
+                                                pool));
+}
+
+svn_error_t *
+svn_fs_validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
+                          svn_fs_t *fs,
+                          svn_mergeinfo_t mergeinfo,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  return svn_error_return(fs->vtable->validate_mergeinfo(validated_mergeinfo,
+                                                         fs, mergeinfo,
+                                                         result_pool,
+                                                         scratch_pool));
 }
 
 svn_error_t *

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs/fs-loader.h Sat Dec 11 00:15:55 2010
@@ -197,6 +197,11 @@ typedef struct fs_vtable_t
   svn_error_t *(*bdb_set_errcall)(svn_fs_t *fs,
                                   void (*handler)(const char *errpfx,
                                                   char *msg));
+  svn_error_t *(*validate_mergeinfo)(svn_mergeinfo_t *validated_mergeinfo,
+                                     svn_fs_t *fs,
+                                     svn_mergeinfo_t mergeinfo,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool);
 } fs_vtable_t;
 
 
@@ -331,6 +336,7 @@ typedef struct root_vtable_t
                                 svn_fs_root_t *root,
                                 const apr_array_header_t *paths,
                                 svn_mergeinfo_inheritance_t inherit,
+                                svn_boolean_t validate_inherited_mergeinfo,
                                 svn_boolean_t include_descendants,
                                 apr_pool_t *pool);
 } root_vtable_t;

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/bdb/locks-table.c Sat Dec 11 00:15:55 2010
@@ -250,7 +250,7 @@ svn_fs_bdb__locks_get(svn_fs_t *fs,
   /* As long as the prefix of the returned KEY matches LOOKUP_PATH we
      know it is either LOOKUP_PATH or a decendant thereof.  */
   if (strcmp(path, "/") != 0)
-    lookup_path = apr_pstrcat(pool, path, "/", NULL);
+    lookup_path = apr_pstrcat(pool, path, "/", (char *)NULL);
   while ((! db_err)
          && strncmp(lookup_path, key.data, strlen(lookup_path)) == 0)
     {

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/dag.c Sat Dec 11 00:15:55 2010
@@ -481,7 +481,7 @@ make_entry(dag_node_t **child_p,
   /* Create the new node's NODE-REVISION */
   memset(&new_noderev, 0, sizeof(new_noderev));
   new_noderev.kind = is_dir ? svn_node_dir : svn_node_file;
-  new_noderev.created_path = svn_uri_join(parent_path, name, pool);
+  new_noderev.created_path = svn_fspath__join(parent_path, name, pool);
   SVN_ERR(svn_fs_base__create_node
           (&new_node_id, svn_fs_base__dag_get_fs(parent), &new_noderev,
            svn_fs_base__id_copy_id(svn_fs_base__dag_get_id(parent)),
@@ -763,7 +763,7 @@ svn_fs_base__dag_clone_child(dag_node_t 
       noderev->predecessor_id = cur_entry->id;
       if (noderev->predecessor_count != -1)
         noderev->predecessor_count++;
-      noderev->created_path = svn_uri_join(parent_path, name, pool);
+      noderev->created_path = svn_fspath__join(parent_path, name, pool);
       SVN_ERR(svn_fs_base__create_successor(&new_node_id, fs, cur_entry->id,
                                             noderev, copy_id, txn_id,
                                             trail, pool));
@@ -1422,7 +1422,7 @@ svn_fs_base__dag_copy(dag_node_t *to_nod
       noderev->predecessor_id = svn_fs_base__id_copy(src_id, pool);
       if (noderev->predecessor_count != -1)
         noderev->predecessor_count++;
-      noderev->created_path = svn_uri_join
+      noderev->created_path = svn_fspath__join
         (svn_fs_base__dag_get_created_path(to_node), entry, pool);
       SVN_ERR(svn_fs_base__create_successor(&id, fs, src_id, noderev,
                                             copy_id, txn_id, trail, pool));

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/fs.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/fs.c Sat Dec 11 00:15:55 2010
@@ -497,6 +497,7 @@ static fs_vtable_t fs_vtable = {
   svn_fs_base__get_lock,
   svn_fs_base__get_locks,
   base_bdb_set_errcall,
+  svn_fs_base__validate_mergeinfo,
 };
 
 /* Where the format number is stored. */

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/lock.c Sat Dec 11 00:15:55 2010
@@ -250,7 +250,7 @@ svn_fs_base__generate_lock_token(const c
      generate a URI that matches the DAV RFC.  We could change this to
      some other URI scheme someday, if we wish. */
   *token = apr_pstrcat(pool, "opaquelocktoken:",
-                       svn_uuid_generate(pool), NULL);
+                       svn_uuid_generate(pool), (char *)NULL);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/reps-strings.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/reps-strings.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/reps-strings.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/reps-strings.c Sat Dec 11 00:15:55 2010
@@ -906,10 +906,12 @@ txn_body_read_rep(void *baton, trail_t *
             {
               representation_t *rep;
 
-              svn_checksum_final(&args->rb->md5_checksum,
-                                 args->rb->md5_checksum_ctx, trail->pool);
-              svn_checksum_final(&args->rb->sha1_checksum,
-                                 args->rb->sha1_checksum_ctx, trail->pool);
+              SVN_ERR(svn_checksum_final(&args->rb->md5_checksum,
+                                         args->rb->md5_checksum_ctx,
+                                         trail->pool));
+              SVN_ERR(svn_checksum_final(&args->rb->sha1_checksum,
+                                         args->rb->sha1_checksum_ctx,
+                                         trail->pool));
               args->rb->checksum_finalized = TRUE;
 
               SVN_ERR(svn_fs_bdb__read_rep(&rep, args->rb->fs,

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/revs-txns.c Sat Dec 11 00:15:55 2010
@@ -1159,7 +1159,6 @@ svn_fs_base__purge_txn(svn_fs_t *fs,
 {
   struct cleanup_txn_args args;
   transaction_t *txn;
-  int i;
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
@@ -1182,6 +1181,8 @@ svn_fs_base__purge_txn(svn_fs_t *fs,
   /* Kill the transaction's copies (which should gracefully...). */
   if (txn->copies)
     {
+      int i;
+
       for (i = 0; i < txn->copies->nelts; i++)
         {
           SVN_ERR(svn_fs_base__retry_txn

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/tree.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_fs_base/tree.c Sat Dec 11 00:15:55 2010
@@ -486,7 +486,7 @@ parent_path_path(parent_path_t *parent_p
   if (parent_path->parent)
     path_so_far = parent_path_path(parent_path->parent, pool);
   return parent_path->entry
-    ? svn_uri_join(path_so_far, parent_path->entry, pool)
+    ? svn_fspath__join(path_so_far, parent_path->entry, pool)
          : path_so_far;
 }
 
@@ -693,7 +693,7 @@ open_path(parent_path_t **parent_path_p,
       entry = svn_fs__next_entry_name(&next, rest, pool);
 
       /* Calculate the path traversed thus far. */
-      path_so_far = svn_uri_join(path_so_far, entry, pool);
+      path_so_far = svn_fspath__join(path_so_far, entry, pool);
 
       if (*entry == '\0')
         {
@@ -1727,7 +1727,7 @@ deltify_mutable(svn_fs_t *fs,
           apr_hash_this(hi, &key, NULL, &val);
           entry = val;
           SVN_ERR(deltify_mutable(fs, root,
-                                  svn_uri_join(path, key, subpool),
+                                  svn_fspath__join(path, key, subpool),
                                   entry->id, entry->kind, txn_id, subpool));
         }
 
@@ -1775,7 +1775,7 @@ deltify_mutable(svn_fs_t *fs,
        For 1.6 and beyond, we just deltify the current node against its
        predecessors, using skip deltas similar to the way FSFS does.  */
 
-    int pred_count, nlevels, lev, count;
+    int pred_count;
     const svn_fs_id_t *pred_id;
     struct txn_pred_count_args tpc_args;
     apr_pool_t *subpools[2];
@@ -1861,6 +1861,8 @@ deltify_mutable(svn_fs_t *fs,
       }
     else
       {
+        int nlevels, lev, count;
+
         /**** REVERSE DELTA STORAGE ****/
 
         /* Decide how many predecessors to redeltify.  To save overhead,
@@ -2269,7 +2271,7 @@ merge(svn_stringbuf_t *conflict_p,
              a modification. In any of these cases, flag a conflict. */
           if (s_entry == NULL || t_entry == NULL)
             return conflict_err(conflict_p,
-                                svn_uri_join(target_path,
+                                svn_fspath__join(target_path,
                                                 a_entry->name,
                                                 iterpool));
 
@@ -2284,7 +2286,7 @@ merge(svn_stringbuf_t *conflict_p,
               || strcmp(svn_fs_base__id_copy_id(t_entry->id),
                         svn_fs_base__id_copy_id(a_entry->id)) != 0)
             return conflict_err(conflict_p,
-                                svn_uri_join(target_path,
+                                svn_fspath__join(target_path,
                                                 a_entry->name,
                                                 iterpool));
 
@@ -2301,14 +2303,14 @@ merge(svn_stringbuf_t *conflict_p,
               || (svn_fs_base__dag_node_kind(t_ent_node) == svn_node_file)
               || (svn_fs_base__dag_node_kind(a_ent_node) == svn_node_file))
             return conflict_err(conflict_p,
-                                svn_uri_join(target_path,
+                                svn_fspath__join(target_path,
                                                 a_entry->name,
                                                 iterpool));
 
           /* Direct modifications were made to the directory
              ANCESTOR-ENTRY in both SOURCE and TARGET.  Recursively
              merge these modifications. */
-          new_tpath = svn_uri_join(target_path, t_entry->name, iterpool);
+          new_tpath = svn_fspath__join(target_path, t_entry->name, iterpool);
           SVN_ERR(merge(conflict_p, new_tpath,
                         t_ent_node, s_ent_node, a_ent_node,
                         txn_id, &sub_mergeinfo_increment, trail, iterpool));
@@ -2344,7 +2346,7 @@ merge(svn_stringbuf_t *conflict_p,
       /* If NAME exists in TARGET, declare a conflict. */
       if (t_entry)
         return conflict_err(conflict_p,
-                            svn_uri_join(target_path,
+                            svn_fspath__join(target_path,
                                             t_entry->name,
                                             iterpool));
 
@@ -2520,7 +2522,7 @@ verify_locks(const char *txn_name,
       /* If this path has already been verified as part of a recursive
          check of one of its parents, no need to do it again.  */
       if (last_recursed
-          && svn_uri_is_child(last_recursed->data, path, subpool))
+          && svn_fspath__is_child(last_recursed->data, path, subpool))
         continue;
 
       /* Fetch the change associated with our path.  */
@@ -4486,7 +4488,7 @@ txn_body_history_prev(void *baton, trail
       if (strcmp(path, copy_dst) == 0)
         remainder = "";
       else
-        remainder = svn_uri_is_child(copy_dst, path, trail->pool);
+        remainder = svn_fspath__is_child(copy_dst, path, trail->pool);
 
       if (remainder)
         {
@@ -4499,7 +4501,7 @@ txn_body_history_prev(void *baton, trail
                   (&dst_rev, fs,
                    svn_fs_base__id_txn_id(copy->dst_noderev_id),
                    trail, trail->pool));
-          src_path = svn_uri_join(copy->src_path, remainder,
+          src_path = svn_fspath__join(copy->src_path, remainder,
                                      trail->pool);
           if (copy->kind == copy_kind_soft)
             retry = TRUE;
@@ -4909,8 +4911,8 @@ prev_location(const char **prev_path,
   SVN_ERR(base_copied_from(&copy_src_rev, &copy_src_path,
                            copy_root, copy_path, pool));
   if (! strcmp(copy_path, path) == 0)
-    remainder = svn_uri_is_child(copy_path, path, pool);
-  *prev_path = svn_uri_join(copy_src_path, remainder, pool);
+    remainder = svn_fspath__is_child(copy_path, path, pool);
+  *prev_path = svn_fspath__join(copy_src_path, remainder, pool);
   *prev_rev = copy_src_rev;
   return SVN_NO_ERROR;
 }
@@ -5088,6 +5090,129 @@ base_node_origin_rev(svn_revnum_t *revis
 
 /* Mergeinfo Queries */
 
+
+/* Implements svn_fs_validate_mergeinfo. */
+svn_error_t *
+svn_fs_base__validate_mergeinfo(svn_mergeinfo_t *validated_mergeinfo,
+                                svn_fs_t *fs,
+                                svn_mergeinfo_t mergeinfo,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+  svn_mergeinfo_t filtered_mergeinfo;
+  apr_hash_t *rev_to_sources;
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
+
+  /* A couple easy outs. */
+  if (mergeinfo == NULL)
+    {
+      *validated_mergeinfo = NULL;
+      return SVN_NO_ERROR;
+    }
+  else if (apr_hash_count(mergeinfo) == 0)
+    {
+      *validated_mergeinfo = apr_hash_make(result_pool);
+      return SVN_NO_ERROR;
+    }
+
+  filtered_mergeinfo = apr_hash_make(scratch_pool);
+  rev_to_sources = apr_hash_make(scratch_pool);
+
+  /* Since svn_fs_check_path needs an svn_fs_root_t based on a revision,
+     we convert MERGEINFO into a mapping of revisions to a hash of source
+     paths for efficiency. */
+  for (hi = apr_hash_first(scratch_pool, mergeinfo);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path = svn__apr_hash_index_key(hi);
+      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+      int i;
+
+      for (i = 0; i < rangelist->nelts; i++)
+        {
+          svn_merge_range_t *range =
+            APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+          svn_revnum_t j;
+
+          for (j = range->start + 1; j <= range->end; j++)
+            {
+              apr_hash_t *paths_for_rev =
+                apr_hash_get(rev_to_sources, &j, sizeof(svn_revnum_t));
+
+              /* No hash associated with this rev yet? */
+              if (!paths_for_rev)
+                {
+                  svn_revnum_t *rev = apr_palloc(scratch_pool, sizeof(*rev));
+
+                  *rev = j;
+                  paths_for_rev = apr_hash_make(scratch_pool);
+                  apr_hash_set(rev_to_sources, rev,
+                               sizeof(svn_revnum_t), paths_for_rev);
+                }
+
+              apr_hash_set(paths_for_rev, path, APR_HASH_KEY_STRING, path);
+            }
+        }
+    }
+
+  iterpool = svn_pool_create(scratch_pool);
+
+  /* Validate the rev->source MERGEINFO equivalent hash, building the
+     validated mergeinfo as we go. */
+  for (hi = apr_hash_first(scratch_pool, rev_to_sources);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const svn_revnum_t *rev = svn__apr_hash_index_key(hi);
+      apr_hash_t *paths = svn__apr_hash_index_val(hi);
+      apr_pool_t *inner_iterpool;
+      apr_hash_index_t *hi2;
+      svn_node_kind_t kind;
+      svn_fs_root_t *mergeinfo_rev_root;
+
+      svn_pool_clear(iterpool);
+      inner_iterpool = svn_pool_create(iterpool);
+
+      SVN_ERR(svn_fs_base__revision_root(&mergeinfo_rev_root, fs,
+                                         *rev, iterpool));
+
+       for (hi2 = apr_hash_first(iterpool, paths);
+            hi2;
+            hi2 = apr_hash_next(hi2))
+         {
+            const char *path = svn__apr_hash_index_key(hi2);
+ 
+            svn_pool_clear(inner_iterpool);
+            SVN_ERR(base_check_path(&kind, mergeinfo_rev_root,
+                                    path, inner_iterpool));
+            if (kind == svn_node_none)
+              {
+                apr_hash_set(paths, path, APR_HASH_KEY_STRING, NULL);
+              }
+            else
+              {
+                svn_mergeinfo_t good_mergeinfo_fragment;
+                const char *mergeinfo_str =
+                  apr_psprintf(inner_iterpool, "%s:%ld", path, *rev);
+
+                SVN_ERR(svn_mergeinfo_parse(&good_mergeinfo_fragment,
+                                            mergeinfo_str, scratch_pool));
+                SVN_ERR(svn_mergeinfo_merge(filtered_mergeinfo,
+                                            good_mergeinfo_fragment,
+                                            scratch_pool));
+              }
+         }
+      svn_pool_destroy(inner_iterpool);
+    }
+
+  svn_pool_destroy(iterpool);
+  *validated_mergeinfo = svn_mergeinfo_dup(filtered_mergeinfo, result_pool);
+  return SVN_NO_ERROR;
+}
+
+
 /* Examine directory NODE's immediately children for mergeinfo.
 
    For those which have explicit mergeinfo, add their mergeinfo to
@@ -5171,7 +5296,7 @@ txn_body_get_mergeinfo_data_and_entries(
           SVN_ERR(svn_mergeinfo_parse(&child_mergeinfo, pval->data,
                                       result_pool));
           apr_hash_set(args->result_catalog,
-                       svn_uri_join(args->node_path, dirent->name,
+                       svn_fspath__join(args->node_path, dirent->name,
                                        result_pool),
                        APR_HASH_KEY_STRING,
                        child_mergeinfo);
@@ -5240,9 +5365,10 @@ crawl_directory_for_mergeinfo(svn_fs_t *
       void *val;
       svn_pool_clear(iterpool);
       apr_hash_this(hi, &key, NULL, &val);
-      crawl_directory_for_mergeinfo(fs, val,
-                                    svn_uri_join(node_path, key, iterpool),
-                                    result_catalog, iterpool);
+      SVN_ERR(crawl_directory_for_mergeinfo(fs, val,
+                                            svn_fspath__join(node_path, key,
+                                                             iterpool),
+                                            result_catalog, iterpool));
     }
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
@@ -5267,7 +5393,7 @@ append_to_merged_froms(svn_mergeinfo_t *
       const void *key;
       void *val;
       apr_hash_this(hi, &key, NULL, &val);
-      apr_hash_set(*output, svn_uri_join(key, rel_path, pool),
+      apr_hash_set(*output, svn_fspath__join(key, rel_path, pool),
                    APR_HASH_KEY_STRING, svn_rangelist_dup(val, pool));
     }
   return SVN_NO_ERROR;
@@ -5276,12 +5402,14 @@ append_to_merged_froms(svn_mergeinfo_t *
 
 /* Calculate the mergeinfo for PATH under revision ROOT using
    inheritance type INHERIT.  Set *MERGEINFO to the mergeinfo, or to
-   NULL if there is none.  Results are allocated in POOL; TRAIL->pool
+   NULL if there is none.  If *MERGEINFO is inherited set *INHERITED
+   to true, false otherwise.  Results are allocated in POOL; TRAIL->POOL
    is used for temporary allocations.  */
 
 struct get_mergeinfo_for_path_baton
 {
   svn_mergeinfo_t *mergeinfo;
+  svn_boolean_t *inherited;
   svn_fs_root_t *root;
   const char *path;
   svn_mergeinfo_inheritance_t inherit;
@@ -5299,6 +5427,7 @@ txn_body_get_mergeinfo_for_path(void *ba
   dag_node_t *node = NULL;
 
   *(args->mergeinfo) = NULL;
+  *(args->inherited) = FALSE;
 
   SVN_ERR(open_path(&parent_path, args->root, args->path, 0,
                     NULL, trail, trail->pool));
@@ -5380,6 +5509,7 @@ txn_body_get_mergeinfo_for_path(void *ba
                                                          nearest_ancestor,
                                                          trail->pool),
                                      args->pool));
+      *(args->inherited) = TRUE;
     }
   return SVN_NO_ERROR;
 }
@@ -5411,14 +5541,17 @@ txn_body_get_node_mergeinfo_stats(void *
 }
 
 
-/* Get the mergeinfo for a set of paths, returned in
-   *MERGEINFO_CATALOG.  Returned values are allocated in POOL, while
-   temporary values are allocated in a sub-pool. */
+/* Get the mergeinfo for a set of paths, returned in *MERGEINFO_CATALOG.
+   If the mergeinfo for any path is inherited and VALIDATE_INHERITED_MERGEINFO
+   is true, then the mergeinfo for that path in *MERGEINFO_CATALOG will only
+   contain path-revs that actually exist in repository.  Returned values are
+   allocated in POOL, while temporary values are allocated in a sub-pool. */
 static svn_error_t *
 get_mergeinfos_for_paths(svn_fs_root_t *root,
                          svn_mergeinfo_catalog_t *mergeinfo_catalog,
                          const apr_array_header_t *paths,
                          svn_mergeinfo_inheritance_t inherit,
+                         svn_boolean_t validate_inherited_mergeinfo,
                          svn_boolean_t include_descendants,
                          apr_pool_t *pool)
 {
@@ -5429,6 +5562,7 @@ get_mergeinfos_for_paths(svn_fs_root_t *
   for (i = 0; i < paths->nelts; i++)
     {
       svn_mergeinfo_t path_mergeinfo;
+      svn_boolean_t inherited;
       struct get_mergeinfo_for_path_baton gmfp_args;
       const char *path = APR_ARRAY_IDX(paths, i, const char *);
 
@@ -5438,6 +5572,7 @@ get_mergeinfos_for_paths(svn_fs_root_t *
 
       /* Get the mergeinfo for PATH itself. */
       gmfp_args.mergeinfo = &path_mergeinfo;
+      gmfp_args.inherited = &inherited;
       gmfp_args.root = root;
       gmfp_args.path = path;
       gmfp_args.inherit = inherit;
@@ -5446,9 +5581,16 @@ get_mergeinfos_for_paths(svn_fs_root_t *
                                      txn_body_get_mergeinfo_for_path,
                                      &gmfp_args, FALSE, iterpool));
       if (path_mergeinfo)
-        apr_hash_set(result_catalog, apr_pstrdup(pool, path),
-                     APR_HASH_KEY_STRING,
-                     path_mergeinfo);
+        {
+          if (inherited && validate_inherited_mergeinfo)
+            SVN_ERR(svn_fs_base__validate_mergeinfo(&path_mergeinfo, root->fs,
+                                                    path_mergeinfo, pool,
+                                                    iterpool));
+
+          apr_hash_set(result_catalog, apr_pstrdup(pool, path),
+                       APR_HASH_KEY_STRING,
+                       path_mergeinfo);
+        }
 
       /* If we're including descendants, do so. */
       if (include_descendants)
@@ -5491,6 +5633,7 @@ base_get_mergeinfo(svn_mergeinfo_catalog
                    svn_fs_root_t *root,
                    const apr_array_header_t *paths,
                    svn_mergeinfo_inheritance_t inherit,
+                   svn_boolean_t validate_inherited_mergeinfo,
                    svn_boolean_t include_descendants,
                    apr_pool_t *pool)
 {
@@ -5504,10 +5647,11 @@ base_get_mergeinfo(svn_mergeinfo_catalog
 
   /* Retrieve a path -> mergeinfo mapping. */
   return get_mergeinfos_for_paths(root, catalog, paths,
-                                  inherit, include_descendants,
-                                  pool);
+                                  inherit, validate_inherited_mergeinfo,
+                                  include_descendants, pool);
 }
 
+
 
 /* Creating root objects.  */