Index: subversion/include/svn_wc.h =================================================================== --- subversion/include/svn_wc.h (revision 17323) +++ subversion/include/svn_wc.h (working copy) @@ -57,7 +57,40 @@ */ const svn_version_t *svn_wc_version (void); +/** Flags for use with svn_wc_translated_file2 + * + * @defgroup translate_flags Translation flags + * + * @{ + */ + /** Translate from Normal Format (the default) */ +#define SVN_WC_TRANSLATE_FROM_NF 0x00000000 + + /** Translate to Normal Format; overrides _FROM_NF */ +#define SVN_WC_TRANSLATE_TO_NF 0x00000001 + + /** Translate the special property only */ +#define SVN_WC_TRANSLATE_SPECIAL_ONLY 0x00000002 + + /** Force all EOLs to the same type */ +#define SVN_WC_TRANSLATE_FORCE_REPAIR 0x00000004 + + /** Guarantee a new file is created on successful return. + * The default shortcuts translation by returning the path + * of the untranslated file when no translation is required. + */ +#define SVN_WC_TRANSLATE_FORCE_COPY 0x00000008 + + /** Create temporary to translate file to in the same directory + * as the translation source. The default is to assume the source + * is a versioned file in a working copy for which a temporary can + * be created in the admin area. */ +#define SVN_WC_TRANSLATE_IN_SRC_DIR 0x00000010 + +/** @} */ + + /* Locking/Opening/Closing */ /** Baton for access to a working copy administrative area. @@ -3142,12 +3175,14 @@ * * @since New in 1.4 */ -svn_error_t *svn_wc_translated_file2 (const char **xlated_p, - const char *vfile, - svn_wc_adm_access_t *adm_access, - svn_boolean_t force_repair, - svn_boolean_t del_temp_on_pool_cleanup, - apr_pool_t *pool); +svn_error_t * +svn_wc_translated_file2 (const char **xlated_path, + const char *src, + const char *path, + svn_wc_adm_access_t *adm_access, + apr_uint32_t flags, + svn_boolean_t del_temp_on_pool_cleanup, + apr_pool_t *pool); /** Same as svn_wc_translated_file2, but will never clean up Index: subversion/libsvn_wc/merge.c =================================================================== --- subversion/libsvn_wc/merge.c (revision 17323) +++ subversion/libsvn_wc/merge.c (working copy) @@ -71,20 +71,12 @@ /* Make sure a temporary copy of 'target' is available with keywords contracted and line endings in repository-normal (LF) form. This is the file that diff3 will read as the 'mine' file. */ - SVN_ERR (svn_wc_translated_file2 (&tmp_target, merge_target, adm_access, - TRUE, TRUE, pool)); - if (tmp_target == merge_target) /* contraction didn't happen */ - { - /* The target is already in repository form, so we just need to - make a verbatim copy of it. */ - SVN_ERR (svn_io_open_unique_file2 (NULL, &tmp_target, - merge_target, - SVN_WC__TMP_EXT, - svn_io_file_del_on_pool_cleanup, - pool)); - SVN_ERR (svn_io_copy_file (merge_target, - tmp_target, TRUE, pool)); - } + SVN_ERR (svn_wc_translated_file2 (&tmp_target, merge_target, + merge_target, adm_access, + SVN_WC_TRANSLATE_TO_NF + | SVN_WC_TRANSLATE_FORCE_REPAIR + | SVN_WC_TRANSLATE_FORCE_COPY, + TRUE, pool)); /* Open a second temporary file for writing; this is where diff3 will write the merged results. */ Index: subversion/libsvn_wc/diff.c =================================================================== --- subversion/libsvn_wc/diff.c (revision 17323) +++ subversion/libsvn_wc/diff.c (working copy) @@ -563,8 +563,10 @@ SVN_ERR (get_local_mimetypes (NULL, &working_mimetype, NULL, adm_access, path, pool)); - SVN_ERR (svn_wc_translated_file2 (&translated, path, adm_access, - TRUE, TRUE, pool)); + SVN_ERR (svn_wc_translated_file2 (&translated, path, path, adm_access, + SVN_WC_TRANSLATE_TO_NF + | SVN_WC_TRANSLATE_FORCE_REPAIR, + TRUE, pool)); SVN_ERR (dir_baton->edit_baton->callbacks->file_added (NULL, NULL, NULL, path, @@ -588,8 +590,11 @@ tmp translated copy too. But what the heck, diff is already expensive, translating twice for the sake of code modularity is liveable. */ - SVN_ERR (svn_wc_translated_file2 (&translated, path, adm_access, - TRUE, TRUE, pool)); + SVN_ERR (svn_wc_translated_file2 (&translated, path, + path, adm_access, + SVN_WC_TRANSLATE_TO_NF + | SVN_WC_TRANSLATE_FORCE_REPAIR, + TRUE, pool)); } if (modified || propchanges->nelts > 0) @@ -1213,8 +1218,11 @@ localfile = empty_file; else /* a detranslated version of the working file */ - SVN_ERR (svn_wc_translated_file2 (&localfile, b->path, adm_access, - TRUE, TRUE, b->pool)); + SVN_ERR (svn_wc_translated_file2 (&localfile, b->path, + b->path, adm_access, + SVN_WC_TRANSLATE_TO_NF + | SVN_WC_TRANSLATE_FORCE_REPAIR, + TRUE, pool)); temp_file_path = b->temp_file_path; } Index: subversion/libsvn_wc/adm_crawler.c =================================================================== --- subversion/libsvn_wc/adm_crawler.c (revision 17323) +++ subversion/libsvn_wc/adm_crawler.c (working copy) @@ -60,9 +60,7 @@ svn_boolean_t use_commit_times, apr_pool_t *pool) { - const char *text_base_path, *tmp_text_base_path; - apr_hash_t *keywords; - const char *eol; + const char *tmp_file, *text_base_path; const svn_wc_entry_t *entry; svn_wc_entry_t newentry; apr_time_t tstamp; @@ -71,32 +69,20 @@ svn_boolean_t special; text_base_path = svn_wc__text_base_path (file_path, FALSE, pool); - tmp_text_base_path = svn_wc__text_base_path (file_path, TRUE, pool); bname = svn_path_basename (file_path, pool); - SVN_ERR (svn_io_copy_file (text_base_path, tmp_text_base_path, - FALSE, pool)); + /* Copy / translate into a temporary file, which afterwards can + be atomically moved over the original working copy file. */ - SVN_ERR (svn_wc__get_eol_style (NULL, &eol, file_path, adm_access, pool)); - SVN_ERR (svn_wc__get_keywords (&keywords, - file_path, adm_access, NULL, pool)); - SVN_ERR (svn_wc__get_special (&special, file_path, adm_access, pool)); - - - /* When copying the tmp-text-base out to the working copy, make - sure to do any eol translations or keyword substitutions, - as dictated by the property values. If these properties - are turned off, then this is just a normal copy. */ - SVN_ERR (svn_subst_copy_and_translate3 (tmp_text_base_path, - file_path, - eol, FALSE, /* don't repair */ - keywords, - TRUE, /* expand keywords */ - special, - pool)); - - SVN_ERR (svn_io_remove_file (tmp_text_base_path, pool)); + SVN_ERR (svn_wc_translated_file2 (&tmp_file, + text_base_path, file_path, adm_access, + SVN_WC_TRANSLATE_FROM_NF + | SVN_WC_TRANSLATE_FORCE_COPY, + TRUE, pool)); + SVN_ERR (svn_wc__prep_file_for_replacement (file_path, TRUE, pool)); + SVN_ERR (svn_io_file_rename (tmp_file, file_path, pool)); + SVN_ERR (svn_wc__maybe_set_read_only (NULL, file_path, adm_access, pool)); /* If necessary, tweak the new working file's executable bit. */ @@ -120,7 +106,7 @@ { SVN_ERR (svn_io_file_affected_time (&tstamp, file_path, pool)); } - + /* Modify our entry's text-timestamp to match the working file. */ modify_flags |= SVN_WC__ENTRY_MODIFY_TEXT_TIME; newentry.text_time = tstamp; Index: subversion/libsvn_wc/log.c =================================================================== --- subversion/libsvn_wc/log.c (revision 17323) +++ subversion/libsvn_wc/log.c (working copy) @@ -234,63 +234,49 @@ case svn_wc__xfer_cp_and_translate: { - apr_hash_t *keywords = NULL; - const char *eol_str = NULL; - svn_boolean_t special = FALSE; + const char *tmp_file; - if (! special_only) - { - /* Note that this action takes properties from dest, not source. */ - SVN_ERR (svn_wc__get_keywords (&keywords, full_dest_path, - adm_access, NULL, pool)); - SVN_ERR (svn_wc__get_eol_style (NULL, &eol_str, full_dest_path, - adm_access, pool)); - } - SVN_ERR (svn_wc__get_special (&special, full_dest_path, adm_access, - pool)); + SVN_ERR (svn_wc_translated_file2 + (&tmp_file, + full_from_path, + full_dest_path, adm_access, + SVN_WC_TRANSLATE_FROM_NF + | SVN_WC_TRANSLATE_FORCE_COPY + | SVN_WC_TRANSLATE_FORCE_REPAIR + | (special_only ? SVN_WC_TRANSLATE_SPECIAL_ONLY : 0), + TRUE, pool)); + SVN_ERR (svn_wc__prep_file_for_replacement (full_dest_path, TRUE, + pool)); + SVN_ERR (svn_io_file_rename (tmp_file, full_dest_path, pool)); - SVN_ERR (svn_subst_copy_and_translate3 (full_from_path, - full_dest_path, - eol_str, - TRUE, - keywords, - TRUE, - special, - pool)); - + /* Set the file read only and/or executable if props dictate */ SVN_ERR (svn_wc__maybe_set_read_only (NULL, full_dest_path, adm_access, pool)); - /* After copying, set the file executable if props dictate. */ - return svn_wc__maybe_set_executable (NULL, full_dest_path, adm_access, - pool); - } + SVN_ERR (svn_wc__maybe_set_executable (NULL, full_dest_path, + adm_access, pool)); + return SVN_NO_ERROR; + } case svn_wc__xfer_cp_and_detranslate: { - apr_hash_t *keywords; - const char *eol_str; - svn_boolean_t special; + const char *tmp_file; - /* Note that this action takes properties from source, not dest. */ - SVN_ERR (svn_wc__get_keywords (&keywords, full_from_path, adm_access, - NULL, pool)); - SVN_ERR (svn_wc__get_eol_style (NULL, &eol_str, full_from_path, - adm_access, pool)); - SVN_ERR (svn_wc__get_special (&special, full_from_path, adm_access, - pool)); + SVN_ERR (svn_wc_translated_file2 + (&tmp_file, + full_from_path, + full_from_path, adm_access, + SVN_WC_TRANSLATE_TO_NF + | SVN_WC_TRANSLATE_FORCE_COPY + | SVN_WC_TRANSLATE_FORCE_REPAIR + | SVN_WC_TRANSLATE_IN_SRC_DIR + | (special_only ? SVN_WC_TRANSLATE_SPECIAL_ONLY : 0), + TRUE, pool)); + SVN_ERR (svn_wc__prep_file_for_replacement (full_dest_path, TRUE, + pool)); + SVN_ERR (svn_io_file_rename (tmp_file, full_dest_path, pool)); - /* If any specific eol style was indicated, then detranslate - back to repository normal form ("\n"), repairingly. But if - no style indicated, don't touch line endings at all. */ - return svn_subst_copy_and_translate3 (full_from_path, - full_dest_path, - (eol_str ? "\n" : NULL), - (eol_str ? TRUE : FALSE), - keywords, - FALSE, /* contract keywords */ - special, - pool); + return SVN_NO_ERROR; } case svn_wc__xfer_mv: @@ -342,10 +328,8 @@ const char *filepath; const char *tmp_text_base; svn_node_kind_t kind; - apr_hash_t *keywords; svn_boolean_t same, did_set; - const char *tmp_wfile, *pdir, *bname; - const char *eol_str; + const char *tmp_wfile; svn_boolean_t special; /* start off assuming that the working file isn't touched. */ @@ -370,58 +354,30 @@ * reread the file if they don't really need to. */ - /* start off getting the latest translation prop values. */ - SVN_ERR (svn_wc__get_eol_style (NULL, &eol_str, filepath, adm_access, pool)); - SVN_ERR (svn_wc__get_keywords (&keywords, filepath, adm_access, NULL, pool)); - SVN_ERR (svn_wc__get_special (&special, filepath, adm_access, pool)); - - svn_path_split (filepath, &pdir, &bname, pool); - tmp_wfile = svn_wc__adm_path (pdir, TRUE, pool, bname, NULL); - - SVN_ERR (svn_io_open_unique_file2 (NULL, &tmp_wfile, - tmp_wfile, SVN_WC__TMP_EXT, - svn_io_file_del_none, pool)); - /* Is there a tmp_text_base that needs to be installed? */ tmp_text_base = svn_wc__text_base_path (filepath, 1, pool); SVN_ERR (svn_io_check_path (tmp_text_base, &kind, pool)); - if (kind == svn_node_file) - SVN_ERR (svn_subst_copy_and_translate3 (tmp_text_base, - tmp_wfile, - eol_str, - FALSE, /* don't repair eol */ - keywords, - TRUE, /* expand keywords */ - special, - pool)); - else - SVN_ERR (svn_subst_copy_and_translate3 (filepath, - tmp_wfile, - eol_str, - FALSE, /* don't repair eol */ - keywords, - TRUE, /* expand keywords */ - special, - pool)); + SVN_ERR (svn_wc_translated_file2 (&tmp_wfile, + (kind == svn_node_file) + ? tmp_text_base : filepath, + filepath, adm_access, + SVN_WC_TRANSLATE_FROM_NF + | SVN_WC_TRANSLATE_FORCE_COPY, + TRUE, pool)); + SVN_ERR (svn_wc__get_special (&special, filepath, adm_access, pool)); if (! special) - { - SVN_ERR (svn_io_files_contents_same_p (&same, tmp_wfile, filepath, pool)); - } + SVN_ERR (svn_io_files_contents_same_p (&same, tmp_wfile, filepath, pool)); else - { same = TRUE; - } - + if (! same) { - SVN_ERR (svn_io_copy_file (tmp_wfile, filepath, FALSE, pool)); + SVN_ERR (svn_io_file_rename (tmp_wfile, filepath, pool)); *overwrote_working = TRUE; } - SVN_ERR (svn_io_remove_file (tmp_wfile, pool)); - SVN_ERR (svn_wc__maybe_set_read_only (&did_set, filepath, adm_access, pool)); if (did_set) /* the file may have been overwritten or its timestamp changed by Index: subversion/libsvn_wc/questions.c =================================================================== --- subversion/libsvn_wc/questions.c (revision 17323) +++ subversion/libsvn_wc/questions.c (working copy) @@ -231,8 +231,11 @@ svn_boolean_t same; const char *tmp_vfile; - SVN_ERR (svn_wc_translated_file2 (&tmp_vfile, versioned_file, adm_access, - TRUE, TRUE, pool)); + SVN_ERR (svn_wc_translated_file2 (&tmp_vfile, versioned_file, + versioned_file, adm_access, + SVN_WC_TRANSLATE_TO_NF + | SVN_WC_TRANSLATE_FORCE_REPAIR, + TRUE, pool)); SVN_ERR (svn_io_files_contents_same_p (&same, tmp_vfile, base_file, pool)); *modified_p = (! same); @@ -263,8 +266,11 @@ SVN_ERR (svn_wc_entry (&entry, versioned_file, adm_access, TRUE, pool)); - SVN_ERR (svn_wc_translated_file2 (&tmp_vfile, versioned_file, adm_access, - TRUE, TRUE, pool)); + SVN_ERR (svn_wc_translated_file2 (&tmp_vfile, versioned_file, + versioned_file, adm_access, + SVN_WC_TRANSLATE_TO_NF + | SVN_WC_TRANSLATE_FORCE_REPAIR, + TRUE, pool)); /* Compare the files, while maybe calculating the base file's checksum. */ { Index: subversion/libsvn_wc/translate.c =================================================================== --- subversion/libsvn_wc/translate.c (revision 17323) +++ subversion/libsvn_wc/translate.c (working copy) @@ -42,37 +42,48 @@ #include "svn_private_config.h" svn_error_t * -svn_wc_translated_file2 (const char **xlated_p, - const char *vfile, +svn_wc_translated_file2 (const char **xlated_path, + const char *src, + const char *path, svn_wc_adm_access_t *adm_access, - svn_boolean_t force_repair, + apr_uint32_t flags, svn_boolean_t del_temp_on_pool_cleanup, apr_pool_t *pool) { - svn_subst_eol_style_t style; - const char *eol; - apr_hash_t *keywords; + svn_subst_eol_style_t style = svn_subst_eol_style_none; + const char *eol = NULL; + apr_hash_t *keywords = NULL; svn_boolean_t special; - - SVN_ERR (svn_wc__get_eol_style (&style, &eol, vfile, adm_access, pool)); - SVN_ERR (svn_wc__get_keywords (&keywords, vfile, adm_access, NULL, pool)); - SVN_ERR (svn_wc__get_special (&special, vfile, adm_access, pool)); + const char *tmp_dir, *tmp_vfile; + svn_boolean_t special_only = flags & SVN_WC_TRANSLATE_SPECIAL_ONLY; - if (! svn_subst_translation_required (style, eol, keywords, special, TRUE)) + if (flags & SVN_WC_TRANSLATE_IN_SRC_DIR) + tmp_vfile = src; + else { - /* Translation would be a no-op, so return the original file. */ - *xlated_p = vfile; - } - else /* some translation is necessary */ - { - const char *tmp_dir, *tmp_vfile; + svn_path_split (path, &tmp_dir, &tmp_vfile, pool); - /* First, reserve a tmp file name. */ - svn_path_split (vfile, &tmp_dir, &tmp_vfile, pool); - tmp_vfile = svn_wc__adm_path (tmp_dir, 1, pool, tmp_vfile, NULL); + } + if (! special_only) + { + SVN_ERR (svn_wc__get_eol_style (&style, &eol, path, adm_access, pool)); + SVN_ERR (svn_wc__get_keywords (&keywords, path, adm_access, NULL, pool)); + } + SVN_ERR (svn_wc__get_special (&special, path, adm_access, pool)); + + + if (! svn_subst_translation_required (style, eol, keywords, special, TRUE) + && (! (flags & SVN_WC_TRANSLATE_FORCE_COPY))) + { + /* Translation would be a no-op, so return the original file. */ + *xlated_path = src; + + } + else /* some translation (or copying) is necessary */ + { SVN_ERR (svn_io_open_unique_file2 (NULL, &tmp_vfile, tmp_vfile, @@ -82,10 +93,17 @@ : svn_io_file_del_none, pool)); - SVN_ERR (svn_subst_translate_to_normal_form - (vfile, tmp_vfile, style, eol, keywords, special, pool)); - - *xlated_p = tmp_vfile; + if (flags & SVN_WC_TRANSLATE_TO_NF) + SVN_ERR (svn_subst_translate_to_normal_form + (src, tmp_vfile, style, eol, keywords, special, pool)); + else /* translate */ + SVN_ERR (svn_subst_copy_and_translate3 (src, + tmp_vfile, + eol, FALSE, + keywords, TRUE, + special, + pool)); + *xlated_path = tmp_vfile; } return SVN_NO_ERROR; @@ -99,8 +117,11 @@ svn_boolean_t force_repair, apr_pool_t *pool) { - return svn_wc_translated_file2 (xlated_p, vfile, adm_access, - force_repair, FALSE, pool); + return svn_wc_translated_file2 (xlated_p, vfile, vfile, adm_access, + SVN_WC_TRANSLATE_TO_NF + | (force_repair ? + SVN_WC_TRANSLATE_FORCE_REPAIR : 0), + FALSE, pool); }