svn-3354

Version:

patched on 1.6.0

Bug Link:

http://subversion.tigris.org/issues/show_bug.cgi?id=3354

http://svn.haxx.se/dev/archive-2009-01/0075.shtml

http://svn.haxx.se/dev/archive-2009-01/0512.shtml

http://svn.haxx.se/dev/archive-2009-01/0620.shtml

Patch Link:

source code patch:

http://svn.apache.org/viewvc?diff_format=h&view=revision&revision=875377

http://svn.apache.org/viewvc?diff_format=h&view=revision&revision=875464

reproduction:

http://subversion.tigris.org/nonav/issues/showattachment.cgi/966/recipe.sh

Symptom:

‘svn update’ fails when file with local mods is moved and modified.

If you run the attached script with current trunk, svn bails out and leaves the working copy in locked state. The problem occurs when an update pulls down both a move and a textual diff for a file in one go.

Error message is the following:

[DEBUG mode] subversion/libsvn_wc/log.c:625: (apr_err=155009)

svn: In directory 'recipe/trunk2'

[DEBUG mode] subversion/libsvn_subr/io.c:2636: (apr_err=2)

svn: Can't open file 'recipe/trunk2/alpha.moved': No such file or directory

/* in this function, the first error message is generated */

static svn_error_t *log_do_file_xfer(...)

{

  err = file_xfer_under_path(loggy->adm_access, name, dest, versioned, action, loggy->rerun, loggy->pool);

  if (err)

    SIGNAL_ERROR(loggy, err);

  return SVN_NO_ERROR;

}

#define SIGNAL_ERROR(loggy, err)                                   \

  svn_xml_signal_bailout                                           \

    (svn_error_createf(pick_error_code(loggy), err,                \

                       _("In directory '%s'"),                     \

                       svn_path_local_style(svn_wc_adm_access_path \

                                            (loggy->adm_access),   \

                                            loggy->pool)),         \

     loggy->parser)

/* in this function, the second error message is generated */

svn_error_t *svn_io_file_open(...)

{

   … …

    status = file_open(new_file, fname_apr, flag | APR_BINARY, perm,                         TRUE, pool);

  if (status)

    return svn_error_wrap_apr(status, _("Can't open file '%s'"),

                              svn_path_local_style(fname, pool));

  else

    return SVN_NO_ERROR;

}

How it is diagnosed:

reproduced

Callstack:

#0  svn_io_file_open (fname= "recipe/trunk2/alpha.moved", flag=33, perm=4095, ...) at subversion/libsvn_subr/io.c:2636

#1  svn_io_copy_file (

src= "recipe/trunk2/alpha.moved", dst= "recipe/trunk2/alpha.moved.mine",                         copy_perms=0) at subversion/libsvn_subr/io.c:675

#2  svn_subst_copy_and_translate3 (src= "recipe/trunk2/alpha.moved", dst= "recipe/trunk2/alpha.moved.mine", ...) at subversion/libsvn_subr/subst.c:1442

#3  file_xfer_under_path (name= "alpha.moved", dest= "alpha.moved.mine", versioned= "alpha.moved", action=svn_wc__xfer_cp_and_translate, rerun=0, ...) at subversion/libsvn_wc/log.c:314

#4  log_do_file_xfer (name= "alpha.moved", action=svn_wc__xfer_cp_and_translate, ...) at subversion/libsvn_wc/log.c:622

#5  start_handler (eltname= "cp-and-translate", ...) at subversion/libsvn_wc/log.c:1599

#6  expat_start_handler (...) at subversion/libsvn_subr/xml.c:316

#7  doContent (startTagLevel=0, s=0x6d1f20 "<cp-and-translate\n   dest=\"alpha.moved.mine\"\n   name=\"alpha.moved\"\n   arg2=\"alpha.moved\"/>\n<modify-entry\n   name=\"alpha.moved\"\n   conflict-wrk=\"alpha.moved.mine\"\n   conflict-new=\"alpha.moved.r3\"\n   co"..., ...) at xmlparse.c:1697

