📄 copy.c
字号:
copy-history is attempted. */ if (src_err || dst_err || (! src_uuid) || (! dst_uuid)) same_repositories = FALSE; else same_repositories = (strcmp(src_uuid, dst_uuid) == 0) ? TRUE : FALSE; } if (src_kind == svn_node_dir) { SVN_ERR(svn_client__checkout_internal (NULL, src_url, dst_path, &revision, &revision, TRUE, FALSE, NULL, ctx, pool)); if ((revision.kind == svn_opt_revision_head) && same_repositories) { /* If we just checked out from the "head" revision, that's fine, but we don't want to pass a '-1' as a copyfrom_rev to svn_wc_add(). That function will dump it right into the entry, and when we try to commit later on, the 'add-dir-with-history' step will be -very- unhappy; it only accepts specific revisions. On the other hand, we *could* say that -1 is a legitimate copyfrom_rev, but I think that's bogus. Somebody made a copy from a particular revision; if they wait a long time to commit, it would be terrible if the copied happened from a newer revision!! */ /* We just did a checkout; whatever revision we just got, that should be the copyfrom_revision when we commit later. */ const svn_wc_entry_t *d_entry; svn_wc_adm_access_t *dst_access; SVN_ERR(svn_wc_adm_open3(&dst_access, adm_access, dst_path, TRUE, -1, ctx->cancel_func, ctx->cancel_baton, pool)); SVN_ERR(svn_wc_entry(&d_entry, dst_path, dst_access, FALSE, pool)); src_revnum = d_entry->revision; } /* Rewrite URLs recursively, remove wcprops, and mark everything as 'copied' -- assuming that the src and dst are from the same repository. (It's kind of weird that svn_wc_add() is the way to do this; see its doc for more about the controversy.) */ if (same_repositories) { /* Schedule dst_path for addition in parent, with copy history. (This function also recursively puts a 'copied' flag on every entry). */ SVN_ERR(svn_wc_add2(dst_path, adm_access, src_url, src_revnum, ctx->cancel_func, ctx->cancel_baton, ctx->notify_func2, ctx->notify_baton2, pool)); } else /* different repositories */ { /* ### Someday, we would just call svn_wc_add(), as above, but with no copyfrom args. I.e. in the directory-foreign-UUID case, we still want everything scheduled for addition, URLs rewritten, and wcprop cache deleted, but WITHOUT any copied flags or copyfrom urls. Unfortunately, svn_wc_add() is such a mess that it chokes at the moment when we pass a NULL copyfromurl. */ return svn_error_createf (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Source URL '%s' is from foreign repository; " "leaving it as a disjoint WC"), src_url); } } /* end directory case */ else if (src_kind == svn_node_file) { apr_file_t *fp; svn_stream_t *fstream; svn_revnum_t real_rev; const char *new_text_path; apr_hash_t *new_props; svn_error_t *err; SVN_ERR(svn_io_open_unique_file2 (&fp, &new_text_path, dst_path, ".tmp", svn_io_file_del_none, pool)); fstream = svn_stream_from_aprfile2(fp, FALSE, pool); SVN_ERR(svn_ra_get_file(ra_session, "", src_revnum, fstream, &real_rev, &new_props, pool)); SVN_ERR(svn_stream_close(fstream)); /* If SRC_REVNUM is invalid (HEAD), then REAL_REV is now the revision that was actually retrieved. This is the value we want to use as 'copyfrom_rev' below. */ if (! SVN_IS_VALID_REVNUM(src_revnum)) src_revnum = real_rev; err = svn_wc_add_repos_file2 (dst_path, adm_access, new_text_path, NULL, new_props, NULL, same_repositories ? src_url : NULL, same_repositories ? src_revnum : SVN_INVALID_REVNUM, pool); /* Ideally, svn_wc_add_repos_file() would take a notify function and baton, and we wouldn't have to make this call here. However, the situation is... complicated. See issue #1552 for the full story. */ if (!err && ctx->notify_func2) { svn_wc_notify_t *notify = svn_wc_create_notify(dst_path, svn_wc_notify_add, pool); notify->kind = src_kind; (*ctx->notify_func2)(ctx->notify_baton2, notify, pool); } svn_sleep_for_timestamps(); SVN_ERR(err); } SVN_ERR(svn_wc_adm_close(adm_access)); return SVN_NO_ERROR;}static svn_error_t *setup_copy(svn_commit_info_t **commit_info_p, const char *src_path, const svn_opt_revision_t *src_revision, const char *dst_path, svn_boolean_t is_move, svn_boolean_t force, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_boolean_t src_is_url, dst_is_url; /* Are either of our paths URLs? */ src_is_url = svn_path_is_url(src_path); dst_is_url = svn_path_is_url(dst_path); if (!src_is_url && !dst_is_url && svn_path_is_child(src_path, dst_path, pool)) return svn_error_createf (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Cannot copy path '%s' into its own child '%s'"), svn_path_local_style(src_path, pool), svn_path_local_style(dst_path, pool)); if (is_move) { if (src_is_url == dst_is_url) { if (strcmp(src_path, dst_path) == 0) return svn_error_createf (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Cannot move path '%s' into itself"), svn_path_local_style(src_path, pool)); } else { /* Disallow moves between the working copy and the repository. */ return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("No support for repos <--> working copy moves")); } } else { if (!src_is_url) { if (src_revision->kind != svn_opt_revision_unspecified && src_revision->kind != svn_opt_revision_working) { /* We can convert the working copy path to a URL based on the entries file. */ svn_wc_adm_access_t *adm_access; /* ### FIXME local */ const svn_wc_entry_t *entry; SVN_ERR(svn_wc_adm_probe_open3(&adm_access, NULL, src_path, FALSE, 0, ctx->cancel_func, ctx->cancel_baton, pool)); SVN_ERR(svn_wc_entry(&entry, src_path, adm_access, FALSE, pool)); SVN_ERR(svn_wc_adm_close(adm_access)); if (! entry) return svn_error_createf (SVN_ERR_UNVERSIONED_RESOURCE, NULL, _("'%s' is not under version control"), svn_path_local_style(src_path, pool)); if (! entry->url) return svn_error_createf (SVN_ERR_ENTRY_MISSING_URL, NULL, _("'%s' does not seem to have a URL associated with it"), svn_path_local_style(src_path, pool)); src_path = entry->url; src_is_url = TRUE; } } } /* Now, call the right handler for the operation. */ if ((! src_is_url) && (! dst_is_url)) { SVN_ERR(wc_to_wc_copy(src_path, dst_path, is_move, force, ctx, pool)); } else if ((! src_is_url) && (dst_is_url)) { SVN_ERR(wc_to_repos_copy(commit_info_p, src_path, dst_path, ctx, pool)); } else if ((src_is_url) && (! dst_is_url)) { SVN_ERR(repos_to_wc_copy(src_path, src_revision, dst_path, ctx, pool)); } else { SVN_ERR(repos_to_repos_copy(commit_info_p, src_path, src_revision, dst_path, ctx, is_move, pool)); } return SVN_NO_ERROR;}/* Public Interfaces */svn_error_t *svn_client_copy3(svn_commit_info_t **commit_info_p, const char *src_path, const svn_opt_revision_t *src_revision, const char *dst_path, svn_client_ctx_t *ctx, apr_pool_t *pool){ return setup_copy(commit_info_p, src_path, src_revision, dst_path, FALSE /* is_move */, TRUE /* force, set to avoid deletion check */, ctx, pool);}svn_error_t *svn_client_copy2(svn_commit_info_t **commit_info_p, const char *src_path, const svn_opt_revision_t *src_revision, const char *dst_path, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_error_t *err; err = svn_client_copy3(commit_info_p, src_path, src_revision, dst_path, ctx, pool); /* If the target exists, try to copy the source as a child of the target. This will obviously fail if target is not a directory, but that's exactly what we want. */ if (err && (err->apr_err == SVN_ERR_ENTRY_EXISTS || err->apr_err == SVN_ERR_FS_ALREADY_EXISTS)) { const char *src_basename = svn_path_basename(src_path, pool); svn_error_clear(err); return svn_client_copy3(commit_info_p, src_path, src_revision, svn_path_join(dst_path, src_basename, pool), ctx, pool); } return err;}svn_error_t *svn_client_copy(svn_client_commit_info_t **commit_info_p, const char *src_path, const svn_opt_revision_t *src_revision, const char *dst_path, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_commit_info_t *commit_info = NULL; svn_error_t *err; err = svn_client_copy2(&commit_info, src_path, src_revision, dst_path, ctx, pool); /* These structs have the same layout for the common fields. */ *commit_info_p = (svn_client_commit_info_t *) commit_info; return err;}svn_error_t *svn_client_move4(svn_commit_info_t **commit_info_p, const char *src_path, const char *dst_path, svn_boolean_t force, svn_client_ctx_t *ctx, apr_pool_t *pool){ const svn_opt_revision_t src_revision = { svn_opt_revision_unspecified, { 0 } }; return setup_copy(commit_info_p, src_path, &src_revision, dst_path, TRUE /* is_move */, force, ctx, pool);}svn_error_t *svn_client_move3(svn_commit_info_t **commit_info_p, const char *src_path, const char *dst_path, svn_boolean_t force, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_error_t *err; err = svn_client_move4(commit_info_p, src_path, dst_path, force, ctx, pool); /* If the target exists, try to move the source as a child of the target. This will obviously fail if target is not a directory, but that's exactly what we want. */ if (err && (err->apr_err == SVN_ERR_ENTRY_EXISTS || err->apr_err == SVN_ERR_FS_ALREADY_EXISTS)) { const char *src_basename = svn_path_basename(src_path, pool); svn_error_clear(err); return svn_client_move4(commit_info_p, src_path, svn_path_join(dst_path, src_basename, pool), force, ctx, pool); } return err;}svn_error_t *svn_client_move2(svn_client_commit_info_t **commit_info_p, const char *src_path, const char *dst_path, svn_boolean_t force, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_commit_info_t *commit_info = NULL; svn_error_t *err; err = svn_client_move3(&commit_info, src_path, dst_path, force, ctx, pool); /* These structs have the same layout for the common fields. */ *commit_info_p = (svn_client_commit_info_t *) commit_info; return err;}svn_error_t *svn_client_move(svn_client_commit_info_t **commit_info_p, const char *src_path, const svn_opt_revision_t *src_revision, const char *dst_path, svn_boolean_t force, svn_client_ctx_t *ctx, apr_pool_t *pool){ svn_commit_info_t *commit_info = NULL; svn_error_t *err; /* It doesn't make sense to specify revisions in a move. */ /* ### todo: this check could fail wrongly. For example, someone could pass in an svn_opt_revision_number that just happens to be the HEAD. It's fair enough to punt then, IMHO, and just demand that the user not specify a revision at all; beats mucking up this function with RA calls and such. */ if (src_revision->kind != svn_opt_revision_unspecified && src_revision->kind != svn_opt_revision_head) { return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE, NULL, _("Cannot specify revisions (except HEAD) with move operations")); } err = setup_copy(&commit_info, src_path, src_revision, dst_path, TRUE /* is_move */, force, ctx, pool); /* These structs have the same layout for the common fields. */ *commit_info_p = (svn_client_commit_info_t *) commit_info; return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -