You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/02/04 21:48:13 UTC

svn commit: r1442344 [17/39] - in /subversion/branches/fsfs-format7: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ doc/...

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_editor.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_editor.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_editor.c Mon Feb  4 20:48:05 2013
@@ -63,6 +63,8 @@
 
 #include "private/svn_subr_private.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_diff_tree.h"
+#include "private/svn_editor.h"
 
 #include "wc.h"
 #include "props.h"
@@ -170,7 +172,7 @@ get_pristine_file(const char **result_ab
   if (!use_base)
     {
       SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, NULL, NULL, NULL, NULL,
-                                            &checksum, NULL, NULL,
+                                            &checksum, NULL, NULL, NULL,
                                             db, local_abspath,
                                             scratch_pool, scratch_pool));
     }
@@ -178,7 +180,7 @@ get_pristine_file(const char **result_ab
     {
       SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
                                        NULL, NULL, NULL, NULL, &checksum,
-                                       NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL,
                                        db, local_abspath,
                                        scratch_pool, scratch_pool));
     }
@@ -286,6 +288,9 @@ struct dir_baton {
   /* The list of incoming BASE->repos propchanges. */
   apr_array_header_t *propchanges;
 
+  /* Has a change on regular properties */
+  svn_boolean_t has_propchange;
+
   /* The overall crawler editor baton. */
   struct edit_baton *eb;
 
@@ -314,6 +319,9 @@ struct file_baton {
   /* The list of incoming BASE->repos propchanges. */
   apr_array_header_t *propchanges;
 
+  /* Has a change on regular properties */
+  svn_boolean_t has_propchange;
+
   /* The current checksum on disk */
   const svn_checksum_t *base_checksum;
 
@@ -411,7 +419,7 @@ make_dir_baton(const char *path,
   db->added = added;
   db->depth = depth;
   db->pool = dir_pool;
-  db->propchanges = apr_array_make(dir_pool, 1, sizeof(svn_prop_t));
+  db->propchanges = apr_array_make(dir_pool, 8, sizeof(svn_prop_t));
   db->compared = apr_hash_make(dir_pool);
   db->path = apr_pstrdup(dir_pool, path);
 
@@ -444,7 +452,7 @@ make_file_baton(const char *path,
   fb->eb = eb;
   fb->added = added;
   fb->pool = file_pool;
-  fb->propchanges  = apr_array_make(file_pool, 1, sizeof(svn_prop_t));
+  fb->propchanges  = apr_array_make(file_pool, 8, sizeof(svn_prop_t));
   fb->path = apr_pstrdup(file_pool, path);
 
   fb->name = svn_dirent_basename(fb->path, NULL);
@@ -485,32 +493,6 @@ get_prop_mimetype(apr_hash_t *props)
   return svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
 }
 
-
-/* Return the property hash resulting from combining PROPS and PROPCHANGES.
- *
- * A note on pool usage: The returned hash and hash keys are allocated in
- * the same pool as PROPS, but the hash values will be taken directly from
- * either PROPS or PROPCHANGES, as appropriate.  Caller must therefore
- * ensure that the returned hash is only used for as long as PROPS and
- * PROPCHANGES remain valid.
- */
-static apr_hash_t *
-apply_propchanges(apr_hash_t *props,
-                  const apr_array_header_t *propchanges)
-{
-  apr_hash_t *newprops = apr_hash_copy(apr_hash_pool_get(props), props);
-  int i;
-
-  for (i = 0; i < propchanges->nelts; ++i)
-    {
-      const svn_prop_t *prop = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
-      apr_hash_set(newprops, prop->name, APR_HASH_KEY_STRING, prop->value);
-    }
-
-  return newprops;
-}
-
-
 /* Diff the file PATH against its text base.  At this
  * stage we are dealing with a file that does exist in the working copy.
  *
@@ -549,15 +531,15 @@ file_diff(struct edit_baton *eb,
     return SVN_NO_ERROR;
 
   SVN_ERR(svn_wc__db_read_info(&status, NULL, &revision, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL,
-                               &have_base, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL,
+                               &original_repos_relpath, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, &have_base, NULL, NULL,
                                db, local_abspath, scratch_pool, scratch_pool));
   if (have_base)
     SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &revert_base_revnum,
                                      NULL, NULL, NULL, NULL, NULL, NULL,
-                                     NULL, NULL, NULL, NULL, NULL, NULL,
+                                     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                      db, local_abspath,
                                      scratch_pool, scratch_pool));
 
@@ -569,7 +551,7 @@ file_diff(struct edit_baton *eb,
      the latter two have corresponding pristine info to diff against.  */
   if (status == svn_wc__db_status_added)
     SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL,
-                                     &original_repos_relpath, NULL, NULL,
+                                     NULL, NULL, NULL,
                                      NULL, NULL, NULL, db, local_abspath,
                                      scratch_pool, scratch_pool));
 
@@ -610,8 +592,8 @@ file_diff(struct edit_baton *eb,
       apr_hash_t *baseprops;
 
       /* Get svn:mime-type from pristine props (in BASE or WORKING) of PATH. */
-      SVN_ERR(svn_wc__get_pristine_props(&baseprops, db, local_abspath,
-                                         scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__db_read_pristine_props(&baseprops, db, local_abspath,
+                                             scratch_pool, scratch_pool));
       if (baseprops)
         base_mimetype = get_prop_mimetype(baseprops);
       else
@@ -731,8 +713,8 @@ file_diff(struct edit_baton *eb,
                          || status == svn_wc__db_status_copied
                          || status == svn_wc__db_status_moved_here);
 
-          SVN_ERR(svn_wc__get_pristine_props(&baseprops, db, local_abspath,
-                                             scratch_pool, scratch_pool));
+          SVN_ERR(svn_wc__db_read_pristine_props(&baseprops, db, local_abspath,
+                                                 scratch_pool, scratch_pool));
 
           /* baseprops will be NULL for added nodes */
           if (!baseprops)
@@ -984,8 +966,8 @@ report_wc_file_as_added(struct edit_bato
   emptyprops = apr_hash_make(scratch_pool);
 
   if (eb->use_text_base)
-    SVN_ERR(svn_wc__get_pristine_props(&wcprops, db, local_abspath,
-                                       scratch_pool, scratch_pool));
+    SVN_ERR(svn_wc__db_read_pristine_props(&wcprops, db, local_abspath,
+                                           scratch_pool, scratch_pool));
   else
     SVN_ERR(svn_wc__get_actual_props(&wcprops, db, local_abspath,
                                      scratch_pool, scratch_pool));
@@ -996,16 +978,21 @@ report_wc_file_as_added(struct edit_bato
 
 
   if (eb->use_text_base)
-    SVN_ERR(get_pristine_file(&source_file, db, local_abspath,
-                              FALSE, scratch_pool, scratch_pool));
+    {
+      SVN_ERR(get_pristine_file(&source_file, db, local_abspath,
+                                FALSE, scratch_pool, scratch_pool));
+      translated_file = source_file; /* No translation needed */
+    }
   else
-    source_file = local_abspath;
+    {
+      source_file = local_abspath;
 
-  SVN_ERR(svn_wc__internal_translated_file(
+      SVN_ERR(svn_wc__internal_translated_file(
            &translated_file, source_file, db, local_abspath,
            SVN_WC_TRANSLATE_TO_NF | SVN_WC_TRANSLATE_USE_GLOBAL_TMP,
            eb->cancel_func, eb->cancel_baton,
            scratch_pool, scratch_pool));
+    }
 
   SVN_ERR(eb->callbacks->file_added(NULL, NULL, NULL,
                                     path,
@@ -1054,8 +1041,8 @@ report_wc_directory_as_added(struct edit
                                         eb->changelist_hash, scratch_pool))
     {
       if (eb->use_text_base)
-        SVN_ERR(svn_wc__get_pristine_props(&wcprops, db, local_abspath,
-                                           scratch_pool, scratch_pool));
+        SVN_ERR(svn_wc__db_read_pristine_props(&wcprops, db, local_abspath,
+                                               scratch_pool, scratch_pool));
       else
         SVN_ERR(svn_wc__get_actual_props(&wcprops, db, local_abspath,
                                          scratch_pool, scratch_pool));
@@ -1227,8 +1214,9 @@ delete_entry(const char *path,
           SVN_ERR(get_pristine_file(&textbase, db, local_abspath,
                                     eb->use_text_base, pool, pool));
 
-          SVN_ERR(svn_wc__get_pristine_props(&baseprops, eb->db, local_abspath,
-                                             pool, pool));
+          SVN_ERR(svn_wc__db_read_pristine_props(&baseprops,
+                                                 eb->db, local_abspath,
+                                                 pool, pool));
           base_mimetype = get_prop_mimetype(baseprops);
 
           SVN_ERR(eb->callbacks->file_deleted(NULL, NULL, path,
@@ -1282,11 +1270,10 @@ add_directory(const char *path,
                       dir_pool);
   *child_baton = db;
 
-  /* Add this path to the parent directory's list of elements that
-     have been compared. */
-  apr_hash_set(pb->compared, apr_pstrdup(pb->pool, db->path),
-               APR_HASH_KEY_STRING, "");
-
+  /* Issue #3797: Don't add this filename to the parent directory's list of
+     elements that have been compared, to show local additions via the local
+     diff. The repository node is unrelated from the working copy version
+     (similar to not-present in the working copy) */
 
   return SVN_NO_ERROR;
 }
@@ -1349,9 +1336,10 @@ close_directory(void *dir_baton,
         {
           if (db->eb->use_text_base)
             {
-              SVN_ERR(svn_wc__get_pristine_props(&originalprops,
-                                                 eb->db, db->local_abspath,
-                                                 scratch_pool, scratch_pool));
+              SVN_ERR(svn_wc__db_read_pristine_props(&originalprops,
+                                                     eb->db, db->local_abspath,
+                                                     scratch_pool,
+                                                     scratch_pool));
             }
           else
             {
@@ -1362,11 +1350,12 @@ close_directory(void *dir_baton,
                                                scratch_pool, scratch_pool));
 
               /* Load the BASE and repository directory properties. */
-              SVN_ERR(svn_wc__get_pristine_props(&base_props,
-                                                 eb->db, db->local_abspath,
-                                                 scratch_pool, scratch_pool));
+              SVN_ERR(svn_wc__db_base_get_props(&base_props,
+                                                eb->db, db->local_abspath,
+                                                scratch_pool, scratch_pool));
 
-              repos_props = apply_propchanges(base_props, db->propchanges);
+              repos_props = svn_prop__patch(base_props, db->propchanges,
+                                            scratch_pool);
 
               /* Recalculate b->propchanges as the change between WORKING
                  and repos. */
@@ -1431,10 +1420,10 @@ add_file(const char *path,
   fb = make_file_baton(path, TRUE, pb, file_pool);
   *file_baton = fb;
 
-  /* Add this filename to the parent directory's list of elements that
-     have been compared. */
-  apr_hash_set(pb->compared, apr_pstrdup(pb->pool, path),
-               APR_HASH_KEY_STRING, "");
+  /* Issue #3797: Don't add this filename to the parent directory's list of
+     elements that have been compared, to show local additions via the local
+     diff. The repository node is unrelated from the working copy version
+     (similar to not-present in the working copy) */
 
   return SVN_NO_ERROR;
 }
@@ -1461,7 +1450,7 @@ open_file(const char *path,
 
   SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                    NULL, NULL, NULL, &fb->base_checksum, NULL,
-                                   NULL, NULL, NULL,
+                                   NULL, NULL, NULL, NULL,
                                    eb->db, fb->local_abspath,
                                    fb->pool, fb->pool));
 
@@ -1640,7 +1629,7 @@ close_file(void *file_baton,
                                          NULL, NULL, NULL, NULL,
                                          &pristine_checksum,
                                          NULL, NULL,
-                                         &had_props, NULL,
+                                         &had_props, NULL, NULL,
                                          db, fb->local_abspath,
                                          scratch_pool, scratch_pool));
 
@@ -1663,7 +1652,7 @@ close_file(void *file_baton,
                                      fb->local_abspath,
                                      scratch_pool, scratch_pool));
 
-  repos_props = apply_propchanges(pristine_props, fb->propchanges);
+  repos_props = svn_prop__patch(pristine_props, fb->propchanges, scratch_pool);
   repos_mimetype = get_prop_mimetype(repos_props);
   repos_file = fb->temp_file_path ? fb->temp_file_path : pristine_file;
 
@@ -1804,6 +1793,13 @@ change_file_prop(void *file_baton,
 {
   struct file_baton *fb = file_baton;
   svn_prop_t *propchange;
+  svn_prop_kind_t propkind;
+
+  propkind = svn_property_kind2(name);
+  if (propkind == svn_prop_wc_kind)
+    return SVN_NO_ERROR;
+  else if (propkind == svn_prop_regular_kind)
+    fb->has_propchange = TRUE;
 
   propchange = apr_array_push(fb->propchanges);
   propchange->name = apr_pstrdup(fb->pool, name);
@@ -1822,6 +1818,13 @@ change_dir_prop(void *dir_baton,
 {
   struct dir_baton *db = dir_baton;
   svn_prop_t *propchange;
+  svn_prop_kind_t propkind;
+
+  propkind = svn_property_kind2(name);
+  if (propkind == svn_prop_wc_kind)
+    return SVN_NO_ERROR;
+  else if (propkind == svn_prop_regular_kind)
+    db->has_propchange = TRUE;
 
   propchange = apr_array_push(db->propchanges);
   propchange->name = apr_pstrdup(db->pool, name);
@@ -1951,3 +1954,399 @@ svn_wc__get_diff_editor(const svn_delta_
 
   return SVN_NO_ERROR;
 }
+
+/* Wrapping svn_wc_diff_callbacks4_t as svn_diff_tree_processor_t */
+
+/* baton for the svn_diff_tree_processor_t wrapper */
+typedef struct wc_diff_wrap_baton_t
+{
+  const svn_wc_diff_callbacks4_t *callbacks;
+  void *callback_baton;
+
+  svn_boolean_t walk_deleted_dirs;
+
+  apr_pool_t *result_pool;
+  const char *empty_file;
+
+} wc_diff_wrap_baton_t;
+
+static svn_error_t *
+wrap_ensure_empty_file(wc_diff_wrap_baton_t *wb,
+                       apr_pool_t *scratch_pool)
+{
+  if (wb->empty_file)
+    return SVN_NO_ERROR;
+
+  /* Create a unique file in the tempdir */
+  SVN_ERR(svn_io_open_uniquely_named(NULL, &wb->empty_file, NULL, NULL, NULL,
+                                     svn_io_file_del_on_pool_cleanup,
+                                     wb->result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_dir_opened(void **new_dir_baton,
+                svn_boolean_t *skip,
+                svn_boolean_t *skip_children,
+                const char *relpath,
+                const svn_diff_source_t *left_source,
+                const svn_diff_source_t *right_source,
+                const svn_diff_source_t *copyfrom_source,
+                void *parent_dir_baton,
+                const svn_diff_tree_processor_t *processor,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+
+  /* Maybe store state and tree_conflicted in baton? */
+  if (left_source != NULL)
+    {
+      /* Open for change or delete */
+      SVN_ERR(wb->callbacks->dir_opened(&tree_conflicted, skip, skip_children,
+                                        relpath,
+                                        right_source
+                                            ? right_source->revision
+                                            : (left_source
+                                                    ? left_source->revision
+                                                    : SVN_INVALID_REVNUM),
+                                        wb->callback_baton,
+                                        scratch_pool));
+
+      if (! right_source && !wb->walk_deleted_dirs)
+        *skip_children = TRUE;
+    }
+  else /* left_source == NULL -> Add */
+    {
+      svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+      SVN_ERR(wb->callbacks->dir_added(&state, &tree_conflicted,
+                                       skip, skip_children,
+                                       relpath,
+                                       right_source->revision,
+                                       copyfrom_source
+                                            ? copyfrom_source->repos_relpath
+                                            : NULL,
+                                       copyfrom_source
+                                            ? copyfrom_source->revision
+                                            : SVN_INVALID_REVNUM,
+                                       wb->callback_baton,
+                                       scratch_pool));
+    }
+
+  *new_dir_baton = NULL;
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_dir_added(const char *relpath,
+               const svn_diff_source_t *right_source,
+               const svn_diff_source_t *copyfrom_source,
+               /*const*/ apr_hash_t *copyfrom_props,
+               /*const*/ apr_hash_t *right_props,
+               void *dir_baton,
+               const svn_diff_tree_processor_t *processor,
+               apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_unknown;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_unknown;
+  apr_hash_t *pristine_props = copyfrom_props;
+  apr_array_header_t *prop_changes = NULL;
+
+  if (right_props && apr_hash_count(right_props))
+    {
+      if (!pristine_props)
+        pristine_props = apr_hash_make(scratch_pool);
+
+      SVN_ERR(svn_prop_diffs(&prop_changes, right_props, pristine_props,
+                             scratch_pool));
+
+      SVN_ERR(wb->callbacks->dir_props_changed(&prop_state,
+                                               &tree_conflicted,
+                                               relpath,
+                                               TRUE /* dir_was_added */,
+                                               prop_changes, pristine_props,
+                                               wb->callback_baton,
+                                               scratch_pool));
+    }
+
+  SVN_ERR(wb->callbacks->dir_closed(&state, &prop_state,
+                                   &tree_conflicted,
+                                   relpath,
+                                   TRUE /* dir_was_added */,
+                                   wb->callback_baton,
+                                   scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_dir_deleted(const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 /*const*/ apr_hash_t *left_props,
+                 void *dir_baton,
+                 const svn_diff_tree_processor_t *processor,
+                 apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+
+  SVN_ERR(wb->callbacks->dir_deleted(&state, &tree_conflicted,
+                                     relpath,
+                                     wb->callback_baton,
+                                     scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_dir_closed(const char *relpath,
+                const svn_diff_source_t *left_source,
+                const svn_diff_source_t *right_source,
+                void *dir_baton,
+                const svn_diff_tree_processor_t *processor,
+                apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+
+  /* No previous implementations provided these arguments, so we
+     are not providing them either */
+  SVN_ERR(wb->callbacks->dir_closed(NULL, NULL, NULL,
+                                    relpath,
+                                    (left_source == NULL) /* added */,
+                                    wb->callback_baton,
+                                    scratch_pool));
+
+return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_dir_changed(const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 const svn_diff_source_t *right_source,
+                 /*const*/ apr_hash_t *left_props,
+                 /*const*/ apr_hash_t *right_props,
+                 const apr_array_header_t *prop_changes,
+                 void *dir_baton,
+                 const struct svn_diff_tree_processor_t *processor,
+                 apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_inapplicable;
+
+  SVN_ERR(wb->callbacks->dir_props_changed(&prop_state, &tree_conflicted,
+                                           relpath,
+                                           (left_source == NULL) /* added */,
+                                           prop_changes,
+                                           left_props,
+                                           wb->callback_baton,
+                                           scratch_pool));
+
+  /* And call dir_closed, etc */
+  SVN_ERR(wrap_dir_closed(relpath, left_source, right_source,
+                          dir_baton, processor,
+                          scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_file_opened(void **new_file_baton,
+                 svn_boolean_t *skip,
+                 const char *relpath,
+                 const svn_diff_source_t *left_source,
+                 const svn_diff_source_t *right_source,
+                 const svn_diff_source_t *copyfrom_source,
+                 void *dir_baton,
+                 const svn_diff_tree_processor_t *processor,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+
+  if (left_source) /* If ! added */
+    SVN_ERR(wb->callbacks->file_opened(&tree_conflicted, skip, relpath,
+                                       right_source
+                                            ? right_source->revision
+                                            : (left_source
+                                                    ? left_source->revision
+                                                    : SVN_INVALID_REVNUM),
+                                       wb->callback_baton, scratch_pool));
+
+  /* No old implementation used the output arguments for notify */
+
+  *new_file_baton = NULL;
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_file_added(const char *relpath,
+                const svn_diff_source_t *copyfrom_source,
+                const svn_diff_source_t *right_source,
+                const char *copyfrom_file,
+                const char *right_file,
+                /*const*/ apr_hash_t *copyfrom_props,
+                /*const*/ apr_hash_t *right_props,
+                void *file_baton,
+                const svn_diff_tree_processor_t *processor,
+                apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_inapplicable;
+  apr_array_header_t *prop_changes;
+
+  if (! copyfrom_props)
+    copyfrom_props = apr_hash_make(scratch_pool);
+
+  SVN_ERR(svn_prop_diffs(&prop_changes, right_props, copyfrom_props,
+                         scratch_pool));
+
+  if (! copyfrom_source)
+    SVN_ERR(wrap_ensure_empty_file(wb, scratch_pool));
+
+  SVN_ERR(wb->callbacks->file_added(&state, &prop_state, &tree_conflicted,
+                                    relpath,
+                                    copyfrom_source
+                                        ? copyfrom_file
+                                        : wb->empty_file,
+                                    right_file,
+                                    copyfrom_source
+                                       ? copyfrom_source->revision
+                                       : 0 /* For legacy reasons */,
+                                    right_source->revision,
+                                    copyfrom_props
+                                     ? svn_prop_get_value(copyfrom_props,
+                                                          SVN_PROP_MIME_TYPE)
+                                     : NULL,
+                                    right_props
+                                     ? svn_prop_get_value(right_props,
+                                                          SVN_PROP_MIME_TYPE)
+                                     : NULL,
+                                    NULL, SVN_INVALID_REVNUM,
+                                    prop_changes, copyfrom_props,
+                                    wb->callback_baton,
+                                    scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+wrap_file_deleted(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const char *left_file,
+                  apr_hash_t *left_props,
+                  void *file_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+
+  SVN_ERR(wrap_ensure_empty_file(wb, scratch_pool));
+
+  SVN_ERR(wb->callbacks->file_deleted(&state, &tree_conflicted,
+                                      relpath,
+                                      left_file, wb->empty_file,
+                                      left_props
+                                       ? svn_prop_get_value(left_props,
+                                                            SVN_PROP_MIME_TYPE)
+                                       : NULL,
+                                      NULL,
+                                      left_props,
+                                      wb->callback_baton,
+                                      scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* svn_diff_tree_processor_t function */
+static svn_error_t *
+wrap_file_changed(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const svn_diff_source_t *right_source,
+                  const char *left_file,
+                  const char *right_file,
+                  /*const*/ apr_hash_t *left_props,
+                  /*const*/ apr_hash_t *right_props,
+                  svn_boolean_t file_modified,
+                  const apr_array_header_t *prop_changes,
+                  void *file_baton,
+                  const svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wb = processor->baton;
+  svn_boolean_t tree_conflicted = FALSE;
+  svn_wc_notify_state_t state = svn_wc_notify_state_inapplicable;
+  svn_wc_notify_state_t prop_state = svn_wc_notify_state_inapplicable;
+
+  SVN_ERR(wrap_ensure_empty_file(wb, scratch_pool));
+
+  SVN_ERR(wb->callbacks->file_changed(&state, &prop_state, &tree_conflicted,
+                                      relpath,
+                                      left_file, right_file,
+                                      left_source->revision,
+                                      right_source->revision,
+                                      left_props
+                                       ? svn_prop_get_value(left_props,
+                                                            SVN_PROP_MIME_TYPE)
+                                       : NULL,
+                                      right_props
+                                       ? svn_prop_get_value(right_props,
+                                                            SVN_PROP_MIME_TYPE)
+                                       : NULL,
+                                       prop_changes,
+                                      left_props,
+                                      wb->callback_baton,
+                                      scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__wrap_diff_callbacks(const svn_diff_tree_processor_t **diff_processor,
+                            const svn_wc_diff_callbacks4_t *callbacks,
+                            void *callback_baton,
+                            svn_boolean_t walk_deleted_dirs,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
+{
+  wc_diff_wrap_baton_t *wrap_baton;
+  svn_diff_tree_processor_t *processor;
+
+  wrap_baton = apr_pcalloc(result_pool, sizeof(*wrap_baton));
+
+  wrap_baton->result_pool = result_pool;
+  wrap_baton->callbacks = callbacks;
+  wrap_baton->callback_baton = callback_baton;
+  wrap_baton->empty_file = NULL;
+  wrap_baton->walk_deleted_dirs = walk_deleted_dirs;
+
+  processor = svn_diff__tree_processor_create(wrap_baton, result_pool);
+
+  processor->dir_opened   = wrap_dir_opened;
+  processor->dir_added    = wrap_dir_added;
+  processor->dir_deleted  = wrap_dir_deleted;
+  processor->dir_changed  = wrap_dir_changed;
+  processor->dir_closed   = wrap_dir_closed;
+
+  processor->file_opened   = wrap_file_opened;
+  processor->file_added    = wrap_file_added;
+  processor->file_deleted  = wrap_file_deleted;
+  processor->file_changed  = wrap_file_changed;
+  /*processor->file_closed   = wrap_file_closed*/; /* Not needed */
+
+  *diff_processor = processor;
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_local.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/diff_local.c Mon Feb  4 20:48:05 2013
@@ -172,7 +172,7 @@ file_diff(struct diff_baton *eb,
                                            &base_revision,
                                            NULL, NULL, NULL, NULL, NULL, NULL,
                                            NULL, &base_checksum, NULL,
-                                           NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL,
                                            db, local_abspath,
                                            scratch_pool, scratch_pool));
 
@@ -204,11 +204,10 @@ file_diff(struct diff_baton *eb,
      the latter two have corresponding pristine info to diff against.  */
   if (status == svn_wc__db_status_added)
     SVN_ERR(svn_wc__db_scan_addition(&status, NULL, NULL, NULL, NULL,
-                                     &original_repos_relpath, NULL, NULL,
+                                     NULL, NULL, NULL,
                                      NULL, NULL, NULL, db, local_abspath,
                                      scratch_pool, scratch_pool));
 
-
   SVN_ERR(get_empty_file(eb, &empty_file, scratch_pool));
 
   /* When we show a delete, we show a diff of the original pristine against
@@ -239,12 +238,13 @@ file_diff(struct diff_baton *eb,
           /* We show a deletion of what was actually deleted */
           SVN_ERR_ASSERT(status == svn_wc__db_status_deleted);
 
-          SVN_ERR(svn_wc__get_pristine_props(&del_props, db, local_abspath,
-                                             scratch_pool, scratch_pool));
+          SVN_ERR(svn_wc__db_read_pristine_props(&del_props, db, local_abspath,
+                                                 scratch_pool, scratch_pool));
 
           SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, NULL, NULL, NULL,
                                                 NULL, &del_checksum, NULL,
-                                                NULL, db, local_abspath,
+                                                NULL, NULL,
+                                                db, local_abspath,
                                                 scratch_pool, scratch_pool));
         }
 
@@ -445,25 +445,11 @@ diff_status_callback(void *baton,
         break; /* Go check other conditions */
     }
 
-  /* Filter items by changelist. */
-  /* ### duplicated in ../libsvn_client/status.c */
-  if (eb->changelist_hash)
-    {
-      if (status->changelist)
-        {
-          /* Skip unless the caller requested this changelist. */
-          if (! apr_hash_get(eb->changelist_hash, status->changelist,
-                             APR_HASH_KEY_STRING))
-            return SVN_NO_ERROR;
-        }
-      else
-        {
-          /* Skip unless the caller requested changelist-lacking items. */
-          if (! apr_hash_get(eb->changelist_hash, "",
-                             APR_HASH_KEY_STRING))
-            return SVN_NO_ERROR;
-        }
-    }
+  if (eb->changelist_hash != NULL
+      && (!status->changelist
+          || ! apr_hash_get(eb->changelist_hash, status->changelist,
+                            APR_HASH_KEY_STRING)))
+    return SVN_NO_ERROR; /* Filtered via changelist */
 
   /* ### The following checks should probably be reversed as it should decide
          when *not* to show a diff, because generally all changed nodes should
@@ -513,9 +499,7 @@ diff_status_callback(void *baton,
       /* Report the prop change. */
       /* ### This case should probably be extended for git-diff, but this
              is what the old diff code provided */
-      if (status->node_status == svn_wc_status_deleted
-          || status->node_status == svn_wc_status_replaced
-          || status->prop_status == svn_wc_status_modified)
+      if (status->prop_status == svn_wc_status_modified)
         {
           apr_array_header_t *propchanges;
           apr_hash_t *baseprops;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/entries.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/entries.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/entries.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/entries.c Mon Feb  4 20:48:05 2013
@@ -64,12 +64,12 @@ typedef struct db_node_t {
   svn_revnum_t revision;
   svn_node_kind_t kind;  /* ### should switch to svn_kind_t */
   svn_checksum_t *checksum;
-  svn_filesize_t translated_size;
+  svn_filesize_t recorded_size;
   svn_revnum_t changed_rev;
   apr_time_t changed_date;
   const char *changed_author;
   svn_depth_t depth;
-  apr_time_t last_mod_time;
+  apr_time_t recorded_time;
   apr_hash_t *properties;
   svn_boolean_t file_external;
 } db_node_t;
@@ -208,6 +208,7 @@ get_info_for_deleted(svn_wc_entry_t *ent
                      svn_kind_t *kind,
                      const char **repos_relpath,
                      const svn_checksum_t **checksum,
+                     svn_wc__db_lock_t **lock,
                      svn_wc__db_t *db,
                      const char *entry_abspath,
                      const svn_wc_entry_t *parent_entry,
@@ -230,8 +231,8 @@ get_info_for_deleted(svn_wc_entry_t *ent
                                        &entry->depth,
                                        checksum,
                                        NULL,
-                                       NULL /* lock */,
-                                       &entry->has_props,
+                                       lock,
+                                       &entry->has_props, NULL,
                                        NULL,
                                        db,
                                        entry_abspath,
@@ -255,7 +256,7 @@ get_info_for_deleted(svn_wc_entry_t *ent
                                             &entry->depth,
                                             checksum,
                                             NULL,
-                                            &entry->has_props,
+                                            &entry->has_props, NULL,
                                             db,
                                             entry_abspath,
                                             result_pool,
@@ -296,7 +297,8 @@ get_info_for_deleted(svn_wc_entry_t *ent
           svn_wc__db_status_t status;
           SVN_ERR(svn_wc__db_base_get_info(&status, NULL, &entry->revision,
                                            NULL, NULL, NULL, NULL, NULL, NULL,
-                                           NULL, NULL, NULL, NULL, NULL, NULL,
+                                           NULL, NULL, NULL, lock, NULL, NULL,
+                                           NULL,
                                            db, entry_abspath,
                                            result_pool, scratch_pool));
 
@@ -565,7 +567,7 @@ read_one_entry(const svn_wc_entry_t **ne
                                            NULL, NULL, NULL,
                                            NULL, NULL, NULL,
                                            NULL, NULL, NULL,
-                                           NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL,
                                            db, entry_abspath,
                                            scratch_pool,
                                            scratch_pool));
@@ -823,6 +825,7 @@ read_one_entry(const svn_wc_entry_t **ne
                                    &kind,
                                    &repos_relpath,
                                    &checksum,
+                                   &lock,
                                    db, entry_abspath,
                                    parent_entry,
                                    have_base, have_more_work,
@@ -1463,7 +1466,7 @@ insert_node(svn_sqlite__db_t *sdb,
                             node->changed_rev,
                             node->changed_date,
                             node->changed_author,
-                            node->last_mod_time));
+                            node->recorded_time));
 
   if (node->repos_relpath)
     {
@@ -1513,8 +1516,8 @@ insert_node(svn_sqlite__db_t *sdb,
     SVN_ERR(svn_sqlite__bind_properties(stmt, 15, node->properties,
                                         scratch_pool));
 
-  if (node->translated_size != SVN_INVALID_FILESIZE)
-    SVN_ERR(svn_sqlite__bind_int64(stmt, 16, node->translated_size));
+  if (node->recorded_size != SVN_INVALID_FILESIZE)
+    SVN_ERR(svn_sqlite__bind_int64(stmt, 16, node->recorded_size));
 
   if (node->file_external)
     SVN_ERR(svn_sqlite__bind_int(stmt, 20, 1));
@@ -1777,6 +1780,17 @@ write_entry(struct write_baton **entry_n
           working_node->revision = parent_node->work->revision;
           working_node->op_depth = parent_node->work->op_depth;
         }
+      else if (parent_node->below_work
+                && parent_node->below_work->repos_relpath)
+        {
+          working_node->repos_id = repos_id;
+          working_node->repos_relpath
+            = svn_relpath_join(parent_node->below_work->repos_relpath,
+                               svn_relpath_basename(local_relpath, NULL),
+                               result_pool);
+          working_node->revision = parent_node->below_work->revision;
+          working_node->op_depth = parent_node->below_work->op_depth;
+        }
       else
         return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
                                  _("No copyfrom URL for '%s'"),
@@ -1905,8 +1919,8 @@ write_entry(struct write_baton **entry_n
       base_node->op_depth = 0;
       base_node->parent_relpath = parent_relpath;
       base_node->revision = entry->revision;
-      base_node->last_mod_time = entry->text_time;
-      base_node->translated_size = entry->working_size;
+      base_node->recorded_time = entry->text_time;
+      base_node->recorded_size = entry->working_size;
 
       if (entry->depth != svn_depth_exclude)
         base_node->depth = entry->depth;
@@ -2081,6 +2095,10 @@ write_entry(struct write_baton **entry_n
       below_working_node->presence = svn_wc__db_status_normal;
       below_working_node->kind = entry->kind;
       below_working_node->repos_id = work->repos_id;
+
+      /* This is just guessing. If the node below would have been switched
+         or if it was updated to a different version, the guess would 
+         fail. But we don't have better information pre wc-ng :( */
       if (work->repos_relpath)
         below_working_node->repos_relpath
           = svn_relpath_join(work->repos_relpath, entry->name,
@@ -2103,13 +2121,37 @@ write_entry(struct write_baton **entry_n
             below_working_node->checksum =
               text_base_info->revert_base.sha1_checksum;
         }
-      below_working_node->translated_size = 0;
+      below_working_node->recorded_size = 0;
       below_working_node->changed_rev = SVN_INVALID_REVNUM;
       below_working_node->changed_date = 0;
       below_working_node->changed_author = NULL;
       below_working_node->depth = svn_depth_infinity;
-      below_working_node->last_mod_time = 0;
+      below_working_node->recorded_time = 0;
       below_working_node->properties = NULL;
+
+      if (working_node
+          && entry->schedule == svn_wc_schedule_delete
+          && working_node->repos_relpath)
+        {
+          /* We are lucky, our guesses above are not necessary. The known
+             correct information is in working. But our op_depth design
+             expects more information here */
+          below_working_node->repos_relpath = working_node->repos_relpath;
+          below_working_node->repos_id = working_node->repos_id;
+          below_working_node->revision = working_node->revision;
+
+          /* Nice for 'svn status' */
+          below_working_node->changed_rev = entry->cmt_rev;
+          below_working_node->changed_date = entry->cmt_date;
+          below_working_node->changed_author = entry->cmt_author;
+
+          /* And now remove it from WORKING, because in wc-ng code
+             should read it from the lower layer */
+          working_node->repos_relpath = NULL;
+          working_node->repos_id = 0;
+          working_node->revision = SVN_INVALID_REVNUM;
+        }
+
       SVN_ERR(insert_node(sdb, below_working_node, scratch_pool));
     }
 
@@ -2120,8 +2162,8 @@ write_entry(struct write_baton **entry_n
       working_node->local_relpath = local_relpath;
       working_node->parent_relpath = parent_relpath;
       working_node->changed_rev = SVN_INVALID_REVNUM;
-      working_node->last_mod_time = entry->text_time;
-      working_node->translated_size = entry->working_size;
+      working_node->recorded_time = entry->text_time;
+      working_node->recorded_size = entry->working_size;
 
       if (entry->depth != svn_depth_exclude)
         working_node->depth = entry->depth;

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/externals.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/externals.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/externals.c Mon Feb  4 20:48:05 2013
@@ -45,6 +45,7 @@
 #include "svn_wc.h"
 
 #include "private/svn_skel.h"
+#include "private/svn_subr_private.h"
 
 #include "wc.h"
 #include "adm_files.h"
@@ -413,6 +414,9 @@ struct edit_baton
   svn_revnum_t recorded_peg_revision;
   svn_revnum_t recorded_revision;
 
+  /* Introducing a new file external */
+  svn_boolean_t added;
+
   svn_wc_conflict_resolver_func2_t conflict_func;
   void *conflict_baton;
   svn_cancel_func_t cancel_func;
@@ -490,6 +494,7 @@ add_file(const char *path,
 
   *file_baton = eb;
   eb->original_revision = SVN_INVALID_REVNUM;
+  eb->added = TRUE;
 
   return SVN_NO_ERROR;
 }
@@ -515,7 +520,7 @@ open_file(const char *path,
                                    NULL, NULL, NULL, &eb->changed_rev,
                                    &eb->changed_date, &eb->changed_author,
                                    NULL, &eb->original_checksum, NULL, NULL,
-                                   &eb->had_props, NULL,
+                                   &eb->had_props, NULL, NULL,
                                    eb->db, eb->local_abspath,
                                    eb->pool, file_pool));
 
@@ -616,6 +621,7 @@ close_file(void *file_baton,
 
   eb->file_closed = TRUE; /* We bump the revision here */
 
+  /* Check the checksum, if provided */
   if (expected_md5_digest)
     {
       svn_checksum_t *expected_md5_checksum;
@@ -658,7 +664,6 @@ close_file(void *file_baton,
     }
 
   /* Merge the changes */
-
   {
     svn_skel_t *all_work_items = NULL;
     svn_skel_t *conflict_skel = NULL;
@@ -680,12 +685,11 @@ close_file(void *file_baton,
         new_checksum = eb->original_checksum;
 
         if (eb->had_props)
-          SVN_ERR(svn_wc__db_base_get_props(&base_props, eb->db,
-                                            eb->local_abspath,
-                                            pool, pool));
+          SVN_ERR(svn_wc__db_base_get_props(
+                    &base_props, eb->db, eb->local_abspath, pool, pool));
 
-        SVN_ERR(svn_wc__db_read_props(&actual_props, eb->db,
-                                      eb->local_abspath, pool, pool));
+        SVN_ERR(svn_wc__db_read_props(
+                  &actual_props, eb->db, eb->local_abspath, pool, pool));
       }
 
     if (!base_props)
@@ -697,6 +701,7 @@ close_file(void *file_baton,
     if (eb->new_sha1_checksum)
       new_checksum = eb->new_sha1_checksum;
 
+    /* Merge the properties */
     {
       apr_array_header_t *entry_prop_changes;
       apr_array_header_t *dav_prop_changes;
@@ -707,6 +712,7 @@ close_file(void *file_baton,
                                    &dav_prop_changes, &regular_prop_changes,
                                    pool));
 
+      /* Read the entry-prop changes to update the last-changed info. */
       for (i = 0; i < entry_prop_changes->nelts; i++)
         {
           const svn_prop_t *prop = &APR_ARRAY_IDX(entry_prop_changes, i,
@@ -728,24 +734,25 @@ close_file(void *file_baton,
                                           pool));
         }
 
+      /* Store the DAV-prop (aka WC-prop) changes.  (This treats a list
+       * of changes as a list of new props, but we only use this when
+       * adding a new file and it's equivalent in that case.) */
       if (dav_prop_changes->nelts > 0)
         new_dav_props = svn_prop_array_to_hash(dav_prop_changes, pool);
 
+      /* Merge the regular prop changes. */
       if (regular_prop_changes->nelts > 0)
         {
+          new_pristine_props = svn_prop__patch(base_props, regular_prop_changes,
+                                               pool);
           SVN_ERR(svn_wc__merge_props(&conflict_skel,
                                       &prop_state,
-                                      &new_pristine_props,
                                       &new_actual_props,
                                       eb->db, eb->local_abspath,
-                                      svn_kind_file,
                                       NULL /* server_baseprops*/,
                                       base_props,
                                       actual_props,
                                       regular_prop_changes,
-                                      TRUE /* base_merge */,
-                                      FALSE /* dry_run */,
-                                      eb->cancel_func, eb->cancel_baton,
                                       pool, pool));
         }
       else
@@ -755,6 +762,7 @@ close_file(void *file_baton,
         }
     }
 
+    /* Merge the text */
     if (eb->new_sha1_checksum)
       {
         svn_node_kind_t disk_kind;
@@ -769,7 +777,8 @@ close_file(void *file_baton,
             install_pristine = TRUE;
             content_state = svn_wc_notify_state_changed;
           }
-        else if (disk_kind != svn_node_file)
+        else if (disk_kind != svn_node_file
+                 || (eb->added && disk_kind == svn_node_file))
           {
             /* The node is obstructed; we just change the DB */
             obstructed = TRUE;
@@ -789,11 +798,12 @@ close_file(void *file_baton,
               }
             else
               {
-                enum svn_wc_merge_outcome_t merge_outcome;
+                svn_boolean_t found_text_conflict;
+
                 /* Ok, we have to do some work to merge a local change */
                 SVN_ERR(svn_wc__perform_file_merge(&work_item,
                                                    &conflict_skel,
-                                                   &merge_outcome,
+                                                   &found_text_conflict,
                                                    eb->db,
                                                    eb->local_abspath,
                                                    eb->wri_abspath,
@@ -812,7 +822,7 @@ close_file(void *file_baton,
                 all_work_items = svn_wc__wq_merge(all_work_items, work_item,
                                                   pool);
 
-                if (merge_outcome == svn_wc_merge_conflict)
+                if (found_text_conflict)
                   content_state = svn_wc_notify_state_conflicted;
                 else
                   content_state = svn_wc_notify_state_merged;
@@ -835,6 +845,7 @@ close_file(void *file_baton,
         /* ### Retranslate on magic property changes, etc. */
       }
 
+    /* Generate a conflict description, if needed */
     if (conflict_skel)
       {
         SVN_ERR(svn_wc__conflict_skel_set_op_switch(
@@ -846,18 +857,23 @@ close_file(void *file_baton,
                                     eb->original_revision,
                                     svn_node_file,
                                     pool),
+                            svn_wc_conflict_version_create2(
+                                    eb->repos_root_url,
+                                    eb->repos_uuid,
+                                    repos_relpath,
+                                    *eb->target_revision,
+                                    svn_node_file,
+                                    pool),
                             pool, pool));
-
-
         SVN_ERR(svn_wc__conflict_create_markers(&work_item,
                                                 eb->db, eb->local_abspath,
                                                 conflict_skel,
                                                 pool, pool));
-
         all_work_items = svn_wc__wq_merge(all_work_items, work_item,
                                           pool);
       }
 
+    /* Install the file in the DB */
     SVN_ERR(svn_wc__db_external_add_file(
                         eb->db,
                         eb->local_abspath,
@@ -889,16 +905,18 @@ close_file(void *file_baton,
        clear the iprops so as not to set them again in close_edit. */
     eb->iprops = NULL;
 
+    /* Run the work queue to complete the installation */
     SVN_ERR(svn_wc__wq_run(eb->db, eb->wri_abspath,
                            eb->cancel_func, eb->cancel_baton, pool));
   }
 
+  /* Notify */
   if (eb->notify_func)
     {
       svn_wc_notify_action_t action;
       svn_wc_notify_t *notify;
 
-      if (SVN_IS_VALID_REVNUM(eb->original_revision))
+      if (!eb->added)
         action = obstructed ? svn_wc_notify_update_shadowed_update
                             : svn_wc_notify_update_update;
       else
@@ -917,7 +935,6 @@ close_file(void *file_baton,
       eb->notify_func(eb->notify_baton, notify, pool);
     }
 
-
   return SVN_NO_ERROR;
 }
 
@@ -1071,7 +1088,7 @@ svn_wc__crawl_file_external(svn_wc_conte
   err = svn_wc__db_base_get_info(NULL, &kind, &revision,
                                  &repos_relpath, &repos_root_url, NULL, NULL,
                                  NULL, NULL, NULL, NULL, NULL, &lock,
-                                 NULL, &update_root,
+                                 NULL, NULL, &update_root,
                                  db, local_abspath,
                                  scratch_pool, scratch_pool);
 
@@ -1238,7 +1255,7 @@ is_external_rolled_out(svn_boolean_t *is
 
   err = svn_wc__db_base_get_info(NULL, NULL, NULL, &repos_relpath,
                                  &repos_root_url, NULL, NULL, NULL, NULL,
-                                 NULL, NULL, NULL, NULL, NULL, NULL,
+                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                  wc_ctx->db, xinfo->local_abspath,
                                  scratch_pool, scratch_pool);
 
@@ -1393,7 +1410,9 @@ svn_wc__external_remove(svn_wc_context_t
   else
     {
       SVN_ERR(svn_wc__db_base_remove(wc_ctx->db, local_abspath,
-                                     FALSE, SVN_INVALID_REVNUM,
+                                     FALSE /* keep_as_working */,
+                                     TRUE /* queue_deletes */,
+                                     SVN_INVALID_REVNUM,
                                      NULL, NULL, scratch_pool));
       SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
                              cancel_func, cancel_baton,

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/info.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/info.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/info.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/info.c Mon Feb  4 20:48:05 2013
@@ -172,7 +172,7 @@ build_info_for_node(svn_wc__info2_t **in
             SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, &tmpinfo->rev, NULL,
                                              NULL, NULL, NULL, NULL, NULL,
                                              NULL, NULL, NULL, NULL, NULL,
-                                             NULL,
+                                             NULL, NULL,
                                              db, local_abspath,
                                              scratch_pool, scratch_pool));
         }
@@ -226,7 +226,7 @@ build_info_for_node(svn_wc__info2_t **in
                                             &tmpinfo->last_changed_author,
                                             &wc_info->depth,
                                             &wc_info->checksum,
-                                            NULL, NULL,
+                                            NULL, NULL, NULL,
                                             db, local_abspath,
                                             result_pool, scratch_pool));
 
@@ -265,7 +265,7 @@ build_info_for_node(svn_wc__info2_t **in
                                            &tmpinfo->repos_root_URL,
                                            &tmpinfo->repos_UUID, NULL, NULL,
                                            NULL, NULL, NULL, NULL,
-                                           NULL, NULL, NULL,
+                                           NULL, NULL, NULL, NULL,
                                            db, local_abspath,
                                            result_pool, scratch_pool));
 

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/merge.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/merge.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/merge.c Mon Feb  4 20:48:05 2013
@@ -45,7 +45,7 @@ typedef struct merge_target_t
   const char *local_abspath;                /* The absolute path to target */
   const char *wri_abspath;                  /* The working copy of target */
 
-  apr_hash_t *actual_props;                 /* The set of actual properties
+  apr_hash_t *old_actual_props;                 /* The set of actual properties
                                                before merging */
   const apr_array_header_t *prop_diff;      /* The property changes */
 
@@ -58,18 +58,18 @@ typedef struct merge_target_t
 /* Return a pointer to the svn_prop_t structure from PROP_DIFF
    belonging to PROP_NAME, if any.  NULL otherwise.*/
 static const svn_prop_t *
-get_prop(const merge_target_t *mt,
+get_prop(const apr_array_header_t *prop_diff,
          const char *prop_name)
 {
-  if (mt && mt->prop_diff)
+  if (prop_diff)
     {
       int i;
-      for (i = 0; i < mt->prop_diff->nelts; i++)
+      for (i = 0; i < prop_diff->nelts; i++)
         {
-          const svn_prop_t *elt = &APR_ARRAY_IDX(mt->prop_diff, i,
+          const svn_prop_t *elt = &APR_ARRAY_IDX(prop_diff, i,
                                                  svn_prop_t);
 
-          if (strcmp(elt->name,prop_name) == 0)
+          if (strcmp(elt->name, prop_name) == 0)
             return elt;
         }
     }
@@ -85,8 +85,8 @@ get_prop(const merge_target_t *mt,
    3. Retranslate
    4. Detranslate
 
-   in 1 pass to get a file which can be compared with the left and right
-   files which were created with the 'new props' above.
+   in one pass, to get a file which can be compared with the left and right
+   files which are in repository normal form.
 
    Property changes make this a little complex though. Changes in
 
@@ -99,39 +99,48 @@ get_prop(const merge_target_t *mt,
 
    Effect for svn:mime-type:
 
-     The value for svn:mime-type affects the translation wrt keywords
-     and eol-style settings.
-
-   I) both old and new mime-types are texty
-      -> just do the translation dance (as lined out below)
-
-   II) the old one is texty, the new one is binary
-      -> detranslate with the old eol-style and keywords
-         (the new re+detranslation is a no-op)
-
-   III) the old one is binary, the new one texty
-      -> detranslate with the new eol-style
-         (the old detranslation is a no-op)
-
-   IV) the old and new ones are binary
-      -> don't detranslate, just make a straight copy
+     If svn:mime-type is considered 'binary', we ignore svn:eol-style (but
+     still translate keywords).
 
+     I) both old and new mime-types are texty
+        -> just do the translation dance (as lined out below)
+           ### actually we do a shortcut with just one translation:
+           detranslate with the old keywords and ... eol-style
+           (the new re+detranslation is a no-op w.r.t. keywords [1])
+
+     II) the old one is texty, the new one is binary
+        -> detranslate with the old eol-style and keywords
+           (the new re+detranslation is a no-op [1])
+
+     III) the old one is binary, the new one texty
+        -> detranslate with the old keywords and new eol-style
+           (the old detranslation is a no-op w.r.t. eol, and
+            the new re+detranslation is a no-op w.r.t. keywords [1])
+
+     IV) the old and new ones are binary
+        -> detranslate with the old keywords
+           (the new re+detranslation is a no-op [1])
 
    Effect for svn:eol-style
 
-   I) On add or change use the new value
-
-   II) otherwise: use the old value (absent means 'no translation')
+     I) On add or change of svn:eol-style, use the new value
 
+     II) otherwise: use the old value (absent means 'no translation')
 
    Effect for svn:keywords
 
-     Always use old settings (re+detranslation are no-op)
+     Always use the old settings (re+detranslation are no-op [1]).
 
+     [1] Translation of keywords from repository normal form to WC form and
+         back is normally a no-op, but is not a no-op if text contains a kw
+         that is only enabled by the new props and is present in non-
+         contracted form (such as "$Rev: 1234 $").  If we want to catch this
+         case we should detranslate with both the old & the new keywords
+         together.
 
    Effect for svn:special
 
-     Always use the old settings (same reasons as for svn:keywords)
+     Always use the old settings (re+detranslation are no-op).
 
   Sets *DETRANSLATED_ABSPATH to the path to the detranslated file,
   this may be the same as SOURCE_ABSPATH if FORCE_COPY is FALSE and no
@@ -156,54 +165,57 @@ detranslate_wc_file(const char **detrans
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
-  svn_boolean_t is_binary;
-  const svn_prop_t *prop;
+  svn_boolean_t old_is_binary, new_is_binary;
   svn_subst_eol_style_t style;
   const char *eol;
   apr_hash_t *keywords;
   svn_boolean_t special;
-  const char *mime_value = svn_prop_get_value(mt->actual_props,
-                                              SVN_PROP_MIME_TYPE);
 
-  is_binary = (mime_value && svn_mime_type_is_binary(mime_value));
+  {
+    const char *old_mime_value
+      = svn_prop_get_value(mt->old_actual_props, SVN_PROP_MIME_TYPE);
+    const svn_prop_t *prop = get_prop(mt->prop_diff, SVN_PROP_MIME_TYPE);
+    const char *new_mime_value
+      = prop ? (prop->value ? prop->value->data : NULL) : old_mime_value;
 
-  /* See if we need to do a straight copy:
-     - old and new mime-types are binary, or
-     - old mime-type is binary and no new mime-type specified */
-  if (is_binary
-      && (((prop = get_prop(mt, SVN_PROP_MIME_TYPE))
-           && prop->value && svn_mime_type_is_binary(prop->value->data))
-          || prop == NULL))
+    old_is_binary = old_mime_value && svn_mime_type_is_binary(old_mime_value);
+    new_is_binary = new_mime_value && svn_mime_type_is_binary(new_mime_value);;
+  }
+
+  /* See what translations we want to do */
+  if (old_is_binary && new_is_binary)
     {
-      /* this is case IV above */
-      keywords = NULL;
+      /* Case IV. Old and new props 'binary': detranslate keywords only */
+      SVN_ERR(svn_wc__get_translate_info(NULL, NULL, &keywords, NULL,
+                                         mt->db, mt->local_abspath,
+                                         mt->old_actual_props, TRUE,
+                                         scratch_pool, scratch_pool));
+      /* ### Why override 'special'? Elsewhere it has precedence. */
       special = FALSE;
       eol = NULL;
       style = svn_subst_eol_style_none;
     }
-  else if ((!is_binary)
-           && (prop = get_prop(mt, SVN_PROP_MIME_TYPE))
-           && prop->value && svn_mime_type_is_binary(prop->value->data))
+  else if (!old_is_binary && new_is_binary)
     {
-      /* Old props indicate texty, new props indicate binary:
+      /* Case II. Old props indicate texty, new props indicate binary:
          detranslate keywords and old eol-style */
       SVN_ERR(svn_wc__get_translate_info(&style, &eol,
                                          &keywords,
                                          &special,
                                          mt->db, mt->local_abspath,
-                                         mt->actual_props, TRUE,
+                                         mt->old_actual_props, TRUE,
                                          scratch_pool, scratch_pool));
     }
   else
     {
-      /* New props indicate texty, regardless of old props */
+      /* Case I & III. New props indicate texty, regardless of old props */
 
       /* In case the file used to be special, detranslate specially */
       SVN_ERR(svn_wc__get_translate_info(&style, &eol,
                                          &keywords,
                                          &special,
                                          mt->db, mt->local_abspath,
-                                         mt->actual_props, TRUE,
+                                         mt->old_actual_props, TRUE,
                                          scratch_pool, scratch_pool));
 
       if (special)
@@ -214,13 +226,15 @@ detranslate_wc_file(const char **detrans
         }
       else
         {
+          const svn_prop_t *prop;
+
           /* In case a new eol style was set, use that for detranslation */
-          if ((prop = get_prop(mt, SVN_PROP_EOL_STYLE)) && prop->value)
+          if ((prop = get_prop(mt->prop_diff, SVN_PROP_EOL_STYLE)) && prop->value)
             {
               /* Value added or changed */
               svn_subst_eol_style_from_value(&style, &eol, prop->value->data);
             }
-          else if (!is_binary)
+          else if (!old_is_binary)
             {
               /* Already fetched */
             }
@@ -229,11 +243,6 @@ detranslate_wc_file(const char **detrans
               eol = NULL;
               style = svn_subst_eol_style_none;
             }
-
-          /* In case there were keywords, detranslate with keywords
-             (iff we were texty) */
-          if (is_binary)
-            keywords = NULL;
         }
     }
 
@@ -288,19 +297,19 @@ detranslate_wc_file(const char **detrans
 }
 
 /* Updates (by copying and translating) the eol style in
-   OLD_TARGET returning the filename containing the
-   correct eol style in NEW_TARGET, if an eol style
-   change is contained in PROP_DIFF */
+   OLD_TARGET_ABSPATH returning the filename containing the
+   correct eol style in NEW_TARGET_ABSPATH, if an eol style
+   change is contained in PROP_DIFF. */
 static svn_error_t *
 maybe_update_target_eols(const char **new_target_abspath,
-                         const merge_target_t *mt,
+                         const apr_array_header_t *prop_diff,
                          const char *old_target_abspath,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
 {
-  const svn_prop_t *prop = get_prop(mt, SVN_PROP_EOL_STYLE);
+  const svn_prop_t *prop = get_prop(prop_diff, SVN_PROP_EOL_STYLE);
 
   if (prop && prop->value)
     {
@@ -366,16 +375,16 @@ init_conflict_markers(const char **targe
 }
 
 /* Do a 3-way merge of the files at paths LEFT, DETRANSLATED_TARGET,
- * and RIGHT, using diff options provided in OPTIONS.  Store the merge
+ * and RIGHT, using diff options provided in MERGE_OPTIONS.  Store the merge
  * result in the file RESULT_F.
  * If there are conflicts, set *CONTAINS_CONFLICTS to true, and use
  * TARGET_LABEL, LEFT_LABEL, and RIGHT_LABEL as labels for conflict
  * markers.  Else, set *CONTAINS_CONFLICTS to false.
  * Do all allocations in POOL. */
-static svn_error_t*
+static svn_error_t *
 do_text_merge(svn_boolean_t *contains_conflicts,
               apr_file_t *result_f,
-              const merge_target_t *mt,
+              const apr_array_header_t *merge_options,
               const char *detranslated_target,
               const char *left,
               const char *right,
@@ -393,9 +402,9 @@ do_text_merge(svn_boolean_t *contains_co
 
   diff3_options = svn_diff_file_options_create(pool);
 
-  if (mt->merge_options)
+  if (merge_options)
     SVN_ERR(svn_diff_file_options_parse(diff3_options,
-                                        mt->merge_options, pool));
+                                        merge_options, pool));
 
 
   init_conflict_markers(&target_marker, &left_marker, &right_marker,
@@ -424,10 +433,11 @@ do_text_merge(svn_boolean_t *contains_co
 /* Same as do_text_merge() above, but use the external diff3
  * command DIFF3_CMD to perform the merge.  Pass MERGE_OPTIONS
  * to the diff3 command.  Do all allocations in POOL. */
-static svn_error_t*
+static svn_error_t *
 do_text_merge_external(svn_boolean_t *contains_conflicts,
                        apr_file_t *result_f,
-                       const merge_target_t *mt,
+                       const char *diff3_cmd,
+                       const apr_array_header_t *merge_options,
                        const char *detranslated_target,
                        const char *left_abspath,
                        const char *right_abspath,
@@ -441,8 +451,8 @@ do_text_merge_external(svn_boolean_t *co
   SVN_ERR(svn_io_run_diff3_3(&exit_code, ".",
                              detranslated_target, left_abspath, right_abspath,
                              target_label, left_label, right_label,
-                             result_f, mt->diff3_cmd,
-                             mt->merge_options, scratch_pool));
+                             result_f, diff3_cmd,
+                             merge_options, scratch_pool));
 
   *contains_conflicts = exit_code == 1;
 
@@ -467,6 +477,7 @@ do_text_merge_external(svn_boolean_t *co
 
    If target_abspath is not versioned use detranslated_target_abspath
    as the target file.
+       ### NOT IMPLEMENTED -- 'detranslated_target_abspath' is not used.
 */
 static svn_error_t *
 preserve_pre_merge_files(svn_skel_t **work_items,
@@ -607,16 +618,42 @@ preserve_pre_merge_files(svn_skel_t **wo
   return SVN_NO_ERROR;
 }
 
-/* Attempt a trivial merge of LEFT_ABSPATH and RIGHT_ABSPATH to TARGET_ABSPATH.
- * The merge is trivial if the file at LEFT_ABSPATH equals the detranslated
- * form of the target at DETRANSLATED_TARGET_ABSPATH, because in this case
- * the content of RIGHT_ABSPATH can be copied to the target.
- * Another trivial case is if DETRANSLATED_TARGET_ABSPATH is identical to 
- * RIGHT_ABSPATH - we can just accept the existing content as merge result.
+/* Attempt a trivial merge of LEFT_ABSPATH and RIGHT_ABSPATH to
+ * the target file at TARGET_ABSPATH.
+ *
+ * These are the inherently trivial cases:
+ *
+ *   left == right == target         =>  no-op
+ *   left != right, left == target   =>  target := right
+ *
+ * This case is also treated as trivial:
+ *
+ *   left != right, right == target  =>  no-op
+ *
+ *   ### Strictly, this case is a conflict, and the no-op outcome is only
+ *       one of the possible resolutions.
+ *
+ *       TODO: Raise a conflict at this level and implement the 'no-op'
+ *       resolution of that conflict at a higher level, in preparation for
+ *       being able to support stricter conflict detection.
+ *
+ * This case is inherently trivial but not currently handled here:
+ *
+ *   left == right != target         =>  no-op
+ *
+ * The files at LEFT_ABSPATH and RIGHT_ABSPATH are in repository normal
+ * form.  The file at DETRANSLATED_TARGET_ABSPATH is a copy of the target,
+ * 'detranslated' to repository normal form, or may be the target file
+ * itself if no translation is necessary.
+ *
+ * When this function updates the target file, it translates to working copy
+ * form.
+ *
  * On success, set *MERGE_OUTCOME to SVN_WC_MERGE_MERGED in case the
  * target was changed, or to SVN_WC_MERGE_UNCHANGED if the target was not
  * changed. Install work queue items allocated in RESULT_POOL in *WORK_ITEMS.
- * On failure, set *MERGE_OUTCOME to SVN_WC_MERGE_NO_MERGE. */
+ * On failure, set *MERGE_OUTCOME to SVN_WC_MERGE_NO_MERGE.
+ */
 static svn_error_t *
 merge_file_trivial(svn_skel_t **work_items,
                    enum svn_wc_merge_outcome_t *merge_outcome,
@@ -660,9 +697,8 @@ merge_file_trivial(svn_skel_t **work_ite
    * copy RIGHT directly. */
   if (same_left_target)
     {
-      /* Check whether the left side equals the right side.
-       * If it does, there is no change to merge so we leave the target
-       * unchanged. */
+      /* If the left side equals the right side, there is no change to merge
+       * so we leave the target unchanged. */
       if (same_left_right)
         {
           *merge_outcome = svn_wc_merge_unchanged;
@@ -704,8 +740,6 @@ merge_file_trivial(svn_skel_t **work_ite
                                            cancel_func, cancel_baton,
                                            scratch_pool));
 
-                  /* no need to strdup right_abspath, as the wq_build_()
-                     call already does that for us */
                   delete_src = TRUE;
                 }
 
@@ -733,9 +767,8 @@ merge_file_trivial(svn_skel_t **work_ite
     }
   else
     {
-      /* Check whether the existing version equals the right side. If it 
-       * does, the locally existing, changed file equals the incoming
-       * file, so there is no conflict. For binary files, we historically
+      /* If the locally existing, changed file equals the incoming 'right'
+       * file, there is no conflict.  For binary files, we historically
        * conflicted them needlessly, while merge_text_file figured it out 
        * eventually and returned svn_wc_merge_unchanged for them, which
        * is what we do here. */
@@ -751,7 +784,26 @@ merge_file_trivial(svn_skel_t **work_ite
 }
 
 
-/* XXX Insane amount of parameters... */
+/* Handle a non-trivial merge of 'text' files.  (Assume that a trivial
+ * merge was not possible.)
+ *
+ * Set *WORK_ITEMS, *CONFLICT_SKEL and *MERGE_OUTCOME according to the
+ * result -- to install the merged file, or to indicate a conflict.
+ *
+ * On successful merge, leave the result in a temporary file and set
+ * *WORK_ITEMS to hold work items that will translate and install that
+ * file into its proper form and place (unless DRY_RUN) and delete the
+ * temporary file (in any case).  Set *MERGE_OUTCOME to 'merged' or
+ * 'unchanged'.
+ *
+ * If a conflict occurs, set *MERGE_OUTCOME to 'conflicted', and (unless
+ * DRY_RUN) set *WORK_ITEMS and *CONFLICT_SKEL to record the conflict
+ * and copies of the pre-merge files.  See preserve_pre_merge_files()
+ * for details.
+ *
+ * On entry, all of the output pointers must be non-null and *CONFLICT_SKEL
+ * must either point to an existing conflict skel or be NULL.
+ */
 static svn_error_t*
 merge_text_file(svn_skel_t **work_items,
                 svn_skel_t **conflict_skel,
@@ -795,7 +847,8 @@ merge_text_file(svn_skel_t **work_items,
   if (mt->diff3_cmd)
       SVN_ERR(do_text_merge_external(&contains_conflicts,
                                      result_f,
-                                     mt,
+                                     mt->diff3_cmd,
+                                     mt->merge_options,
                                      detranslated_target_abspath,
                                      left_abspath,
                                      right_abspath,
@@ -806,7 +859,7 @@ merge_text_file(svn_skel_t **work_items,
   else /* Use internal merge. */
     SVN_ERR(do_text_merge(&contains_conflicts,
                           result_f,
-                          mt,
+                          mt->merge_options,
                           detranslated_target_abspath,
                           left_abspath,
                           right_abspath,
@@ -817,6 +870,7 @@ merge_text_file(svn_skel_t **work_items,
 
   SVN_ERR(svn_io_file_close(result_f, pool));
 
+  /* Determine the MERGE_OUTCOME, and record any conflict. */
   if (contains_conflicts && ! dry_run)
     {
       *merge_outcome = svn_wc_merge_conflict;
@@ -864,7 +918,7 @@ merge_text_file(svn_skel_t **work_items,
          whatever special file types we may invent in the future. */
       SVN_ERR(svn_wc__get_translate_info(NULL, NULL, NULL,
                                          &special, mt->db, mt->local_abspath,
-                                         mt->actual_props, TRUE,
+                                         mt->old_actual_props, TRUE,
                                          pool, pool));
       SVN_ERR(svn_io_files_contents_same_p(&same, result_target,
                                            (special ?
@@ -898,7 +952,32 @@ done:
   return SVN_NO_ERROR;
 }
 
-/* XXX Insane amount of parameters... */
+/* Handle a non-trivial merge of 'binary' files: don't actually merge, just
+ * flag a conflict.  (Assume that a trivial merge was not possible.)
+ *
+ * Copy* the files at LEFT_ABSPATH and RIGHT_ABSPATH into the same directory
+ * as the target file, giving them unique names that start with the target
+ * file's name and end with LEFT_LABEL and RIGHT_LABEL respectively.
+ * If the merge target has been 'detranslated' to repository normal form,
+ * move the detranslated file similarly to a unique name ending with
+ * TARGET_LABEL.
+ *
+ * ### * Why do we copy the left and right temp files when we could (maybe
+ *     not always?) move them?
+ *
+ * On entry, all of the output pointers must be non-null and *CONFLICT_SKEL
+ * must either point to an existing conflict skel or be NULL.
+ *
+ * Set *WORK_ITEMS, *CONFLICT_SKEL and *MERGE_OUTCOME to indicate the
+ * conflict.
+ *
+ * ### Why do we not use preserve_pre_merge_files() in here?  The
+ *     behaviour would be slightly different, more consistent: the
+ *     preserved 'left' and 'right' files would be translated to working
+ *     copy form, which may make a difference when a binary file
+ *     contains keyword expansions or when some versions of the file are
+ *     not 'binary' even though we're merging in 'binary files' mode.
+ */
 static svn_error_t *
 merge_binary_file(svn_skel_t **work_items,
                   svn_skel_t **conflict_skel,
@@ -925,9 +1004,6 @@ merge_binary_file(svn_skel_t **work_item
 
   svn_dirent_split(&merge_dirpath, &merge_filename, mt->local_abspath, pool);
 
-  /* If we get here the binary files differ. Because we don't know how
-   * to merge binary files in a non-trivial way we always flag a conflict. */
-
   if (dry_run)
     {
       *merge_outcome = svn_wc_merge_conflict;
@@ -994,7 +1070,6 @@ merge_binary_file(svn_skel_t **work_item
   return SVN_NO_ERROR;
 }
 
-/* XXX Insane amount of parameters... */
 svn_error_t *
 svn_wc__internal_merge(svn_skel_t **work_items,
                        svn_skel_t **conflict_skel,
@@ -1007,7 +1082,7 @@ svn_wc__internal_merge(svn_skel_t **work
                        const char *left_label,
                        const char *right_label,
                        const char *target_label,
-                       apr_hash_t *actual_props,
+                       apr_hash_t *old_actual_props,
                        svn_boolean_t dry_run,
                        const char *diff3_cmd,
                        const apr_array_header_t *merge_options,
@@ -1033,18 +1108,18 @@ svn_wc__internal_merge(svn_skel_t **work
   mt.db = db;
   mt.local_abspath = target_abspath;
   mt.wri_abspath = wri_abspath;
-  mt.actual_props = actual_props;
+  mt.old_actual_props = old_actual_props;
   mt.prop_diff = prop_diff;
   mt.diff3_cmd = diff3_cmd;
   mt.merge_options = merge_options;
 
   /* Decide if the merge target is a text or binary file. */
-  if ((mimeprop = get_prop(&mt, SVN_PROP_MIME_TYPE))
+  if ((mimeprop = get_prop(prop_diff, SVN_PROP_MIME_TYPE))
       && mimeprop->value)
     is_binary = svn_mime_type_is_binary(mimeprop->value->data);
   else
     {
-      const char *value = svn_prop_get_value(mt.actual_props,
+      const char *value = svn_prop_get_value(mt.old_actual_props,
                                              SVN_PROP_MIME_TYPE);
 
       is_binary = value && svn_mime_type_is_binary(value);
@@ -1059,7 +1134,7 @@ svn_wc__internal_merge(svn_skel_t **work
   /* We cannot depend on the left file to contain the same eols as the
      right file. If the merge target has mods, this will mark the entire
      file as conflicted, so we need to compensate. */
-  SVN_ERR(maybe_update_target_eols(&left_abspath, &mt, left_abspath,
+  SVN_ERR(maybe_update_target_eols(&left_abspath, prop_diff, left_abspath,
                                    cancel_func, cancel_baton,
                                    scratch_pool, scratch_pool));
 
@@ -1070,8 +1145,12 @@ svn_wc__internal_merge(svn_skel_t **work
                              result_pool, scratch_pool));
   if (*merge_outcome == svn_wc_merge_no_merge)
     {
+      /* We have a non-trivial merge.  If we classify it as a merge of
+       * 'binary' files we'll just raise a conflict, otherwise we'll do
+       * the actual merge of 'text' file contents. */
       if (is_binary)
         {
+          /* Raise a text conflict */
           SVN_ERR(merge_binary_file(work_items,
                                     conflict_skel,
                                     merge_outcome,
@@ -1145,7 +1224,7 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
   svn_skel_t *work_items;
   svn_skel_t *conflict_skel = NULL;
   apr_hash_t *pristine_props = NULL;
-  apr_hash_t *actual_props = NULL;
+  apr_hash_t *old_actual_props;
   apr_hash_t *new_actual_props = NULL;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(left_abspath));
@@ -1217,20 +1296,22 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
 
     if (props_mod)
       {
-        SVN_ERR(svn_wc__db_read_props(&actual_props,
+        SVN_ERR(svn_wc__db_read_props(&old_actual_props,
                                       wc_ctx->db, target_abspath,
                                       scratch_pool, scratch_pool));
       }
     else if (pristine_props)
-      actual_props = apr_hash_copy(scratch_pool, pristine_props);
+      old_actual_props = pristine_props;
     else
-      actual_props = apr_hash_make(scratch_pool);
+      old_actual_props = apr_hash_make(scratch_pool);
   }
 
+  /* Merge the properties, if requested.  We merge the properties first
+   * because the properties can affect the text (EOL style, keywords). */
   if (merge_props_outcome)
     {
       int i;
-      apr_hash_t *new_pristine_props;
+
       /* The PROPCHANGES may not have non-"normal" properties in it. If entry
          or wc props were allowed, then the following code would install them
          into the BASE and/or WORKING properties(!).  */
@@ -1249,16 +1330,14 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
 
       SVN_ERR(svn_wc__merge_props(&conflict_skel,
                                   merge_props_outcome,
-                                  &new_pristine_props, &new_actual_props,
-                                  wc_ctx->db, target_abspath, svn_kind_file,
-                                  original_props, pristine_props, actual_props,
-                                  prop_diff, FALSE /* base_merge */,
-                                  dry_run,
-                                  cancel_func, cancel_baton,
+                                  &new_actual_props,
+                                  wc_ctx->db, target_abspath,
+                                  original_props, pristine_props, old_actual_props,
+                                  prop_diff,
                                   scratch_pool, scratch_pool));
     }
 
-  /* Queue all the work.  */
+  /* Merge the text. */
   SVN_ERR(svn_wc__internal_merge(&work_items,
                                  &conflict_skel,
                                  merge_content_outcome,
@@ -1268,7 +1347,7 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
                                  target_abspath,
                                  target_abspath,
                                  left_label, right_label, target_label,
-                                 actual_props,
+                                 old_actual_props,
                                  dry_run,
                                  diff3_cmd,
                                  merge_options,
@@ -1317,28 +1396,28 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
                                scratch_pool));
 
       if (conflict_skel && conflict_func)
-        SVN_ERR(svn_wc__conflict_invoke_resolver(wc_ctx->db, target_abspath,
-                                                 conflict_skel, merge_options,
-                                                 conflict_func, conflict_baton,
-                                                 scratch_pool));
+        {
+          svn_boolean_t text_conflicted, prop_conflicted;
+
+          SVN_ERR(svn_wc__conflict_invoke_resolver(
+                    wc_ctx->db, target_abspath,
+                    conflict_skel, merge_options,
+                    conflict_func, conflict_baton,
+                    cancel_func, cancel_baton,
+                    scratch_pool));
+
+          /* Reset *MERGE_CONTENT_OUTCOME etc. if a conflict was resolved. */
+          SVN_ERR(svn_wc__internal_conflicted_p(
+                    &text_conflicted, &prop_conflicted, NULL,
+                    wc_ctx->db, target_abspath, scratch_pool));
+          if (*merge_props_outcome == svn_wc_notify_state_conflicted
+              && ! prop_conflicted)
+            *merge_props_outcome = svn_wc_notify_state_merged;
+          if (*merge_content_outcome == svn_wc_merge_conflict
+              && ! text_conflicted)
+            *merge_content_outcome = svn_wc_merge_merged;
+        }
     }
   
   return SVN_NO_ERROR;
 }
-
-
-/* Constructor for the result-structure returned by conflict callbacks. */
-svn_wc_conflict_result_t *
-svn_wc_create_conflict_result(svn_wc_conflict_choice_t choice,
-                              const char *merged_file,
-                              apr_pool_t *pool)
-{
-  svn_wc_conflict_result_t *result = apr_pcalloc(pool, sizeof(*result));
-  result->choice = choice;
-  result->merged_file = merged_file;
-  result->save_merged = FALSE;
-
-  /* If we add more fields to svn_wc_conflict_result_t, add them here. */
-
-  return result;
-}