subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pbu...@apache.org
Subject svn commit: r1360909 [5/14] - in /subversion/branches/inheritable-props: ./ build/generator/ build/generator/templates/ notes/wc-ng/ subversion/bindings/javahl/native/ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/bindings/j...
Date Thu, 12 Jul 2012 20:24:57 GMT
Modified: subversion/branches/inheritable-props/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/inheritable-props/subversion/libsvn_wc/conflicts.c?rev=1360909&r1=1360908&r2=1360909&view=diff
==============================================================================
--- subversion/branches/inheritable-props/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/branches/inheritable-props/subversion/libsvn_wc/conflicts.c Thu Jul 12 20:24:53 2012
@@ -45,14 +45,966 @@
 #include "wc_db.h"
 #include "conflicts.h"
 #include "workqueue.h"
+#include "props.h"
 
 #include "private/svn_wc_private.h"
 #include "private/svn_skel.h"
+#include "private/svn_string_private.h"
 
 #include "svn_private_config.h"
 
+/* --------------------------------------------------------------------
+ * Conflict skel management
+ */
+
 svn_skel_t *
-svn_wc__conflict_skel_new(apr_pool_t *result_pool)
+svn_wc__conflict_skel_create(apr_pool_t *result_pool)
+{
+  svn_skel_t *conflict_skel = svn_skel__make_empty_list(result_pool);
+
+  /* Add empty CONFLICTS list */
+  svn_skel__prepend(svn_skel__make_empty_list(result_pool), conflict_skel);
+
+  /* Add empty WHY list */
+  svn_skel__prepend(svn_skel__make_empty_list(result_pool), conflict_skel);
+
+  return conflict_skel;
+}
+
+svn_error_t *
+svn_wc__conflict_skel_is_complete(svn_boolean_t *complete,
+                                  const svn_skel_t *conflict_skel)
+{
+  *complete = FALSE;
+
+  if (svn_skel__list_length(conflict_skel) < 2)
+    return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
+                            _("Not a conflict skel"));
+
+  if (svn_skel__list_length(conflict_skel->children) < 2)
+    return SVN_NO_ERROR; /* WHY is not set */
+
+  if (svn_skel__list_length(conflict_skel->children->next) == 0)
+    return SVN_NO_ERROR; /* No conflict set */
+
+  *complete = TRUE;
+  return SVN_NO_ERROR;
+}
+
+/* Serialize a svn_wc_conflict_version_t before the existing data in skel */
+static svn_error_t *
+conflict__prepend_location(svn_skel_t *skel,
+                           const svn_wc_conflict_version_t *location,
+                           svn_boolean_t allow_NULL,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  svn_skel_t *loc;
+  SVN_ERR_ASSERT(location || allow_NULL);
+
+  if (!location)
+    {
+      svn_skel__prepend(svn_skel__make_empty_list(result_pool), skel);
+      return SVN_NO_ERROR;
+    }
+
+  /* ("subversion" repos_root_url repos_uuid repos_relpath rev kind) */
+  loc = svn_skel__make_empty_list(result_pool);
+
+  svn_skel__prepend_str(svn_node_kind_to_word(location->node_kind),
+                        loc, result_pool);
+
+  svn_skel__prepend_int(location->peg_rev, loc, result_pool);
+
+  svn_skel__prepend_str(apr_pstrdup(result_pool, location->path_in_repos), loc,
+                        result_pool);
+
+  if (!location->repos_uuid) /* Can theoretically be NULL */
+    svn_skel__prepend(svn_skel__make_empty_list(result_pool), loc);
+  else
+    svn_skel__prepend_str(location->repos_uuid, loc, result_pool);
+
+  svn_skel__prepend_str(apr_pstrdup(result_pool, location->repos_url), loc,
+                        result_pool);
+
+  svn_skel__prepend_str(SVN_WC__CONFLICT_SRC_SUBVERSION, loc, result_pool);
+
+  svn_skel__prepend(loc, skel);
+  return SVN_NO_ERROR;
+}
+
+/* Deserialize a svn_wc_conflict_version_t from the skel.
+   Set *LOCATION to NULL when the data is not a svn_wc_conflict_version_t. */
+static svn_error_t *
+conflict__read_location(svn_wc_conflict_version_t **location,
+                        const svn_skel_t *skel,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  const char *repos_root_url;
+  const char *repos_uuid;
+  const char *repos_relpath;
+  svn_revnum_t revision;
+  apr_int64_t v;
+  svn_node_kind_t node_kind;  /* note that 'none' is a legitimate value */
+  const char *kind_str;
+
+  const svn_skel_t *c = skel->children;
+
+  if (!svn_skel__matches_atom(c, SVN_WC__CONFLICT_SRC_SUBVERSION))
+    {
+      *location = NULL;
+      return SVN_NO_ERROR;
+    }
+  c = c->next;
+
+  repos_root_url = apr_pstrmemdup(scratch_pool, c->data, c->len);
+  c = c->next;
+
+  if (c->is_atom)
+    repos_uuid = apr_pstrmemdup(scratch_pool, c->data, c->len);
+  else
+    repos_uuid = NULL;
+  c = c->next;
+
+  repos_relpath = apr_pstrmemdup(scratch_pool, c->data, c->len);
+  c = c->next;
+
+  SVN_ERR(svn_skel__parse_int(&v, c, scratch_pool));
+  revision = (svn_revnum_t)v;
+  c = c->next;
+
+  kind_str = apr_pstrmemdup(scratch_pool, c->data, c->len);
+  node_kind = svn_node_kind_from_word(kind_str);
+
+  *location = svn_wc_conflict_version_create2(repos_root_url,
+                                              repos_uuid,
+                                              repos_relpath,
+                                              revision,
+                                              node_kind,
+                                              result_pool);
+  return SVN_NO_ERROR;
+}
+
+/* Get the operation part of CONFLICT_SKELL or NULL if no operation is set
+   at this time */
+static svn_error_t *
+conflict__get_operation(svn_skel_t **why,
+                        const svn_skel_t *conflict_skel)
+{
+  SVN_ERR_ASSERT(conflict_skel
+                 && conflict_skel->children
+                 && conflict_skel->children->next
+                 && !conflict_skel->children->next->is_atom);
+
+  *why = conflict_skel->children;
+
+  if (!(*why)->children)
+    *why = NULL; /* Operation is not set yet */
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__conflict_skel_set_op_update(svn_skel_t *conflict_skel,
+                                    const svn_wc_conflict_version_t *original,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool)
+{
+  svn_skel_t *why;
+  svn_skel_t *origins;
+
+  SVN_ERR_ASSERT(conflict_skel
+                 && conflict_skel->children
+                 && conflict_skel->children->next
+                 && !conflict_skel->children->next->is_atom);
+
+  SVN_ERR(conflict__get_operation(&why, conflict_skel));
+
+  SVN_ERR_ASSERT(why == NULL); /* No operation set */
+
+  why = conflict_skel->children;
+
+  origins = svn_skel__make_empty_list(result_pool);
+
+  SVN_ERR(conflict__prepend_location(origins, original, TRUE,
+                                     result_pool, scratch_pool));
+
+  svn_skel__prepend(origins, why);
+  svn_skel__prepend_str(SVN_WC__CONFLICT_OP_UPDATE, why, result_pool);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_skel_set_op_switch(svn_skel_t *conflict_skel,
+                                    const svn_wc_conflict_version_t *original,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool)
+{
+  svn_skel_t *why;
+  svn_skel_t *origins;
+
+  SVN_ERR_ASSERT(conflict_skel
+                 && conflict_skel->children
+                 && conflict_skel->children->next
+                 && !conflict_skel->children->next->is_atom);
+
+  SVN_ERR(conflict__get_operation(&why, conflict_skel));
+
+  SVN_ERR_ASSERT(why == NULL); /* No operation set */
+
+  why = conflict_skel->children;
+
+  origins = svn_skel__make_empty_list(result_pool);
+
+  SVN_ERR(conflict__prepend_location(origins, original, TRUE,
+                                     result_pool, scratch_pool));
+
+  svn_skel__prepend(origins, why);
+  svn_skel__prepend_str(SVN_WC__CONFLICT_OP_SWITCH, why, result_pool);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_skel_set_op_merge(svn_skel_t *conflict_skel,
+                                   const svn_wc_conflict_version_t *left,
+                                   const svn_wc_conflict_version_t *right,
+                                   apr_pool_t *result_pool,
+                                   apr_pool_t *scratch_pool)
+{
+  svn_skel_t *why;
+  svn_skel_t *origins;
+
+  SVN_ERR_ASSERT(conflict_skel
+                 && conflict_skel->children
+                 && conflict_skel->children->next
+                 && !conflict_skel->children->next->is_atom);
+
+  SVN_ERR(conflict__get_operation(&why, conflict_skel));
+
+  SVN_ERR_ASSERT(why == NULL); /* No operation set */
+
+  why = conflict_skel->children;
+
+  origins = svn_skel__make_empty_list(result_pool);
+
+  SVN_ERR(conflict__prepend_location(origins, right, TRUE,
+                                     result_pool, scratch_pool));
+
+  SVN_ERR(conflict__prepend_location(origins, left, TRUE,
+                                     result_pool, scratch_pool));
+
+  svn_skel__prepend(origins, why);
+  svn_skel__prepend_str(SVN_WC__CONFLICT_OP_MERGE, why, result_pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Gets the conflict data of the specified type CONFLICT_TYPE from
+   CONFLICT_SKEL, or NULL if no such conflict is recorded */
+static svn_error_t *
+conflict__get_conflict(svn_skel_t **conflict,
+                       const svn_skel_t *conflict_skel,
+                       const char *conflict_type)
+{
+  svn_skel_t *c;
+
+  SVN_ERR_ASSERT(conflict_skel
+                 && conflict_skel->children
+                 && conflict_skel->children->next
+                 && !conflict_skel->children->next->is_atom);
+
+  for(c = conflict_skel->children->next->children;
+      c;
+      c = c->next)
+    {
+      if (svn_skel__matches_atom(c->children, conflict_type))
+        {
+          *conflict = c;
+          return SVN_NO_ERROR;
+        }
+    }
+
+  *conflict = NULL;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_skel_add_text_conflict(svn_skel_t *conflict_skel,
+                                        svn_wc__db_t *db,
+                                        const char *wri_abspath,
+                                        const char *mine_abspath,
+                                        const char *their_old_abspath,
+                                        const char *their_abspath,
+                                        apr_pool_t *result_pool,
+                                        apr_pool_t *scratch_pool)
+{
+  svn_skel_t *text_conflict;
+  svn_skel_t *markers;
+
+  SVN_ERR(conflict__get_conflict(&text_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_TEXT));
+
+  SVN_ERR_ASSERT(!text_conflict); /* ### Use proper error? */
+
+  /* Current skel format
+     ("text"
+      (OLD MINE OLD-THEIRS THEIRS)) */
+
+  text_conflict = svn_skel__make_empty_list(result_pool);
+  markers = svn_skel__make_empty_list(result_pool);
+
+if (their_abspath)
+    {
+      const char *their_relpath;
+
+      SVN_ERR(svn_wc__db_to_relpath(&their_relpath,
+                                    db, wri_abspath, their_abspath,
+                                    result_pool, scratch_pool));
+      svn_skel__prepend_str(their_relpath, markers, result_pool);
+    }
+  else
+    svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);
+
+  if (mine_abspath)
+    {
+      const char *mine_relpath;
+
+      SVN_ERR(svn_wc__db_to_relpath(&mine_relpath,
+                                    db, wri_abspath, mine_abspath,
+                                    result_pool, scratch_pool));
+      svn_skel__prepend_str(mine_relpath, markers, result_pool);
+    }
+  else
+    svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);
+
+  if (their_old_abspath)
+    {
+      const char *original_relpath;
+
+      SVN_ERR(svn_wc__db_to_relpath(&original_relpath,
+                                    db, wri_abspath, their_old_abspath,
+                                    result_pool, scratch_pool));
+      svn_skel__prepend_str(original_relpath, markers, result_pool);
+    }
+  else
+    svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);
+
+  svn_skel__prepend(markers, text_conflict);
+  svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_TEXT, text_conflict,
+                        result_pool);
+
+  /* And add it to the conflict skel */
+  svn_skel__prepend(text_conflict, conflict_skel->children->next);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_skel_add_prop_conflict(svn_skel_t *conflict_skel,
+                                        svn_wc__db_t *db,
+                                        const char *wri_abspath,
+                                        const char *marker_abspath,
+                                        apr_hash_t *mine_props,
+                                        apr_hash_t *their_old_props,
+                                        apr_hash_t *their_props,
+                                        apr_hash_t *conflicted_prop_names,
+                                        apr_pool_t *result_pool,
+                                        apr_pool_t *scratch_pool)
+{
+  svn_skel_t *prop_conflict;
+  svn_skel_t *props;
+  svn_skel_t *conflict_names;
+  svn_skel_t *markers;
+  apr_hash_index_t *hi;
+
+  SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_PROP));
+
+  SVN_ERR_ASSERT(!prop_conflict); /* ### Use proper error? */
+
+  /* This function currently implements:
+     ("prop"
+      ("marker_relpath")
+      prop-conflicted_prop_names
+      old-props
+      mine-props
+      their-props)
+     NULL lists are recorded as "" */
+
+  prop_conflict = svn_skel__make_empty_list(result_pool);
+
+  if (their_props)
+    {
+      SVN_ERR(svn_skel__unparse_proplist(&props, their_props, result_pool));
+      svn_skel__prepend(props, prop_conflict);
+    }
+  else
+    svn_skel__prepend_str("", prop_conflict, result_pool); /* No their_props */
+
+  if (mine_props)
+    {
+      SVN_ERR(svn_skel__unparse_proplist(&props, mine_props, result_pool));
+      svn_skel__prepend(props, prop_conflict);
+    }
+  else
+    svn_skel__prepend_str("", prop_conflict, result_pool); /* No mine_props */
+
+  if (their_old_props)
+    {
+      SVN_ERR(svn_skel__unparse_proplist(&props, their_old_props,
+                                         result_pool));
+      svn_skel__prepend(props, prop_conflict);
+    }
+  else
+    svn_skel__prepend_str("", prop_conflict, result_pool); /* No old_props */
+
+  conflict_names = svn_skel__make_empty_list(result_pool);
+  for (hi = apr_hash_first(scratch_pool, conflicted_prop_names);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      svn_skel__prepend_str(apr_pstrdup(result_pool,
+                                        svn__apr_hash_index_key(hi)),
+                            conflict_names,
+                            result_pool);
+    }
+  svn_skel__prepend(conflict_names, prop_conflict);
+
+  markers = svn_skel__make_empty_list(result_pool);
+
+  if (marker_abspath)
+    {
+      const char *marker_relpath;
+      SVN_ERR(svn_wc__db_to_relpath(&marker_relpath, db, wri_abspath,
+                                    marker_abspath,
+                                    result_pool, scratch_pool));
+
+      svn_skel__prepend_str(marker_relpath, markers, result_pool);
+    }
+/*else // ### set via svn_wc__conflict_create_markers
+    svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);*/
+
+  svn_skel__prepend(markers, prop_conflict);
+
+  svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_PROP, prop_conflict, result_pool);
+
+  /* And add it to the conflict skel */
+  svn_skel__prepend(prop_conflict, conflict_skel->children->next);
+
+  return SVN_NO_ERROR;
+}
+
+/* A map for svn_wc_conflict_reason_t values. */
+static const svn_token_map_t local_change_map[] =
+{
+  { "edited",           svn_wc_conflict_reason_edited },
+  { "obstructed",       svn_wc_conflict_reason_obstructed },
+  { "deleted",          svn_wc_conflict_reason_deleted },
+  { "missing",          svn_wc_conflict_reason_missing },
+  { "unversioned",      svn_wc_conflict_reason_unversioned },
+  { "added",            svn_wc_conflict_reason_added },
+  { "replaced",         svn_wc_conflict_reason_replaced },
+  { "moved-away",       svn_wc_conflict_reason_moved_away },
+  { "moved-here",       svn_wc_conflict_reason_moved_here },
+  /* ### Do we really need this. The edit state is on a different node,
+         which might just change while the tree conflict exists? */
+  { "moved-and-edited", svn_wc_conflict_reason_moved_away_and_edited },
+  { NULL }
+};
+
+static const svn_token_map_t incoming_change_map[] =
+{
+  { "edited",           svn_wc_conflict_action_edit },
+  { "added",            svn_wc_conflict_action_add },
+  { "deleted",          svn_wc_conflict_action_delete },
+  { "replaced",         svn_wc_conflict_action_replace },
+  { NULL }
+};
+
+svn_error_t *
+svn_wc__conflict_skel_add_tree_conflict(svn_skel_t *conflict_skel,
+                                        svn_wc__db_t *db,
+                                        const char *wri_abspath,
+                                        svn_wc_conflict_reason_t local_change,
+                                        svn_wc_conflict_action_t incoming_change,
+                                        apr_pool_t *result_pool,
+                                        apr_pool_t *scratch_pool)
+{
+  svn_skel_t *tree_conflict;
+  svn_skel_t *markers;
+
+  SVN_ERR(conflict__get_conflict(&tree_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_TREE));
+
+  SVN_ERR_ASSERT(!tree_conflict); /* ### Use proper error? */
+
+  tree_conflict = svn_skel__make_empty_list(result_pool);
+
+  svn_skel__prepend_str(
+                svn_token__to_word(incoming_change_map, incoming_change),
+                tree_conflict, result_pool);
+
+  svn_skel__prepend_str(
+                svn_token__to_word(local_change_map, local_change),
+                tree_conflict, result_pool);
+
+  /* Tree conflicts have no marker files */
+  markers = svn_skel__make_empty_list(result_pool);
+  svn_skel__prepend(markers, tree_conflict);
+
+  svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_TREE, tree_conflict,
+                        result_pool);
+
+  /* And add it to the conflict skel */
+  svn_skel__prepend(tree_conflict, conflict_skel->children->next);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_skel_resolve(svn_boolean_t *completely_resolved,
+                              svn_skel_t *conflict_skel,
+                              svn_wc__db_t *db,
+                              const char *wri_abspath,
+                              svn_boolean_t resolve_text,
+                              const char *resolve_prop,
+                              svn_boolean_t resolve_tree,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  svn_skel_t *op;
+  svn_skel_t **pconflict;
+  SVN_ERR(conflict__get_operation(&op, conflict_skel));
+
+  if (!op)
+    return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
+                            _("Not a completed conflict skel"));
+
+  /* We are going to drop items from a linked list. Instead of keeping
+     a pointer to the item we want to drop we store a pointer to the
+     pointer of what we may drop, to allow setting it to the next item. */
+
+  pconflict = &(conflict_skel->children->next->children);
+  while (*pconflict)
+    {
+      svn_skel_t *c = (*pconflict)->children;
+
+      if (resolve_text
+          && svn_skel__matches_atom(c, SVN_WC__CONFLICT_KIND_TEXT))
+        {
+          /* Remove the text conflict from the linked list */
+          *pconflict = (*pconflict)->next;
+          continue;
+        }
+      else if (resolve_prop
+               && svn_skel__matches_atom(c, SVN_WC__CONFLICT_KIND_PROP))
+        {
+          svn_skel_t **ppropnames = &(c->next->next->children);
+
+          if (resolve_prop[0] == '\0')
+            *ppropnames = NULL; /* remove all conflicted property names */
+          else
+            while (*ppropnames)
+              {
+                if (svn_skel__matches_atom(*ppropnames, resolve_prop))
+                  {
+                    *ppropnames = (*ppropnames)->next;
+                    break;
+                  }
+                ppropnames = &((*ppropnames)->next);
+              }
+
+          /* If no conflicted property names left */
+          if (!c->next->next->children)
+            {
+              /* Remove the propery conflict skel from the linked list */
+             *pconflict = (*pconflict)->next;
+             continue;
+            }
+        }
+      else if (resolve_tree
+               && svn_skel__matches_atom(c, SVN_WC__CONFLICT_KIND_TREE))
+        {
+          /* Remove the tree conflict from the linked list */
+          *pconflict = (*pconflict)->next;
+          continue;
+        }
+
+      pconflict = &((*pconflict)->next);
+    }
+
+  if (completely_resolved)
+    {
+      /* Nice, we can just call the complete function */
+      svn_boolean_t complete_conflict;
+      SVN_ERR(svn_wc__conflict_skel_is_complete(&complete_conflict,
+                                                conflict_skel));
+
+      *completely_resolved = !complete_conflict;
+    }
+  return SVN_NO_ERROR;
+}
+
+
+/* A map for svn_wc_operation_t values. */
+static const svn_token_map_t operation_map[] =
+{
+  { "",   svn_wc_operation_none },
+  { SVN_WC__CONFLICT_OP_UPDATE, svn_wc_operation_update },
+  { SVN_WC__CONFLICT_OP_SWITCH, svn_wc_operation_switch },
+  { SVN_WC__CONFLICT_OP_MERGE,  svn_wc_operation_merge },
+  { NULL }
+};
+
+svn_error_t *
+svn_wc__conflict_read_info(svn_wc_operation_t *operation,
+                           const apr_array_header_t **locations,
+                           svn_boolean_t *text_conflicted,
+                           svn_boolean_t *prop_conflicted,
+                           svn_boolean_t *tree_conflicted,
+                           svn_wc__db_t *db,
+                           const char *wri_abspath,
+                           const svn_skel_t *conflict_skel,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  svn_skel_t *op;
+  const svn_skel_t *c;
+
+  SVN_ERR(conflict__get_operation(&op, conflict_skel));
+
+  if (!op)
+    return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
+                            _("Not a completed conflict skel"));
+
+  c = op->children;
+  if (operation)
+    {
+      int value = svn_token__from_mem(operation_map, c->data, c->len);
+
+      if (value != SVN_TOKEN_UNKNOWN)
+        *operation = value;
+      else
+        *operation = svn_wc_operation_none;
+    }
+  c = c->next;
+
+  if (locations && c->children)
+    {
+      const svn_skel_t *loc_skel;
+      svn_wc_conflict_version_t *loc;
+      apr_array_header_t *locs = apr_array_make(result_pool, 2, sizeof(loc));
+
+      for (loc_skel = c->children; loc_skel; loc_skel = loc_skel->next)
+        {
+          SVN_ERR(conflict__read_location(&loc, loc_skel, result_pool,
+                                          scratch_pool));
+
+          APR_ARRAY_PUSH(locs, svn_wc_conflict_version_t *) = loc;
+        }
+
+      *locations = locs;
+    }
+  else if (locations)
+    *locations = NULL;
+
+  if (text_conflicted)
+    {
+      svn_skel_t *c_skel;
+      SVN_ERR(conflict__get_conflict(&c_skel, conflict_skel,
+                                     SVN_WC__CONFLICT_KIND_TEXT));
+
+      *text_conflicted = (c_skel != NULL);
+    }
+
+  if (prop_conflicted)
+    {
+      svn_skel_t *c_skel;
+      SVN_ERR(conflict__get_conflict(&c_skel, conflict_skel,
+                                     SVN_WC__CONFLICT_KIND_PROP));
+
+      *prop_conflicted = (c_skel != NULL);
+    }
+
+  if (tree_conflicted)
+    {
+      svn_skel_t *c_skel;
+      SVN_ERR(conflict__get_conflict(&c_skel, conflict_skel,
+                                     SVN_WC__CONFLICT_KIND_TREE));
+
+      *tree_conflicted = (c_skel != NULL);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__conflict_read_text_conflict(const char **mine_abspath,
+                                    const char **their_old_abspath,
+                                    const char **their_abspath,
+                                    svn_wc__db_t *db,
+                                    const char *wri_abspath,
+                                    const svn_skel_t *conflict_skel,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool)
+{
+  svn_skel_t *text_conflict;
+  const svn_skel_t *m;
+
+  SVN_ERR(conflict__get_conflict(&text_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_TEXT));
+
+  if (!text_conflict)
+    return svn_error_create(SVN_ERR_WC_MISSING, NULL, _("Conflict not set"));
+
+  m = text_conflict->children->next->children;
+
+  if (their_old_abspath)
+    {
+      if (m->is_atom)
+        {
+          const char *original_relpath;
+
+          original_relpath = apr_pstrmemdup(scratch_pool, m->data, m->len);
+          SVN_ERR(svn_wc__db_from_relpath(their_old_abspath,
+                                          db, wri_abspath, original_relpath,
+                                          result_pool, scratch_pool));
+        }
+      else
+        *their_old_abspath = NULL;
+    }
+  m = m->next;
+
+  if (mine_abspath)
+    {
+      if (m->is_atom)
+        {
+          const char *mine_relpath;
+
+          mine_relpath = apr_pstrmemdup(scratch_pool, m->data, m->len);
+          SVN_ERR(svn_wc__db_from_relpath(mine_abspath,
+                                          db, wri_abspath, mine_relpath,
+                                          result_pool, scratch_pool));
+        }
+      else
+        *mine_abspath = NULL;
+    }
+  m = m->next;
+
+  if (their_abspath)
+    {
+      if (m->is_atom)
+        {
+          const char *their_relpath;
+
+          their_relpath = apr_pstrmemdup(scratch_pool, m->data, m->len);
+          SVN_ERR(svn_wc__db_from_relpath(their_abspath,
+                                          db, wri_abspath, their_relpath,
+                                          result_pool, scratch_pool));
+        }
+      else
+        *their_abspath = NULL;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_read_prop_conflict(const char **marker_abspath,
+                                    apr_hash_t **mine_props,
+                                    apr_hash_t **their_old_props,
+                                    apr_hash_t **their_props,
+                                    apr_hash_t **conflicted_prop_names,
+                                    svn_wc__db_t *db,
+                                    const char *wri_abspath,
+                                    const svn_skel_t *conflict_skel,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool)
+{
+  svn_skel_t *prop_conflict;
+  const svn_skel_t *c;
+
+  SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_PROP));
+
+  if (!prop_conflict)
+    return svn_error_create(SVN_ERR_WC_MISSING, NULL, _("Conflict not set"));
+
+  c = prop_conflict->children;
+
+  c = c->next; /* Skip "prop" */
+
+  /* Get marker file */
+  if (marker_abspath)
+    {
+      const char *marker_relpath;
+
+      if (c->children && c->children->is_atom)
+        {
+          marker_relpath = apr_pstrmemdup(result_pool, c->children->data,
+                                        c->children->len);
+
+          SVN_ERR(svn_wc__db_from_relpath(marker_abspath, db, wri_abspath,
+                                          marker_relpath,
+                                          result_pool, scratch_pool));
+        }
+      else
+        *marker_abspath = NULL;
+    }
+  c = c->next;
+
+  /* Get conflicted properties */
+  if (conflicted_prop_names)
+    {
+      const svn_skel_t *name;
+      *conflicted_prop_names = apr_hash_make(result_pool);
+
+      for (name = c->children; name; name = name->next)
+        {
+          apr_hash_set(*conflicted_prop_names,
+                       apr_pstrmemdup(result_pool, name->data, name->len),
+                       APR_HASH_KEY_STRING,
+                       "");
+        }
+    }
+  c = c->next;
+
+  /* Get original properties */
+  if (their_old_props)
+    {
+      if (c->is_atom)
+        *their_old_props = apr_hash_make(result_pool);
+      else
+        SVN_ERR(svn_skel__parse_proplist(their_old_props, c, result_pool));
+    }
+  c = c->next;
+
+  /* Get mine properties */
+  if (mine_props)
+    {
+      if (c->is_atom)
+        *mine_props = apr_hash_make(result_pool);
+      else
+        SVN_ERR(svn_skel__parse_proplist(mine_props, c, result_pool));
+    }
+  c = c->next;
+
+  /* Get their properties */
+  if (their_props)
+    {
+      if (c->is_atom)
+        *their_props = apr_hash_make(result_pool);
+      else
+        SVN_ERR(svn_skel__parse_proplist(their_props, c, result_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *local_change,
+                                    svn_wc_conflict_action_t *incoming_change,
+                                    svn_wc__db_t *db,
+                                    const char *wri_abspath,
+                                    const svn_skel_t *conflict_skel,
+                                    apr_pool_t *result_pool,
+                                    apr_pool_t *scratch_pool)
+{
+  svn_skel_t *tree_conflict;
+  const svn_skel_t *c;
+
+  SVN_ERR(conflict__get_conflict(&tree_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_TREE));
+
+  if (!tree_conflict)
+    return svn_error_create(SVN_ERR_WC_MISSING, NULL, _("Conflict not set"));
+
+  c = tree_conflict->children;
+
+  c = c->next; /* Skip "tree" */
+
+  c = c->next; /* Skip markers */
+
+  if (local_change)
+    {
+      int value = svn_token__from_mem(local_change_map, c->data, c->len);
+
+      if (value != SVN_TOKEN_UNKNOWN)
+        *local_change = value;
+      else
+        *local_change = svn_wc_conflict_reason_edited;
+    }
+  c = c->next;
+
+  if (incoming_change)
+    {
+      int value = svn_token__from_mem(incoming_change_map, c->data, c->len);
+
+      if (value != SVN_TOKEN_UNKNOWN)
+        *incoming_change = value;
+      else
+        *incoming_change = svn_wc_conflict_action_edit;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_read_markers(const apr_array_header_t **markers,
+                              svn_wc__db_t *db,
+                              const char *wri_abspath,
+                              const svn_skel_t *conflict_skel,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  const svn_skel_t *conflict;
+  apr_array_header_t *list = NULL;
+
+  SVN_ERR_ASSERT(conflict_skel != NULL);
+
+  /* Walk the conflicts */
+  for (conflict = conflict_skel->children->next->children;
+       conflict;
+       conflict = conflict->next)
+    {
+      const svn_skel_t *marker;
+
+      /* Get the list of markers stored per conflict */
+      for (marker = conflict->children->next->children;
+           marker;
+           marker = marker->next)
+        {
+          /* Skip placeholders */
+          if (! marker->is_atom)
+            continue;
+
+          if (! list)
+            list = apr_array_make(result_pool, 4, sizeof(const char *));
+
+          SVN_ERR(svn_wc__db_from_relpath(
+                        &APR_ARRAY_PUSH(list, const char*),
+                        db, wri_abspath,
+                        apr_pstrmemdup(scratch_pool, marker->data,
+                                       marker->len),
+                        result_pool, scratch_pool));
+        }
+    }
+  *markers = list;
+
+  return SVN_NO_ERROR;
+}
+
+/* --------------------------------------------------------------------
+ */
+/* Helper for svn_wc__conflict_create_markers */
+static svn_skel_t *
+prop_conflict_skel_new(apr_pool_t *result_pool)
 {
   svn_skel_t *operation = svn_skel__make_empty_list(result_pool);
   svn_skel_t *result = svn_skel__make_empty_list(result_pool);
@@ -62,6 +1014,7 @@ svn_wc__conflict_skel_new(apr_pool_t *re
 }
 
 
+/* Helper for prop_conflict_skel_add */
 static void
 prepend_prop_value(const svn_string_t *value,
                    svn_skel_t *skel,
@@ -81,8 +1034,9 @@ prepend_prop_value(const svn_string_t *v
 }
 
 
-svn_error_t *
-svn_wc__conflict_skel_add_prop_conflict(
+/* Helper for svn_wc__conflict_create_markers */
+static svn_error_t *
+prop_conflict_skel_add(
   svn_skel_t *skel,
   const char *prop_name,
   const svn_string_t *original_value,
@@ -111,7 +1065,1017 @@ svn_wc__conflict_skel_add_prop_conflict(
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__conflict_create_markers(svn_skel_t **work_items,
+                                svn_wc__db_t *db,
+                                const char *local_abspath,
+                                svn_skel_t *conflict_skel,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+  svn_boolean_t prop_conflicted;
+  svn_wc_operation_t operation;
+  *work_items = NULL;
+
+  SVN_ERR(svn_wc__conflict_read_info(&operation, NULL,
+                                     NULL, &prop_conflicted, NULL,
+                                     db, local_abspath,
+                                     conflict_skel,
+                                     scratch_pool, scratch_pool));
+
+  if (prop_conflicted)
+    {
+      const char *marker_abspath = NULL;
+      svn_node_kind_t kind;
+      const char *marker_dir;
+      const char *marker_name;
+      const char *marker_relpath;
+
+      /* Ok, currently we have to do a few things for property conflicts:
+         - Create a marker file
+         - Create a WQ item that sets the marker name
+         - Create a WQ item that fills the marker with the expected data
+
+         This can be simplified once we really store conflict_skel in wc.db */
+
+      SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
+
+      if (kind == svn_node_dir)
+        {
+          marker_dir = local_abspath;
+          marker_name = SVN_WC__THIS_DIR_PREJ;
+        }
+      else
+        svn_dirent_split(&marker_dir, &marker_name, local_abspath,
+                         scratch_pool);
+
+      SVN_ERR(svn_io_open_uniquely_named(NULL, &marker_abspath,
+                                         marker_dir,
+                                         marker_name,
+                                         SVN_WC__PROP_REJ_EXT,
+                                         svn_io_file_del_none,
+                                         scratch_pool, scratch_pool));
+
+      SVN_ERR(svn_wc__db_to_relpath(&marker_relpath, db, local_abspath,
+                                    marker_abspath, result_pool, result_pool));
+
+      /* And store the marker in the skel */
+      {
+        svn_skel_t *prop_conflict;
+        SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
+                                       SVN_WC__CONFLICT_KIND_PROP));
+
+        svn_skel__prepend_str(marker_relpath, prop_conflict->children->next,
+                            result_pool);
+      }
+
+      /* Store the data in the WQ item in the same format used as 1.7.
+         Once we store the data in DB it is easier to just read it back
+         from the workqueue */
+      {
+        svn_skel_t *prop_data;
+        apr_hash_index_t *hi;
+        apr_hash_t *old_props;
+        apr_hash_t *mine_props;
+        apr_hash_t *their_original_props;
+        apr_hash_t *their_props;
+        apr_hash_t *conflicted_props;
+
+        SVN_ERR(svn_wc__conflict_read_prop_conflict(NULL,
+                                                    &mine_props,
+                                                    &their_original_props,
+                                                    &their_props,
+                                                    &conflicted_props,
+                                                    db, local_abspath,
+                                                    conflict_skel,
+                                                    scratch_pool,
+                                                    scratch_pool));
+
+        if (operation == svn_wc_operation_merge)
+          SVN_ERR(svn_wc__db_read_pristine_props(&old_props, db, local_abspath,
+                                                 scratch_pool, scratch_pool));
+        else
+          old_props = their_props;
+
+        prop_data = prop_conflict_skel_new(result_pool);
+
+        for (hi = apr_hash_first(scratch_pool, conflicted_props);
+             hi;
+             hi = apr_hash_next(hi))
+          {
+            const char *propname = svn__apr_hash_index_key(hi);
+
+            prop_conflict_skel_add(
+                            prop_data, propname,
+                            old_props
+                                    ? apr_hash_get(old_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                    : NULL,
+                            mine_props
+                                    ? apr_hash_get(mine_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                    : NULL,
+                            their_props
+                                    ? apr_hash_get(their_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                      : NULL,
+                            their_original_props
+                                    ? apr_hash_get(their_original_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                      : NULL,
+                            result_pool, scratch_pool);
+          }
+
+        SVN_ERR(svn_wc__wq_build_prej_install(work_items,
+                                              db, local_abspath,
+                                              prop_data,
+                                              scratch_pool, scratch_pool));
+      }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Helper function for the three apply_* functions below, used when
+ * merging properties together.
+ *
+ * Given property PROPNAME on LOCAL_ABSPATH, and four possible property
+ * values, generate four tmpfiles and pass them to CONFLICT_FUNC callback.
+ * This gives the client an opportunity to interactively resolve the
+ * property conflict.
+ *
+ * BASE_VAL/WORKING_VAL represent the current state of the working
+ * copy, and INCOMING_OLD_VAL/INCOMING_NEW_VAL represents the incoming
+ * propchange.  Any of these values might be NULL, indicating either
+ * non-existence or intent-to-delete.
+ *
+ * If the callback isn't available, or if it responds with
+ * 'choose_postpone', then set *CONFLICT_REMAINS to TRUE and return.
+ *
+ * If the callback responds with a choice of 'base', 'theirs', 'mine',
+ * or 'merged', then install the proper value into ACTUAL_PROPS and
+ * set *CONFLICT_REMAINS to FALSE.
+ */
+static svn_error_t *
+generate_propconflict(svn_boolean_t *conflict_remains,
+                      svn_wc__db_t *db,
+                      const char *local_abspath,
+                      const svn_wc_conflict_version_t *left_version,
+                      const svn_wc_conflict_version_t *right_version,
+                      const char *propname,
+                      const svn_string_t *base_val,
+                      const svn_string_t *working_val,
+                      const svn_string_t *incoming_old_val,
+                      const svn_string_t *incoming_new_val,
+                      svn_wc_conflict_resolver_func2_t conflict_func,
+                      void *conflict_baton,
+                      apr_pool_t *scratch_pool)
+{
+  svn_wc_conflict_result_t *result = NULL;
+  svn_wc_conflict_description2_t *cdesc;
+  const char *dirpath = svn_dirent_dirname(local_abspath, scratch_pool);
+  svn_kind_t kind;
+  const svn_string_t *new_value = NULL;
+
+  SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, FALSE, FALSE,
+                               scratch_pool));
+
+  cdesc = svn_wc_conflict_description_create_prop2(
+                local_abspath,
+                (kind == svn_kind_dir) ? svn_node_dir : svn_node_file,
+                propname, scratch_pool);
+
+  cdesc->src_left_version = left_version;
+  cdesc->src_right_version = right_version;
+
+  /* Create a tmpfile for each of the string_t's we've got.  */
+  if (working_val)
+    {
+      const char *file_name;
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath, working_val->data,
+                                  working_val->len,
+                                  svn_io_file_del_on_pool_cleanup,
+                                  scratch_pool));
+      cdesc->my_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+    }
+
+  if (incoming_new_val)
+    {
+      const char *file_name;
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath, incoming_new_val->data,
+                                  incoming_new_val->len,
+                                  svn_io_file_del_on_pool_cleanup,
+                                  scratch_pool));
+      cdesc->their_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+    }
+
+  if (!base_val && !incoming_old_val)
+    {
+      /* If base and old are both NULL, then that's fine, we just let
+         base_file stay NULL as-is.  Both agents are attempting to add a
+         new property.  */
+    }
+
+  else if ((base_val && !incoming_old_val)
+           || (!base_val && incoming_old_val))
+    {
+      /* If only one of base and old are defined, then we've got a
+         situation where one agent is attempting to add the property
+         for the first time, and the other agent is changing a
+         property it thinks already exists.  In this case, we return
+         whichever older-value happens to be defined, so that the
+         conflict-callback can still attempt a 3-way merge. */
+
+      const svn_string_t *conflict_base_val = base_val ? base_val
+                                                       : incoming_old_val;
+      const char *file_name;
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath,
+                                  conflict_base_val->data,
+                                  conflict_base_val->len,
+                                  svn_io_file_del_on_pool_cleanup,
+                                  scratch_pool));
+      cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+    }
+
+  else  /* base and old are both non-NULL */
+    {
+      const svn_string_t *conflict_base_val;
+      const char *file_name;
+
+      if (! svn_string_compare(base_val, incoming_old_val))
+        {
+          /* What happens if 'base' and 'old' don't match up?  In an
+             ideal situation, they would.  But if they don't, this is
+             a classic example of a patch 'hunk' failing to apply due
+             to a lack of context.  For example: imagine that the user
+             is busy changing the property from a value of "cat" to
+             "dog", but the incoming propchange wants to change the
+             same property value from "red" to "green".  Total context
+             mismatch.
+
+             HOWEVER: we can still pass one of the two base values as
+             'base_file' to the callback anyway.  It's still useful to
+             present the working and new values to the user to
+             compare. */
+
+          if (working_val && svn_string_compare(base_val, working_val))
+            conflict_base_val = incoming_old_val;
+          else
+            conflict_base_val = base_val;
+        }
+      else
+        {
+          conflict_base_val = base_val;
+        }
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath, conflict_base_val->data,
+                                  conflict_base_val->len,
+                                  svn_io_file_del_on_pool_cleanup, scratch_pool));
+      cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+
+      if (working_val && incoming_new_val)
+        {
+          svn_stream_t *mergestream;
+          svn_diff_t *diff;
+          svn_diff_file_options_t *options =
+            svn_diff_file_options_create(scratch_pool);
+
+          SVN_ERR(svn_stream_open_unique(&mergestream, &cdesc->merged_file,
+                                         NULL, svn_io_file_del_on_pool_cleanup,
+                                         scratch_pool, scratch_pool));
+          SVN_ERR(svn_diff_mem_string_diff3(&diff, conflict_base_val,
+                                            working_val,
+                                            incoming_new_val, options, scratch_pool));
+          SVN_ERR(svn_diff_mem_string_output_merge2
+                  (mergestream, diff, conflict_base_val, working_val,
+                   incoming_new_val, NULL, NULL, NULL, NULL,
+                   svn_diff_conflict_display_modified_latest, scratch_pool));
+          SVN_ERR(svn_stream_close(mergestream));
+        }
+    }
+
+  if (!incoming_old_val && incoming_new_val)
+    cdesc->action = svn_wc_conflict_action_add;
+  else if (incoming_old_val && !incoming_new_val)
+    cdesc->action = svn_wc_conflict_action_delete;
+  else
+    cdesc->action = svn_wc_conflict_action_edit;
+
+  if (base_val && !working_val)
+    cdesc->reason = svn_wc_conflict_reason_deleted;
+  else if (!base_val && working_val)
+    cdesc->reason = svn_wc_conflict_reason_obstructed;
+  else
+    cdesc->reason = svn_wc_conflict_reason_edited;
+
+  /* Invoke the interactive conflict callback. */
+  {
+    SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
+                          scratch_pool));
+  }
+  if (result == NULL)
+    {
+      *conflict_remains = TRUE;
+      return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                              NULL, _("Conflict callback violated API:"
+                                      " returned no results."));
+    }
+
+
+  switch (result->choice)
+    {
+      default:
+      case svn_wc_conflict_choose_postpone:
+        {
+          *conflict_remains = TRUE;
+          break;
+        }
+      case svn_wc_conflict_choose_mine_full:
+        {
+          /* No need to change actual_props; it already contains working_val */
+          *conflict_remains = FALSE;
+          new_value = working_val;
+          break;
+        }
+      /* I think _mine_full and _theirs_full are appropriate for prop
+         behavior as well as the text behavior.  There should even be
+         analogous behaviors for _mine and _theirs when those are
+         ready, namely: fold in all non-conflicting prop changes, and
+         then choose _mine side or _theirs side for conflicting ones. */
+      case svn_wc_conflict_choose_theirs_full:
+        {
+          *conflict_remains = FALSE;
+          new_value = incoming_new_val;
+          break;
+        }
+      case svn_wc_conflict_choose_base:
+        {
+          *conflict_remains = FALSE;
+          new_value = base_val;
+          break;
+        }
+      case svn_wc_conflict_choose_merged:
+        {
+          if (!cdesc->merged_file && !result->merged_file)
+            return svn_error_create
+                (SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                 NULL, _("Conflict callback violated API:"
+                         " returned no merged file."));
+          else
+            {
+              svn_stringbuf_t *merged_stringbuf;
+              svn_string_t *merged_string;
+
+              SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf,
+                                               result->merged_file ?
+                                                    result->merged_file :
+                                                    cdesc->merged_file,
+                                               scratch_pool));
+              merged_string = svn_stringbuf__morph_into_string(merged_stringbuf);
+              *conflict_remains = FALSE;
+              new_value = merged_string;
+            }
+          break;
+        }
+    }
+
+  if (!*conflict_remains)
+    {
+      apr_hash_t *props;
+
+      /* For now, just set the property values. This should really do some of the
+         more advanced things from svn_wc_prop_set() */
+
+      SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
+                                    scratch_pool));
+
+      apr_hash_set(props, propname, APR_HASH_KEY_STRING, new_value);
+
+      SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, props,
+                                      FALSE, NULL, NULL,
+                                      scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Deal with the result of the conflict resolution callback, as indicated by
+ * CHOICE.
+ *
+ * Set *WORK_ITEMS to new work items that will ...
+ * Set *MERGE_OUTCOME to the result of the 3-way merge.
+ *
+ * LEFT_ABSPATH, RIGHT_ABSPATH, and TARGET_ABSPATH are the input files to
+ * the 3-way merge, and MERGED_FILE is the merged result as generated by the
+ * internal or external merge or by the conflict resolution callback.
+ *
+ * DETRANSLATED_TARGET is the detranslated version of TARGET_ABSPATH
+ * (see detranslate_wc_file() above).  DIFF3_OPTIONS are passed to the
+ * diff3 implementation in case a 3-way merge has to be carried out. */
+static svn_error_t*
+eval_text_conflict_func_result(svn_skel_t **work_items,
+                               enum svn_wc_merge_outcome_t *merge_outcome,
+                               svn_wc_conflict_choice_t choice,
+                               const apr_array_header_t *merge_options,
+                               svn_wc__db_t *db,
+                               const char *local_abspath,
+                               const char *left_abspath,
+                               const char *right_abspath,
+                               const char *merged_file,
+                               const char *detranslated_target,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  const char *install_from = NULL;
+  svn_boolean_t remove_source = FALSE;
+
+  *work_items = NULL;
+
+  switch (choice)
+    {
+      /* If the callback wants to use one of the fulltexts
+         to resolve the conflict, so be it.*/
+      case svn_wc_conflict_choose_base:
+        {
+          install_from = left_abspath;
+          *merge_outcome = svn_wc_merge_merged;
+          break;
+        }
+      case svn_wc_conflict_choose_theirs_full:
+        {
+          install_from = right_abspath;
+          *merge_outcome = svn_wc_merge_merged;
+          break;
+        }
+      case svn_wc_conflict_choose_mine_full:
+        {
+          /* Do nothing to merge_target, let it live untouched! */
+          *merge_outcome = svn_wc_merge_merged;
+          return SVN_NO_ERROR;
+        }
+      case svn_wc_conflict_choose_theirs_conflict:
+      case svn_wc_conflict_choose_mine_conflict:
+        {
+          const char *chosen_path;
+          const char *temp_dir;
+          svn_stream_t *chosen_stream;
+          svn_diff_t *diff;
+          svn_diff_conflict_display_style_t style;
+          svn_diff_file_options_t *diff3_options;
+
+          diff3_options = svn_diff_file_options_create(scratch_pool);
+
+          if (merge_options)
+             SVN_ERR(svn_diff_file_options_parse(diff3_options,
+                                                 merge_options,
+                                                 scratch_pool));
+
+          style = choice == svn_wc_conflict_choose_theirs_conflict
+                    ? svn_diff_conflict_display_latest
+                    : svn_diff_conflict_display_modified;
+
+          SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db,
+                                                 local_abspath,
+                                                 scratch_pool, scratch_pool));
+          SVN_ERR(svn_stream_open_unique(&chosen_stream, &chosen_path,
+                                         temp_dir, svn_io_file_del_none,
+                                         scratch_pool, scratch_pool));
+
+          SVN_ERR(svn_diff_file_diff3_2(&diff,
+                                        left_abspath,
+                                        detranslated_target, right_abspath,
+                                        diff3_options, scratch_pool));
+          SVN_ERR(svn_diff_file_output_merge2(chosen_stream, diff,
+                                              left_abspath,
+                                              detranslated_target,
+                                              right_abspath,
+                                              /* markers ignored */
+                                              NULL, NULL,
+                                              NULL, NULL,
+                                              style,
+                                              scratch_pool));
+          SVN_ERR(svn_stream_close(chosen_stream));
+
+          install_from = chosen_path;
+          remove_source = TRUE;
+          *merge_outcome = svn_wc_merge_merged;
+          break;
+        }
+
+        /* For the case of 3-way file merging, we don't
+           really distinguish between these return values;
+           if the callback claims to have "generally
+           resolved" the situation, we still interpret
+           that as "OK, we'll assume the merged version is
+           good to use". */
+      case svn_wc_conflict_choose_merged:
+        {
+          install_from = merged_file;
+          *merge_outcome = svn_wc_merge_merged;
+          break;
+        }
+      case svn_wc_conflict_choose_postpone:
+      default:
+        {
+#if 0
+          /* ### what should this value be? no caller appears to initialize
+             ### it, so we really SHOULD be setting a value here.  */
+          *merge_outcome = svn_wc_merge_merged;
+#endif
+
+          /* Assume conflict remains. */
+          return SVN_NO_ERROR;
+        }
+    }
+
+  SVN_ERR_ASSERT(install_from != NULL);
+
+  {
+    svn_skel_t *work_item;
+
+    SVN_ERR(svn_wc__wq_build_file_install(&work_item,
+                                          db, local_abspath,
+                                          install_from,
+                                          FALSE /* use_commit_times */,
+                                          FALSE /* record_fileinfo */,
+                                          result_pool, scratch_pool));
+    *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+
+    if (remove_source)
+      {
+        SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
+                                             db, install_from,
+                                             result_pool, scratch_pool));
+        *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+      }
+  }
+
+  return SVN_NO_ERROR;
+}
+
+/* Helper for maybe_resolve_conflicts() below. */
+static const svn_wc_conflict_description2_t *
+setup_text_conflict_desc(const char *left_abspath,
+                         const char *right_abspath,
+                         const char *target_abspath,
+                         const svn_wc_conflict_version_t *left_version,
+                         const svn_wc_conflict_version_t *right_version,
+                         const char *result_target,
+                         const char *detranslated_target,
+                         const char *mimeprop,
+                         svn_boolean_t is_binary,
+                         apr_pool_t *pool)
+{
+  svn_wc_conflict_description2_t *cdesc;
+
+  cdesc = svn_wc_conflict_description_create_text2(target_abspath, pool);
+  cdesc->is_binary = is_binary;
+  cdesc->mime_type = mimeprop;
+  cdesc->base_abspath = left_abspath;
+  cdesc->their_abspath = right_abspath;
+  cdesc->my_abspath = detranslated_target;
+  cdesc->merged_file = result_target;
+
+  cdesc->src_left_version = left_version;
+  cdesc->src_right_version = right_version;
+
+  return cdesc;
+}
+
+/* Create a new file in the same directory as VERSIONED_ABSPATH, with the
+   same basename as VERSIONED_ABSPATH, with a ".edited" extension, and set
+   *WORK_ITEM to a new work item that will copy and translate from the file
+   SOURCE to that new file.  It will be translated from repository-normal
+   form to working-copy form according to the versioned properties of
+   VERSIONED_ABSPATH that are current when the work item is executed.
+
+   DB should have a write lock for the directory containing SOURCE.
+
+   Allocate *WORK_ITEM in RESULT_POOL. */
+static svn_error_t*
+save_merge_result(svn_skel_t **work_item,
+                  svn_wc__db_t *db,
+                  const char *local_abspath,
+                  const char *source,
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
+{
+  const char *edited_copy_abspath;
+  const char *dir_abspath;
+  const char *filename;
+
+  svn_dirent_split(&dir_abspath, &filename, local_abspath, scratch_pool);
+
+  /* ### Should use preserved-conflict-file-exts. */
+  /* Create the .edited file within this file's DIR_ABSPATH  */
+  SVN_ERR(svn_io_open_uniquely_named(NULL,
+                                     &edited_copy_abspath,
+                                     dir_abspath,
+                                     filename,
+                                     ".edited",
+                                     svn_io_file_del_none,
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__wq_build_file_copy_translated(work_item,
+                                                db, local_abspath,
+                                                source, edited_copy_abspath,
+                                                result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+/* XXX Insane amount of parameters... */
+/* RESULT_TARGET is the path to the merged file produced by the internal or
+   external 3-way merge. */
+static svn_error_t*
+resolve_text_conflicts(svn_skel_t **work_items,
+                       svn_wc__db_t *db,
+                       const char *local_abspath,
+                       const apr_array_header_t *merge_options,
+                       const char *left_abspath,
+                       const char *right_abspath,
+                       enum svn_wc_merge_outcome_t *merge_outcome,
+                       const svn_wc_conflict_version_t *left_version,
+                       const svn_wc_conflict_version_t *right_version,
+                       const char *result_target,
+                       const char *detranslated_target,
+                       svn_wc_conflict_resolver_func2_t conflict_func,
+                       void *conflict_baton,
+                       svn_cancel_func_t cancel_func,
+                       void *cancel_baton,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  svn_wc_conflict_result_t *result;
+  svn_skel_t *work_item;
+  const svn_wc_conflict_description2_t *cdesc;
+  apr_hash_t *props;
+
+  *work_items = NULL;
+
+  /* Give the conflict resolution callback a chance to clean
+     up the conflicts before we mark the file 'conflicted' */
+
+    SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
+                                scratch_pool, scratch_pool));
+
+    cdesc = setup_text_conflict_desc(left_abspath,
+                                    right_abspath,
+                                    local_abspath,
+                                    left_version,
+                                    right_version,
+                                    result_target,
+                                    detranslated_target,
+                                    svn_prop_get_value(props,
+                                                        SVN_PROP_MIME_TYPE),
+                                    FALSE,
+                                    scratch_pool);
+
+    SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
+                        scratch_pool));
+    if (result == NULL)
+    return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                            NULL, _("Conflict callback violated API:"
+                                    " returned no results"));
+
+    if (result->save_merged)
+    {
+        SVN_ERR(save_merge_result(work_items,
+                                  db, local_abspath,
+                                  /* Look for callback's own
+                                      merged-file first: */
+                                  result->merged_file
+                                      ? result->merged_file
+                                      : result_target,
+                                  result_pool, scratch_pool));
+    }
+
+  SVN_ERR(eval_text_conflict_func_result(&work_item,
+                                         merge_outcome,
+                                         result->choice,
+                                         merge_options,
+                                         db, local_abspath,
+                                         left_abspath,
+                                         right_abspath,
+                                         result->merged_file
+                                           ? result->merged_file
+                                           : result_target,
+                                         detranslated_target,
+                                         result_pool, scratch_pool));
+  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+
+  if (result->choice != svn_wc_conflict_choose_postpone)
+    /* The conflicts have been dealt with, nothing else
+     * to do for us here. */
+    return SVN_NO_ERROR;
+
+  /* The conflicts have not been dealt with. */
+  *merge_outcome = svn_wc_merge_conflict;
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
+                                 const char *local_abspath,
+                                 const svn_skel_t *conflict_skel,
+                                 const apr_array_header_t *merge_options,
+                                 svn_wc_conflict_resolver_func2_t resolver_func,
+                                 void *resolver_baton,
+                                 apr_pool_t *scratch_pool)
+{
+  svn_boolean_t text_conflicted;
+  svn_boolean_t prop_conflicted;
+  svn_wc_operation_t operation;
+
+  SVN_ERR(svn_wc__conflict_read_info(&operation, NULL,
+                                     &text_conflicted, &prop_conflicted, NULL,
+                                     db, local_abspath, conflict_skel,
+                                     scratch_pool, scratch_pool));
+
+  /* Quick and dirty compatibility wrapper. My guess would be that most resolvers
+     would want to look at all properties at the same time.
+
+     ### svn currently only invokes this from the merge code to collect the list of
+     ### conflicted paths. Eventually this code will be the base for 'svn resolve'
+     ### and at that time the test coverage will improve
+     */
+  if (prop_conflicted)
+    {
+      apr_hash_t *old_props;
+      apr_hash_t *mine_props;
+      apr_hash_t *their_props;
+      apr_hash_t *old_their_props;
+      apr_hash_t *conflicted;
+      apr_pool_t *iterpool;
+      apr_hash_index_t *hi;
+      svn_boolean_t mark_resolved = TRUE;
+
+      SVN_ERR(svn_wc__conflict_read_prop_conflict(NULL,
+                                                  &mine_props,
+                                                  &old_their_props,
+                                                  &their_props,
+                                                  &conflicted,
+                                                  db, local_abspath,
+                                                  conflict_skel,
+                                                  scratch_pool, scratch_pool));
+
+      if (operation == svn_wc_operation_merge)
+        SVN_ERR(svn_wc__db_read_pristine_props(&old_props, db, local_abspath,
+                                               scratch_pool, scratch_pool));
+      else
+        old_props = their_props;
+
+      iterpool = svn_pool_create(scratch_pool);
+
+      for (hi = apr_hash_first(scratch_pool, conflicted);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *propname = svn__apr_hash_index_key(hi);
+          svn_boolean_t conflict_remains = TRUE;
+
+          svn_pool_clear(iterpool);
+
+          SVN_ERR(generate_propconflict(&conflict_remains,
+                                        db, local_abspath,
+                                        NULL, NULL, propname,
+                                        old_props
+                                          ? apr_hash_get(old_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        mine_props
+                                          ? apr_hash_get(mine_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        old_their_props
+                                          ? apr_hash_get(old_their_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        their_props
+                                          ? apr_hash_get(their_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        resolver_func, resolver_baton,
+                                        iterpool));
+
+          if (conflict_remains)
+            mark_resolved = FALSE;
+        }
+
+      if (mark_resolved)
+        SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, TRUE,
+                                            FALSE, NULL, scratch_pool));
+    }
+
+  if (text_conflicted)
+    {
+      const char *mine_abspath;
+      const char *their_original_abspath;
+      const char *their_abspath;
+      svn_skel_t *work_item = NULL;
+      svn_wc_merge_outcome_t merge_outcome = svn_wc_merge_conflict;
+
+      SVN_ERR(svn_wc__conflict_read_text_conflict(&their_original_abspath,
+                                                  &mine_abspath,
+                                                  &their_abspath,
+                                                  db, local_abspath,
+                                                  conflict_skel,
+                                                  scratch_pool, scratch_pool));
+
+      SVN_ERR(resolve_text_conflicts(&work_item, db, local_abspath,
+                                     merge_options,
+                                     their_original_abspath, their_abspath,
+                                     &merge_outcome,
+                                     NULL /* left_version */,
+                                     NULL /* right_version */,
+                                     local_abspath,
+                                     mine_abspath,
+                                     resolver_func, resolver_baton,
+                                     NULL, NULL,
+                                     scratch_pool, scratch_pool));
+
+      if (merge_outcome == svn_wc_merge_merged)
+        {
+          SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, TRUE, FALSE,
+                                              FALSE, work_item, scratch_pool));
+          SVN_ERR(svn_wc__wq_run(db, local_abspath, NULL, NULL, scratch_pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__read_conflicts(const apr_array_header_t **conflicts,
+                       svn_wc__db_t *db,
+                       const char *local_abspath,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  svn_skel_t *conflict_skel;
+  apr_array_header_t *cflcts;
+  svn_boolean_t prop_conflicted;
+  svn_boolean_t text_conflicted;
+  svn_boolean_t tree_conflicted;
+  svn_wc_operation_t operation;
+  const apr_array_header_t *locations;
+
+  SVN_ERR(svn_wc__db_read_conflict(&conflict_skel, db, local_abspath,
+                                   scratch_pool, scratch_pool));
+
+  if (!conflict_skel)
+    {
+      /* Some callers expect not NULL */
+      *conflicts = apr_array_make(result_pool, 0,
+                                  sizeof(svn_wc_conflict_description2_t*));;
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(svn_wc__conflict_read_info(&operation, &locations, &text_conflicted,
+                                     &prop_conflicted, &tree_conflicted,
+                                     db, local_abspath, conflict_skel,
+                                     scratch_pool, scratch_pool));
+
+  cflcts = apr_array_make(result_pool, 4,
+                          sizeof(svn_wc_conflict_description2_t*));
+
+  if (prop_conflicted)
+    {
+      svn_wc_conflict_description2_t *desc;
+      desc  = svn_wc_conflict_description_create_prop2(local_abspath,
+                                                       svn_node_unknown,
+                                                       "",
+                                                       result_pool);
+
+      SVN_ERR(svn_wc__conflict_read_prop_conflict(&desc->their_abspath,
+                                                  NULL, NULL,  NULL, NULL,
+                                                  db, local_abspath,
+                                                  conflict_skel,
+                                                  result_pool, scratch_pool));
+
+      APR_ARRAY_PUSH(cflcts, svn_wc_conflict_description2_t*) = desc;
+    }
+
+  if (text_conflicted)
+    {
+      svn_wc_conflict_description2_t *desc;
+      desc  = svn_wc_conflict_description_create_text2(local_abspath,
+                                                       result_pool);
+
+      SVN_ERR(svn_wc__conflict_read_text_conflict(&desc->my_abspath,
+                                                  &desc->base_abspath,
+                                                  &desc->their_abspath,
+                                                  db, local_abspath,
+                                                  conflict_skel,
+                                                  result_pool, scratch_pool));
+
+      desc->merged_file = apr_pstrdup(result_pool, local_abspath);
+
+      APR_ARRAY_PUSH(cflcts, svn_wc_conflict_description2_t*) = desc;
+    }
+
+  if (tree_conflicted)
+    {
+      svn_wc_conflict_description2_t *desc;
+      svn_wc_conflict_version_t *v1;
+      svn_wc_conflict_version_t *v2;
+      svn_node_kind_t tc_kind;
+      svn_wc_conflict_reason_t local_change;
+      svn_wc_conflict_action_t incoming_change;
+
+      SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change,
+                                                  &incoming_change,
+                                                  db, local_abspath,
+                                                  conflict_skel,
+                                                  scratch_pool, scratch_pool));
+
+      v1 = (locations && locations->nelts > 0)
+                    ? APR_ARRAY_IDX(locations, 0, svn_wc_conflict_version_t *)
+                    : NULL;
+
+      v2 = (locations && locations->nelts > 1)
+                    ? APR_ARRAY_IDX(locations, 1, svn_wc_conflict_version_t *)
+                    : NULL;
+
+      if (incoming_change != svn_wc_conflict_action_delete
+          && (operation == svn_wc_operation_update
+              || operation == svn_wc_operation_switch))
+        {
+          svn_wc__db_status_t status;
+          svn_revnum_t revision;
+          const char *repos_relpath;
+          const char *repos_root_url;
+          const char *repos_uuid;
+          svn_kind_t kind;
+          svn_error_t *err;
+
+          /* ### Theoretically we should just fetch the BASE information
+                 here. This code might need tweaks until all tree conflicts
+                 are installed in the proper state */
+
+          SVN_ERR_ASSERT(v2 == NULL); /* Not set for update and switch */
+
+          /* With an update or switch we have to fetch the second location
+             for a tree conflict from WORKING. (For text or prop from BASE)
+           */
+          err = svn_wc__db_base_get_info(&status, &kind, &revision,
+                                         &repos_relpath, &repos_root_url,
+                                         &repos_uuid, NULL, NULL, NULL,
+                                         NULL, NULL, NULL, NULL, NULL, NULL,
+                                         db, local_abspath,
+                                         scratch_pool, scratch_pool);
+
+          if (err)
+            {
+              if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+                return svn_error_trace(err);
+
+              svn_error_clear(err);
+              /* Ignore BASE */
+
+              tc_kind = svn_node_file; /* Avoid assertion */
+            }
+          else if (repos_relpath)
+            {
+              v2 = svn_wc_conflict_version_create2(repos_root_url,
+                                                   repos_uuid,
+                                                   repos_relpath,
+                                                   revision,
+                                            svn__node_kind_from_kind(kind),
+                                                   scratch_pool);
+              tc_kind = svn__node_kind_from_kind(kind);
+            }
+          else
+            tc_kind = svn_node_file; /* Avoid assertion */
+        }
+      else
+        {
+          if (v1)
+            tc_kind = v1->node_kind;
+          else if (v2)
+            tc_kind = v2->node_kind;
+          else
+            tc_kind = svn_node_file; /* Avoid assertion */
+        }
+
+      desc  = svn_wc_conflict_description_create_tree2(local_abspath, tc_kind,
+                                                       operation, v1, v2,
+                                                       result_pool);
+
+      desc->reason = local_change;
+      desc->action = incoming_change;
+
+      APR_ARRAY_PUSH(cflcts, const svn_wc_conflict_description2_t *) = desc;
+    }
 
+  *conflicts = cflcts;
+  return SVN_NO_ERROR;
+}
 
 
 /*** Resolving a conflict automatically ***/
@@ -140,42 +2104,42 @@ resolve_conflict_on_node(svn_boolean_t *
                          svn_wc_conflict_choice_t conflict_choice,
                          svn_cancel_func_t cancel_func_t,
                          void *cancel_baton,
-                         apr_pool_t *pool)
+                         apr_pool_t *scratch_pool)
 {
-  const char *conflict_old = NULL;
-  const char *conflict_new = NULL;
-  const char *conflict_working = NULL;
-  const char *prop_reject_file = NULL;
-  int i;
-  const apr_array_header_t *conflicts;
+  svn_skel_t *conflicts;
+  svn_boolean_t text_conflicted;
+  svn_boolean_t prop_conflicted;
+  svn_boolean_t tree_conflicted;
   svn_skel_t *work_items = NULL;
   svn_skel_t *work_item;
+  apr_pool_t *pool = scratch_pool;
 
   *did_resolve = FALSE;
 
-  SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
-                                    pool, pool));
-
-  for (i = 0; i < conflicts->nelts; i++)
-    {
-      const svn_wc_conflict_description2_t *desc;
+  SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath,
+                                   scratch_pool, scratch_pool));
 
-      desc = APR_ARRAY_IDX(conflicts, i,
-                           const svn_wc_conflict_description2_t*);
+  if (!conflicts)
+    return SVN_NO_ERROR;
 
-      if (desc->kind == svn_wc_conflict_kind_text)
-        {
-          conflict_old = desc->base_abspath;
-          conflict_new = desc->their_abspath;
-          conflict_working = desc->my_abspath;
-        }
-      else if (desc->kind == svn_wc_conflict_kind_property)
-        prop_reject_file = desc->their_abspath;
-    }
+  SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, &text_conflicted,
+                                     &prop_conflicted, &tree_conflicted,
+                                     db, local_abspath, conflicts,
+                                     scratch_pool, scratch_pool));
 
-  if (resolve_text)
+  if (resolve_text && text_conflicted)
     {
+      const char *conflict_old = NULL;
+      const char *conflict_new = NULL;
+      const char *conflict_working = NULL;
       const char *auto_resolve_src;
+      svn_node_kind_t node_kind;
+
+      SVN_ERR(svn_wc__conflict_read_text_conflict(&conflict_working,
+                                                  &conflict_old,
+                                                  &conflict_new,
+                                                  db, local_abspath, conflicts,
+                                                  scratch_pool, scratch_pool));
 
       /* Handle automatic conflict resolution before the temporary files are
        * deleted, if necessary. */
@@ -247,11 +2211,6 @@ resolve_conflict_on_node(svn_boolean_t *
                     auto_resolve_src, local_abspath, pool, pool));
           work_items = svn_wc__wq_merge(work_items, work_item, pool);
         }
-    }
-
-  if (resolve_text)
-    {
-      svn_node_kind_t node_kind;
 
       /* Legacy behavior: Only report text conflicts as resolved when at least
          one conflict marker file exists.
@@ -298,9 +2257,16 @@ resolve_conflict_on_node(svn_boolean_t *
             }
         }
     }
-  if (resolve_props)
+
+  if (resolve_props && prop_conflicted)
     {
       svn_node_kind_t node_kind;
+      const char *prop_reject_file;
+
+      SVN_ERR(svn_wc__conflict_read_prop_conflict(&prop_reject_file,
+                                                  NULL, NULL, NULL, NULL,
+                                                  db, local_abspath, conflicts,
+                                                  scratch_pool, scratch_pool));
 
       /* Legacy behavior: Only report property conflicts as resolved when the
          property reject file exists
@@ -395,8 +2361,8 @@ conflict_status_walker(void *baton,
 
   iterpool = svn_pool_create(scratch_pool);
 
-  SVN_ERR(svn_wc__db_read_conflicts(&conflicts, db, local_abspath,
-                                    scratch_pool, iterpool));
+  SVN_ERR(svn_wc__read_conflicts(&conflicts, db, local_abspath,
+                                 scratch_pool, iterpool));
 
   for (i = 0; i < conflicts->nelts; i++)
     {



Mime
View raw message