📄 copy.c
字号:
/*
* copy.c: wc 'copy' functionality.
*
* ====================================================================
* Copyright (c) 2000-2004 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 "svn_wc.h"
#include "svn_string.h"
#include "svn_pools.h"
#include "svn_error.h"
#include "svn_path.h"
#include "wc.h"
#include "adm_files.h"
#include "props.h"
#include "translate.h"
#include "svn_private_config.h"
/*** Code. ***/
svn_error_t *
svn_wc__remove_wcprops (svn_wc_adm_access_t *adm_access,
svn_boolean_t recurse,
apr_pool_t *pool)
{
apr_hash_t *entries;
apr_hash_index_t *hi;
const char *wcprop_path;
apr_pool_t *subpool = svn_pool_create (pool);
svn_error_t *err;
/* Read PATH's entries. */
SVN_ERR (svn_wc_entries_read (&entries, adm_access, FALSE, subpool));
/* Remove this_dir's wcprops */
SVN_ERR (svn_wc__wcprop_path (&wcprop_path,
svn_wc_adm_access_path (adm_access),
adm_access, FALSE, subpool));
err = svn_io_remove_file (wcprop_path, subpool);
if (err)
svn_error_clear (err);
/* Recursively loop over all children. */
for (hi = apr_hash_first (subpool, entries); hi; hi = apr_hash_next (hi))
{
const void *key;
void *val;
const char *name;
const svn_wc_entry_t *current_entry;
const char *child_path;
apr_hash_this (hi, &key, NULL, &val);
name = key;
current_entry = val;
/* Ignore the "this dir" entry. */
if (! strcmp (name, SVN_WC_ENTRY_THIS_DIR))
continue;
child_path = svn_path_join (svn_wc_adm_access_path (adm_access), name,
subpool);
/* If a file, remove it from wcprops. */
if (current_entry->kind == svn_node_file)
{
SVN_ERR (svn_wc__wcprop_path (&wcprop_path, child_path, adm_access,
FALSE, subpool));
err = svn_io_remove_file (wcprop_path, subpool);
if (err)
svn_error_clear (err);
/* ignoring any error value from the removal; most likely,
apr_file_remove will complain about trying to a remove a
file that's not there. But this more efficient than
doing an independant stat for each file's existence
before trying to remove it, no? */
}
/* If a dir, recurse. */
else if (recurse && current_entry->kind == svn_node_dir)
{
svn_wc_adm_access_t *child_access;
SVN_ERR (svn_wc_adm_retrieve (&child_access, adm_access, child_path,
subpool));
SVN_ERR (svn_wc__remove_wcprops (child_access, recurse, subpool));
}
}
/* Cleanup */
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
/* This function effectively creates and schedules a file for
addition, but does extra administrative things to allow it to
function as a 'copy'.
ASSUMPTIONS:
- src_path points to a file under version control
- dst_parent points to a dir under version control, in the same
working copy.
- dst_basename will be the 'new' name of the copied file in dst_parent
*/
static svn_error_t *
copy_file_administratively (const char *src_path,
svn_wc_adm_access_t *src_access,
svn_wc_adm_access_t *dst_parent,
const char *dst_basename,
svn_wc_notify_func_t notify_copied,
void *notify_baton,
apr_pool_t *pool)
{
svn_node_kind_t dst_kind;
const svn_wc_entry_t *src_entry, *dst_entry;
svn_boolean_t special;
/* The 'dst_path' is simply dst_parent/dst_basename */
const char *dst_path
= svn_path_join (svn_wc_adm_access_path (dst_parent), dst_basename, pool);
/* Sanity check: if dst file exists already, don't allow overwrite. */
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,
_("'%s' already exists and is in the way"),
dst_path);
/* Even if DST_PATH doesn't exist it may still be a versioned file; it
may be scheduled for deletion, or the user may simply have removed the
working copy. Since we are going to write to DST_PATH text-base and
prop-base we need to detect such cases and abort. */
SVN_ERR (svn_wc_entry (&dst_entry, dst_path, dst_parent, FALSE, pool));
if (dst_entry && dst_entry->kind == svn_node_file)
{
if (dst_entry->schedule == svn_wc_schedule_delete)
return svn_error_createf (SVN_ERR_ENTRY_EXISTS, NULL,
_("'%s' is scheduled for deletion; it must"
" be committed before being overwritten"),
dst_path);
else
return svn_error_createf (SVN_ERR_ENTRY_EXISTS, NULL,
_("There is already a versioned item '%s'"),
dst_path);
}
/* Sanity check: you cannot make a copy of something that's not
in the repository. See comment at the bottom of this file for an
explanation. */
SVN_ERR (svn_wc_entry (&src_entry, src_path, src_access, FALSE, pool));
if (! src_entry)
return svn_error_createf
(SVN_ERR_UNVERSIONED_RESOURCE, NULL,
_("Cannot copy or move '%s': it's not under version control"),
src_path);
if ((src_entry->schedule == svn_wc_schedule_add)
|| (! src_entry->url)
|| (src_entry->copied))
return svn_error_createf
(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Cannot copy or move '%s': it's not in the repository yet; "
"try committing first"),
src_path);
/* Now, make an actual copy of the working file. If this is a
special file, we can't copy it directly, but should instead
use the translation routines to create the new file. */
SVN_ERR (svn_wc__get_special (&special, src_path, src_access, pool));
if (! special)
SVN_ERR (svn_io_copy_file (src_path, dst_path, TRUE, pool));
else
SVN_ERR (svn_subst_copy_and_translate2 (src_path,
dst_path, NULL, FALSE,
NULL,
TRUE, /* expand */
TRUE, /* special */
pool));
/* Copy the pristine text-base over. Why? Because it's the *only*
way we can detect any upcoming local mods on the copy.
In other words, we're talking about the scenario where somebody
makes local mods to 'foo.c', then does an 'svn cp foo.c bar.c'.
In this case, bar.c should still be locally modified too.
Why do we want the copy to have local mods? Even though the user
will only see an 'A' instead of an 'M', local mods means that the
client doesn't have to send anything but a small delta during
commit; the server can make efficient use of the copyfrom args.
As long as we're copying the text-base over, we should copy the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -