⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 copy.c

📁 subversion-1.4.3-1.tar.gz 配置svn的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * copy.c:  copy/move wrappers around wc 'copy' functionality. * * ==================================================================== * Copyright (c) 2000-2006 CollabNet.  All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution.  The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals.  For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== *//* ==================================================================== *//*** Includes. ***/#include <string.h>#include <assert.h>#include "svn_wc.h"#include "svn_client.h"#include "svn_error.h"#include "svn_path.h"#include "svn_opt.h"#include "svn_time.h"#include "client.h"#include "svn_private_config.h"/*** Code. ***//* * if (not exist src_path) *   return ERR_BAD_SRC error * * if (exist dst_path) *   return ERR_OBSTRUCTION error * else *   copy src_path into parent_of_dst_path as basename (dst_path) * * if (this is a move) *   delete src_path *//* Copy SRC_PATH into DST_PATH as DST_BASENAME, deleting SRC_PATH   afterwards if IS_MOVE is TRUE.  Use POOL for all necessary   allocations.*/static svn_error_t *wc_to_wc_copy(const char *src_path,              const char *dst_path,              svn_boolean_t is_move,              svn_boolean_t force,              svn_client_ctx_t *ctx,              apr_pool_t *pool){  svn_node_kind_t src_kind, dst_kind, dst_parent_kind;  const char *dst_parent, *base_name;  svn_wc_adm_access_t *adm_access, *src_access;  svn_error_t *err;  /* Verify that SRC_PATH exists. */  SVN_ERR(svn_io_check_path(src_path, &src_kind, pool));  if (src_kind == svn_node_none)    return svn_error_createf(SVN_ERR_NODE_UNKNOWN_KIND, NULL,                             _("Path '%s' does not exist"),                             svn_path_local_style(src_path, pool));  /* If DST_PATH does not exist, then its basename will become a new     file or dir added to its parent (possibly an implicit '.').     Else, just error out. */  SVN_ERR(svn_io_check_path(dst_path, &dst_kind, pool));  if (dst_kind != svn_node_none)    return svn_error_createf(SVN_ERR_ENTRY_EXISTS, NULL,                             _("Path '%s' already exists"),                             svn_path_local_style(dst_path, pool));  svn_path_split(dst_path, &dst_parent, &base_name, pool);  /* Make sure the destination parent is a directory and produce a clear     error message if it is not. */  SVN_ERR(svn_io_check_path(dst_parent, &dst_parent_kind, pool));  if (dst_parent_kind != svn_node_dir)    return svn_error_createf(SVN_ERR_WC_NOT_DIRECTORY, NULL,                             _("Path '%s' is not a directory"),                             svn_path_local_style(dst_parent, pool));  if (is_move)    {      const char *src_parent;      svn_path_split(src_path, &src_parent, NULL, pool);      SVN_ERR(svn_wc_adm_open3(&src_access, NULL, src_parent, TRUE,                               src_kind == svn_node_dir ? -1 : 0,                               ctx->cancel_func, ctx->cancel_baton, pool));      /* Need to avoid attempting to open the same dir twice when source         and destination overlap. */      if (strcmp(src_parent, dst_parent) == 0)        {          adm_access = src_access;        }      else         {          const char *src_parent_abs, *dst_parent_abs;          SVN_ERR(svn_path_get_absolute(&src_parent_abs, src_parent, pool));          SVN_ERR(svn_path_get_absolute(&dst_parent_abs, dst_parent, pool));          if ((src_kind == svn_node_dir)              && (svn_path_is_child(src_parent_abs, dst_parent_abs, pool)))            {              SVN_ERR(svn_wc_adm_retrieve(&adm_access, src_access,                                          dst_parent, pool));            }          else            {              SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, dst_parent,                                       TRUE, 0, ctx->cancel_func,                                       ctx->cancel_baton,pool));            }        }      if (!force)        /* Ensure there are no "awkward" files. */        SVN_ERR_W(svn_client__can_delete(src_path, ctx, pool),                  _("Move will not be attempted unless forced"));    }  else     {      SVN_ERR(svn_wc_adm_open3(&adm_access, NULL, dst_parent, TRUE, 0,                               ctx->cancel_func, ctx->cancel_baton, pool));    }                                /* Perform the copy and (optionally) delete. */  /* ### If this is not a move, we won't have locked the source, so we     ### won't detect any outstanding locks. If the source is locked and     ### requires cleanup should we abort the copy? */  err = svn_wc_copy2(src_path, adm_access, base_name,                     ctx->cancel_func, ctx->cancel_baton,                     ctx->notify_func2, ctx->notify_baton2, pool);  svn_sleep_for_timestamps();  SVN_ERR(err);  if (is_move)    {      SVN_ERR(svn_wc_delete2(src_path, src_access,                             ctx->cancel_func, ctx->cancel_baton,                             ctx->notify_func2, ctx->notify_baton2, pool));      if (adm_access != src_access)        SVN_ERR(svn_wc_adm_close(adm_access));      SVN_ERR(svn_wc_adm_close(src_access));    }  else    {      SVN_ERR(svn_wc_adm_close(adm_access));    }  return SVN_NO_ERROR;}struct path_driver_cb_baton{  const svn_delta_editor_t *editor;  void *edit_baton;  svn_node_kind_t src_kind;  const char *src_url;  const char *src_path;  const char *dst_path;  svn_boolean_t is_move;  svn_boolean_t resurrection;  svn_revnum_t src_revnum;};static svn_error_t *path_driver_cb_func(void **dir_baton,                    void *parent_baton,                    void *callback_baton,                    const char *path,                    apr_pool_t *pool){  struct path_driver_cb_baton *cb_baton = callback_baton;  svn_boolean_t do_delete = FALSE, do_add = FALSE;  /* Initialize return value. */  *dir_baton = NULL;  /* This function should never get an empty PATH.  We can neither     create nor delete the empty PATH, so if someone is calling us     with such, the code is just plain wrong. */  assert(! svn_path_is_empty(path));  /* If this is a resurrection, we know the source and dest paths are     the same, and that our driver will only be calling us once.  */  if (cb_baton->resurrection)    {      /* If this is a move, we do nothing.  Otherwise, we do the copy.  */      if (! cb_baton->is_move)        do_add = TRUE;    }  /* Not a resurrection. */  else     {      /* If this is a move, we check PATH to see if it is the source         or the destination of the move. */      if (cb_baton->is_move)        {          if (strcmp(cb_baton->src_path, path) == 0)            do_delete = TRUE;          else            do_add = TRUE;        }      /* Not a move?  This must just be the copy addition. */      else        {          do_add = TRUE;        }    }  if (do_delete)    {      SVN_ERR(cb_baton->editor->delete_entry(path, SVN_INVALID_REVNUM,                                             parent_baton, pool));    }  if (do_add)    {      SVN_ERR(svn_path_check_valid(path, pool));      if (cb_baton->src_kind == svn_node_file)        {          void *file_baton;          SVN_ERR(cb_baton->editor->add_file(path, parent_baton,                                              cb_baton->src_url,                                              cb_baton->src_revnum,                                              pool, &file_baton));          SVN_ERR(cb_baton->editor->close_file(file_baton, NULL, pool));        }      else        {          SVN_ERR(cb_baton->editor->add_directory(path, parent_baton,                                                  cb_baton->src_url,                                                   cb_baton->src_revnum,                                                   pool, dir_baton));        }    }  return SVN_NO_ERROR;}static svn_error_t *repos_to_repos_copy(svn_commit_info_t **commit_info_p,                    const char *src_url,                     const svn_opt_revision_t *src_revision,                     const char *dst_url,                     svn_client_ctx_t *ctx,                    svn_boolean_t is_move,                    apr_pool_t *pool){  apr_array_header_t *paths = apr_array_make(pool, 2, sizeof(const char *));  const char *top_url, *src_rel, *dst_rel, *message, *repos_root;  svn_revnum_t youngest;  svn_ra_session_t *ra_session;  svn_node_kind_t src_kind, dst_kind;  const svn_delta_editor_t *editor;  void *edit_baton;  void *commit_baton;  svn_revnum_t src_revnum;  svn_boolean_t resurrection = FALSE;  struct path_driver_cb_baton cb_baton;  svn_error_t *err;  /* We have to open our session to the longest path common to both     SRC_URL and DST_URL in the repository so we can do existence     checks on both paths, and so we can operate on both paths in the     case of a move. */  top_url = svn_path_get_longest_ancestor(src_url, dst_url, pool);  /* Special edge-case!  (issue #683)  If you're resurrecting a     deleted item like this:  'svn cp -rN src_URL dst_URL', then it's     possible for src_URL == dst_URL == top_url.  In this situation,     we want to open an RA session to the *parent* of all three. */  if (strcmp(src_url, dst_url) == 0)    {      resurrection = TRUE;      top_url = svn_path_dirname(top_url, pool);    }  /* Open an RA session for the URL. Note that we don't have a local     directory, nor a place to put temp files. */  err = svn_client__open_ra_session_internal(&ra_session, top_url,                                             NULL, NULL, NULL, FALSE, TRUE,                                              ctx, pool);  /* If the two URLs appear not to be in the same repository, then     top_url will be empty and the call to svn_ra_open2()     above will have failed.  Below we check for that, and propagate a     descriptive error back to the user.        Ideally, we'd contact the repositories and compare their UUIDs to     determine whether or not src and dst are in the same repository,     instead of depending on an essentially textual comparison.     However, it is simpler to assume that if someone is using the     same repository, then they will use the same hostname/path to     refer to it both times.  Conversely, if the repositories are     different, then they can't share a non-empty prefix, so top_url     would still be "" and svn_ra_get_library() would still error.     Thus we can get this check without extra network turnarounds to     fetch the UUIDs.   */  if (err)    {      if ((err->apr_err == SVN_ERR_RA_ILLEGAL_URL)          && ((top_url == NULL) || (top_url[0] == '\0')))        {          return svn_error_createf            (SVN_ERR_UNSUPPORTED_FEATURE, NULL,             _("Source and dest appear not to be in the same repository "               "(src: '%s'; dst: '%s')"),             src_url, dst_url);        }      else        return err;    }  SVN_ERR(svn_ra_get_repos_root(ra_session, &repos_root, pool));  if (strcmp(dst_url, repos_root) != 0      && svn_path_is_child(dst_url, src_url, pool) != NULL)    {      resurrection = TRUE;      top_url = svn_path_dirname(top_url, pool);      SVN_ERR(svn_ra_reparent(ra_session, top_url, pool));    }  /* Get the portions of the SRC and DST URLs that are relative to     TOP_URL, and URI-decode those sections. */  src_rel = svn_path_is_child(top_url, src_url, pool);  if (src_rel)    src_rel = svn_path_uri_decode(src_rel, pool);  else    src_rel = "";  dst_rel = svn_path_is_child(top_url, dst_url, pool);  if (dst_rel)    dst_rel = svn_path_uri_decode(dst_rel, pool);  else    dst_rel = "";  /* We can't move something into itself, period. */  if (svn_path_is_empty(src_rel) && is_move)    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,                             _("Cannot move URL '%s' into itself"), src_url);  /* Pass NULL for the path, to ensure error if trying to get a     revision based on the working copy. */  SVN_ERR(svn_client__get_revision_number          (&src_revnum, ra_session, src_revision, NULL, pool));    /* Fetch the youngest revision. */  SVN_ERR(svn_ra_get_latest_revnum(ra_session, &youngest, pool));  /* Use YOUNGEST for copyfrom args if not provided. */  if (! SVN_IS_VALID_REVNUM(src_revnum))    src_revnum = youngest;    /* Verify that SRC_URL exists in the repository. */  SVN_ERR(svn_ra_check_path(ra_session, src_rel, src_revnum, &src_kind,                            pool));  if (src_kind == svn_node_none)    return svn_error_createf       (SVN_ERR_FS_NOT_FOUND, NULL,       _("Path '%s' does not exist in revision %ld"),       src_url, src_revnum);  /* Figure out the basename that will result from this operation. */  SVN_ERR(svn_ra_check_path(ra_session, dst_rel, youngest, &dst_kind, pool));  if (dst_kind != svn_node_none)    {      /* We disallow the overwriting of existing paths. */      return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,                               _("Path '%s' already exists"), dst_rel);    }  /* Create a new commit item and add it to the array. */  if (ctx->log_msg_func || ctx->log_msg_func2)    {      svn_client_commit_item2_t *item;      const char *tmp_file;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -