svn_error_t * svn_wc_create_tmp_file2(apr_file_t **fp, const char **new_name, const char *path, svn_io_file_del_t delete_when, apr_pool_t *pool) { svn_wc__db_t *db; const char *local_abspath; const char *temp_dir; svn_error_t *err; SVN_ERR_ASSERT(fp || new_name); SVN_ERR(svn_wc__db_open(&db, NULL /* config */, TRUE /* auto_upgrade */, TRUE /* enforce_empty_wq */, pool, pool)); SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); err = svn_wc__db_temp_wcroot_tempdir(&temp_dir, db, local_abspath, pool, pool); err = svn_error_compose_create(err, svn_wc__db_close(db)); if (err) return svn_error_trace(err); SVN_ERR(svn_io_open_unique_file3(fp, new_name, temp_dir, delete_when, pool, pool)); return SVN_NO_ERROR; }
svn_error_t * svn_wc__internal_translated_file(const char **xlated_abspath, const char *src_abspath, svn_wc__db_t *db, const char *versioned_abspath, apr_uint32_t flags, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_subst_eol_style_t style; const char *eol; apr_hash_t *keywords; svn_boolean_t special; SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath)); SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_abspath)); SVN_ERR(svn_wc__get_translate_info(&style, &eol, &keywords, &special, db, versioned_abspath, NULL, FALSE, scratch_pool, scratch_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_abspath = src_abspath; } else /* some translation (or copying) is necessary */ { const char *tmp_dir; const char *tmp_vfile; svn_boolean_t repair_forced = (flags & SVN_WC_TRANSLATE_FORCE_EOL_REPAIR) != 0; svn_boolean_t expand = (flags & SVN_WC_TRANSLATE_TO_NF) == 0; if (flags & SVN_WC_TRANSLATE_USE_GLOBAL_TMP) tmp_dir = NULL; else SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db, versioned_abspath, scratch_pool, scratch_pool)); SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_vfile, tmp_dir, (flags & SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP) ? svn_io_file_del_none : svn_io_file_del_on_pool_cleanup, result_pool, scratch_pool)); /* ### ugh. the repair behavior does NOT match the docstring. bleah. ### all of these translation functions are crap and should go ### away anyways. we'll just deprecate most of the functions and ### properly document the survivors */ if (expand) { /* from normal form */ repair_forced = TRUE; } else { /* to normal form */ if (style == svn_subst_eol_style_native) eol = SVN_SUBST_NATIVE_EOL_STR; else if (style == svn_subst_eol_style_fixed) repair_forced = TRUE; else if (style != svn_subst_eol_style_none) return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL); } SVN_ERR(svn_subst_copy_and_translate4(src_abspath, tmp_vfile, eol, repair_forced, keywords, expand, special, cancel_func, cancel_baton, result_pool)); *xlated_abspath = tmp_vfile; } return SVN_NO_ERROR; }
/* The guts of svn_wc_copy3() and svn_wc_move(). * The additional parameter IS_MOVE indicates whether this is a copy or * a move operation. * * If MOVE_DEGRADED_TO_COPY is not NULL and a move had to be degraded * to a copy, then set *MOVE_DEGRADED_TO_COPY. */ static svn_error_t * copy_or_move(svn_boolean_t *move_degraded_to_copy, svn_wc_context_t *wc_ctx, const char *src_abspath, const char *dst_abspath, svn_boolean_t metadata_only, svn_boolean_t is_move, svn_boolean_t allow_mixed_revisions, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, void *notify_baton, apr_pool_t *scratch_pool) { svn_wc__db_t *db = wc_ctx->db; svn_node_kind_t src_db_kind; const char *dstdir_abspath; svn_boolean_t conflicted; const char *tmpdir_abspath; const char *src_wcroot_abspath; const char *dst_wcroot_abspath; svn_boolean_t within_one_wc; svn_wc__db_status_t src_status; svn_error_t *err; SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath)); SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); dstdir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool); /* Ensure DSTDIR_ABSPATH belongs to the same repository as SRC_ABSPATH; throw an error if not. */ { svn_wc__db_status_t dstdir_status; const char *src_repos_root_url, *dst_repos_root_url; const char *src_repos_uuid, *dst_repos_uuid; const char *src_repos_relpath; err = svn_wc__db_read_info(&src_status, &src_db_kind, NULL, &src_repos_relpath, &src_repos_root_url, &src_repos_uuid, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &conflicted, NULL, NULL, NULL, NULL, NULL, NULL, db, src_abspath, scratch_pool, scratch_pool); if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) { /* Replicate old error code and text */ svn_error_clear(err); return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL, _("'%s' is not under version control"), svn_dirent_local_style(src_abspath, scratch_pool)); } else SVN_ERR(err); /* Do this now, as we know the right data is cached */ SVN_ERR(svn_wc__db_get_wcroot(&src_wcroot_abspath, db, src_abspath, scratch_pool, scratch_pool)); switch (src_status) { case svn_wc__db_status_deleted: return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("Deleted node '%s' can't be copied."), svn_dirent_local_style(src_abspath, scratch_pool)); case svn_wc__db_status_excluded: case svn_wc__db_status_server_excluded: case svn_wc__db_status_not_present: return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, _("The node '%s' was not found."), svn_dirent_local_style(src_abspath, scratch_pool)); default: break; } if (is_move && ! strcmp(src_abspath, src_wcroot_abspath)) { return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("'%s' is the root of a working copy and " "cannot be moved"), svn_dirent_local_style(src_abspath, scratch_pool)); } if (is_move && src_repos_relpath && !src_repos_relpath[0]) { return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, _("'%s' represents the repository root " "and cannot be moved"), svn_dirent_local_style(src_abspath, scratch_pool)); } err = svn_wc__db_read_info(&dstdir_status, NULL, NULL, NULL, &dst_repos_root_url, &dst_repos_uuid, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, db, dstdir_abspath, scratch_pool, scratch_pool); if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) { /* An unversioned destination directory exists on disk. */ svn_error_clear(err); return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL, _("'%s' is not under version control"), svn_dirent_local_style(dstdir_abspath, scratch_pool)); } else SVN_ERR(err); /* Do this now, as we know the right data is cached */ SVN_ERR(svn_wc__db_get_wcroot(&dst_wcroot_abspath, db, dstdir_abspath, scratch_pool, scratch_pool)); if (!src_repos_root_url) { if (src_status == svn_wc__db_status_added) SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, &src_repos_root_url, &src_repos_uuid, NULL, NULL, NULL, NULL, db, src_abspath, scratch_pool, scratch_pool)); else /* If not added, the node must have a base or we can't copy */ SVN_ERR(svn_wc__db_scan_base_repos(NULL, &src_repos_root_url, &src_repos_uuid, db, src_abspath, scratch_pool, scratch_pool)); } if (!dst_repos_root_url) { if (dstdir_status == svn_wc__db_status_added) SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, NULL, &dst_repos_root_url, &dst_repos_uuid, NULL, NULL, NULL, NULL, db, dstdir_abspath, scratch_pool, scratch_pool)); else /* If not added, the node must have a base or we can't copy */ SVN_ERR(svn_wc__db_scan_base_repos(NULL, &dst_repos_root_url, &dst_repos_uuid, db, dstdir_abspath, scratch_pool, scratch_pool)); } if (strcmp(src_repos_root_url, dst_repos_root_url) != 0 || strcmp(src_repos_uuid, dst_repos_uuid) != 0) return svn_error_createf( SVN_ERR_WC_INVALID_SCHEDULE, NULL, _("Cannot copy to '%s', as it is not from repository '%s'; " "it is from '%s'"), svn_dirent_local_style(dst_abspath, scratch_pool), src_repos_root_url, dst_repos_root_url); if (dstdir_status == svn_wc__db_status_deleted) return svn_error_createf( SVN_ERR_WC_INVALID_SCHEDULE, NULL, _("Cannot copy to '%s' as it is scheduled for deletion"), svn_dirent_local_style(dst_abspath, scratch_pool)); /* ### should report dstdir_abspath instead of dst_abspath? */ } /* TODO(#2843): Rework the error report. */ /* Check if the copy target is missing or hidden and thus not exist on the disk, before actually doing the file copy. */ { svn_wc__db_status_t dst_status; err = svn_wc__db_read_info(&dst_status, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, db, dst_abspath, scratch_pool, scratch_pool); if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND) return svn_error_trace(err); svn_error_clear(err); if (!err) switch (dst_status) { case svn_wc__db_status_excluded: return svn_error_createf( SVN_ERR_ENTRY_EXISTS, NULL, _("'%s' is already under version control " "but is excluded."), svn_dirent_local_style(dst_abspath, scratch_pool)); case svn_wc__db_status_server_excluded: return svn_error_createf( SVN_ERR_ENTRY_EXISTS, NULL, _("'%s' is already under version control"), svn_dirent_local_style(dst_abspath, scratch_pool)); case svn_wc__db_status_deleted: case svn_wc__db_status_not_present: break; /* OK to add */ default: return svn_error_createf(SVN_ERR_ENTRY_EXISTS, NULL, _("There is already a versioned item '%s'"), svn_dirent_local_style(dst_abspath, scratch_pool)); } } /* Check that the target path is not obstructed, if required. */ if (!metadata_only) { svn_node_kind_t dst_kind; /* (We need only to check the root of the copy, not every path inside copy_versioned_file/_dir.) */ SVN_ERR(svn_io_check_path(dst_abspath, &dst_kind, scratch_pool)); if (dst_kind != svn_node_none) return svn_error_createf(SVN_ERR_ENTRY_EXISTS, NULL, _("'%s' already exists and is in the way"), svn_dirent_local_style(dst_abspath, scratch_pool)); } SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db, dstdir_abspath, scratch_pool, scratch_pool)); within_one_wc = (strcmp(src_wcroot_abspath, dst_wcroot_abspath) == 0); if (is_move && !within_one_wc) { if (move_degraded_to_copy) *move_degraded_to_copy = TRUE; is_move = FALSE; } if (!within_one_wc) SVN_ERR(svn_wc__db_pristine_transfer(db, src_abspath, dst_wcroot_abspath, cancel_func, cancel_baton, scratch_pool)); if (src_db_kind == svn_node_file || src_db_kind == svn_node_symlink) { err = copy_versioned_file(db, src_abspath, dst_abspath, dst_abspath, tmpdir_abspath, metadata_only, conflicted, is_move, cancel_func, cancel_baton, notify_func, notify_baton, scratch_pool); } else { if (is_move && src_status == svn_wc__db_status_normal) { svn_revnum_t min_rev; svn_revnum_t max_rev; /* Verify that the move source is a single-revision subtree. */ SVN_ERR(svn_wc__db_min_max_revisions(&min_rev, &max_rev, db, src_abspath, FALSE, scratch_pool)); if (SVN_IS_VALID_REVNUM(min_rev) && SVN_IS_VALID_REVNUM(max_rev) && min_rev != max_rev) { if (!allow_mixed_revisions) return svn_error_createf(SVN_ERR_WC_MIXED_REVISIONS, NULL, _("Cannot move mixed-revision " "subtree '%s' [%ld:%ld]; " "try updating it first"), svn_dirent_local_style(src_abspath, scratch_pool), min_rev, max_rev); is_move = FALSE; if (move_degraded_to_copy) *move_degraded_to_copy = TRUE; } } err = copy_versioned_dir(db, src_abspath, dst_abspath, dst_abspath, tmpdir_abspath, metadata_only, is_move, cancel_func, cancel_baton, notify_func, notify_baton, scratch_pool); } if (err && svn_error_find_cause(err, SVN_ERR_CANCELLED)) return svn_error_trace(err); if (is_move) err = svn_error_compose_create(err, svn_wc__db_op_handle_move_back(NULL, db, dst_abspath, src_abspath, NULL /* work_items */, scratch_pool)); /* Run the work queue with the remaining work */ SVN_ERR(svn_error_compose_create( err, svn_wc__wq_run(db, dst_abspath, cancel_func, cancel_baton, scratch_pool))); return SVN_NO_ERROR; }