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

svn commit: r984206 [18/35] - in /subversion/branches/ignore-mergeinfo: ./ build/ build/generator/ build/generator/templates/ build/hudson/ build/hudson/jobs/subversion-1.6.x-solaris/ build/hudson/jobs/subversion-1.6.x-ubuntu/ build/hudson/jobs/subvers...

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/merge.c?rev=984206&r1=984205&r2=984206&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/merge.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/merge.c Tue Aug 10 20:55:56 2010
@@ -35,6 +35,8 @@
 #include "lock.h"
 #include "workqueue.h"
 
+#include "private/svn_skel.h"
+
 #include "svn_private_config.h"
 
 
@@ -118,10 +120,12 @@ get_prop(const apr_array_header_t *prop_
 static svn_error_t *
 detranslate_wc_file(const char **detranslated_abspath,
                     svn_wc__db_t *db,
-                    const char *merge_abspath,
+                    const char *target_abspath,
                     svn_boolean_t force_copy,
                     const apr_array_header_t *prop_diff,
                     const char *source_abspath,
+                    svn_cancel_func_t cancel_func,
+                    void *cancel_baton,
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
@@ -133,7 +137,7 @@ detranslate_wc_file(const char **detrans
   svn_boolean_t special;
 
   /* Decide if the merge target currently is a text or binary file. */
-  SVN_ERR(svn_wc__marked_as_binary(&is_binary, merge_abspath, db,
+  SVN_ERR(svn_wc__marked_as_binary(&is_binary, target_abspath, db,
                                    scratch_pool));
 
   /* See if we need to do a straight copy:
@@ -156,16 +160,18 @@ detranslate_wc_file(const char **detrans
     {
       /* Old props indicate texty, new props indicate binary:
          detranslate keywords and old eol-style */
-      SVN_ERR(svn_wc__get_keywords(&keywords, db, merge_abspath, NULL,
+      SVN_ERR(svn_wc__get_keywords(&keywords, db, target_abspath, NULL,
                                    scratch_pool, scratch_pool));
-      SVN_ERR(svn_wc__get_special(&special, db, merge_abspath, scratch_pool));
+      SVN_ERR(svn_wc__get_special(&special, db, target_abspath, scratch_pool));
+      SVN_ERR(svn_wc__get_eol_style(&style, &eol, db, target_abspath,
+                                    scratch_pool, scratch_pool));
     }
   else
     {
       /* New props indicate texty, regardless of old props */
 
       /* In case the file used to be special, detranslate specially */
-      SVN_ERR(svn_wc__get_special(&special, db, merge_abspath, scratch_pool));
+      SVN_ERR(svn_wc__get_special(&special, db, target_abspath, scratch_pool));
 
       if (special)
         {
@@ -182,7 +188,7 @@ detranslate_wc_file(const char **detrans
               svn_subst_eol_style_from_value(&style, &eol, prop->value->data);
             }
           else if (!is_binary)
-            SVN_ERR(svn_wc__get_eol_style(&style, &eol, db, merge_abspath,
+            SVN_ERR(svn_wc__get_eol_style(&style, &eol, db, target_abspath,
                                           scratch_pool, scratch_pool));
           else
             {
@@ -193,7 +199,7 @@ detranslate_wc_file(const char **detrans
           /* In case there were keywords, detranslate with keywords
              (iff we were texty) */
           if (!is_binary)
-            SVN_ERR(svn_wc__get_keywords(&keywords, db, merge_abspath, NULL,
+            SVN_ERR(svn_wc__get_keywords(&keywords, db, target_abspath, NULL,
                                          scratch_pool, scratch_pool));
           else
             keywords = NULL;
@@ -209,7 +215,7 @@ detranslate_wc_file(const char **detrans
       /* Force a copy into the temporary wc area to avoid having
          temporary files created below to appear in the actual wc. */
 
-      /* ### svn_subst_copy_and_translate3() also creates a tempfile
+      /* ### svn_subst_copy_and_translate4() also creates a tempfile
          ### internally.  Anyway to piggyback on that? */
       SVN_ERR(svn_io_open_unique_file3(NULL, &detranslated, NULL,
                                       svn_io_file_del_on_pool_cleanup,
@@ -225,13 +231,14 @@ detranslate_wc_file(const char **detrans
                && style != svn_subst_eol_style_none)
         return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL);
 
-      SVN_ERR(svn_subst_copy_and_translate3(source_abspath,
+      SVN_ERR(svn_subst_copy_and_translate4(source_abspath,
                                             detranslated,
                                             eol,
                                             TRUE /* repair */,
                                             keywords,
                                             FALSE /* contract keywords */,
                                             special,
+                                            cancel_func, cancel_baton,
                                             scratch_pool));
 
       SVN_ERR(svn_dirent_get_absolute(detranslated_abspath, detranslated,
@@ -252,6 +259,8 @@ maybe_update_target_eols(const char **ne
                          svn_wc__db_t *db,
                          const char *old_target_abspath,
                          const apr_array_header_t *prop_diff,
+                         svn_cancel_func_t cancel_func,
+                         void *cancel_baton,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
 {
@@ -270,11 +279,15 @@ maybe_update_target_eols(const char **ne
       /* Always 'repair' EOLs here, so that we can apply a diff that
          changes from inconsistent newlines and no 'svn:eol-style' to
          consistent newlines and 'svn:eol-style' set.  */
-      SVN_ERR(svn_subst_copy_and_translate3(old_target_abspath,
+      SVN_ERR(svn_subst_copy_and_translate4(old_target_abspath,
                                             tmp_new,
-                                            eol, TRUE /* repair EOLs */,
-                                            NULL, FALSE,
-                                            FALSE, scratch_pool));
+                                            eol,
+                                            TRUE /* repair */,
+                                            NULL /* keywords */,
+                                            FALSE /* expand */,
+                                            FALSE /* special */,
+                                            cancel_func, cancel_baton,
+                                            scratch_pool));
       *new_target_abspath = apr_pstrdup(result_pool, tmp_new);
     }
   else
@@ -388,36 +401,46 @@ do_text_merge_external(svn_boolean_t *co
   return SVN_NO_ERROR;
 }
 
-/* Loggy-copy the merge result obtained during interactive conflict
- * resolution to the file RESULT_TARGET. The merge result is expected
- * in the same directory as TARGET_ABSPATH the same basename as
- * TARGET_ABSPATH, but followed by ".edited".
- * Use LOG_ACCUM as log accumulator.  DB contains an access baton with
- * a write lock for the directory containing RESULT_TARGET.
- * Do all allocations in POOL.
- */
+/* Return a work item to copy/translate the merge result, obtained during
+   interactive conflict resolution, to the file RESULT_TARGET. The merge
+   result is expected in the same directory as TARGET_ABSPATH, with the same
+   basename as TARGET_ABSPATH, with a ".edited" extension.
+
+   DB should have a write lock for the directory containing RESULT_TARGET.
+
+   *WORK_ITEM will be allocated in RESULT_POOL. All temporary allocations
+   will be allocated in SCRATCH_POOL.  */
 static svn_error_t*
-save_merge_result(svn_stringbuf_t **log_accum,
+save_merge_result(svn_skel_t **work_item,
                   svn_wc__db_t *db,
                   const char *target_abspath,
                   const char *result_target,
-                  apr_pool_t *pool)
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
-  const char *edited_copy;
-  const char *merge_dirpath, *merge_filename;
+  const char *edited_copy_abspath;
+  const char *dir_abspath;
+  const char *merge_filename;
 
-  svn_dirent_split(target_abspath, &merge_dirpath, &merge_filename, pool);
+  svn_dirent_split(target_abspath, &dir_abspath, &merge_filename,
+                   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,
-                                     merge_dirpath,
+                                     &edited_copy_abspath,
+                                     dir_abspath,
                                      merge_filename,
                                      ".edited",
                                      svn_io_file_del_none,
-                                     pool, pool));
-  SVN_ERR(svn_wc__loggy_copy(log_accum, merge_dirpath,
-                             result_target, edited_copy, pool, pool));
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_wc__loggy_translated_file(work_item,
+                                        db, dir_abspath,
+                                        edited_copy_abspath,
+                                        result_target,
+                                        target_abspath,
+                                        result_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -431,37 +454,42 @@ save_merge_result(svn_stringbuf_t **log_
  * diff3 implementation in case a 3-way  merge has to be carried out.
  * Do all allocations in POOL. */
 static svn_error_t*
-eval_conflict_func_result(enum svn_wc_merge_outcome_t *merge_outcome,
+eval_conflict_func_result(svn_skel_t **work_items,
+                          enum svn_wc_merge_outcome_t *merge_outcome,
                           svn_wc_conflict_result_t *result,
-                          svn_stringbuf_t **log_accum,
                           svn_wc__db_t *db,
-                          const char *left,
-                          const char *right,
-                          const char *merge_target,
+                          const char *left_abspath,
+                          const char *right_abspath,
+                          const char *target_abspath,
                           const char *copyfrom_text,
                           const char *adm_abspath,
                           const char *result_target,
                           const char *detranslated_target,
                           svn_diff_file_options_t *options,
-                          apr_pool_t *pool)
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
+  apr_pool_t *pool = scratch_pool;  /* ### temporary rename  */
+  const char *install_from = NULL;
+  svn_boolean_t remove_source = FALSE;
+
+  *work_items = NULL;
+
   switch (result->choice)
     {
       /* If the callback wants to use one of the fulltexts
          to resolve the conflict, so be it.*/
       case svn_wc_conflict_choose_base:
         {
-          SVN_ERR(svn_wc__loggy_copy(log_accum, adm_abspath,
-                                     left, merge_target, pool, pool));
+          install_from = left_abspath;
           *merge_outcome = svn_wc_merge_merged;
-          return SVN_NO_ERROR;
+          break;
         }
       case svn_wc_conflict_choose_theirs_full:
         {
-          SVN_ERR(svn_wc__loggy_copy(log_accum, adm_abspath,
-                                     right, merge_target, pool, pool));
+          install_from = right_abspath;
           *merge_outcome = svn_wc_merge_merged;
-          return SVN_NO_ERROR;
+          break;
         }
       case svn_wc_conflict_choose_mine_full:
         {
@@ -489,22 +517,24 @@ eval_conflict_func_result(enum svn_wc_me
                                          svn_io_file_del_none, pool, pool));
 
           SVN_ERR(svn_diff_file_diff3_2(&diff,
-                                        left, detranslated_target, right,
+                                        left_abspath,
+                                        detranslated_target, right_abspath,
                                         options, pool));
           SVN_ERR(svn_diff_file_output_merge2(chosen_stream, diff,
-                                              left,
+                                              left_abspath,
                                               detranslated_target,
-                                              right,
+                                              right_abspath,
                                               /* markers ignored */
                                               NULL, NULL,
                                               NULL, NULL,
                                               style,
                                               pool));
           SVN_ERR(svn_stream_close(chosen_stream));
-          SVN_ERR(svn_wc__loggy_copy(log_accum, adm_abspath,
-                                     chosen_path, merge_target, pool, pool));
+
+          install_from = chosen_path;
+          remove_source = TRUE;
           *merge_outcome = svn_wc_merge_merged;
-          return SVN_NO_ERROR;
+          break;
         }
 
         /* For the case of 3-way file merging, we don't
@@ -515,40 +545,65 @@ eval_conflict_func_result(enum svn_wc_me
            good to use". */
       case svn_wc_conflict_choose_merged:
         {
-          SVN_ERR(svn_wc__loggy_copy(log_accum, adm_abspath,
-                                     /* Look for callback's own
-                                        merged-file first: */
-                                     result->merged_file
-                                       ? result->merged_file
-                                       : result_target,
-                                     merge_target,
-                                     pool, pool));
+          /* Look for callback's own merged-file first:  */
+          install_from = (result->merged_file
+                            ? result->merged_file
+                            : result_target);
           *merge_outcome = svn_wc_merge_merged;
-          return SVN_NO_ERROR;
+          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
+
           /* Issue #3354: We need to install the copyfrom_text,
            * which now carries conflicts, into ACTUAL, by copying
            * it to the merge target. */
           if (copyfrom_text)
             {
-              SVN_ERR(svn_wc__loggy_copy(log_accum, adm_abspath,
-                                     copyfrom_text, merge_target,
-                                     pool, pool));
+              install_from = copyfrom_text;
+              break;
             }
 
           /* 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, target_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;
 }
 
 /* Preserve the three pre-merge files, and modify the
    entry (mark as conflicted, track the preserved files). */
 static svn_error_t*
-preserve_pre_merge_files(svn_stringbuf_t **log_accum,
+preserve_pre_merge_files(svn_skel_t **work_items,
                          svn_wc__db_t *db,
                          const char *left_abspath,
                          const char *right_abspath,
@@ -556,13 +611,20 @@ preserve_pre_merge_files(svn_stringbuf_t
                          const char *left_label,
                          const char *right_label,
                          const char *target_label,
-                         apr_pool_t *pool)
+                         svn_cancel_func_t cancel_func,
+                         void *cancel_baton,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
 {
+  apr_pool_t *pool = scratch_pool;  /* ### temporary rename  */
   const char *left_copy, *right_copy, *target_copy;
   const char *tmp_left, *tmp_right, *detranslated_target_copy;
   const char *dir_abspath, *target_name;
   const char *temp_dir;
   svn_wc_entry_t tmp_entry;
+  svn_skel_t *work_item;
+
+  *work_items = NULL;
 
   svn_dirent_split(target_abspath, &dir_abspath, &target_name, pool);
   SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db, target_abspath,
@@ -641,47 +703,52 @@ preserve_pre_merge_files(svn_stringbuf_t
      are written, so everything should be fine.  Really.  */
 
   /* Create LEFT and RIGHT backup files, in expanded form.
-     We use merge_target's current properties to do the translation. */
+     We use TARGET_ABSPATH's current properties to do the translation. */
   /* Derive the basenames of the 3 backup files. */
-  SVN_WC__FLUSH_LOG_ACCUM(db, dir_abspath, *log_accum, pool);
-  SVN_ERR(svn_wc__loggy_translated_file(db, dir_abspath,
+  SVN_ERR(svn_wc__loggy_translated_file(&work_item, db, dir_abspath,
                                         left_copy, tmp_left,
-                                        target_abspath, pool));
-  SVN_ERR(svn_wc__loggy_translated_file(db, dir_abspath,
+                                        target_abspath, result_pool));
+  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+
+  SVN_ERR(svn_wc__loggy_translated_file(&work_item, db, dir_abspath,
                                         right_copy, tmp_right,
-                                        target_abspath, pool));
+                                        target_abspath, result_pool));
+  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
 
-  /* Back up MERGE_TARGET through detranslation/retranslation:
+  /* Back up TARGET_ABSPATH through detranslation/retranslation:
      the new translation properties may not match the current ones */
   SVN_ERR(svn_wc__internal_translated_file(
            &detranslated_target_copy, target_abspath, db, target_abspath,
            SVN_WC_TRANSLATE_TO_NF | SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP,
+           cancel_func, cancel_baton,
            pool, pool));
-  SVN_ERR(svn_wc__loggy_translated_file(db, dir_abspath,
+  SVN_ERR(svn_wc__loggy_translated_file(&work_item, db, dir_abspath,
                                         target_copy, detranslated_target_copy,
-                                        target_abspath, pool));
+                                        target_abspath, result_pool));
+  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
 
   tmp_entry.conflict_old = svn_dirent_is_child(dir_abspath, left_copy, pool);
   tmp_entry.conflict_new = svn_dirent_is_child(dir_abspath, right_copy, pool);
   tmp_entry.conflict_wrk = svn_dirent_basename(target_copy, pool);
 
-  /* Mark merge_target's entry as "Conflicted", and start tracking
+  /* Mark TARGET_ABSPATH's entry as "Conflicted", and start tracking
      the backup files in the entry as well. */
-  SVN_ERR(svn_wc__loggy_entry_modify(log_accum, dir_abspath,
+  SVN_ERR(svn_wc__loggy_entry_modify(&work_item, db, dir_abspath,
                                      target_abspath, &tmp_entry,
                                      SVN_WC__ENTRY_MODIFY_CONFLICT_OLD
                                        | SVN_WC__ENTRY_MODIFY_CONFLICT_NEW
                                        | SVN_WC__ENTRY_MODIFY_CONFLICT_WRK,
-                                     pool, pool));
+                                     result_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_description_t *
-setup_text_conflict_desc(const char *left,
-                         const char *right,
-                         const char *merge_abspath,
+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,
@@ -692,12 +759,12 @@ setup_text_conflict_desc(const char *lef
 {
   svn_wc_conflict_description2_t *cdesc;
 
-  cdesc = svn_wc_conflict_description_create_text2(merge_abspath, pool);
+  cdesc = svn_wc_conflict_description_create_text2(target_abspath, pool);
   cdesc->is_binary = FALSE;
   cdesc->mime_type = (mimeprop && mimeprop->value)
                      ? mimeprop->value->data : NULL,
-  cdesc->base_file = left;
-  cdesc->their_file = right;
+  cdesc->base_file = left_abspath;
+  cdesc->their_file = right_abspath;
   cdesc->my_file = detranslated_target;
   cdesc->merged_file = result_target;
 
@@ -709,11 +776,11 @@ setup_text_conflict_desc(const char *lef
 
 /* XXX Insane amount of parameters... */
 static svn_error_t*
-maybe_resolve_conflicts(svn_stringbuf_t **log_accum,
+maybe_resolve_conflicts(svn_skel_t **work_items,
                         svn_wc__db_t *db,
-                        const char *left,
-                        const char *right,
-                        const char *merge_target,
+                        const char *left_abspath,
+                        const char *right_abspath,
+                        const char *target_abspath,
                         const char *copyfrom_text,
                         const char *left_label,
                         const char *right_label,
@@ -729,14 +796,15 @@ maybe_resolve_conflicts(svn_stringbuf_t 
                         void *conflict_baton,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
-                        apr_pool_t *pool)
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
 {
+  apr_pool_t *pool = scratch_pool;  /* ### temporary rename  */
   svn_wc_conflict_result_t *result = NULL;
-  const char *left_abspath, *right_abspath, *target_abspath, *dir_abspath;
+  const char *dir_abspath;
+  svn_skel_t *work_item;
 
-  SVN_ERR(svn_dirent_get_absolute(&left_abspath, left, pool));
-  SVN_ERR(svn_dirent_get_absolute(&right_abspath, right, pool));
-  SVN_ERR(svn_dirent_get_absolute(&target_abspath, merge_target, pool));
+  *work_items = NULL;
 
   dir_abspath = svn_dirent_dirname(target_abspath, pool);
 
@@ -769,31 +837,35 @@ maybe_resolve_conflicts(svn_stringbuf_t 
         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(log_accum,
-                                  db,
-                                  target_abspath,
-                                  /* Look for callback's own
-                                     merged-file first: */
-                                  result->merged_file
-                                    ? result->merged_file
-                                    : result_target,
-                                  pool));
+        {
+          SVN_ERR(save_merge_result(work_items,
+                                    db,
+                                    target_abspath,
+                                    /* Look for callback's own
+                                       merged-file first: */
+                                    result->merged_file
+                                      ? result->merged_file
+                                      : result_target,
+                                    result_pool, scratch_pool));
+        }
     }
 
-  SVN_ERR(eval_conflict_func_result(merge_outcome,
+  SVN_ERR(eval_conflict_func_result(&work_item,
+                                    merge_outcome,
                                     result,
-                                    log_accum,
                                     db,
-                                    left,
-                                    right,
-                                    merge_target,
+                                    left_abspath,
+                                    right_abspath,
+                                    target_abspath,
                                     copyfrom_text,
                                     dir_abspath,
                                     result_target,
                                     detranslated_target,
                                     options,
-                                    pool));
+                                    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
@@ -801,7 +873,7 @@ maybe_resolve_conflicts(svn_stringbuf_t 
     return SVN_NO_ERROR;
 
   /* The conflicts have not been dealt with. */
-  SVN_ERR(preserve_pre_merge_files(log_accum,
+  SVN_ERR(preserve_pre_merge_files(&work_item,
                                    db,
                                    left_abspath,
                                    right_abspath,
@@ -809,7 +881,9 @@ maybe_resolve_conflicts(svn_stringbuf_t 
                                    left_label,
                                    right_label,
                                    target_label,
-                                   pool));
+                                   cancel_func, cancel_baton,
+                                   result_pool, scratch_pool));
+  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
 
   *merge_outcome = svn_wc_merge_conflict;
 
@@ -818,7 +892,7 @@ maybe_resolve_conflicts(svn_stringbuf_t 
 
 /* XXX Insane amount of parameters... */
 static svn_error_t*
-merge_text_file(svn_stringbuf_t **log_accum,
+merge_text_file(svn_skel_t **work_items,
                 enum svn_wc_merge_outcome_t *merge_outcome,
                 svn_wc__db_t *db,
                 const char *left_abspath,
@@ -839,8 +913,10 @@ merge_text_file(svn_stringbuf_t **log_ac
                 void *conflict_baton,
                 svn_cancel_func_t cancel_func,
                 void *cancel_baton,
-                apr_pool_t *pool)
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
 {
+  apr_pool_t *pool = scratch_pool;  /* ### temporary rename  */
   svn_diff_file_options_t *options;
   svn_boolean_t contains_conflicts;
   apr_file_t *result_f;
@@ -848,6 +924,8 @@ merge_text_file(svn_stringbuf_t **log_ac
   const char *dir_abspath, *base_name;
   const char *temp_dir;
 
+  *work_items = NULL;
+
   svn_dirent_split(target_abspath, &dir_abspath, &base_name, pool);
 
   /* Open a second temporary file for writing; this is where diff3
@@ -895,7 +973,7 @@ merge_text_file(svn_stringbuf_t **log_ac
 
   if (contains_conflicts && ! dry_run)
     {
-      SVN_ERR(maybe_resolve_conflicts(log_accum,
+      SVN_ERR(maybe_resolve_conflicts(work_items,
                                       db,
                                       left_abspath,
                                       right_abspath,
@@ -913,7 +991,8 @@ merge_text_file(svn_stringbuf_t **log_ac
                                       options,
                                       conflict_func, conflict_baton,
                                       cancel_func, cancel_baton,
-                                      pool));
+                                      result_pool, scratch_pool));
+
       if (*merge_outcome == svn_wc_merge_merged)
         return SVN_NO_ERROR;
     }
@@ -940,21 +1019,31 @@ merge_text_file(svn_stringbuf_t **log_ac
     }
 
   if (*merge_outcome != svn_wc_merge_unchanged && ! dry_run)
-    /* replace MERGE_TARGET with the new merged file, expanding. */
-    SVN_ERR(svn_wc__loggy_copy(log_accum, dir_abspath,
-                               result_target, target_abspath, pool, pool));
+    {
+      svn_skel_t *work_item;
+
+      /* replace TARGET_ABSPATH with the new merged file, expanding. */
+      SVN_ERR(svn_wc__wq_build_file_install(&work_item,
+                                            db, target_abspath,
+                                            result_target,
+                                            FALSE /* use_commit_times */,
+                                            FALSE /* record_fileinfo */,
+                                            result_pool, scratch_pool));
+      *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+    }
+
   return SVN_NO_ERROR;
 }
 
 
 /* XXX Insane amount of parameters... */
-static svn_error_t*
-merge_binary_file(svn_stringbuf_t **log_accum,
+static svn_error_t *
+merge_binary_file(svn_skel_t **work_items,
                   enum svn_wc_merge_outcome_t *merge_outcome,
                   svn_wc__db_t *db,
-                  const char *left,
-                  const char *right,
-                  const char *merge_target,
+                  const char *left_abspath,
+                  const char *right_abspath,
+                  const char *target_abspath,
                   const char *left_label,
                   const char *right_label,
                   const char *target_label,
@@ -964,21 +1053,23 @@ merge_binary_file(svn_stringbuf_t **log_
                   const svn_prop_t *mimeprop,
                   svn_wc_conflict_resolver_func_t conflict_func,
                   void *conflict_baton,
-                  svn_cancel_func_t cancel_func,
-                  void *cancel_baton,
-                  apr_pool_t *pool)
+                  apr_pool_t *result_pool,
+                  apr_pool_t *scratch_pool)
 {
+  apr_pool_t *pool = scratch_pool;  /* ### temporary rename  */
   /* ### when making the binary-file backups, should we be honoring
      keywords and eol stuff?   */
   const char *left_copy, *right_copy;
   const char *left_base, *right_base;
-  const char *merge_abspath;
   const char *merge_dirpath, *merge_filename;
   svn_wc_entry_t tmp_entry;
+  svn_skel_t *work_item;
 
-  SVN_ERR(svn_dirent_get_absolute(&merge_abspath, merge_target, pool));
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
+
+  *work_items = NULL;
 
-  svn_dirent_split(merge_abspath, &merge_dirpath, &merge_filename, pool);
+  svn_dirent_split(target_abspath, &merge_dirpath, &merge_filename, pool);
 
   /* Give the conflict resolution callback a chance to clean
      up the conflict before we mark the file 'conflicted' */
@@ -986,8 +1077,10 @@ merge_binary_file(svn_stringbuf_t **log_
     {
       svn_wc_conflict_result_t *result = NULL;
       const svn_wc_conflict_description_t *cdesc;
+      const char *install_from = NULL;
 
-      cdesc = setup_text_conflict_desc(left, right, merge_abspath,
+      cdesc = setup_text_conflict_desc(left_abspath, right_abspath,
+                                       target_abspath,
                                        left_version, right_version,
                                        NULL /* result_target */,
                                        detranslated_target_abspath,
@@ -1005,19 +1098,15 @@ merge_binary_file(svn_stringbuf_t **log_
              unless the conflict-callback did the merging itself. */
           case svn_wc_conflict_choose_base:
             {
-              SVN_ERR(svn_wc__loggy_copy(log_accum,
-                                     merge_dirpath,
-                                     left, merge_target, pool, pool));
+              install_from = left_abspath;
               *merge_outcome = svn_wc_merge_merged;
-              return SVN_NO_ERROR;
+              break;
             }
           case svn_wc_conflict_choose_theirs_full:
             {
-              SVN_ERR(svn_wc__loggy_copy(log_accum,
-                                     merge_dirpath,
-                                     right, merge_target, pool, pool));
+              install_from = right_abspath;
               *merge_outcome = svn_wc_merge_merged;
-              return SVN_NO_ERROR;
+              break;
             }
             /* For a binary file, if the response is to use the
                user's file, we do nothing.  We also do nothing if
@@ -1041,12 +1130,9 @@ merge_binary_file(svn_stringbuf_t **log_
                 }
               else
                 {
-                  SVN_ERR(svn_wc__loggy_copy(log_accum,
-                                     merge_dirpath,
-                                     result->merged_file, merge_target,
-                                     pool, pool));
+                  install_from = result->merged_file;
                   *merge_outcome = svn_wc_merge_merged;
-                  return SVN_NO_ERROR;
+                  break;
                 }
             }
           case svn_wc_conflict_choose_postpone:
@@ -1055,6 +1141,19 @@ merge_binary_file(svn_stringbuf_t **log_
               /* Assume conflict remains, fall through to code below. */
             }
         }
+
+      if (install_from != NULL)
+        {
+          SVN_ERR(svn_wc__wq_build_file_install(work_items,
+                                                db, target_abspath,
+                                                install_from,
+                                                FALSE /* use_commit_times */,
+                                                FALSE /* record_fileinfo */,
+                                                result_pool, scratch_pool));
+
+          /* A merge choice was made, so we're done here.  */
+          return SVN_NO_ERROR;
+        }
     }
 
   /* reserve names for backups of left and right fulltexts */
@@ -1075,11 +1174,11 @@ merge_binary_file(svn_stringbuf_t **log_
                                      pool, pool));
 
   /* create the backup files */
-  SVN_ERR(svn_io_copy_file(left, left_copy, TRUE, pool));
-  SVN_ERR(svn_io_copy_file(right, right_copy, TRUE, pool));
+  SVN_ERR(svn_io_copy_file(left_abspath, left_copy, TRUE, pool));
+  SVN_ERR(svn_io_copy_file(right_abspath, right_copy, TRUE, pool));
 
   /* Was the merge target detranslated? */
-  if (strcmp(merge_abspath, detranslated_target_abspath) != 0)
+  if (strcmp(target_abspath, detranslated_target_abspath) != 0)
     {
       /* Create a .mine file too */
       const char *mine_copy;
@@ -1091,34 +1190,38 @@ merge_binary_file(svn_stringbuf_t **log_
                                          target_label,
                                          svn_io_file_del_none,
                                          pool, pool));
-      SVN_ERR(svn_wc__loggy_move(log_accum,
+      SVN_ERR(svn_wc__loggy_move(work_items, db,
                                  merge_dirpath,
                                  detranslated_target_abspath,
                                  mine_copy,
-                                 pool, pool));
+                                 result_pool));
+
       mine_copy = svn_dirent_is_child(merge_dirpath,
                                       mine_copy, pool);
       tmp_entry.conflict_wrk = mine_copy;
     }
   else
-    tmp_entry.conflict_wrk = NULL;
+    {
+      tmp_entry.conflict_wrk = NULL;
+    }
 
   /* Derive the basenames of the backup files. */
   left_base = svn_dirent_basename(left_copy, pool);
   right_base = svn_dirent_basename(right_copy, pool);
 
-  /* Mark merge_target's entry as "Conflicted", and start tracking
+  /* Mark target_abspath's entry as "Conflicted", and start tracking
      the backup files in the entry as well. */
   tmp_entry.conflict_old = left_base;
   tmp_entry.conflict_new = right_base;
   SVN_ERR(svn_wc__loggy_entry_modify(
-            log_accum,
-            merge_dirpath, merge_target,
+            &work_item,
+            db, merge_dirpath, target_abspath,
             &tmp_entry,
             SVN_WC__ENTRY_MODIFY_CONFLICT_OLD
               | SVN_WC__ENTRY_MODIFY_CONFLICT_NEW
               | SVN_WC__ENTRY_MODIFY_CONFLICT_WRK,
-            pool, pool));
+            result_pool));
+  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
 
   *merge_outcome = svn_wc_merge_conflict; /* a conflict happened */
 
@@ -1127,7 +1230,7 @@ merge_binary_file(svn_stringbuf_t **log_
 
 /* XXX Insane amount of parameters... */
 svn_error_t *
-svn_wc__internal_merge(svn_stringbuf_t **log_accum,
+svn_wc__internal_merge(svn_skel_t **work_items,
                        enum svn_wc_merge_outcome_t *merge_outcome,
                        svn_wc__db_t *db,
                        const char *left_abspath,
@@ -1147,20 +1250,23 @@ svn_wc__internal_merge(svn_stringbuf_t *
                        void *conflict_baton,
                        svn_cancel_func_t cancel_func,
                        void *cancel_baton,
-                       apr_pool_t *pool)
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
+  apr_pool_t *pool = scratch_pool;  /* ### temporary rename  */
   const char *working_abspath;
   const char *detranslated_target_abspath;
-  const char *dir_abspath;
   svn_boolean_t is_binary = FALSE;
   const svn_prop_t *mimeprop;
+  svn_skel_t *work_item;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(left_abspath));
   SVN_ERR_ASSERT(svn_dirent_is_absolute(right_abspath));
   SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
-  SVN_ERR_ASSERT(copyfrom_abspath == NULL || svn_dirent_is_absolute(copyfrom_abspath));
+  SVN_ERR_ASSERT(copyfrom_abspath == NULL
+                 || svn_dirent_is_absolute(copyfrom_abspath));
 
-  dir_abspath = svn_dirent_dirname(target_abspath, pool);
+  *work_items = NULL;
 
   /* Sanity check:  the merge target must be under revision control,
    * unless the merge target is a copyfrom text, which lives in a
@@ -1196,13 +1302,14 @@ svn_wc__internal_merge(svn_stringbuf_t *
   working_abspath = copyfrom_abspath ? copyfrom_abspath : target_abspath;
   SVN_ERR(detranslate_wc_file(&detranslated_target_abspath, db, target_abspath,
                               (! is_binary) && diff3_cmd != NULL,
-                              prop_diff, working_abspath, pool, pool));
+                              prop_diff, working_abspath,
+                              cancel_func, cancel_baton, pool, pool));
 
   /* 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, db, left_abspath, prop_diff,
-                                   pool, pool));
+                                   cancel_func, cancel_baton, pool, pool));
 
   if (is_binary)
     {
@@ -1210,7 +1317,7 @@ svn_wc__internal_merge(svn_stringbuf_t *
         /* in dry-run mode, binary files always conflict */
         *merge_outcome = svn_wc_merge_conflict;
       else
-        SVN_ERR(merge_binary_file(log_accum,
+        SVN_ERR(merge_binary_file(work_items,
                                   merge_outcome,
                                   db,
                                   left_abspath,
@@ -1225,51 +1332,46 @@ svn_wc__internal_merge(svn_stringbuf_t *
                                   mimeprop,
                                   conflict_func,
                                   conflict_baton,
-                                  cancel_func,
-                                  cancel_baton,
-                                  pool));
+                                  result_pool, scratch_pool));
     }
   else
-    SVN_ERR(merge_text_file(log_accum,
-                            merge_outcome,
-                            db,
-                            left_abspath,
-                            right_abspath,
-                            target_abspath,
-                            left_label,
-                            right_label,
-                            target_label,
-                            dry_run,
-                            diff3_cmd,
-                            merge_options,
-                            left_version,
-                            right_version,
-                            copyfrom_abspath,
-                            detranslated_target_abspath,
-                            mimeprop,
-                            conflict_func,
-                            conflict_baton,
-                            cancel_func,
-                            cancel_baton,
-                            pool));
+    {
+      SVN_ERR(merge_text_file(work_items,
+                              merge_outcome,
+                              db,
+                              left_abspath,
+                              right_abspath,
+                              target_abspath,
+                              left_label,
+                              right_label,
+                              target_label,
+                              dry_run,
+                              diff3_cmd,
+                              merge_options,
+                              left_version,
+                              right_version,
+                              copyfrom_abspath,
+                              detranslated_target_abspath,
+                              mimeprop,
+                              conflict_func, conflict_baton,
+                              cancel_func, cancel_baton,
+                              result_pool, scratch_pool));
+    }
 
   /* Merging is complete.  Regardless of text or binariness, we might
      need to tweak the executable bit on the new working file, and
      possibly make it read-only. */
   if (! dry_run)
     {
-      SVN_ERR(svn_wc__loggy_maybe_set_executable(log_accum, dir_abspath,
-                                                 target_abspath,
-                                                 pool, pool));
-      SVN_ERR(svn_wc__loggy_maybe_set_readonly(log_accum, dir_abspath,
+      SVN_ERR(svn_wc__wq_build_sync_file_flags(&work_item, db,
                                                target_abspath,
-                                               pool, pool));
+                                               result_pool, scratch_pool));
+      *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
     }
 
   return SVN_NO_ERROR;
 }
 
-
 
 svn_error_t *
 svn_wc_merge4(enum svn_wc_merge_outcome_t *merge_outcome,
@@ -1292,9 +1394,20 @@ svn_wc_merge4(enum svn_wc_merge_outcome_
               void *cancel_baton,
               apr_pool_t *scratch_pool)
 {
-  svn_stringbuf_t *log_accum = svn_stringbuf_create("", scratch_pool);
+  const char *dir_abspath = svn_dirent_dirname(target_abspath, scratch_pool);
+  svn_skel_t *work_items;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(left_abspath));
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(right_abspath));
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
+
+  /* Before we do any work, make sure we hold a write lock.  */
+  if (!dry_run)
+    SVN_ERR(svn_wc__write_check(wc_ctx->db, dir_abspath, scratch_pool));
 
-  SVN_ERR(svn_wc__internal_merge(&log_accum, merge_outcome,
+  /* Queue all the work.  */
+  SVN_ERR(svn_wc__internal_merge(&work_items,
+                                 merge_outcome,
                                  wc_ctx->db,
                                  left_abspath, left_version,
                                  right_abspath, right_version,
@@ -1307,21 +1420,13 @@ svn_wc_merge4(enum svn_wc_merge_outcome_
                                  prop_diff,
                                  conflict_func, conflict_baton,
                                  cancel_func, cancel_baton,
-                                 scratch_pool));
+                                 scratch_pool, scratch_pool));
 
-  /* Write our accumulation of log entries into a log file */
+  /* If this isn't a dry run, then run the work!  */
   if (!dry_run)
     {
-      const char *dir_abspath = svn_dirent_dirname(target_abspath,
-                                                   scratch_pool);
-
-      /* Verify that we're holding this directory's write lock.  */
-      SVN_ERR(svn_wc__write_check(wc_ctx->db, dir_abspath, scratch_pool));
-
-      /* Add all the work items to the queue, then run it.  */
-      /* ### add_loggy takes a DIR, but wq_run is a simple WRI_ABSPATH  */
-      SVN_ERR(svn_wc__wq_add_loggy(wc_ctx->db, dir_abspath,
-                                   log_accum, scratch_pool));
+      SVN_ERR(svn_wc__db_wq_add(wc_ctx->db, target_abspath, work_items,
+                                scratch_pool));
       SVN_ERR(svn_wc__wq_run(wc_ctx->db, target_abspath,
                              cancel_func, cancel_baton,
                              scratch_pool));

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/node.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/node.c?rev=984206&r1=984205&r2=984206&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/node.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/node.c Tue Aug 10 20:55:56 2010
@@ -106,6 +106,7 @@ svn_wc__node_get_repos_info(const char *
                             svn_wc_context_t *wc_ctx,
                             const char *local_abspath,
                             svn_boolean_t scan_added,
+                            svn_boolean_t scan_deleted,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool)
 {
@@ -157,7 +158,9 @@ svn_wc__node_get_repos_info(const char *
           || status == svn_wc__db_status_obstructed
           || status == svn_wc__db_status_absent
           || status == svn_wc__db_status_excluded
-          || status == svn_wc__db_status_not_present))
+          || status == svn_wc__db_status_not_present
+          || (scan_deleted && (status == svn_wc__db_status_deleted))
+          || (scan_deleted && (status == svn_wc__db_status_obstructed_delete))))
     {
       SVN_ERR(svn_wc__db_scan_base_repos(NULL, repos_root_url, repos_uuid,
                                          wc_ctx->db, local_abspath,
@@ -169,16 +172,27 @@ svn_wc__node_get_repos_info(const char *
 }
 
 svn_error_t *
-svn_wc__node_get_kind(svn_node_kind_t *kind,
-                      svn_wc_context_t *wc_ctx,
-                      const char *abspath,
-                      svn_boolean_t show_hidden,
-                      apr_pool_t *scratch_pool)
+svn_wc_read_kind(svn_node_kind_t *kind,
+                 svn_wc_context_t *wc_ctx,
+                 const char *abspath,
+                 svn_boolean_t show_hidden,
+                 apr_pool_t *scratch_pool)
 {
   svn_wc__db_kind_t db_kind;
+  svn_error_t *err;
+
+  err = svn_wc__db_read_kind(&db_kind, wc_ctx->db, abspath, FALSE,
+                             scratch_pool);
+
+  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      *kind = svn_node_none;
+      return SVN_NO_ERROR;
+    }
+  else
+    SVN_ERR(err);
 
-  SVN_ERR(svn_wc__db_read_kind(&db_kind, wc_ctx->db, abspath, TRUE,
-                               scratch_pool));
   switch (db_kind)
     {
       case svn_wc__db_kind_file:
@@ -191,16 +205,14 @@ svn_wc__node_get_kind(svn_node_kind_t *k
         *kind = svn_node_file;
         break;
       case svn_wc__db_kind_unknown:
-        *kind = svn_node_unknown;  /* ### should probably be svn_node_none  */
+        *kind = svn_node_unknown;
         break;
       default:
         SVN_ERR_MALFUNCTION();
     }
 
-  /* If we found a svn_node_file or svn_node_dir, but it is hidden,
-     then consider *KIND to be svn_node_none unless SHOW_HIDDEN is true. */
-  if (! show_hidden
-      && (*kind == svn_node_file || *kind == svn_node_dir))
+  /* Make sure hidden nodes return svn_node_none. */
+  if (! show_hidden)
     {
       svn_boolean_t hidden;
 
@@ -274,6 +286,40 @@ svn_wc__node_get_changelist(const char *
 }
 
 svn_error_t *
+svn_wc__node_get_base_checksum(const svn_checksum_t **checksum,
+                               svn_wc_context_t *wc_ctx,
+                               const char *local_abspath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  return svn_error_return(svn_wc__db_read_info(NULL, NULL, NULL, NULL,
+                                               NULL, NULL, NULL, NULL,
+                                               NULL, NULL, NULL, checksum,
+                                               NULL, NULL, NULL, NULL,
+                                               NULL, NULL, NULL, NULL,
+                                               NULL, NULL, NULL, NULL,
+                                               wc_ctx->db, local_abspath,
+                                               result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_wc__node_get_translated_size(svn_filesize_t *translated_size,
+                                 svn_wc_context_t *wc_ctx,
+                                 const char *local_abspath,
+                                 apr_pool_t *scratch_pool)
+{
+  return svn_error_return(svn_wc__db_read_info(NULL, NULL, NULL, NULL,
+                                               NULL, NULL, NULL, NULL,
+                                               NULL, NULL, NULL, NULL,
+                                               translated_size,
+                                               NULL, NULL, NULL,
+                                               NULL, NULL, NULL, NULL,
+                                               NULL, NULL, NULL, NULL,
+                                               wc_ctx->db, local_abspath,
+                                               scratch_pool, scratch_pool));
+}
+
+svn_error_t *
 svn_wc__internal_node_get_url(const char **url,
                               svn_wc__db_t *db,
                               const char *local_abspath,
@@ -283,27 +329,29 @@ svn_wc__internal_node_get_url(const char
   svn_wc__db_status_t status;
   const char *repos_relpath;
   const char *repos_root_url;
+  svn_boolean_t base_shadowed;
 
   SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, &repos_relpath,
                                &repos_root_url,
                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                               NULL, NULL, NULL,
+                               &base_shadowed, NULL, NULL,
                                db, local_abspath,
                                scratch_pool, scratch_pool));
   if (repos_relpath == NULL)
     {
       if (status == svn_wc__db_status_normal
           || status == svn_wc__db_status_incomplete
-          || status == svn_wc__db_status_deleted)
+          || (base_shadowed
+              && (status == svn_wc__db_status_deleted
+                  || status == svn_wc__db_status_obstructed_delete)))
         {
           SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, &repos_root_url,
                                              NULL,
                                              db, local_abspath,
                                              scratch_pool, scratch_pool));
         }
-      else if (status == svn_wc__db_status_added
-               || status == svn_wc__db_status_obstructed_add)
+      else if (status == svn_wc__db_status_added)
         {
           SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &repos_relpath,
                                            &repos_root_url, NULL, NULL, NULL,
@@ -311,8 +359,24 @@ svn_wc__internal_node_get_url(const char
                                            db, local_abspath,
                                            scratch_pool, scratch_pool));
         }
+      else if (status == svn_wc__db_status_absent
+               || status == svn_wc__db_status_excluded
+               || status == svn_wc__db_status_not_present
+               || (!base_shadowed
+                   && (status == svn_wc__db_status_deleted
+                       || status == svn_wc__db_status_obstructed_delete)))
+        {
+          const char *parent_abspath;
+
+          svn_dirent_split(local_abspath, &parent_abspath, &repos_relpath,
+                           scratch_pool);
+          SVN_ERR(svn_wc__internal_node_get_url(&repos_root_url, db,
+                                                parent_abspath,
+                                                scratch_pool, scratch_pool));
+        }
       else
         {
+          /* Status: obstructed, obstructed_add */
           *url = NULL;
           return SVN_NO_ERROR;
         }
@@ -338,6 +402,129 @@ svn_wc__node_get_url(const char **url,
                             result_pool, scratch_pool));
 }
 
+svn_error_t *
+svn_wc__node_get_copyfrom_info(const char **copyfrom_url,
+                               svn_revnum_t *copyfrom_rev,
+                               svn_boolean_t *is_copy_target,
+                               svn_wc_context_t *wc_ctx,
+                               const char *local_abspath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  svn_wc__db_t *db = wc_ctx->db;
+  const char *original_root_url;
+  const char *original_repos_relpath;
+  svn_revnum_t original_revision;
+  svn_wc__db_status_t status;
+
+  if (copyfrom_url)
+    *copyfrom_url = NULL;
+  if (copyfrom_rev)
+    *copyfrom_rev = SVN_INVALID_REVNUM;
+  if (is_copy_target)
+    *is_copy_target = FALSE;
+
+  SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, &original_repos_relpath,
+                               &original_root_url, NULL, &original_revision,
+                               NULL, NULL, NULL, NULL, NULL, db,
+                               local_abspath, scratch_pool, scratch_pool));
+  if (original_root_url && original_repos_relpath)
+    {
+      /* If this was the root of the copy then the URL is immediately
+         available... */
+      const char *my_copyfrom_url;
+
+      if (copyfrom_url || is_copy_target)
+        my_copyfrom_url = svn_path_url_add_component2(original_root_url,
+                                                      original_repos_relpath,
+                                                      result_pool);
+
+      if (copyfrom_url)
+        *copyfrom_url = my_copyfrom_url;
+
+      if (copyfrom_rev)
+        *copyfrom_rev = original_revision;
+
+      if (is_copy_target)
+        {
+          /* ### At this point we'd just set is_copy_target to TRUE, *but* we
+           * currently want to model wc-1 behaviour.  Particularly, this
+           * affects mixed-revision copies (e.g. wc-wc copy):
+           * - Wc-1 saw only the root of a mixed-revision copy as the copy's
+           *   root.
+           * - Wc-ng returns an explicit original_root_url,
+           *   original_repos_relpath pair for each subtree with mismatching
+           *   revision.
+           * We need to compensate for that: Find out if the parent of
+           * this node is also copied and has a matching copy_from URL. If so,
+           * nevermind the revision, just like wc-1 did, and say this was not
+           * a separate copy target. */
+          const char *parent_abspath;
+          const char *base_name;
+          const char *parent_copyfrom_url;
+
+          svn_dirent_split(local_abspath, &parent_abspath, &base_name,
+                           scratch_pool);
+
+          /* This is a copied node, so we should never fall off the top of a
+           * working copy here. */
+          SVN_ERR(svn_wc__node_get_copyfrom_info(&parent_copyfrom_url,
+                                                 NULL, NULL,
+                                                 wc_ctx, parent_abspath,
+                                                 scratch_pool, scratch_pool));
+
+          /* So, count this as a separate copy target only if the URLs
+           * don't match up, or if the parent isn't copied at all. */
+          if (parent_copyfrom_url == NULL
+              || strcmp(my_copyfrom_url,
+                        svn_path_url_add_component2(parent_copyfrom_url,
+                                                    base_name,
+                                                    scratch_pool)) != 0)
+            *is_copy_target = TRUE;
+        }
+    }
+  else if ((status == svn_wc__db_status_added
+            || status == svn_wc__db_status_obstructed_add)
+           && (copyfrom_rev || copyfrom_url))
+    {
+      /* ...But if this is merely the descendant of an explicitly
+         copied/moved directory, we need to do a bit more work to
+         determine copyfrom_url and copyfrom_rev. */
+      const char *op_root_abspath;
+
+      SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath, NULL, NULL,
+                                       NULL, &original_repos_relpath,
+                                       &original_root_url, NULL,
+                                       &original_revision, db, local_abspath,
+                                       scratch_pool, scratch_pool));
+      if (status == svn_wc__db_status_copied ||
+          status == svn_wc__db_status_moved_here)
+        {
+          const char *src_parent_url;
+          const char *src_relpath;
+
+          src_parent_url = svn_path_url_add_component2(original_root_url,
+                                                       original_repos_relpath,
+                                                       scratch_pool);
+          src_relpath = svn_dirent_is_child(op_root_abspath, local_abspath,
+                                            scratch_pool);
+          if (src_relpath)
+            {
+              if (copyfrom_url)
+                *copyfrom_url = svn_path_url_add_component2(src_parent_url,
+                                                            src_relpath,
+                                                            result_pool);
+              if (copyfrom_rev)
+                *copyfrom_rev = original_revision;
+            }
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 /* A recursive node-walker, helper for svn_wc__node_walk_children(). */
 static svn_error_t *
@@ -500,8 +687,8 @@ svn_wc__node_is_status_deleted(svn_boole
                                wc_ctx->db, local_abspath,
                                scratch_pool, scratch_pool));
 
-  /* ### Do we need to consider svn_wc__db_status_obstructed_delete? */
-  *is_deleted = (status == svn_wc__db_status_deleted);
+  *is_deleted = (status == svn_wc__db_status_deleted) ||
+                (status == svn_wc__db_status_obstructed_delete);
 
   return SVN_NO_ERROR;
 }
@@ -570,10 +757,10 @@ svn_wc__node_is_status_present(svn_boole
 }
 
 svn_error_t *
-svn_wc__node_is_status_added(svn_boolean_t *is_added,
-                             svn_wc_context_t *wc_ctx,
-                             const char *local_abspath,
-                             apr_pool_t *scratch_pool)
+svn_wc__node_is_added(svn_boolean_t *is_added,
+                      svn_wc_context_t *wc_ctx,
+                      const char *local_abspath,
+                      apr_pool_t *scratch_pool)
 {
   svn_wc__db_status_t status;
 
@@ -584,11 +771,63 @@ svn_wc__node_is_status_added(svn_boolean
                                NULL, NULL,
                                wc_ctx->db, local_abspath,
                                scratch_pool, scratch_pool));
-  *is_added = (status == svn_wc__db_status_added);
+  *is_added = (status == svn_wc__db_status_added
+               || status == svn_wc__db_status_obstructed_add);
 
   return SVN_NO_ERROR;
 }
 
+
+/* Equivalent to the old notion of "entry->schedule == schedule_replace"  */
+svn_error_t *
+svn_wc__internal_is_replaced(svn_boolean_t *replaced,
+                             svn_wc__db_t *db,
+                             const char *local_abspath,
+                             apr_pool_t *scratch_pool)
+{
+  svn_wc__db_status_t status;
+  svn_boolean_t base_shadowed;
+  svn_wc__db_status_t base_status;
+
+  SVN_ERR(svn_wc__db_read_info(
+            &status, NULL, NULL,
+            NULL, NULL, NULL, NULL, NULL, NULL,
+            NULL, NULL, NULL, NULL, NULL, NULL,
+            NULL, NULL, NULL, NULL,
+            NULL, NULL, &base_shadowed,
+            NULL, NULL,
+            db, local_abspath,
+            scratch_pool, scratch_pool));
+  if (base_shadowed)
+    SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL,
+                                     NULL, NULL, NULL,
+                                     NULL, NULL, NULL,
+                                     NULL, NULL, NULL,
+                                     NULL, NULL, NULL,
+                                     db, local_abspath,
+                                     scratch_pool, scratch_pool));
+
+  *replaced = ((status == svn_wc__db_status_added
+                || status == svn_wc__db_status_obstructed_add)
+               && base_shadowed
+               && base_status != svn_wc__db_status_not_present);
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__node_is_replaced(svn_boolean_t *replaced,
+                         svn_wc_context_t *wc_ctx,
+                         const char *local_abspath,
+                         apr_pool_t *scratch_pool)
+{
+  return svn_error_return(svn_wc__internal_is_replaced(replaced, wc_ctx->db,
+                                                       local_abspath,
+                                                       scratch_pool));
+}
+
+
 svn_error_t *
 svn_wc__node_get_base_rev(svn_revnum_t *base_revision,
                           svn_wc_context_t *wc_ctx,
@@ -626,11 +865,158 @@ svn_wc__node_get_base_rev(svn_revnum_t *
 }
 
 svn_error_t *
-svn_wc__node_get_lock_token(const char **lock_token,
-                            svn_wc_context_t *wc_ctx,
-                            const char *local_abspath,
-                            apr_pool_t *result_pool,
-                            apr_pool_t *scratch_pool)
+svn_wc__node_get_working_rev_info(svn_revnum_t *revision,
+                                  svn_revnum_t *changed_rev, 
+                                  apr_time_t *changed_date, 
+                                  const char **changed_author,
+                                  svn_wc_context_t *wc_ctx, 
+                                  const char *local_abspath, 
+                                  apr_pool_t *scratch_pool,
+                                  apr_pool_t *result_pool)
+{
+  svn_wc__db_status_t status;
+  svn_boolean_t base_shadowed;
+
+  SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL, NULL,
+                               changed_rev, changed_date, changed_author,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, &base_shadowed, NULL,
+                               NULL, wc_ctx->db, local_abspath, result_pool,
+                               scratch_pool));
+
+  if (status == svn_wc__db_status_deleted)
+    {
+      const char *work_del_abspath = NULL;
+      const char *base_del_abspath = NULL;
+
+      SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, NULL,
+                                       NULL, &work_del_abspath, wc_ctx->db,
+                                       local_abspath, scratch_pool,
+                                       result_pool));
+      if (work_del_abspath)
+        {
+          SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, NULL, NULL,
+                                       NULL, changed_rev, changed_date,
+                                       changed_author, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, &base_shadowed,
+                                       NULL, NULL, wc_ctx->db, work_del_abspath,
+                                       result_pool, scratch_pool));
+        }
+      else
+        {
+          SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL,
+                                           NULL, NULL, changed_rev,
+                                           changed_date, changed_author,
+                                           NULL, NULL, NULL, NULL, NULL,
+                                           NULL, wc_ctx->db,
+                                           base_del_abspath, result_pool,
+                                           scratch_pool));
+        }
+    }
+  else if (base_shadowed)
+    {
+      SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, NULL, NULL,
+                                       NULL, changed_rev, changed_date,
+                                       changed_author, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, wc_ctx->db, local_abspath,
+                                       result_pool, scratch_pool));
+    }
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__node_get_commit_base_rev(svn_revnum_t *commit_base_revision,
+                                 svn_wc_context_t *wc_ctx,
+                                 const char *local_abspath,
+                                 apr_pool_t *scratch_pool)
+{
+  svn_wc__db_status_t status;
+  svn_boolean_t base_shadowed;
+
+  SVN_ERR(svn_wc__db_read_info(&status, NULL,
+                               commit_base_revision,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                               NULL, NULL, &base_shadowed, NULL, NULL,
+                               wc_ctx->db, local_abspath, scratch_pool,
+                               scratch_pool));
+
+  /* If this returned a valid revnum, there is no WORKING node. The node is
+     cleanly checked out, no modifications, copies or replaces. */
+  if (SVN_IS_VALID_REVNUM(*commit_base_revision))
+    return SVN_NO_ERROR;
+
+  if (status == svn_wc__db_status_added)
+    {
+      /* If the node was copied/moved-here, return the copy/move source
+         revision (not this node's base revision). If it's just added,
+         return SVN_INVALID_REVNUM. */
+      SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, commit_base_revision,
+                                       wc_ctx->db, local_abspath,
+                                       scratch_pool, scratch_pool));
+
+      if (! SVN_IS_VALID_REVNUM(*commit_base_revision) && base_shadowed)
+        /* It is a replace that does not feature a copy/move-here.
+           Return the revert-base revision. */
+        return svn_error_return(
+          svn_wc__node_get_base_rev(commit_base_revision, wc_ctx,
+                                    local_abspath, scratch_pool));
+    }
+  else if (status == svn_wc__db_status_deleted)
+    {
+      const char *work_del_abspath;
+      const char *parent_abspath;
+      svn_wc__db_status_t parent_status;
+
+      SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL, NULL,
+                                       &work_del_abspath,
+                                       wc_ctx->db, local_abspath,
+                                       scratch_pool, scratch_pool));
+      if (work_del_abspath != NULL)
+        {
+          /* This is a deletion within a copied subtree. Get the copied-from
+           * revision. */
+          parent_abspath = svn_dirent_dirname(work_del_abspath, scratch_pool);
+
+          SVN_ERR(svn_wc__db_read_info(&parent_status,
+                                       NULL, NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL,
+                                       wc_ctx->db, parent_abspath,
+                                       scratch_pool, scratch_pool));
+
+          SVN_ERR_ASSERT(parent_status == svn_wc__db_status_added
+                         || parent_status == svn_wc__db_status_obstructed_add);
+
+          SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, NULL, NULL, NULL,
+                                           NULL, NULL,
+                                           commit_base_revision,
+                                           wc_ctx->db, parent_abspath,
+                                           scratch_pool, scratch_pool));
+        }
+      else
+        /* This is a normal delete. Get the base revision. */
+        return svn_error_return(
+          svn_wc__node_get_base_rev(commit_base_revision, wc_ctx,
+                                    local_abspath, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__node_get_lock_info(const char **lock_token,
+                           const char **lock_owner,
+                           const char **lock_comment,
+                           apr_time_t *lock_date,
+                           svn_wc_context_t *wc_ctx,
+                           const char *local_abspath,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
 {
   svn_wc__db_lock_t *lock;
 
@@ -641,7 +1027,99 @@ svn_wc__node_get_lock_token(const char *
                                NULL, &lock,
                                wc_ctx->db, local_abspath,
                                result_pool, scratch_pool));
-  *lock_token = lock ? lock->token : NULL;
+  if (lock_token)
+    *lock_token = lock ? lock->token : NULL;
+  if (lock_owner)
+    *lock_owner = lock ? lock->owner : NULL;
+  if (lock_comment)
+    *lock_comment = lock ? lock->comment : NULL;
+  if (lock_date)
+    *lock_date = lock ? lock->date : 0;
+      
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__internal_is_file_external(svn_boolean_t *file_external,
+                                  svn_wc__db_t *db,
+                                  const char *local_abspath,
+                                  apr_pool_t *scratch_pool)
+{
+  const char *serialized;
+
+  SVN_ERR(svn_wc__db_temp_get_file_external(&serialized,
+                                            db, local_abspath,
+                                            scratch_pool, scratch_pool));
+  *file_external = (serialized != NULL);
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__node_is_file_external(svn_boolean_t *file_external,
+                              svn_wc_context_t *wc_ctx,
+                              const char *local_abspath,
+                              apr_pool_t *scratch_pool)
+{
+  return svn_error_return(svn_wc__internal_is_file_external(file_external,
+                                                            wc_ctx->db,
+                                                            local_abspath,
+                                                            scratch_pool));
+}
+
+svn_error_t *
+svn_wc__node_check_conflicts(svn_boolean_t *prop_conflicted,
+                             svn_boolean_t *text_conflicted,
+                             svn_boolean_t *tree_conflicted,
+                             svn_wc_context_t *wc_ctx,
+                             const char *local_abspath,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  const apr_array_header_t *conflicts;
+  int i;
+
+  if (prop_conflicted)
+    *prop_conflicted = FALSE;
+  if (text_conflicted)
+    *text_conflicted = FALSE;
+  if (tree_conflicted)
+    *tree_conflicted = FALSE;
+
+  SVN_ERR(svn_wc__db_read_conflicts(&conflicts, wc_ctx->db, local_abspath,
+                                    result_pool, scratch_pool));
+
+  for (i = 0; i < conflicts->nelts; i++)
+    {
+      const svn_wc_conflict_description2_t *cd;
+      cd = APR_ARRAY_IDX(conflicts, i, svn_wc_conflict_description2_t *);
+      if (prop_conflicted && cd->kind == svn_wc_conflict_kind_property)
+        *prop_conflicted = TRUE;
+      else if (text_conflicted && cd->kind == svn_wc_conflict_kind_text)
+        *text_conflicted = TRUE;
+      else if (tree_conflicted && cd->kind == svn_wc_conflict_kind_tree)
+        *tree_conflicted = TRUE;
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__temp_get_keep_local(svn_boolean_t *keep_local,
+                            svn_wc_context_t *wc_ctx,
+                            const char *local_abspath,
+                            apr_pool_t *scratch_pool)
+{
+  svn_boolean_t is_deleted;
+
+  SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath,
+                                         scratch_pool));
+  if (is_deleted)
+    SVN_ERR(svn_wc__db_temp_determine_keep_local(keep_local, wc_ctx->db,
+                                                 local_abspath, scratch_pool));
+  else
+    *keep_local = FALSE;
 
   return SVN_NO_ERROR;
 }