You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC

svn commit: r1717223 [12/50] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/...

Modified: subversion/branches/ra-git/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/ra.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/ra.c Mon Nov 30 10:24:16 2015
@@ -758,7 +758,7 @@ repos_locations(const char **start_url,
   /* We'd better have all the paths we were looking for! */
   if (start_url)
     {
-      start_path = apr_hash_get(rev_locs, &start_revnum, sizeof(svn_revnum_t));
+      start_path = apr_hash_get(rev_locs, &start_revnum, sizeof(start_revnum));
       if (! start_path)
         return svn_error_createf
           (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
@@ -770,7 +770,7 @@ repos_locations(const char **start_url,
 
   if (end_url)
     {
-      end_path = apr_hash_get(rev_locs, &end_revnum, sizeof(svn_revnum_t));
+      end_path = apr_hash_get(rev_locs, &end_revnum, sizeof(end_revnum));
       if (! end_path)
         return svn_error_createf
           (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,

Modified: subversion/branches/ra-git/subversion/libsvn_client/resolved.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/resolved.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/resolved.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/resolved.c Mon Nov 30 10:24:16 2015
@@ -41,6 +41,9 @@
 #include "private/svn_wc_private.h"
 
 #include "svn_private_config.h"
+
+#define ARRAY_LEN(ary) ((sizeof (ary)) / (sizeof ((ary)[0])))
+
 
 /*** Code. ***/
 
@@ -144,3 +147,1040 @@ svn_client_resolve(const char *path,
 
   return svn_error_trace(err);
 }
+
+
+/*** Dealing with conflicts. ***/
+
+struct svn_client_conflict_t
+{
+  const char *local_abspath;
+  svn_client_ctx_t *ctx;
+  apr_hash_t *prop_conflicts;
+
+  /* Indicate which options were chosen to resolve a text or tree conflict
+   * on the conflited node. */
+  svn_client_conflict_option_id_t resolution_text;
+  svn_client_conflict_option_id_t resolution_tree;
+
+  /* A mapping from const char* property name to pointers to
+   * svn_client_conflict_option_t for all properties which had their
+   * conflicts resolved. Indicates which options were chosen to resolve
+   * the property conflicts. */
+  apr_hash_t *resolved_props;
+
+  /* For backwards compat. */
+  const svn_wc_conflict_description2_t *legacy_text_conflict;
+  const svn_wc_conflict_description2_t *legacy_prop_conflict;
+  const svn_wc_conflict_description2_t *legacy_tree_conflict;
+};
+
+/* Resolves conflict to OPTION and sets CONFLICT->RESOLUTION accordingly. */
+typedef svn_error_t *(*conflict_option_resolve_func_t)(
+  svn_client_conflict_option_t *option,
+  svn_client_conflict_t *conflict,
+  apr_pool_t *scratch_pool);
+
+struct svn_client_conflict_option_t
+{
+  svn_client_conflict_option_id_t id;
+  const char *description;
+
+  svn_client_conflict_t *conflict;
+  conflict_option_resolve_func_t do_resolve_func;
+
+  /* Data which is specific to particular conflicts and options. */
+  union {
+    struct {
+      /* Indicates the property to resolve in case of a property conflict.
+       * If set to "", all properties are resolved to this option. */
+      const char *propname;
+
+      /* A merged property value, if supplied by the API user, else NULL. */
+      const svn_string_t *merged_propval;
+    } prop;
+  } type_data;
+
+};
+
+/*
+ * Return a legacy conflict choice corresponding to OPTION_ID.
+ * Return svn_wc_conflict_choose_undefined if no corresponding
+ * legacy conflict choice exists.
+ */
+static svn_wc_conflict_choice_t
+conflict_option_id_to_wc_conflict_choice(
+  svn_client_conflict_option_id_t option_id)
+{
+
+  switch (option_id)
+    {
+      case svn_client_conflict_option_undefined:
+        return svn_wc_conflict_choose_undefined;
+
+      case svn_client_conflict_option_postpone:
+        return svn_wc_conflict_choose_postpone;
+
+      case svn_client_conflict_option_base_text:
+        return svn_wc_conflict_choose_base;
+
+      case svn_client_conflict_option_incoming_text:
+        return svn_wc_conflict_choose_theirs_full;
+
+      case svn_client_conflict_option_working_text:
+        return svn_wc_conflict_choose_mine_full;
+
+      case svn_client_conflict_option_incoming_text_where_conflicted:
+        return svn_wc_conflict_choose_theirs_conflict;
+
+      case svn_client_conflict_option_working_text_where_conflicted:
+        return svn_wc_conflict_choose_mine_conflict;
+
+      case svn_client_conflict_option_merged_text:
+        return svn_wc_conflict_choose_merged;
+
+      case svn_client_conflict_option_unspecified:
+        return svn_wc_conflict_choose_unspecified;
+
+      default:
+        break;
+    }
+
+  return svn_wc_conflict_choose_undefined;
+}
+
+static void
+add_legacy_desc_to_conflict(const svn_wc_conflict_description2_t *desc,
+                            svn_client_conflict_t *conflict,
+                            apr_pool_t *result_pool)
+{
+  switch (desc->kind)
+    {
+      case svn_wc_conflict_kind_text:
+        conflict->legacy_text_conflict = desc;
+        break;
+
+      case svn_wc_conflict_kind_property:
+        conflict->legacy_prop_conflict = desc;
+        break;
+
+      case svn_wc_conflict_kind_tree:
+        conflict->legacy_tree_conflict = desc;
+        break;
+
+      default:
+        SVN_ERR_ASSERT_NO_RETURN(FALSE); /* unknown kind of conflict */
+    }
+}
+
+/* Set up a conflict object. If legacy conflict descriptor DESC is not NULL,
+ * set up the conflict object for backwards compatibility. */
+static svn_error_t *
+conflict_get_internal(svn_client_conflict_t **conflict,
+                      const char *local_abspath,
+                      const svn_wc_conflict_description2_t *desc,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  const apr_array_header_t *descs;
+  int i;
+
+  *conflict = apr_pcalloc(result_pool, sizeof(**conflict));
+
+  if (desc)
+    {
+      /* Add a single legacy conflict descriptor. */
+      (*conflict)->local_abspath = desc->local_abspath;
+      (*conflict)->resolution_text = svn_client_conflict_option_undefined;
+      (*conflict)->resolution_tree = svn_client_conflict_option_undefined;
+      (*conflict)->resolved_props = apr_hash_make(result_pool);
+      add_legacy_desc_to_conflict(desc, *conflict, result_pool);
+
+      return SVN_NO_ERROR;
+    }
+
+  (*conflict)->local_abspath = apr_pstrdup(result_pool, local_abspath);
+  (*conflict)->resolution_text = svn_client_conflict_option_undefined;
+  (*conflict)->resolution_tree = svn_client_conflict_option_undefined;
+  (*conflict)->resolved_props = apr_hash_make(result_pool);
+  (*conflict)->ctx = ctx;
+
+  /* Add all legacy conflict descriptors we can find. Eventually, this code
+   * path should stop relying on svn_wc_conflict_description2_t entirely. */
+  SVN_ERR(svn_wc__read_conflict_descriptions2_t(&descs, ctx->wc_ctx,
+                                                local_abspath,
+                                                result_pool, scratch_pool));
+  for (i = 0; i < descs->nelts; i++)
+    {
+      desc = APR_ARRAY_IDX(descs, i, const svn_wc_conflict_description2_t *);
+      if (desc->kind == svn_wc_conflict_kind_property)
+        {
+          if ((*conflict)->prop_conflicts == NULL)
+            (*conflict)->prop_conflicts = apr_hash_make(result_pool);
+          svn_hash_sets((*conflict)->prop_conflicts, desc->property_name, desc);
+        }
+      add_legacy_desc_to_conflict(desc, *conflict, result_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_get(svn_client_conflict_t **conflict,
+                        const char *local_abspath,
+                        svn_client_ctx_t *ctx,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(conflict_get_internal(conflict, local_abspath, NULL,
+                                               ctx, result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_client_conflict_from_wc_description2_t(
+  svn_client_conflict_t **conflict,
+  const svn_wc_conflict_description2_t *desc,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(conflict_get_internal(conflict, NULL, desc, NULL,
+                                               result_pool, scratch_pool));
+}
+
+void
+svn_client_conflict_option_set_merged_propval(
+  svn_client_conflict_option_t *option,
+  const svn_string_t *merged_propval)
+{
+  option->type_data.prop.merged_propval = merged_propval;
+}
+
+/* 
+ * Resolve the conflict at LOCAL_ABSPATH. Currently only supports
+ * an OPTION_ID which can be mapped to svn_wc_conflict_choice_t and
+ * maps a single option_id to text, prop, and/or tree conflicts.
+ */
+static svn_error_t *
+resolve_conflict(svn_client_conflict_option_id_t option_id,
+                 const char *local_abspath,
+                 svn_boolean_t resolve_text,
+                 const char * resolve_prop,
+                 svn_boolean_t resolve_tree,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *scratch_pool)
+{
+  svn_wc_conflict_choice_t conflict_choice;
+  const char *lock_abspath;
+  svn_error_t *err;
+
+  conflict_choice = conflict_option_id_to_wc_conflict_choice(option_id);
+  SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, ctx->wc_ctx,
+                                                 local_abspath,
+                                                 scratch_pool, scratch_pool));
+  err = svn_wc__resolve_conflicts(ctx->wc_ctx, local_abspath,
+                                  svn_depth_empty,
+                                  resolve_text, resolve_prop, resolve_tree,
+                                  conflict_choice,
+                                  NULL, NULL, /* legacy conflict_func/baton */
+                                  ctx->cancel_func,
+                                  ctx->cancel_baton,
+                                  ctx->notify_func2,
+                                  ctx->notify_baton2,
+                                  scratch_pool);
+  err = svn_error_compose_create(err, svn_wc__release_write_lock(ctx->wc_ctx,
+                                                                 lock_abspath,
+                                                                 scratch_pool));
+  svn_io_sleep_for_timestamps(local_abspath, scratch_pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements conflict_option_resolve_func_t. */
+static svn_error_t *
+resolve_text_conflict(svn_client_conflict_option_t *option,
+                      svn_client_conflict_t *conflict,
+                      apr_pool_t *scratch_pool)
+{
+  svn_client_conflict_option_id_t option_id;
+  const char *local_abspath;
+
+  option_id = svn_client_conflict_option_get_id(option);
+  local_abspath = svn_client_conflict_get_local_abspath(conflict);
+  SVN_ERR(resolve_conflict(option_id, local_abspath, TRUE, NULL, FALSE,
+                           conflict->ctx, scratch_pool));
+  conflict->resolution_text = option_id;
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements conflict_option_resolve_func_t. */
+static svn_error_t *
+resolve_prop_conflict(svn_client_conflict_option_t *option,
+                      svn_client_conflict_t *conflict,
+                      apr_pool_t *scratch_pool)
+{
+  svn_client_conflict_option_id_t option_id;
+  const char *local_abspath;
+  const char *propname = option->type_data.prop.propname;
+
+  option_id = svn_client_conflict_option_get_id(option);
+  local_abspath = svn_client_conflict_get_local_abspath(conflict);
+  SVN_ERR(resolve_conflict(option_id, local_abspath,
+                           FALSE, propname, FALSE,
+                           conflict->ctx, scratch_pool));
+
+  if (propname[0] == '\0')
+    {
+      apr_hash_index_t *hi;
+
+      /* All properties have been resolved to the same option. */
+      for (hi = apr_hash_first(scratch_pool, conflict->prop_conflicts);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *this_propname = apr_hash_this_key(hi);
+
+          svn_hash_sets(conflict->resolved_props,
+                        apr_pstrdup(apr_hash_pool_get(conflict->resolved_props),
+                                    this_propname),
+                        option);
+          svn_hash_sets(conflict->prop_conflicts, this_propname, NULL);
+        }
+    }
+  else
+    {
+      svn_hash_sets(conflict->resolved_props,
+                    apr_pstrdup(apr_hash_pool_get(conflict->resolved_props),
+                                propname),
+                   option);
+      svn_hash_sets(conflict->prop_conflicts, propname, NULL);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+/* Implements conflict_option_resolve_func_t. */
+resolve_tree_conflict(svn_client_conflict_option_t *option,
+                      svn_client_conflict_t *conflict,
+                      apr_pool_t *scratch_pool)
+{
+  svn_client_conflict_option_id_t option_id;
+  const char *local_abspath;
+
+  option_id = svn_client_conflict_option_get_id(option);
+  local_abspath = svn_client_conflict_get_local_abspath(conflict);
+  SVN_ERR(resolve_conflict(option_id, local_abspath, FALSE, NULL, TRUE,
+                           conflict->ctx, scratch_pool));
+  conflict->resolution_tree = option_id;
+
+  return SVN_NO_ERROR;
+}
+
+/* Resolver options for a text conflict */
+static const svn_client_conflict_option_t text_conflict_options[] =
+{
+  {
+    svn_client_conflict_option_postpone,
+    N_("mark the conflict to be resolved later"),
+    NULL,
+    resolve_text_conflict
+  },
+
+  {
+    svn_client_conflict_option_incoming_text,
+    N_("accept incoming version of entire file"),
+    NULL,
+    resolve_text_conflict
+  },
+
+  {
+    svn_client_conflict_option_working_text,
+    N_("accept working copy version of entire file"),
+    NULL,
+    resolve_text_conflict
+  },
+
+  {
+    svn_client_conflict_option_incoming_text_where_conflicted,
+    N_("accept incoming version of all text conflicts in file"),
+    NULL,
+    resolve_text_conflict
+  },
+
+  {
+    svn_client_conflict_option_working_text_where_conflicted,
+    N_("accept working copy version of all text conflicts in file"),
+    NULL,
+    resolve_text_conflict
+  },
+
+};
+
+/* Resolver options for a binary file conflict */
+static const svn_client_conflict_option_t binary_conflict_options[] =
+{
+  {
+    svn_client_conflict_option_postpone,
+    N_("mark the conflict to be resolved later"),
+    NULL,
+    resolve_text_conflict,
+  },
+
+  {
+    svn_client_conflict_option_incoming_text,
+    N_("accept incoming version of binary file"),
+    NULL,
+    resolve_text_conflict
+  },
+
+  {
+    svn_client_conflict_option_working_text,
+    N_("accept working copy version of binary file"),
+    NULL,
+    resolve_text_conflict
+  },
+
+};
+
+/* Resolver options for a property conflict */
+static const svn_client_conflict_option_t prop_conflict_options[] =
+{
+  {
+    svn_client_conflict_option_postpone,
+    N_("mark the conflict to be resolved later"),
+    NULL,
+    resolve_prop_conflict
+  },
+
+  {
+    svn_client_conflict_option_incoming_text,
+    N_("accept incoming version of entire property value"),
+    NULL,
+    resolve_prop_conflict
+  },
+
+  {
+    svn_client_conflict_option_working_text,
+    N_("accept working copy version of entire property value"),
+    NULL,
+    resolve_prop_conflict
+  },
+
+};
+
+/* Resolver options for a tree conflict */
+static const svn_client_conflict_option_t tree_conflict_options[] =
+{
+  {
+    svn_client_conflict_option_postpone,
+    N_("mark the conflict to be resolved later"),
+    NULL,
+    resolve_tree_conflict
+  },
+
+  {
+    /* ### Use 'working text' for now since libsvn_wc does not know another
+     * ### choice to resolve to working yet. */
+    svn_client_conflict_option_working_text,
+    N_("accept current working copy state"),
+    NULL,
+    resolve_tree_conflict
+  },
+
+};
+
+static svn_error_t *
+assert_text_conflict(svn_client_conflict_t *conflict, apr_pool_t *scratch_pool)
+{
+  svn_boolean_t text_conflicted;
+
+  SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted, NULL, NULL,
+                                             conflict, scratch_pool,
+                                             scratch_pool));
+
+  SVN_ERR_ASSERT(text_conflicted); /* ### return proper error? */
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+assert_prop_conflict(svn_client_conflict_t *conflict, apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *props_conflicted;
+
+  SVN_ERR(svn_client_conflict_get_conflicted(NULL, &props_conflicted, NULL,
+                                             conflict, scratch_pool,
+                                             scratch_pool));
+
+  /* ### return proper error? */
+  SVN_ERR_ASSERT(props_conflicted && props_conflicted->nelts > 0);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+assert_tree_conflict(svn_client_conflict_t *conflict, apr_pool_t *scratch_pool)
+{
+  svn_boolean_t tree_conflicted;
+
+  SVN_ERR(svn_client_conflict_get_conflicted(NULL, NULL, &tree_conflicted,
+                                             conflict, scratch_pool,
+                                             scratch_pool));
+
+  SVN_ERR_ASSERT(tree_conflicted); /* ### return proper error? */
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_text_get_resolution_options(apr_array_header_t **options,
+                                                svn_client_conflict_t *conflict,
+                                                apr_pool_t *result_pool,
+                                                apr_pool_t *scratch_pool)
+{
+  const char *mime_type;
+  int i;
+
+  SVN_ERR(assert_text_conflict(conflict, scratch_pool));
+
+  *options = apr_array_make(result_pool, ARRAY_LEN(text_conflict_options),
+                            sizeof(svn_client_conflict_option_t *));
+
+  mime_type = svn_client_conflict_text_get_mime_type(conflict);
+  if (mime_type && svn_mime_type_is_binary(mime_type))
+    {
+      for (i = 0; i < ARRAY_LEN(binary_conflict_options); i++)
+        {
+          APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) =
+            &binary_conflict_options[i];
+        }
+    }
+  else
+    {
+      for (i = 0; i < ARRAY_LEN(text_conflict_options); i++)
+        {
+          APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) =
+            &text_conflict_options[i];
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_prop_get_resolution_options(apr_array_header_t **options,
+                                                svn_client_conflict_t *conflict,
+                                                apr_pool_t *result_pool,
+                                                apr_pool_t *scratch_pool)
+{
+  int i;
+
+  SVN_ERR(assert_prop_conflict(conflict, scratch_pool));
+
+  *options = apr_array_make(result_pool, ARRAY_LEN(prop_conflict_options),
+                            sizeof(svn_client_conflict_option_t *));
+  for (i = 0; i < ARRAY_LEN(prop_conflict_options); i++)
+    {
+      APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) =
+        &prop_conflict_options[i];
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_tree_get_resolution_options(apr_array_header_t **options,
+                                                svn_client_conflict_t *conflict,
+                                                apr_pool_t *result_pool,
+                                                apr_pool_t *scratch_pool)
+{
+  int i;
+
+  SVN_ERR(assert_tree_conflict(conflict, scratch_pool));
+
+  *options = apr_array_make(result_pool, ARRAY_LEN(tree_conflict_options),
+                            sizeof(svn_client_conflict_option_t *));
+  for (i = 0; i < ARRAY_LEN(tree_conflict_options); i++)
+    {
+      APR_ARRAY_PUSH((*options), const svn_client_conflict_option_t *) =
+        &tree_conflict_options[i];
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_client_conflict_option_id_t
+svn_client_conflict_option_get_id(svn_client_conflict_option_t *option)
+{
+  return option->id;
+}
+
+svn_error_t *
+svn_client_conflict_option_describe(const char **description,
+                                    svn_client_conflict_option_t *option,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool)
+{
+  *description = apr_pstrdup(result_pool, option->description);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_text_resolve(svn_client_conflict_t *conflict,
+                                 svn_client_conflict_option_t *option,
+                                 apr_pool_t *scratch_pool)
+{
+  SVN_ERR(assert_text_conflict(conflict, scratch_pool));
+  SVN_ERR(option->do_resolve_func(option, conflict, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_client_conflict_option_t *
+svn_client_conflict_option_find_by_id(apr_array_header_t *options,
+                                      svn_client_conflict_option_id_t option_id)
+{
+  int i;
+
+  for (i = 0; i < options->nelts; i++)
+    {
+      svn_client_conflict_option_t *this_option;
+      svn_client_conflict_option_id_t this_option_id;
+      
+      this_option = APR_ARRAY_IDX(options, i, svn_client_conflict_option_t *);
+      this_option_id = svn_client_conflict_option_get_id(this_option);
+
+      if (this_option_id == option_id)
+        return this_option;
+    }
+
+  return NULL;
+}
+
+svn_error_t *
+svn_client_conflict_text_resolve_by_id(
+  svn_client_conflict_t *conflict,
+  svn_client_conflict_option_id_t option_id,
+  apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *resolution_options;
+  svn_client_conflict_option_t *option;
+
+  SVN_ERR(svn_client_conflict_text_get_resolution_options(
+            &resolution_options, conflict,
+            scratch_pool, scratch_pool));
+  option = svn_client_conflict_option_find_by_id(resolution_options,
+                                                 option_id);
+  if (option == NULL)
+    return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+                               _("Inapplicable conflict resolution option "
+                                 "ID '%d' given for conflicted path '%s'"),
+                               option_id,
+                               svn_dirent_local_style(conflict->local_abspath,
+                                                      scratch_pool));
+  SVN_ERR(svn_client_conflict_text_resolve(conflict, option, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_client_conflict_option_id_t
+svn_client_conflict_text_get_resolution(const svn_client_conflict_t *conflict)
+{
+  return conflict->resolution_text;
+}
+
+svn_error_t *
+svn_client_conflict_prop_resolve(svn_client_conflict_t *conflict,
+                                 const char *propname,
+                                 svn_client_conflict_option_t *option,
+                                 apr_pool_t *scratch_pool)
+{
+  SVN_ERR(assert_prop_conflict(conflict, scratch_pool));
+  option->type_data.prop.propname = propname;
+  SVN_ERR(option->do_resolve_func(option, conflict, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_prop_resolve_by_id(
+  svn_client_conflict_t *conflict,
+  const char *propname,
+  svn_client_conflict_option_id_t option_id,
+  apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *resolution_options;
+  svn_client_conflict_option_t *option;
+
+  SVN_ERR(svn_client_conflict_prop_get_resolution_options(
+            &resolution_options, conflict,
+            scratch_pool, scratch_pool));
+  option = svn_client_conflict_option_find_by_id(resolution_options,
+                                                 option_id);
+  if (option == NULL)
+    return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+                               _("Inapplicable conflict resolution option "
+                                 "ID '%d' given for conflicted path '%s'"),
+                               option_id,
+                               svn_dirent_local_style(conflict->local_abspath,
+                                                      scratch_pool));
+  SVN_ERR(svn_client_conflict_prop_resolve(conflict, propname, option,
+                                           scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_client_conflict_option_id_t
+svn_client_conflict_prop_get_resolution(const svn_client_conflict_t *conflict,
+                                        const char *propname)
+{
+  svn_client_conflict_option_t *option;
+
+  option = svn_hash_gets(conflict->resolved_props, propname);
+  if (option == NULL)
+    return svn_client_conflict_option_undefined;
+
+  return svn_client_conflict_option_get_id(option);
+}
+
+svn_error_t *
+svn_client_conflict_tree_resolve(svn_client_conflict_t *conflict,
+                                 svn_client_conflict_option_t *option,
+                                 apr_pool_t *scratch_pool)
+{
+  SVN_ERR(assert_tree_conflict(conflict, scratch_pool));
+  SVN_ERR(option->do_resolve_func(option, conflict, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_tree_resolve_by_id(
+  svn_client_conflict_t *conflict,
+  svn_client_conflict_option_id_t option_id,
+  apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *resolution_options;
+  svn_client_conflict_option_t *option;
+
+  SVN_ERR(svn_client_conflict_tree_get_resolution_options(
+            &resolution_options, conflict,
+            scratch_pool, scratch_pool));
+  option = svn_client_conflict_option_find_by_id(resolution_options,
+                                                 option_id);
+  if (option == NULL)
+    return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+                               _("Inapplicable conflict resolution option "
+                                 "ID '%d' given for conflicted path '%s'"),
+                               option_id,
+                               svn_dirent_local_style(conflict->local_abspath,
+                                                      scratch_pool));
+  SVN_ERR(svn_client_conflict_tree_resolve(conflict, option, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_client_conflict_option_id_t
+svn_client_conflict_tree_get_resolution(const svn_client_conflict_t *conflict)
+{
+  return conflict->resolution_tree;
+}
+
+/* Return the legacy conflict descriptor which is wrapped by CONFLICT. */
+static const svn_wc_conflict_description2_t *
+get_conflict_desc2_t(const svn_client_conflict_t *conflict)
+{
+  if (conflict->legacy_text_conflict)
+    return conflict->legacy_text_conflict;
+
+  if (conflict->legacy_tree_conflict)
+    return conflict->legacy_tree_conflict;
+
+  if (conflict->legacy_prop_conflict)
+    return conflict->legacy_prop_conflict;
+
+  return NULL;
+}
+
+svn_wc_conflict_kind_t
+svn_client_conflict_get_kind(const svn_client_conflict_t *conflict)
+{
+  return get_conflict_desc2_t(conflict)->kind;
+}
+
+svn_error_t *
+svn_client_conflict_get_conflicted(svn_boolean_t *text_conflicted,
+                                   apr_array_header_t **props_conflicted,
+                                   svn_boolean_t *tree_conflicted,
+                                   svn_client_conflict_t *conflict,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool)
+{
+  if (text_conflicted)
+    *text_conflicted = (conflict->legacy_text_conflict != NULL);
+
+  if (props_conflicted)
+    {
+      if (conflict->legacy_prop_conflict)
+        {
+          *props_conflicted = apr_array_make(result_pool, 1,
+                                             sizeof(const char*));
+          APR_ARRAY_PUSH((*props_conflicted), const char *) =
+            conflict->legacy_prop_conflict->property_name;
+        }
+      else if (conflict->prop_conflicts)
+        SVN_ERR(svn_hash_keys(props_conflicted, conflict->prop_conflicts,
+                              result_pool));
+      else
+        *props_conflicted = NULL;
+    }
+
+  if (tree_conflicted)
+    *tree_conflicted = (conflict->legacy_tree_conflict != NULL);
+
+  return SVN_NO_ERROR;
+}
+
+const char *
+svn_client_conflict_get_local_abspath(const svn_client_conflict_t *conflict)
+{
+  return conflict->local_abspath;
+}
+
+svn_wc_operation_t
+svn_client_conflict_get_operation(const svn_client_conflict_t *conflict)
+{
+  return get_conflict_desc2_t(conflict)->operation;
+}
+
+svn_wc_conflict_action_t
+svn_client_conflict_get_incoming_change(const svn_client_conflict_t *conflict)
+{
+  return get_conflict_desc2_t(conflict)->action;
+}
+
+svn_wc_conflict_reason_t
+svn_client_conflict_get_local_change(const svn_client_conflict_t *conflict)
+{
+  return get_conflict_desc2_t(conflict)->reason;
+}
+
+svn_error_t *
+svn_client_conflict_get_repos_info(const char **repos_root_url,
+                                   const char **repos_uuid,
+                                   const svn_client_conflict_t *conflict,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool)
+{
+  if (repos_root_url)
+    {
+      if (get_conflict_desc2_t(conflict)->src_left_version)
+        *repos_root_url =
+          get_conflict_desc2_t(conflict)->src_left_version->repos_url;
+      else if (get_conflict_desc2_t(conflict)->src_right_version)
+        *repos_root_url =
+          get_conflict_desc2_t(conflict)->src_right_version->repos_url;
+      else
+        *repos_root_url = NULL;
+    }
+
+  if (repos_uuid)
+    {
+      if (get_conflict_desc2_t(conflict)->src_left_version)
+        *repos_uuid =
+          get_conflict_desc2_t(conflict)->src_left_version->repos_uuid;
+      else if (get_conflict_desc2_t(conflict)->src_right_version)
+        *repos_uuid =
+          get_conflict_desc2_t(conflict)->src_right_version->repos_uuid;
+      else
+        *repos_uuid = NULL;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_get_incoming_old_repos_location(
+  const char **incoming_old_repos_relpath,
+  svn_revnum_t *incoming_old_pegrev,
+  svn_node_kind_t *incoming_old_node_kind,
+  const svn_client_conflict_t *conflict,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool)
+{
+  if (incoming_old_repos_relpath)
+    {
+      if (get_conflict_desc2_t(conflict)->src_left_version)
+        *incoming_old_repos_relpath =
+          get_conflict_desc2_t(conflict)->src_left_version->path_in_repos;
+      else
+        *incoming_old_repos_relpath = NULL;
+    }
+
+  if (incoming_old_pegrev)
+    {
+      if (get_conflict_desc2_t(conflict)->src_left_version)
+        *incoming_old_pegrev =
+          get_conflict_desc2_t(conflict)->src_left_version->peg_rev;
+      else
+        *incoming_old_pegrev = SVN_INVALID_REVNUM;
+    }
+
+  if (incoming_old_node_kind)
+    {
+      if (get_conflict_desc2_t(conflict)->src_left_version)
+        *incoming_old_node_kind =
+          get_conflict_desc2_t(conflict)->src_left_version->node_kind;
+      else
+        *incoming_old_node_kind = svn_node_none;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_conflict_get_incoming_new_repos_location(
+  const char **incoming_new_repos_relpath,
+  svn_revnum_t *incoming_new_pegrev,
+  svn_node_kind_t *incoming_new_node_kind,
+  const svn_client_conflict_t *conflict,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool)
+{
+  if (incoming_new_repos_relpath)
+    {
+      if (get_conflict_desc2_t(conflict)->src_right_version)
+        *incoming_new_repos_relpath =
+          get_conflict_desc2_t(conflict)->src_right_version->path_in_repos;
+      else
+        *incoming_new_repos_relpath = NULL;
+    }
+
+  if (incoming_new_pegrev)
+    {
+      if (get_conflict_desc2_t(conflict)->src_right_version)
+        *incoming_new_pegrev =
+          get_conflict_desc2_t(conflict)->src_right_version->peg_rev;
+      else
+        *incoming_new_pegrev = SVN_INVALID_REVNUM;
+    }
+
+  if (incoming_new_node_kind)
+    {
+      if (get_conflict_desc2_t(conflict)->src_right_version)
+        *incoming_new_node_kind =
+          get_conflict_desc2_t(conflict)->src_right_version->node_kind;
+      else
+        *incoming_new_node_kind = svn_node_none;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_node_kind_t
+svn_client_conflict_tree_get_victim_node_kind(
+  const svn_client_conflict_t *conflict)
+{
+  SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict)
+      == svn_wc_conflict_kind_tree);
+
+  return get_conflict_desc2_t(conflict)->node_kind;
+}
+
+const char *
+svn_client_conflict_prop_get_propname(const svn_client_conflict_t *conflict)
+{
+  SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict)
+      == svn_wc_conflict_kind_property);
+
+  return get_conflict_desc2_t(conflict)->property_name;
+}
+
+svn_error_t *
+svn_client_conflict_prop_get_propvals(const svn_string_t **base_propval,
+                                      const svn_string_t **working_propval,
+                                      const svn_string_t **incoming_old_propval,
+                                      const svn_string_t **incoming_new_propval,
+                                      const svn_client_conflict_t *conflict,
+  apr_pool_t *result_pool)
+{
+  SVN_ERR_ASSERT(svn_client_conflict_get_kind(conflict) ==
+                 svn_wc_conflict_kind_property);
+
+  if (base_propval)
+    *base_propval =
+      svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_base,
+                     result_pool);
+
+  if (working_propval)
+    *working_propval =
+      svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_working,
+                     result_pool);
+
+  if (incoming_old_propval)
+    *incoming_old_propval =
+      svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_incoming_old,
+                     result_pool);
+
+  if (incoming_new_propval)
+    *incoming_new_propval =
+      svn_string_dup(get_conflict_desc2_t(conflict)->prop_value_incoming_new,
+                     result_pool);
+
+  return SVN_NO_ERROR;
+}
+
+const char *
+svn_client_conflict_prop_get_reject_abspath(
+  const svn_client_conflict_t *conflict)
+{
+  SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict)
+      == svn_wc_conflict_kind_property);
+
+  /* svn_wc_conflict_description2_t stores this path in 'their_abspath' */
+  return get_conflict_desc2_t(conflict)->their_abspath;
+}
+
+const char *
+svn_client_conflict_text_get_mime_type(const svn_client_conflict_t *conflict)
+{
+  SVN_ERR_ASSERT_NO_RETURN(svn_client_conflict_get_kind(conflict)
+      == svn_wc_conflict_kind_text);
+
+  return get_conflict_desc2_t(conflict)->mime_type;
+}
+
+svn_error_t *
+svn_client_conflict_text_get_contents(const char **base_abspath,
+                                      const char **working_abspath,
+                                      const char **incoming_old_abspath,
+                                      const char **incoming_new_abspath,
+                                      const svn_client_conflict_t *conflict,
+                                      apr_pool_t *result_pool,
+                                      apr_pool_t *scratch_pool)
+{
+  SVN_ERR_ASSERT(svn_client_conflict_get_kind(conflict)
+      == svn_wc_conflict_kind_text);
+
+  if (base_abspath)
+    {
+      if (svn_client_conflict_get_operation(conflict) ==
+          svn_wc_operation_merge)
+        *base_abspath = NULL; /* ### WC base contents not available yet */
+      else /* update/switch */
+        *base_abspath = get_conflict_desc2_t(conflict)->base_abspath;
+    }
+
+  if (working_abspath)
+    *working_abspath = get_conflict_desc2_t(conflict)->my_abspath;
+
+  if (incoming_old_abspath)
+    *incoming_old_abspath = get_conflict_desc2_t(conflict)->base_abspath;
+
+  if (incoming_new_abspath)
+    *incoming_new_abspath = get_conflict_desc2_t(conflict)->their_abspath;
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/ra-git/subversion/libsvn_client/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/upgrade.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/upgrade.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/upgrade.c Mon Nov 30 10:24:16 2015
@@ -83,11 +83,13 @@ fetch_repos_info(const char **repos_root
 }
 
 /* Forward definition. Upgrades svn:externals properties in the working copy
-   LOCAL_ABSPATH to the WC-NG  storage.
+   LOCAL_ABSPATH to the WC-NG  storage. INFO_BATON will be used to fetch
+   repository info using fetch_repos_info() function if needed.
  */
 static svn_error_t *
 upgrade_externals_from_properties(svn_client_ctx_t *ctx,
                                   const char *local_abspath,
+                                  struct repos_info_baton *info_baton,
                                   apr_pool_t *scratch_pool);
 
 svn_error_t *
@@ -172,14 +174,131 @@ svn_client_upgrade(const char *path,
          (There is no way to detect the difference from libsvn_client :( ) */
 
       SVN_ERR(upgrade_externals_from_properties(ctx, local_abspath,
-                                                scratch_pool));
+                                                &info_baton, scratch_pool));
     }
   return SVN_NO_ERROR;
 }
 
+/* Helper for upgrade_externals_from_properties: upgrades one external ITEM
+   in EXTERNALS_PARENT. Uses SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+upgrade_external_item(svn_client_ctx_t *ctx,
+                      const char *externals_parent_abspath,
+                      const char *externals_parent_url,
+                      const char *externals_parent_repos_root_url,
+                      svn_wc_external_item2_t *item,
+                      struct repos_info_baton *info_baton,
+                      apr_pool_t *scratch_pool)
+{
+  const char *resolved_url;
+  const char *external_abspath;
+  const char *repos_relpath;
+  const char *repos_root_url;
+  const char *repos_uuid;
+  svn_node_kind_t external_kind;
+  svn_revnum_t peg_revision;
+  svn_revnum_t revision;
+  svn_error_t *err;
+
+  external_abspath = svn_dirent_join(externals_parent_abspath,
+                                     item->target_dir,
+                                     scratch_pool);
+
+  SVN_ERR(svn_wc__resolve_relative_external_url(
+              &resolved_url,
+              item,
+              externals_parent_repos_root_url,
+              externals_parent_url,
+              scratch_pool, scratch_pool));
+
+  /* This is a hack. We only need to call svn_wc_upgrade() on external
+   * dirs, as file externals are upgraded along with their defining
+   * WC.  Reading the kind will throw an exception on an external dir,
+   * saying that the wc must be upgraded.  If it's a file, the lookup
+   * is done in an adm_dir belonging to the defining wc (which has
+   * already been upgraded) and no error is returned.  If it doesn't
+   * exist (external that isn't checked out yet), we'll just get
+   * svn_node_none. */
+  err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx,
+                          external_abspath, TRUE, FALSE, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
+    {
+      svn_error_clear(err);
+
+      SVN_ERR(svn_client_upgrade(external_abspath, ctx, scratch_pool));
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  /* The upgrade of any dir should be done now, get the now reliable
+   * kind. */
+  SVN_ERR(svn_wc_read_kind2(&external_kind, ctx->wc_ctx, external_abspath,
+                            TRUE, FALSE, scratch_pool));
+
+  /* Update the EXTERNALS table according to the root URL,
+   * relpath and uuid known in the upgraded external WC. */
+
+  /* We should probably have a function that provides all three
+   * of root URL, repos relpath and uuid at once, but here goes... */
+
+  /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
+   * when the node is not present in the file system.
+   * svn_wc__node_get_repos_info() would try to derive the URL. */
+  SVN_ERR(svn_wc__node_get_repos_info(NULL,
+                                      &repos_relpath,
+                                      &repos_root_url,
+                                      &repos_uuid,
+                                      ctx->wc_ctx,
+                                      external_abspath,
+                                      scratch_pool, scratch_pool));
+
+  /* If we haven't got any information from the checked out external,
+   * or if the URL information mismatches the external's definition,
+   * ask fetch_repos_info() to find out the repos root. */
+  if (0 != strcmp(resolved_url,
+                  svn_path_url_add_component2(repos_root_url,
+                                              repos_relpath,
+                                              scratch_pool)))
+    {
+      SVN_ERR(fetch_repos_info(&repos_root_url, &repos_uuid, info_baton,
+                               resolved_url, scratch_pool, scratch_pool));
+
+      repos_relpath = svn_uri_skip_ancestor(repos_root_url,
+                                            resolved_url,
+                                            scratch_pool);
+
+      /* There's just the URL, no idea what kind the external is.
+       * That's fine, as the external isn't even checked out yet.
+       * The kind will be set during the next 'update'. */
+      external_kind = svn_node_unknown;
+    }
+
+  peg_revision = (item->peg_revision.kind == svn_opt_revision_number
+                     ? item->peg_revision.value.number
+                     : SVN_INVALID_REVNUM);
+
+  revision = (item->revision.kind == svn_opt_revision_number
+                 ? item->revision.value.number
+                 : SVN_INVALID_REVNUM);
+
+  SVN_ERR(svn_wc__upgrade_add_external_info(ctx->wc_ctx,
+                                            external_abspath,
+                                            external_kind,
+                                            externals_parent_abspath,
+                                            repos_relpath,
+                                            repos_root_url,
+                                            repos_uuid,
+                                            peg_revision,
+                                            revision,
+                                            scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 upgrade_externals_from_properties(svn_client_ctx_t *ctx,
                                   const char *local_abspath,
+                                  struct repos_info_baton *info_baton,
                                   apr_pool_t *scratch_pool)
 {
   apr_hash_index_t *hi;
@@ -187,7 +306,6 @@ upgrade_externals_from_properties(svn_cl
   apr_pool_t *iterpool2;
   apr_hash_t *externals;
   svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
-  struct repos_info_baton info_baton;
 
   /* Now it's time to upgrade the externals too. We do it after the wc
      upgrade to avoid that errors in the externals causes the wc upgrade to
@@ -205,34 +323,32 @@ upgrade_externals_from_properties(svn_cl
        hi = apr_hash_next(hi))
     {
       int i;
-      const char *externals_parent_abspath;
       const char *externals_parent_url;
       const char *externals_parent_repos_root_url;
       const char *externals_parent_repos_relpath;
-      const char *externals_parent = apr_hash_this_key(hi);
+      const char *externals_parent_abspath = apr_hash_this_key(hi);
       svn_string_t *external_desc = apr_hash_this_val(hi);
       apr_array_header_t *externals_p;
       svn_error_t *err;
 
       svn_pool_clear(iterpool);
+
+      /* svn_client_propget5() has API promise to return absolute paths. */
+      SVN_ERR_ASSERT(svn_dirent_is_absolute(externals_parent_abspath));
+
       externals_p = apr_array_make(iterpool, 1,
                                    sizeof(svn_wc_external_item2_t*));
 
       /* In this loop, an error causes the respective externals definition, or
        * the external (inner loop), to be skipped, so that upgrade carries on
        * with the other externals. */
-
-      err = svn_dirent_get_absolute(&externals_parent_abspath,
-                                    externals_parent, iterpool);
-
-      if (!err)
-        err = svn_wc__node_get_repos_info(NULL,
-                                          &externals_parent_repos_relpath,
-                                          &externals_parent_repos_root_url,
-                                          NULL,
-                                          ctx->wc_ctx,
-                                          externals_parent_abspath,
-                                          iterpool, iterpool);
+      err = svn_wc__node_get_repos_info(NULL,
+                                        &externals_parent_repos_relpath,
+                                        &externals_parent_repos_root_url,
+                                        NULL,
+                                        ctx->wc_ctx,
+                                        externals_parent_abspath,
+                                        iterpool, iterpool);
 
       if (!err)
         externals_parent_url = svn_path_url_add_component2(
@@ -246,7 +362,7 @@ upgrade_externals_from_properties(svn_cl
       if (err)
         {
           svn_wc_notify_t *notify =
-              svn_wc_create_notify(externals_parent,
+              svn_wc_create_notify(externals_parent_abspath,
                                    svn_wc_notify_failed_external,
                                    scratch_pool);
           notify->err = err;
@@ -263,130 +379,21 @@ upgrade_externals_from_properties(svn_cl
       for (i = 0; i < externals_p->nelts; i++)
         {
           svn_wc_external_item2_t *item;
-          const char *resolved_url;
-          const char *external_abspath;
-          const char *repos_relpath;
-          const char *repos_root_url;
-          const char *repos_uuid;
-          svn_node_kind_t external_kind;
-          svn_revnum_t peg_revision;
-          svn_revnum_t revision;
 
           item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);
 
           svn_pool_clear(iterpool2);
-          external_abspath = svn_dirent_join(externals_parent_abspath,
-                                             item->target_dir,
-                                             iterpool2);
-
-          err = svn_wc__resolve_relative_external_url(
-                                              &resolved_url,
-                                              item,
-                                              externals_parent_repos_root_url,
-                                              externals_parent_url,
-                                              scratch_pool, scratch_pool);
-          if (err)
-            goto handle_error;
-
-          /* This is a hack. We only need to call svn_wc_upgrade() on external
-           * dirs, as file externals are upgraded along with their defining
-           * WC.  Reading the kind will throw an exception on an external dir,
-           * saying that the wc must be upgraded.  If it's a file, the lookup
-           * is done in an adm_dir belonging to the defining wc (which has
-           * already been upgraded) and no error is returned.  If it doesn't
-           * exist (external that isn't checked out yet), we'll just get
-           * svn_node_none. */
-          err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx,
-                                  external_abspath, TRUE, FALSE, iterpool2);
-          if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
-            {
-              svn_error_clear(err);
-
-              err = svn_client_upgrade(external_abspath, ctx, iterpool2);
-              if (err)
-                goto handle_error;
-            }
-          else if (err)
-            goto handle_error;
-
-          /* The upgrade of any dir should be done now, get the now reliable
-           * kind. */
-          err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx, external_abspath,
-                                  TRUE, FALSE, iterpool2);
-          if (err)
-            goto handle_error;
-
-          /* Update the EXTERNALS table according to the root URL,
-           * relpath and uuid known in the upgraded external WC. */
-
-          /* We should probably have a function that provides all three
-           * of root URL, repos relpath and uuid at once, but here goes... */
-
-          /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
-           * when the node is not present in the file system.
-           * svn_wc__node_get_repos_info() would try to derive the URL. */
-          err = svn_wc__node_get_repos_info(NULL,
-                                            &repos_relpath,
-                                            &repos_root_url,
-                                            &repos_uuid,
-                                            ctx->wc_ctx,
-                                            external_abspath,
-                                            iterpool2, iterpool2);
-          if (err)
-            goto handle_error;
-
-          /* If we haven't got any information from the checked out external,
-           * or if the URL information mismatches the external's definition,
-           * ask fetch_repos_info() to find out the repos root. */
-          if (0 != strcmp(resolved_url,
-                          svn_path_url_add_component2(repos_root_url,
-                                                      repos_relpath,
-                                                      scratch_pool)))
-            {
-              err = fetch_repos_info(&repos_root_url,
-                                     &repos_uuid,
-                                     &info_baton,
-                                     resolved_url,
-                                     scratch_pool, scratch_pool);
-              if (err)
-                goto handle_error;
-
-              repos_relpath = svn_uri_skip_ancestor(repos_root_url,
-                                                    resolved_url,
-                                                    iterpool2);
-
-              /* There's just the URL, no idea what kind the external is.
-               * That's fine, as the external isn't even checked out yet.
-               * The kind will be set during the next 'update'. */
-              external_kind = svn_node_unknown;
-            }
-
-          if (err)
-            goto handle_error;
+          err = upgrade_external_item(ctx, externals_parent_abspath,
+                                      externals_parent_url,
+                                      externals_parent_repos_root_url,
+                                      item, info_baton, iterpool2);
 
-          peg_revision = (item->peg_revision.kind == svn_opt_revision_number
-                          ? item->peg_revision.value.number
-                          : SVN_INVALID_REVNUM);
-
-          revision = (item->revision.kind == svn_opt_revision_number
-                      ? item->revision.value.number
-                      : SVN_INVALID_REVNUM);
-
-          err = svn_wc__upgrade_add_external_info(ctx->wc_ctx,
-                                                  external_abspath,
-                                                  external_kind,
-                                                  externals_parent,
-                                                  repos_relpath,
-                                                  repos_root_url,
-                                                  repos_uuid,
-                                                  peg_revision,
-                                                  revision,
-                                                  iterpool2);
-handle_error:
           if (err)
             {
               svn_wc_notify_t *notify =
-                  svn_wc_create_notify(external_abspath,
+                  svn_wc_create_notify(svn_dirent_join(externals_parent_abspath,
+                                                       item->target_dir,
+                                                       iterpool2),
                                        svn_wc_notify_failed_external,
                                        scratch_pool);
               notify->err = err;

Modified: subversion/branches/ra-git/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_delta/compat.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_delta/compat.c Mon Nov 30 10:24:16 2015
@@ -816,8 +816,9 @@ static svn_error_t *
 open_delta_target(svn_stream_t **stream, void *baton,
                 apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
-  const char **delta_target = baton;
-  return svn_stream_open_unique(stream, delta_target, NULL,
+  struct change_node *change = baton;
+  return svn_stream_open_unique(stream, &change->contents_abspath,
+                                NULL,
                                 svn_io_file_del_on_pool_cleanup,
                                 result_pool, scratch_pool);
 }
@@ -850,8 +851,7 @@ ev2_apply_textdelta(void *file_baton,
                                             FALSE, handler_pool);
 
   change->contents_changed = TRUE;
-  target = svn_stream_lazyopen_create(open_delta_target,
-                                      &change->contents_abspath,
+  target = svn_stream_lazyopen_create(open_delta_target, change,
                                       FALSE, fb->eb->edit_pool);
 
   svn_txdelta_apply(hb->source, target,
@@ -1223,15 +1223,23 @@ alter_file_cb(void *baton,
               apr_pool_t *scratch_pool)
 {
   struct editor_baton *eb = baton;
-  const char *tmp_filename;
   svn_stream_t *tmp_stream;
-  svn_checksum_t *md5_checksum;
   struct change_node *change = insert_change(relpath, eb->changes);
 
+  /* Note: this node may already have information in CHANGE as a result
+     of an earlier copy/move operation.  */
+
   /* ### should we verify the kind is truly a file?  */
+  change->kind = svn_node_file;
+  change->changing = revision;
+  if (props != NULL)
+    change->props = svn_prop_hash_dup(props, eb->edit_pool);
 
   if (contents)
     {
+      const char *tmp_filename;
+      svn_checksum_t *md5_checksum;
+
       /* We may need to re-checksum these contents */
       if (checksum && checksum->kind == svn_checksum_md5)
         md5_checksum = (svn_checksum_t *)checksum;
@@ -1246,17 +1254,7 @@ alter_file_cb(void *baton,
                                      eb->edit_pool, scratch_pool));
       SVN_ERR(svn_stream_copy3(contents, tmp_stream, NULL, NULL,
                                scratch_pool));
-    }
 
-  /* Note: this node may already have information in CHANGE as a result
-     of an earlier copy/move operation.  */
-
-  change->kind = svn_node_file;
-  change->changing = revision;
-  if (props != NULL)
-    change->props = svn_prop_hash_dup(props, eb->edit_pool);
-  if (contents != NULL)
-    {
       change->contents_changed = TRUE;
       change->contents_abspath = tmp_filename;
       change->checksum = svn_checksum_dup(md5_checksum, eb->edit_pool);

Modified: subversion/branches/ra-git/subversion/libsvn_delta/debug_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_delta/debug_editor.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_delta/debug_editor.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_delta/debug_editor.c Mon Nov 30 10:24:16 2015
@@ -23,7 +23,7 @@
 
 #include "svn_io.h"
 
-#include "debug_editor.h"
+#include "private/svn_delta_private.h"
 
 struct edit_baton
 {

Modified: subversion/branches/ra-git/subversion/libsvn_delta/svndiff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_delta/svndiff.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_delta/svndiff.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_delta/svndiff.c Mon Nov 30 10:24:16 2015
@@ -36,6 +36,20 @@
 #include "private/svn_string_private.h"
 #include "private/svn_dep_compat.h"
 
+static const char SVNDIFF_V0[] = { 'S', 'V', 'N', 0 };
+static const char SVNDIFF_V1[] = { 'S', 'V', 'N', 1 };
+
+#define SVNDIFF_HEADER_SIZE (sizeof(SVNDIFF_V0))
+
+static const char *
+get_svndiff_header(int version)
+{
+  if (version == 1)
+    return SVNDIFF_V1;
+  else
+    return SVNDIFF_V0;
+}
+
 /* ----- Text delta to svndiff ----- */
 
 /* We make one of these and get it passed back to us in calls to the
@@ -46,7 +60,8 @@ struct encoder_baton {
   svn_boolean_t header_done;
   int version;
   int compression_level;
-  apr_pool_t *pool;
+  /* Pool for temporary allocations, will be cleared periodically. */
+  apr_pool_t *scratch_pool;
 };
 
 /* This is at least as big as the largest size for a single instruction. */
@@ -72,7 +87,7 @@ static svn_error_t *
 send_simple_insertion_window(svn_txdelta_window_t *window,
                              struct encoder_baton *eb)
 {
-  unsigned char headers[4 + 5 * SVN__MAX_ENCODED_UINT_LEN
+  unsigned char headers[SVNDIFF_HEADER_SIZE + 5 * SVN__MAX_ENCODED_UINT_LEN
                           + MAX_INSTRUCTION_LEN];
   unsigned char ibuf[MAX_INSTRUCTION_LEN];
   unsigned char *header_current;
@@ -89,11 +104,8 @@ send_simple_insertion_window(svn_txdelta
   if (!eb->header_done)
     {
       eb->header_done = TRUE;
-      headers[0] = 'S';
-      headers[1] = 'V';
-      headers[2] = 'N';
-      headers[3] = (unsigned char)eb->version;
-      header_current = headers + 4;
+      memcpy(headers, get_svndiff_header(eb->version), SVNDIFF_HEADER_SIZE);
+      header_current = headers + SVNDIFF_HEADER_SIZE;
     }
   else
     {
@@ -135,58 +147,28 @@ send_simple_insertion_window(svn_txdelta
   return SVN_NO_ERROR;
 }
 
+/* Encodes delta window WINDOW to svndiff-format.
+   The svndiff version is VERSION. COMPRESSION_LEVEL is the zlib
+   compression level to use.
+   Returned values will be allocated in POOL or refer to *WINDOW
+   fields. */
 static svn_error_t *
-window_handler(svn_txdelta_window_t *window, void *baton)
+encode_window(svn_stringbuf_t **instructions_p,
+              svn_stringbuf_t **header_p,
+              const svn_string_t **newdata_p,
+              svn_txdelta_window_t *window,
+              int version,
+              int compression_level,
+              apr_pool_t *pool)
 {
-  struct encoder_baton *eb = baton;
-  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)
-    {
-      char svnver[4] = {'S','V','N','\0'};
-      len = 4;
-      svnver[3] = (char)eb->version;
-      SVN_ERR(svn_stream_write(eb->output, svnver, &len));
-      eb->header_done = TRUE;
-    }
-
-  if (window == NULL)
-    {
-      svn_stream_t *output = eb->output;
-
-      /* We're done; clean up.
-
-         We clean our pool first. Given that the output stream was passed
-         TO us, we'll assume it has a longer lifetime, and that it will not
-         be affected by our pool destruction.
-
-         The contrary point of view (close the stream first): that could
-         tell our user that everything related to the output stream is done,
-         and a cleanup of the user pool should occur. However, that user
-         pool could include the subpool we created for our work (eb->pool),
-         which would then make our call to svn_pool_destroy() puke.
-       */
-      svn_pool_destroy(eb->pool);
-
-      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.  */
@@ -213,21 +195,21 @@ window_handler(svn_txdelta_window_t *win
   append_encoded_int(header, window->sview_offset);
   append_encoded_int(header, window->sview_len);
   append_encoded_int(header, window->tview_len);
-  if (eb->version == 1)
+  if (version == 1)
     {
-      SVN_ERR(svn__compress(instructions, i1, eb->compression_level));
-      instructions = i1;
+      svn_stringbuf_t *compressed_instructions;
+      compressed_instructions = svn_stringbuf_create_empty(pool);
+      SVN_ERR(svn__compress(instructions->data, instructions->len,
+                            compressed_instructions, compression_level));
+      instructions = compressed_instructions;
     }
   append_encoded_int(header, instructions->len);
-  if (eb->version == 1)
+  if (version == 1)
     {
       svn_stringbuf_t *compressed = svn_stringbuf_create_empty(pool);
-      svn_stringbuf_t *original = svn_stringbuf_create_empty(pool);
-      original->data = (char *)window->new_data->data; /* won't be modified */
-      original->len = window->new_data->len;
-      original->blocksize = window->new_data->len + 1;
 
-      SVN_ERR(svn__compress(original, compressed, eb->compression_level));
+      SVN_ERR(svn__compress(window->new_data->data, window->new_data->len,
+                            compressed, compression_level));
       newdata = svn_stringbuf__morph_into_string(compressed);
     }
   else
@@ -235,6 +217,51 @@ window_handler(svn_txdelta_window_t *win
 
   append_encoded_int(header, newdata->len);
 
+  *instructions_p = instructions;
+  *header_p = header;
+  *newdata_p = newdata;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+window_handler(svn_txdelta_window_t *window, void *baton)
+{
+  struct encoder_baton *eb = baton;
+  apr_size_t len;
+  svn_stringbuf_t *instructions;
+  svn_stringbuf_t *header;
+  const svn_string_t *newdata;
+
+  /* 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)
+    {
+      len = SVNDIFF_HEADER_SIZE;
+      SVN_ERR(svn_stream_write(eb->output, get_svndiff_header(eb->version),
+                               &len));
+      eb->header_done = TRUE;
+    }
+
+  if (window == NULL)
+    {
+      /* We're done; clean up. */
+      SVN_ERR(svn_stream_close(eb->output));
+
+      svn_pool_destroy(eb->scratch_pool);
+
+      return SVN_NO_ERROR;
+    }
+
+  svn_pool_clear(eb->scratch_pool);
+
+  SVN_ERR(encode_window(&instructions, &header, &newdata, window,
+                        eb->version, eb->compression_level,
+                        eb->scratch_pool));
+
   /* Write out the window.  */
   len = header->len;
   SVN_ERR(svn_stream_write(eb->output, header->data, &len));
@@ -249,7 +276,6 @@ window_handler(svn_txdelta_window_t *win
       SVN_ERR(svn_stream_write(eb->output, newdata->data, &len));
     }
 
-  svn_pool_destroy(pool);
   return SVN_NO_ERROR;
 }
 
@@ -261,13 +287,12 @@ svn_txdelta_to_svndiff3(svn_txdelta_wind
                         int compression_level,
                         apr_pool_t *pool)
 {
-  apr_pool_t *subpool = svn_pool_create(pool);
   struct encoder_baton *eb;
 
-  eb = apr_palloc(subpool, sizeof(*eb));
+  eb = apr_palloc(pool, sizeof(*eb));
   eb->output = output;
   eb->header_done = FALSE;
-  eb->pool = subpool;
+  eb->scratch_pool = svn_pool_create(pool);
   eb->version = svndiff_version;
   eb->compression_level = compression_level;
 
@@ -334,6 +359,17 @@ struct decode_baton
 
   /* svndiff version in use by delta.  */
   unsigned char version;
+
+  /* Length of parsed delta window header. 0 if window is not parsed yet. */
+  apr_size_t window_header_len;
+
+  /* Five integer fields of parsed delta window header. Valid only if
+     WINDOW_HEADER_LEN > 0 */
+  svn_filesize_t  sview_offset;
+  apr_size_t sview_len;
+  apr_size_t tview_len;
+  apr_size_t inslen;
+  apr_size_t newlen;
 };
 
 
@@ -483,21 +519,6 @@ count_and_verify_instructions(int *ninst
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-zlib_decode(const unsigned char *in, apr_size_t inLen, svn_stringbuf_t *out,
-            apr_size_t limit)
-{
-  /* construct a fake string buffer as parameter to svn__decompress.
-     This is fine as that function never writes to it. */
-  svn_stringbuf_t compressed;
-  compressed.pool = NULL;
-  compressed.data = (char *)in;
-  compressed.len = inLen;
-  compressed.blocksize = inLen + 1;
-
-  return svn__decompress(&compressed, out, limit);
-}
-
 /* Given the five integer fields of a window header and a pointer to
    the remainder of the window contents, fill in a delta window
    structure *WINDOW.  New allocations will be performed in POOL;
@@ -513,7 +534,7 @@ decode_window(svn_txdelta_window_t *wind
   int ninst;
   apr_size_t npos;
   svn_txdelta_op_t *ops, *op;
-  svn_string_t *new_data = apr_palloc(pool, sizeof(*new_data));
+  svn_string_t *new_data;
 
   window->sview_offset = sview_offset;
   window->sview_len = sview_len;
@@ -526,28 +547,22 @@ decode_window(svn_txdelta_window_t *wind
       svn_stringbuf_t *instout = svn_stringbuf_create_empty(pool);
       svn_stringbuf_t *ndout = svn_stringbuf_create_empty(pool);
 
-      SVN_ERR(zlib_decode(insend, newlen, ndout,
-                          SVN_DELTA_WINDOW_SIZE));
-      SVN_ERR(zlib_decode(data, insend - data, instout,
-                          MAX_INSTRUCTION_SECTION_LEN));
+      SVN_ERR(svn__decompress(insend, newlen, ndout,
+                              SVN_DELTA_WINDOW_SIZE));
+      SVN_ERR(svn__decompress(data, insend - data, instout,
+                              MAX_INSTRUCTION_SECTION_LEN));
 
       newlen = ndout->len;
       data = (unsigned char *)instout->data;
       insend = (unsigned char *)instout->data + instout->len;
 
-      new_data->data = (const char *) ndout->data;
-      new_data->len = newlen;
+      new_data = svn_stringbuf__morph_into_string(ndout);
     }
   else
     {
       /* Copy the data because an svn_string_t must have the invariant
          data[len]=='\0'. */
-      char *buf = apr_palloc(pool, newlen + 1);
-
-      memcpy(buf, insend, newlen);
-      buf[newlen] = '\0';
-      new_data->data = buf;
-      new_data->len = newlen;
+      new_data = svn_string_ncreate((const char*)insend, newlen, pool);
     }
 
   /* Count the instructions and make sure they are all valid.  */
@@ -578,10 +593,6 @@ decode_window(svn_txdelta_window_t *wind
   return SVN_NO_ERROR;
 }
 
-static const char SVNDIFF_V0[] = { 'S', 'V', 'N', 0 };
-static const char SVNDIFF_V1[] = { 'S', 'V', 'N', 1 };
-#define SVNDIFF_HEADER_SIZE (sizeof(SVNDIFF_V0))
-
 static svn_error_t *
 write_handler(void *baton,
               const char *buffer,
@@ -589,8 +600,6 @@ write_handler(void *baton,
 {
   struct decode_baton *db = (struct decode_baton *) baton;
   const unsigned char *p, *end;
-  svn_filesize_t sview_offset;
-  apr_size_t sview_len, tview_len, inslen, newlen, remaining;
   apr_size_t buflen = *len;
 
   /* Chew up four bytes at the beginning for the header.  */
@@ -628,90 +637,114 @@ write_handler(void *baton,
 
   while (1)
     {
-      apr_pool_t *newpool;
       svn_txdelta_window_t window;
 
       /* Read the header, if we have enough bytes for that.  */
       p = (const unsigned char *) db->buffer->data;
       end = (const unsigned char *) db->buffer->data + db->buffer->len;
 
-      p = decode_file_offset(&sview_offset, p, end);
-      if (p == NULL)
-        return SVN_NO_ERROR;
-
-      p = decode_size(&sview_len, p, end);
-      if (p == NULL)
-        return SVN_NO_ERROR;
-
-      p = decode_size(&tview_len, p, end);
-      if (p == NULL)
-        return SVN_NO_ERROR;
-
-      p = decode_size(&inslen, p, end);
-      if (p == NULL)
-        return SVN_NO_ERROR;
-
-      p = decode_size(&newlen, p, end);
-      if (p == NULL)
-        return SVN_NO_ERROR;
-
-      if (tview_len > SVN_DELTA_WINDOW_SIZE ||
-          sview_len > SVN_DELTA_WINDOW_SIZE ||
-          /* for svndiff1, newlen includes the original length */
-          newlen > SVN_DELTA_WINDOW_SIZE + SVN__MAX_ENCODED_UINT_LEN ||
-          inslen > MAX_INSTRUCTION_SECTION_LEN)
-        return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
-                                _("Svndiff contains a too-large window"));
-
-      /* Check for integer overflow.  */
-      if (sview_offset < 0 || inslen + newlen < inslen
-          || sview_len + tview_len < sview_len
-          || (apr_size_t)sview_offset + sview_len < (apr_size_t)sview_offset)
-        return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
-                                _("Svndiff contains corrupt window header"));
-
-      /* Check for source windows which slide backwards.  */
-      if (sview_len > 0
-          && (sview_offset < db->last_sview_offset
-              || (sview_offset + sview_len
-                  < db->last_sview_offset + db->last_sview_len)))
-        return svn_error_create
-          (SVN_ERR_SVNDIFF_BACKWARD_VIEW, NULL,
-           _("Svndiff has backwards-sliding source views"));
+      if (db->window_header_len == 0)
+        {
+          svn_filesize_t sview_offset;
+          apr_size_t sview_len, tview_len, inslen, newlen;
+          const unsigned char *hdr_start = p;
+
+          p = decode_file_offset(&sview_offset, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&sview_len, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&tview_len, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&inslen, p, end);
+          if (p == NULL)
+              break;
+
+          p = decode_size(&newlen, p, end);
+          if (p == NULL)
+              break;
+
+          if (tview_len > SVN_DELTA_WINDOW_SIZE ||
+              sview_len > SVN_DELTA_WINDOW_SIZE ||
+              /* for svndiff1, newlen includes the original length */
+              newlen > SVN_DELTA_WINDOW_SIZE + SVN__MAX_ENCODED_UINT_LEN ||
+              inslen > MAX_INSTRUCTION_SECTION_LEN)
+            return svn_error_create(
+                     SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
+                     _("Svndiff contains a too-large window"));
+
+          /* Check for integer overflow.  */
+          if (sview_offset < 0 || inslen + newlen < inslen
+              || sview_len + tview_len < sview_len
+              || (apr_size_t)sview_offset + sview_len < (apr_size_t)sview_offset)
+            return svn_error_create(
+                      SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
+                      _("Svndiff contains corrupt window header"));
+
+          /* Check for source windows which slide backwards.  */
+          if (sview_len > 0
+              && (sview_offset < db->last_sview_offset
+                  || (sview_offset + sview_len
+                      < db->last_sview_offset + db->last_sview_len)))
+            return svn_error_create(
+                     SVN_ERR_SVNDIFF_BACKWARD_VIEW, NULL,
+                     _("Svndiff has backwards-sliding source views"));
+
+          /* Remember parsed window header. */
+          db->window_header_len = p - hdr_start;
+          db->sview_offset = sview_offset;
+          db->sview_len = sview_len;
+          db->tview_len = tview_len;
+          db->inslen = inslen;
+          db->newlen = newlen;
+        }
+      else
+        {
+          /* Skip already parsed window header. */
+          p += db->window_header_len;
+        }
 
       /* Wait for more data if we don't have enough bytes for the
-         whole window.  */
-      if ((apr_size_t) (end - p) < inslen + newlen)
+         whole window. */
+      if ((apr_size_t) (end - p) < db->inslen + db->newlen)
         return SVN_NO_ERROR;
 
       /* Decode the window and send it off. */
-      SVN_ERR(decode_window(&window, sview_offset, sview_len, tview_len,
-                            inslen, newlen, p, db->subpool,
-                            db->version));
+      SVN_ERR(decode_window(&window, db->sview_offset, db->sview_len,
+                            db->tview_len, db->inslen, db->newlen, p,
+                            db->subpool, db->version));
       SVN_ERR(db->consumer_func(&window, db->consumer_baton));
 
-      /* Make a new subpool and buffer, saving aside the remaining
-         data in the old buffer.  */
-      newpool = svn_pool_create(db->pool);
-      p += inslen + newlen;
-      remaining = db->buffer->data + db->buffer->len - (const char *) p;
-      db->buffer =
-        svn_stringbuf_ncreate((const char *) p, remaining, newpool);
+      p += db->inslen + db->newlen;
+
+      /* Remove processed data from the buffer.  */
+      svn_stringbuf_remove(db->buffer, 0, db->buffer->len - (end - p));
+
+      /* Reset window header length. */
+      db->window_header_len = 0;
 
       /* Remember the offset and length of the source view for next time.  */
-      db->last_sview_offset = sview_offset;
-      db->last_sview_len = sview_len;
+      db->last_sview_offset = db->sview_offset;
+      db->last_sview_len = db->sview_len;
 
-      /* We've copied stuff out of the old pool. Toss that pool and use
-         our new pool.
-         ### might be nice to avoid the copy and just use svn_pool_clear
-         ### to get rid of whatever the "other stuff" is. future project...
-      */
-      svn_pool_destroy(db->subpool);
-      db->subpool = newpool;
+      /* Clear subpool. */
+      svn_pool_clear(db->subpool);
     }
 
-  /* NOTREACHED */
+  /* At this point we processed all integral windows and DB->BUFFER is empty
+     or contains partially read window header.
+     Check that unprocessed data is not larger than theoretical maximum
+     window header size. */
+  if (db->buffer->len > 5 * SVN__MAX_ENCODED_UINT_LEN)
+    return svn_error_create(SVN_ERR_SVNDIFF_CORRUPT_WINDOW, NULL,
+                            _("Svndiff contains a too-large window header"));
+
+  return SVN_NO_ERROR;
 }
 
 /* Minimal svn_stream_t write handler, doing nothing */
@@ -749,23 +782,25 @@ svn_txdelta_parse_svndiff(svn_txdelta_wi
                           svn_boolean_t error_on_early_close,
                           apr_pool_t *pool)
 {
-  apr_pool_t *subpool = svn_pool_create(pool);
-  struct decode_baton *db = apr_palloc(pool, sizeof(*db));
   svn_stream_t *stream;
 
-  db->consumer_func = handler;
-  db->consumer_baton = handler_baton;
-  db->pool = subpool;
-  db->subpool = svn_pool_create(subpool);
-  db->buffer = svn_stringbuf_create_empty(db->subpool);
-  db->last_sview_offset = 0;
-  db->last_sview_len = 0;
-  db->header_bytes = 0;
-  db->error_on_early_close = error_on_early_close;
-  stream = svn_stream_create(db, pool);
-
   if (handler != svn_delta_noop_window_handler)
     {
+      apr_pool_t *subpool = svn_pool_create(pool);
+      struct decode_baton *db = apr_palloc(pool, sizeof(*db));
+
+      db->consumer_func = handler;
+      db->consumer_baton = handler_baton;
+      db->pool = subpool;
+      db->subpool = svn_pool_create(subpool);
+      db->buffer = svn_stringbuf_create_empty(db->pool);
+      db->last_sview_offset = 0;
+      db->last_sview_len = 0;
+      db->header_bytes = 0;
+      db->error_on_early_close = error_on_early_close;
+      db->window_header_len = 0;
+      stream = svn_stream_create(db, pool);
+
       svn_stream_set_write(stream, write_handler);
       svn_stream_set_close(stream, close_handler);
     }
@@ -773,6 +808,7 @@ svn_txdelta_parse_svndiff(svn_txdelta_wi
     {
       /* And else we just ignore everything as efficiently as we can.
          by only hooking a no-op handler */
+      stream = svn_stream_create(NULL, pool);
       svn_stream_set_write(stream, noop_write_handler);
     }
   return stream;

Modified: subversion/branches/ra-git/subversion/libsvn_delta/text_delta.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_delta/text_delta.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_delta/text_delta.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_delta/text_delta.c Mon Nov 30 10:24:16 2015
@@ -180,8 +180,7 @@ svn_txdelta_window_dup(const svn_txdelta
   build_baton.num_ops = window->num_ops;
   build_baton.src_ops = window->src_ops;
   build_baton.ops_size = window->num_ops;
-  build_baton.ops = apr_palloc(pool, ops_size);
-  memcpy(build_baton.ops, window->ops, ops_size);
+  build_baton.ops = apr_pmemdup(pool, window->ops, ops_size);
   build_baton.new_data =
     svn_stringbuf_create_from_string(window->new_data, pool);
 

Modified: subversion/branches/ra-git/subversion/libsvn_delta/xdelta.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_delta/xdelta.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_delta/xdelta.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_delta/xdelta.c Mon Nov 30 10:24:16 2015
@@ -111,7 +111,7 @@ struct block
   apr_uint32_t adlersum;
 
 /* Even in 64 bit systems, store only 32 bit offsets in our hash table
-   (our delta window size much much smaller then 4GB).
+   (our delta window size much much smaller than 4GB).
    That reduces the hash table size by 50% from 32to 16KB
    and makes it easier to fit into the CPU's L1 cache. */
   apr_uint32_t pos;    /* NO_POSITION -> block is not used */

Modified: subversion/branches/ra-git/subversion/libsvn_diff/binary_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_diff/binary_diff.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_diff/binary_diff.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_diff/binary_diff.c Mon Nov 30 10:24:16 2015
@@ -28,6 +28,10 @@
 #include "svn_diff.h"
 #include "svn_types.h"
 
+#include "diff.h"
+
+#include "svn_private_config.h"
+
 /* Copies the data from ORIGINAL_STREAM to a temporary file, returning both
    the original and compressed size. */
 static svn_error_t *
@@ -42,7 +46,6 @@ create_compressed(apr_file_t **result,
 {
   svn_stream_t *compressed;
   svn_filesize_t bytes_read = 0;
-  apr_finfo_t finfo;
   apr_size_t rd;
 
   SVN_ERR(svn_io_open_uniquely_named(result, NULL, NULL, "diffgz",
@@ -56,7 +59,7 @@ create_compressed(apr_file_t **result,
   if (original_stream)
     do
     {
-      char buffer[SVN_STREAM_CHUNK_SIZE];
+      char buffer[SVN__STREAM_CHUNK_SIZE];
       rd = sizeof(buffer);
 
       if (cancel_func)
@@ -67,7 +70,7 @@ create_compressed(apr_file_t **result,
       bytes_read += rd;
       SVN_ERR(svn_stream_write(compressed, buffer, &rd));
     }
-    while(rd == SVN_STREAM_CHUNK_SIZE);
+    while(rd == SVN__STREAM_CHUNK_SIZE);
   else
     {
       apr_size_t zero = 0;
@@ -77,8 +80,7 @@ create_compressed(apr_file_t **result,
   SVN_ERR(svn_stream_close(compressed)); /* Flush compression */
 
   *full_size = bytes_read;
-  SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE, *result, scratch_pool));
-  *compressed_size = finfo.size;
+  SVN_ERR(svn_io_file_size_get(compressed_size, *result, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -92,6 +94,64 @@ static const char b85str[] =
     "abcdefghijklmnopqrstuvwxyz"
     "!#$%&()*+-;<=>?@^_`{|}~";
 
+/* Helper function for svn_diff__base85_decode_line */
+static svn_error_t *
+base85_value(int *value, char c)
+{
+  const char *p = strchr(b85str, c);
+  if (!p)
+    return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+                            _("Invalid base85 value"));
+
+  *value = (p - b85str);
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_diff__base85_decode_line(char *output_data,
+                             apr_ssize_t output_len,
+                             const char *base85_data,
+                             apr_ssize_t base85_len,
+                             apr_pool_t *scratch_pool)
+{
+  {
+    apr_ssize_t expected_data = (output_len + 3) / 4 * 5;
+
+    if (base85_len != expected_data)
+      return svn_error_create(SVN_ERR_DIFF_UNEXPECTED_DATA, NULL,
+                              _("Unexpected base85 line length"));
+  }
+
+  while (base85_len)
+    {
+      unsigned info = 0;
+      apr_ssize_t i, n;
+
+      for (i = 0; i < 5; i++)
+        {
+          int value;
+
+          SVN_ERR(base85_value(&value, base85_data[i]));
+          info *= 85;
+          info += value;
+        }
+
+      for (i = 0, n=24; i < 4; i++, n-=8)
+        {
+          if (i < output_len)
+            output_data[i] = (info >> n) & 0xFF;
+        }
+
+      base85_data += 5;
+      base85_len -= 5;
+      output_data += 4;
+      output_len -= 4;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
 /* Git length encoding table for write_literal */
 static const char b85lenstr[] =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@@ -194,28 +254,26 @@ svn_diff_output_binary(svn_stream_t *out
 
   SVN_ERR(svn_stream_puts(output_stream, "GIT binary patch" APR_EOL_STR));
 
-  /* ### git would first calculate if a git-delta original->latest would be
+  /* ### git would first calculate if a git-delta latest->original would be
          shorter than the zipped data. For now lets assume that it is not
          and just dump the literal data */
-  SVN_ERR(write_literal(original_full,
-                        svn_stream_from_aprfile2(original_apr, FALSE, subpool),
+  SVN_ERR(write_literal(latest_full,
+                        svn_stream_from_aprfile2(latest_apr, FALSE, subpool),
                         output_stream,
                         cancel_func, cancel_baton,
                         scratch_pool));
   svn_pool_clear(subpool);
   SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR));
 
-  /* ### git would first calculate if a git-delta latest->original would be
+  /* ### git would first calculate if a git-delta original->latest would be
          shorter than the zipped data. For now lets assume that it is not
          and just dump the literal data */
-  SVN_ERR(write_literal(latest_full,
-                        svn_stream_from_aprfile2(latest_apr, FALSE, subpool),
+  SVN_ERR(write_literal(original_full,
+                        svn_stream_from_aprfile2(original_apr, FALSE, subpool),
                         output_stream,
                         cancel_func, cancel_baton,
                         scratch_pool));
   svn_pool_destroy(subpool);
 
-  SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR));
-
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_diff/diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_diff/diff.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_diff/diff.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_diff/diff.h Mon Nov 30 10:24:16 2015
@@ -214,4 +214,14 @@ svn_diff__unified_write_hunk_header(svn_
                                     apr_pool_t *scratch_pool);
 
 
+/* Decodes a single line of base85 data in BASE85_DATA of length BASE85_LEN,
+   to OUTPUT_DATA of length OUTPUT_LEN.
+ */
+svn_error_t *
+svn_diff__base85_decode_line(char *output_data,
+                             apr_ssize_t output_len,
+                             const char *base85_data,
+                             apr_ssize_t base85_len,
+                             apr_pool_t *scratch_pool);
+
 #endif /* DIFF_H */