#8  XML_ParseBuffer (...) at xmlparse.c:1155

#9  svn_xml_parse (...) at subversion/libsvn_subr/xml.c:398

#10 run_log (...) at subversion/libsvn_wc/log.c:1846

#11 svn_wc__run_log (...) at subversion/libsvn_wc/log.c:1923

#12 close_directory (...) at subversion/libsvn_wc/update_editor.c:2548

#13 close_directory (...) at subversion/libsvn_wc/ambient_depth_filter_editor.c:478

#14 close_directory (...) at subversion/libsvn_delta/cancel.c:256

#15 close_directory (...) at subversion/libsvn_delta/cancel.c:256

#16 drive (...) at subversion/libsvn_repos/reporter.c:1186

#17 finish_report (...) at subversion/libsvn_repos/reporter.c:1245

#18 svn_repos_finish_report (...) at subversion/libsvn_repos/reporter.c:1335

#19 reporter_finish_report (...) at subversion/libsvn_ra_local/ra_plugin.c:207

#20 svn_wc_crawl_revisions4 (path= "recipe/trunk2", ...) at subversion/libsvn_wc/adm_crawler.c:711

#21 svn_client__update_internal (path= "recipe/trunk2", ...) at subversion/libsvn_client/update.c:254

#22 svn_client_update3 (...) at subversion/libsvn_client/update.c:337

#23 svn_cl__update (...) at subversion/svn/update-cmd.c:84

#24 main (...) at subversion/svn/main.c:2122

/* in this function, the error happens at the first time */

svn_error_t *svn_io_file_open(...)

{

   … …

    /* fname_apr = "recipe/trunk2/alpha.moved" */

    status = file_open(new_file, fname_apr, flag | APR_BINARY, perm,                         TRUE, pool);

  if (status)

    return svn_error_wrap_apr(status, _("Can't open file '%s'"),

                              svn_path_local_style(fname, pool));

  else

    return SVN_NO_ERROR;

}

….

/* in this function, the first error message is generated */

static svn_error_t *log_do_file_xfer(...)

{

/*dest = ‘alpha.moved.mine’, versioned = ‘alpha.moved’, action = svn_wc__xfer_cp_and_translate */

  err = file_xfer_under_path(loggy->adm_access, name, dest, versioned, action, loggy->rerun, loggy->pool);

  if (err)

    SIGNAL_ERROR(loggy, err);

  return SVN_NO_ERROR;

}

/* after finishing XML parser, error message is hanled in here */

svn_error_t *svn_xml_parse(...)

{

  ...

  /* Parse some xml data */

  success = XML_Parse(svn_parser->parser, buf, len, is_final);

  ...

  /* Did an error occur somewhere *inside* the expat callbacks? */

  if (svn_parser->error)

    {

      err = svn_parser->error;

      svn_xml_free_parser(svn_parser);

      return err;

    }

  return SVN_NO_ERROR;

}

Root Cause:

Brief:

The conflicted file does not exist on the working copy. The error happens because the code assumes that a copy of the conflicted file already exists in the working copy.

Detail:

If a text conflict is found while merging local changes from the copyfrom file to the copied file added by the update, the merge_target only exists in WC meta-data. But it does not yet exist in the working copy. So what we probably should be doing is checking wheter the merge_target exists in the working copy and if not, create it with conflict markers.

Call stack:

#0  eval_conflict_func_result (merge_outcome=0x7fffffffd518, result=0x6d94a8, log_accum=0x7fffffffd528, left=0x6c4930 "recipe/trunk2/.svn/tmp/tempfile.tmp", right=0x6d6668 "recipe/trunk2/.svn/tmp/text-base/alpha.moved.svn-base", merge_target=0x6ac480 "recipe/trunk2/alpha.moved", adm_access=0x658270, result_target=0x6d7c68 "recipe/trunk2/.svn/tmp/alpha.moved.tmp", detranslated_target=0x6de3b8 "recipe/trunk2/.svn/tmp/tempfile.2.tmp", options=0x6d8dc0, pool=0x69e058) at subversion/libsvn_wc/merge.c:454

#1  0x00002aaaaad3490d in maybe_resolve_conflicts (log_accum=0x7fffffffd528, left=0x6c4930 "recipe/trunk2/.svn/tmp/tempfile.tmp", right=0x6d6668 "recipe/trunk2/.svn/tmp/text-base/alpha.moved.svn-base", merge_target=0x6ac480 "recipe/trunk2/alpha.moved", adm_access=0x658270, left_label=0x6d7b58 ".copied", right_label=0x6d7b60 ".r3", target_label=0x6d7b68 ".mine", conflict_func=0x407c1b <svn_cl__conflict_handler>, conflict_baton=0x656a30, merge_outcome=0x7fffffffd518, left_version=0x0, right_version=0x0, result_target=0x6d7c68 "recipe/trunk2/.svn/tmp/alpha.moved.tmp", detranslated_target=0x6de3b8 "recipe/trunk2/.svn/tmp/tempfile.2.tmp", mimeprop=0x0, merge_dirpath=0x6d7b90 "recipe/trunk2", merge_filename=0x6d7ba0 "alpha.moved", options=0x6d8dc0, pool=0x69e058) at subversion/libsvn_wc/merge.c:806

#2  0x00002aaaaad34c83 in merge_text_file (left=0x6c4930 "recipe/trunk2/.svn/tmp/tempfile.tmp", right=0x6d6668 "recipe/trunk2/.svn/tmp/text-base/alpha.moved.svn-base", merge_target=0x6ac480 "recipe/trunk2/alpha.moved", adm_access=0x658270, left_label=0x6d7b58 ".copied", right_label=0x6d7b60 ".r3", target_label=0x6d7b68 ".mine", dry_run=0, diff3_cmd=0x0, merge_options=0x0, conflict_func=0x407c1b <svn_cl__conflict_handler>, conflict_baton=0x656a30, log_accum=0x7fffffffd528, merge_outcome=0x7fffffffd518, left_version=0x0, right_version=0x0, copyfrom_text=0x6de3b8 "recipe/trunk2/.svn/tmp/tempfile.2.tmp", result_target=0x6d7c68 "recipe/trunk2/.svn/tmp/alpha.moved.tmp", detranslated_target=0x6de3b8 "recipe/trunk2/.svn/tmp/tempfile.2.tmp", mimeprop=0x0, merge_dirpath=0x6d7b90 "recipe/trunk2", merge_filename=0x6d7ba0 "alpha.moved", pool=0x69e058) at subversion/libsvn_wc/merge.c:916

#3  0x00002aaaaad357a0 in svn_wc__merge_internal (log_accum=0x7fffffffd528, merge_outcome=0x7fffffffd518, left=0x6c4930 "recipe/trunk2/.svn/tmp/tempfile.tmp", left_version=0x0, right=0x6d6668 "recipe/trunk2/.svn/tmp/text-base/alpha.moved.svn-base", right_version=0x0, merge_target=0x6ac480 "recipe/trunk2/alpha.moved", copyfrom_text=0x6de3b8 "recipe/trunk2/.svn/tmp/tempfile.2.tmp", adm_access=0x658270, left_label=0x6d7b58 ".copied", right_label=0x6d7b60 ".r3", target_label=0x6d7b68 ".mine", dry_run=0, diff3_cmd=0x0, merge_options=0x0, prop_diff=0x6ac510, conflict_func=0x407c1b <svn_cl__conflict_handler>, conflict_baton=0x656a30, pool=0x69e058) at subversion/libsvn_wc/merge.c:1236

#4  0x00002aaaaad4c56c in merge_file (content_state=0x7fffffffd6ac, prop_state=0x7fffffffd6a8, lock_state=0x7fffffffd6a4, fb=0x6ac3d8, new_text_base_path=0x6d6668 "recipe/trunk2/.svn/tmp/text-base/alpha.moved.svn-base", actual_checksum=0x6d66a0, pool=0x69e058) at subversion/libsvn_wc/update_editor.c:3868

...

#9  0x00002aaaab599728 in update_entry (b=0x6621f0, s_rev=1, s_path=0x0, s_entry=0x0, t_path=0x69e0e0 "/trunk/alpha.moved", t_entry=0x69c2e8, dir_baton=0x698e78, e_path=0x69e0d0 "alpha.moved", info=0x0, wc_depth=svn_depth_infinity, requested_depth=svn_depth_unknown, pool=0x69e058) at subversion/libsvn_repos/reporter.c:871

#10 0x00002aaaab59a036 in delta_dirs (b=0x6621f0, s_rev=1, s_path=0x672050 "/trunk", t_path=0x6622a0 "/trunk", dir_baton=0x698e78, e_path=0x2aaaab5a1edf "", start_empty=0, wc_depth=svn_depth_infinity, requested_depth=svn_depth_unknown, pool=0x657f68) at subversion/libsvn_repos/reporter.c:1113

#11 0x00002aaaab59a4ce in drive (b=0x6621f0, s_rev=1, info=0x663550, pool=0x657f68) at subversion/libsvn_repos/reporter.c:1178

#12 0x00002aaaab59a8b1 in finish_report (b=0x6621f0, pool=0x657f68) at subversion/libsvn_repos/reporter.c:1245

...

#15 0x00002aaaaad0fdcd in svn_wc_crawl_revisions4 (path=0x656bd8 "recipe/trunk2", adm_access=0x658270, reporter=0x2aaaab57b040, report_baton=0x6634e0, restore_files=1, depth=svn_depth_unknown, honor_depth_exclude=1, depth_compatibility_trick=0, use_commit_times=0, notify_func=0x4132c2 <notify>, notify_baton=0x656be8, traversal_info=0x657fe0, pool=0x657f68) at subversion/libsvn_wc/adm_crawler.c:711

The Patch is:

--- subversion/trunk/subversion/libsvn_wc/merge.c        2009/01/17 10:01:44        875376

+++ subversion/trunk/subversion/libsvn_wc/merge.c        2009/01/17 13:43:26        875377

@@ -445,6 +445,7 @@ eval_conflict_func_result(enum svn_wc_me

                           const char *left,

                           const char *right,

                           const char *merge_target,

+                          const char *copyfrom_text,

                           svn_wc_adm_access_t *adm_access,

                           const char *result_target,

                           const char *detranslated_target,

@@ -538,35 +539,18 @@ eval_conflict_func_result(enum svn_wc_me

       case svn_wc_conflict_choose_postpone:

       default:

         {

+          /* Issue #3354: We need to install the copyfrom_text,

+           * which now carries conflicts, into ACTUAL, by copying

+           * it to the merge target. */

            /* copyfrom_text = 0x6de3b8 "recipe/trunk2/.svn/tmp/tempfile.2.tmp" */

           /* it’s not in the working copy but meta-file location. we need to copy this file to the working copy so that we can use this file in the near future */

+          if (copyfrom_text)

+            {

+              SVN_ERR(svn_wc__loggy_copy(log_accum, adm_access,

+                                         copyfrom_text, merge_target,

+                                         pool));

+            }

+

           /* Assume conflict remains. */

           return SVN_NO_ERROR;

         }

     }

 }

@@ -751,6 +735,7 @@ maybe_resolve_conflicts(svn_stringbuf_t

                         const char *left,

                         const char *right,

                         const char *merge_target,

+                        const char *copyfrom_text,

                         svn_wc_adm_access_t *adm_access,

                         const char *left_label,

                         const char *right_label,

@@ -809,6 +794,7 @@ maybe_resolve_conflicts(svn_stringbuf_t

                                         left,

                                         right,

                                         merge_target,

+                                        copyfrom_text,

                                         adm_access,

                                         result_target,

                                         detranslated_target,

@@ -917,6 +903,7 @@ merge_text_file(const char *left,

                                       left,

                                       right,

                                       merge_target,

+                                      copyfrom_text,

                                       adm_access,

                                       left_label,

                                       right_label,

Failure symptom category

missing functions

Is there any log message?

Yes

How can we automatically insert the log message?

log the error return value (checked)