📄 adm_ops.c
字号:
if (!strcmp (name, SVN_WC_ENTRY_THIS_DIR))
continue;
down_path = svn_path_join (path, name, pool);
SVN_ERR (erase_from_wc (down_path, dir_access, entry->kind,
cancel_func, cancel_baton, pool));
}
/* Now handle any remaining unversioned items */
SVN_ERR (svn_io_get_dirents (&unver, path, pool));
for (hi = apr_hash_first (pool, unver); hi; hi = apr_hash_next (hi))
{
const void *key;
const char *name;
const char *down_path;
apr_hash_this (hi, &key, NULL, NULL);
name = key;
/* The admin directory will show up, we don't want to delete it */
if (!strcmp (name, SVN_WC_ADM_DIR_NAME))
continue;
/* Versioned directories will show up, don't delete those either */
if (apr_hash_get (ver, name, APR_HASH_KEY_STRING))
continue;
down_path = svn_path_join (path, name, pool);
SVN_ERR (erase_unversioned_from_wc
(down_path, cancel_func, cancel_baton, pool));
}
}
/* ### TODO: move this dir into parent's .svn area */
break;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_delete (const char *path,
svn_wc_adm_access_t *adm_access,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func_t notify_func,
void *notify_baton,
apr_pool_t *pool)
{
svn_wc_adm_access_t *dir_access;
const svn_wc_entry_t *entry;
const char *parent, *base_name;
svn_boolean_t was_schedule_add;
svn_node_kind_t was_kind;
svn_boolean_t was_deleted = FALSE; /* Silence a gcc uninitialized warning */
SVN_ERR (svn_wc_adm_probe_try2 (&dir_access, adm_access, path,
TRUE, -1, pool));
if (dir_access)
SVN_ERR (svn_wc_entry (&entry, path, dir_access, FALSE, pool));
else
entry = NULL;
if (!entry)
return erase_unversioned_from_wc (path, cancel_func, cancel_baton, pool);
/* Note: Entries caching? What happens to this entry when the entries
file is updated? Lets play safe and copy the values */
was_schedule_add = entry->schedule == svn_wc_schedule_add;
was_kind = entry->kind;
svn_path_split (path, &parent, &base_name, pool);
if (was_kind == svn_node_dir)
{
svn_wc_adm_access_t *parent_access;
apr_hash_t *entries;
const svn_wc_entry_t *entry_in_parent;
/* The deleted state is only available in the entry in parent's
entries file */
SVN_ERR (svn_wc_adm_retrieve (&parent_access, adm_access, parent, pool));
SVN_ERR (svn_wc_entries_read (&entries, parent_access, TRUE, pool));
entry_in_parent = apr_hash_get (entries, base_name, APR_HASH_KEY_STRING);
was_deleted = entry_in_parent ? entry_in_parent->deleted : FALSE;
if (was_schedule_add && !was_deleted)
{
/* Deleting a directory that has been added but not yet
committed is easy, just remove the administrative dir. */
if (dir_access != adm_access)
{
SVN_ERR (svn_wc_remove_from_revision_control
(dir_access, SVN_WC_ENTRY_THIS_DIR, FALSE, FALSE,
cancel_func, cancel_baton, pool));
}
else
{
/* adm_probe_retrieve returned the parent access baton,
which is the same access baton that we came in here
with! this means we're dealing with a missing item
that's scheduled for addition. Easiest to just
remove the entry. */
svn_wc__entry_remove (entries, base_name);
SVN_ERR (svn_wc__entries_write (entries, parent_access, pool));
}
}
else
{
/* if adm_probe_retrieve returned the parent access baton,
(which is the same access baton that we came in here
with), this means we're dealing with a missing directory.
So there's no tree to mark for deletion. Instead, the
next phase of code will simply schedule the directory for
deletion in its parent. */
if (dir_access != adm_access)
{
/* Recursively mark a whole tree for deletion. */
SVN_ERR (mark_tree (dir_access, SVN_WC__ENTRY_MODIFY_SCHEDULE,
svn_wc_schedule_delete, FALSE,
cancel_func, cancel_baton,
notify_func, notify_baton,
pool));
}
}
}
if (!(was_kind == svn_node_dir && was_schedule_add && !was_deleted))
{
/* We need to mark this entry for deletion in its parent's entries
file, so we split off base_name from the parent path, then fold in
the addition of a delete flag. */
svn_wc_entry_t tmp_entry;
tmp_entry.schedule = svn_wc_schedule_delete;
SVN_ERR (svn_wc__entry_modify (adm_access, base_name, &tmp_entry,
SVN_WC__ENTRY_MODIFY_SCHEDULE, TRUE,
pool));
}
/* Report the deletion to the caller. */
if (notify_func != NULL)
(*notify_func) (notify_baton, path, svn_wc_notify_delete,
svn_node_unknown,
NULL,
svn_wc_notify_state_unknown,
svn_wc_notify_state_unknown,
SVN_INVALID_REVNUM);
/* By the time we get here, anything that was scheduled to be added has
become unversioned */
if (was_schedule_add)
SVN_ERR (erase_unversioned_from_wc
(path, cancel_func, cancel_baton, pool));
else
SVN_ERR (erase_from_wc (path, adm_access, was_kind,
cancel_func, cancel_baton, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_get_ancestry (char **url,
svn_revnum_t *rev,
const char *path,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
const svn_wc_entry_t *ent;
SVN_ERR (svn_wc_entry (&ent, path, adm_access, FALSE, pool));
if (url)
*url = apr_pstrdup (pool, ent->url);
if (rev)
*rev = ent->revision;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_add (const char *path,
svn_wc_adm_access_t *parent_access,
const char *copyfrom_url,
svn_revnum_t copyfrom_rev,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func_t notify_func,
void *notify_baton,
apr_pool_t *pool)
{
const char *parent_dir, *base_name;
const svn_wc_entry_t *orig_entry, *parent_entry;
svn_wc_entry_t tmp_entry;
svn_boolean_t is_replace = FALSE;
svn_node_kind_t kind;
apr_uint32_t modify_flags = 0;
svn_wc_adm_access_t *adm_access;
/* Make sure something's there. */
SVN_ERR (svn_io_check_path (path, &kind, pool));
if (kind == svn_node_none)
return svn_error_createf (SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("'%s' not found"), path);
if (kind == svn_node_unknown)
return svn_error_createf (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Unsupported node kind for path '%s'"), path);
/* Get the original entry for this path if one exists (perhaps
this is actually a replacement of a previously deleted thing).
Note that this is one of the few functions that is allowed to see
'deleted' entries; it's totally fine to have an entry that is
scheduled for addition and still previously 'deleted'. */
SVN_ERR (svn_wc_adm_probe_try2 (&adm_access, parent_access, path,
TRUE, copyfrom_url != NULL ? -1 : 0,
pool));
if (adm_access)
SVN_ERR (svn_wc_entry (&orig_entry, path, adm_access, TRUE, pool));
else
orig_entry = NULL;
/* You can only add something that is not in revision control, or
that is slated for deletion from revision control, or has been
previously 'deleted', unless, of course, you're specifying an
addition with -history-; then it's okay for the object to be
under version control already; it's not really new. */
if (orig_entry)
{
if ((! copyfrom_url)
&& (orig_entry->schedule != svn_wc_schedule_delete)
&& (! orig_entry->deleted))
{
return svn_error_createf
(SVN_ERR_ENTRY_EXISTS, NULL,
_("'%s' is already under version control"), path);
}
else if (orig_entry->kind != kind)
{
/* ### todo: At some point, we obviously don't want to block
replacements where the node kind changes. When this
happens, svn_wc_revert() needs to learn how to revert
this situation. At present we are using a specific node-change
error so that clients can detect it. */
return svn_error_createf
(SVN_ERR_WC_NODE_KIND_CHANGE, NULL,
_("Can't replace '%s' with a node of a differing type; "
"commit the deletion, update the parent, and then add '%s'"),
path, path);
}
if (orig_entry->schedule == svn_wc_schedule_delete)
is_replace = TRUE;
}
/* Split off the base_name from the parent directory. */
svn_path_split (path, &parent_dir, &base_name, pool);
SVN_ERR (svn_wc_entry (&parent_entry, parent_dir, parent_access, FALSE,
pool));
if (! parent_entry)
return svn_error_createf
(SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("Can't find parent directory's entry while trying to add '%s'"),
path);
if (parent_entry->schedule == svn_wc_schedule_delete)
return svn_error_createf
(SVN_ERR_WC_SCHEDULE_CONFLICT, NULL,
_("Can't add '%s' to a parent directory scheduled for deletion"),
path);
/* Init the modify flags. */
modify_flags = SVN_WC__ENTRY_MODIFY_SCHEDULE | SVN_WC__ENTRY_MODIFY_KIND;
if (! (is_replace || copyfrom_url))
modify_flags |= SVN_WC__ENTRY_MODIFY_REVISION;
/* If a copy ancestor was given, put the proper ancestry info in a hash. */
if (copyfrom_url)
{
tmp_entry.copyfrom_url = copyfrom_url;
tmp_entry.copyfrom_rev = copyfrom_rev;
tmp_entry.copied = TRUE;
modify_flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_URL;
modify_flags |= SVN_WC__ENTRY_MODIFY_COPYFROM_REV;
modify_flags |= SVN_WC__ENTRY_MODIFY_COPIED;
}
tmp_entry.revision = 0;
tmp_entry.kind = kind;
tmp_entry.schedule = svn_wc_schedule_add;
/* Now, add the entry for this item to the parent_dir's
entries file, marking it for addition. */
SVN_ERR (svn_wc__entry_modify (parent_access, base_name, &tmp_entry,
modify_flags, TRUE, pool));
/* If this is a replacement without history, we need to reset the
properties for PATH. */
if (orig_entry && (! copyfrom_url))
{
const char *prop_path;
SVN_ERR (svn_wc__prop_path (&prop_path, path, adm_access, FALSE, pool));
SVN_ERR (remove_file_if_present (prop_path, pool));
}
if (kind == svn_node_dir) /* scheduling a directory for addition */
{
if (! copyfrom_url)
{
const svn_wc_entry_t *p_entry; /* ### why not use parent_entry? */
const char *new_url;
/* Get the entry for this directory's parent. We need to snatch
the ancestor path out of there. */
SVN_ERR (svn_wc_entry (&p_entry, parent_dir, parent_access, FALSE,
pool));
/* Derive the parent path for our new addition here. */
new_url = svn_path_url_add_component (p_entry->url, base_name, pool);
/* Make sure this new directory has an admistrative subdirectory
created inside of it */
SVN_ERR (svn_wc_ensure_adm (path, NULL, new_url, 0, pool));
}
else
{
/* When we are called with the copyfrom arguments set and with
the admin directory already in existance, then the dir will
contain the copyfrom settings. So we need to pass the
copyfrom arguments to the ensure call. */
SVN_ERR (svn_wc_ensure_adm (path, NULL, copyfrom_url,
copyfrom_rev, pool));
}
/* We want the locks to persist, so use the access baton's pool */
if (! orig_entry || orig_entry->deleted)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -