📄 adm_ops.c
字号:
SVN_WC__ENTRY_ATTR_CHECKSUM,
hex_digest,
NULL);
/* Regardless of whether it's a file or dir, the "main" logfile
contains a command to bump the revision attribute (and
timestamp.) */
svn_xml_make_open_tag (&logtags, pool, svn_xml_self_closing,
SVN_WC__LOG_COMMITTED,
SVN_WC__LOG_ATTR_NAME, base_name,
SVN_WC__LOG_ATTR_REVISION,
revstr,
NULL);
/* Do wcprops in the same log txn as revision, etc. */
if (wcprop_changes && (wcprop_changes->nelts > 0))
{
int i;
for (i = 0; i < wcprop_changes->nelts; i++)
{
svn_prop_t *prop = APR_ARRAY_IDX (wcprop_changes, i, svn_prop_t *);
svn_xml_make_open_tag (&logtags, pool, svn_xml_self_closing,
SVN_WC__LOG_MODIFY_WCPROP,
SVN_WC__LOG_ATTR_NAME,
base_name,
SVN_WC__LOG_ATTR_PROPNAME,
prop->name,
prop->value ? SVN_WC__LOG_ATTR_PROPVAL : NULL,
prop->value ? prop->value->data : NULL,
NULL);
}
}
SVN_ERR_W (svn_io_file_write_full (log_fp, logtags->data,
logtags->len, NULL, pool),
apr_psprintf (pool, _("Error writing log file for '%s'"), path));
SVN_ERR (svn_wc__close_adm_file (log_fp, svn_wc_adm_access_path (adm_access),
SVN_WC__ADM_LOG,
TRUE, /* sync */
pool));
/* Run the log file we just created. */
SVN_ERR (svn_wc__run_log (adm_access, NULL, pool));
if (recurse)
{
apr_hash_t *entries;
apr_hash_index_t *hi;
apr_pool_t *subpool = svn_pool_create (pool);
/* Read PATH's entries; this is the absolute path. */
SVN_ERR (svn_wc_entries_read (&entries, adm_access, TRUE, pool));
/* Recursively loop over all children. */
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
{
const void *key;
void *val;
const char *name;
const svn_wc_entry_t *current_entry;
const char *this_path;
svn_wc_adm_access_t *child_access;
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;
/* Create child path by telescoping the main path. */
this_path = svn_path_join (path, name, subpool);
if (current_entry->kind == svn_node_dir)
SVN_ERR (svn_wc_adm_retrieve (&child_access, adm_access, this_path,
subpool));
else
child_access = adm_access;
/* Recurse, but only allow further recursion if the child is
a directory. Pass null for wcprop_changes, because the
ones present in the current call are only applicable to
this one committed item. */
SVN_ERR (svn_wc_process_committed
(this_path, child_access,
(current_entry->kind == svn_node_dir) ? TRUE : FALSE,
new_revnum, rev_date, rev_author, NULL, subpool));
svn_pool_clear (subpool);
}
svn_pool_destroy (subpool);
}
return SVN_NO_ERROR;
}
/* Remove FILE if it exists and is a file. If it does not exist, do
nothing. If it is not a file, error. */
static svn_error_t *
remove_file_if_present (const char *file, apr_pool_t *pool)
{
svn_node_kind_t kind;
/* Does this file exist? If not, get outta here. */
SVN_ERR (svn_io_check_path (file, &kind, pool));
if (kind == svn_node_none)
return SVN_NO_ERROR;
/* Else, remove the file. */
return svn_io_remove_file (file, pool);
}
/* Recursively mark a tree ADM_ACCESS for with a SCHEDULE and/or EXISTENCE
flag and/or COPIED flag, depending on the state of MODIFY_FLAGS. */
static svn_error_t *
mark_tree (svn_wc_adm_access_t *adm_access,
apr_uint32_t modify_flags,
svn_wc_schedule_t schedule,
svn_boolean_t copied,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func_t notify_func,
void *notify_baton,
apr_pool_t *pool)
{
apr_pool_t *subpool = svn_pool_create (pool);
apr_hash_t *entries;
apr_hash_index_t *hi;
const svn_wc_entry_t *entry;
/* Read the entries file for this directory. */
SVN_ERR (svn_wc_entries_read (&entries, adm_access, FALSE, pool));
/* Mark each entry in the entries file. */
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
{
const char *fullpath;
const void *key;
void *val;
const char *base_name;
svn_wc_entry_t *dup_entry;
/* Get the next entry */
apr_hash_this (hi, &key, NULL, &val);
entry = val;
/* Skip "this dir". */
if (! strcmp ((const char *)key, SVN_WC_ENTRY_THIS_DIR))
continue;
base_name = key;
fullpath = svn_path_join (svn_wc_adm_access_path (adm_access), base_name,
subpool);
/* If this is a directory, recurse. */
if (entry->kind == svn_node_dir)
{
svn_wc_adm_access_t *child_access;
SVN_ERR (svn_wc_adm_retrieve (&child_access, adm_access, fullpath,
subpool));
SVN_ERR (mark_tree (child_access, modify_flags,
schedule, copied,
cancel_func, cancel_baton,
notify_func, notify_baton,
subpool));
}
/* Need to duplicate the entry because we are changing the scheduling */
dup_entry = svn_wc_entry_dup (entry, subpool);
dup_entry->schedule = schedule;
dup_entry->copied = copied;
SVN_ERR (svn_wc__entry_modify (adm_access, base_name, dup_entry,
modify_flags, TRUE, subpool));
/* Tell someone what we've done. */
if (schedule == svn_wc_schedule_delete && notify_func != NULL)
(*notify_func) (notify_baton, fullpath, svn_wc_notify_delete,
svn_node_unknown,
NULL,
svn_wc_notify_state_unknown,
svn_wc_notify_state_unknown,
SVN_INVALID_REVNUM);
/* Clear our per-iteration pool. */
svn_pool_clear (subpool);
}
/* Handle "this dir" for states that need it done post-recursion. */
entry = apr_hash_get (entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING);
/* Uncommitted directories (schedule add) that are to be scheduled for
deletion are a special case, they don't need to be changed as they
will be removed from their parent's entry list. */
if (! (entry->schedule == svn_wc_schedule_add
&& schedule == svn_wc_schedule_delete))
{
/* Need to duplicate the entry because we are changing the scheduling */
svn_wc_entry_t *dup_entry = svn_wc_entry_dup (entry, subpool);
if (modify_flags & SVN_WC__ENTRY_MODIFY_SCHEDULE)
dup_entry->schedule = schedule;
if (modify_flags & SVN_WC__ENTRY_MODIFY_COPIED)
dup_entry->copied = copied;
SVN_ERR (svn_wc__entry_modify (adm_access, NULL, dup_entry, modify_flags,
TRUE, subpool));
}
/* Destroy our per-iteration pool. */
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
/* Remove/erase PATH from the working copy. This involves deleting PATH
* from the physical filesystem. PATH is assumed to be an unversioned file
* or directory.
*
* If CANCEL_FUNC is non-null, invoke it with CANCEL_BATON at various
* points, return any error immediately.
*/
static svn_error_t *
erase_unversioned_from_wc (const char *path,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
svn_node_kind_t kind;
SVN_ERR (svn_io_check_path (path, &kind, pool));
switch (kind)
{
case svn_node_none:
/* Nothing to do. */
break;
default:
/* ### TODO: what do we do here? To handle Unix symlinks we
fallthrough to svn_node_file... gulp! */
case svn_node_file:
SVN_ERR (svn_io_remove_file (path, pool));
break;
case svn_node_dir:
/* ### It would be more in the spirit of things to feed the
### cancellation check through to svn_io_remove_dir()... */
if (cancel_func)
SVN_ERR (cancel_func (cancel_baton));
SVN_ERR (svn_io_remove_dir (path, pool));
if (cancel_func)
SVN_ERR (cancel_func (cancel_baton));
break;
}
return SVN_NO_ERROR;
}
/* Remove/erase PATH from the working copy. For files this involves
* deletion from the physical filesystem. For directories it involves the
* deletion from the filesystem of all unversioned children, and all
* versioned children that are files. By the time we get here, added but
* not committed items will have been scheduled for deletion which means
* they have become unversioned.
*
* The result is that all that remains are versioned directories, each with
* its .svn directory and .svn contents.
*
* If CANCEL_FUNC is non-null, invoke it with CANCEL_BATON at various
* points, return any error immediately.
*
* KIND is the node kind appropriate for PATH
*/
static svn_error_t *
erase_from_wc (const char *path,
svn_wc_adm_access_t *adm_access,
svn_node_kind_t kind,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
/* Check that the item exists in the wc. */
svn_node_kind_t wc_kind;
SVN_ERR (svn_io_check_path (path, &wc_kind, pool));
if (wc_kind == svn_node_none)
return SVN_NO_ERROR;
if (cancel_func)
SVN_ERR (cancel_func (cancel_baton));
switch (kind)
{
default:
/* ### TODO: what do we do here? */
break;
case svn_node_file:
SVN_ERR (svn_io_remove_file (path, pool));
break;
case svn_node_dir:
{
apr_hash_t *ver, *unver;
apr_hash_index_t *hi;
svn_wc_adm_access_t *dir_access;
/* ### Suspect that an iteration or recursion subpool would be
good here. */
/* First handle the versioned items, this is better (probably) than
simply using svn_io_get_dirents for everything as it avoids the
need to do svn_io_check_path on each versioned item */
SVN_ERR (svn_wc_adm_retrieve (&dir_access, adm_access, path, pool));
SVN_ERR (svn_wc_entries_read (&ver, dir_access, FALSE, pool));
for (hi = apr_hash_first (pool, ver); hi; hi = apr_hash_next (hi))
{
const void *key;
void *val;
const char *name;
const svn_wc_entry_t *entry;
const char *down_path;
apr_hash_this (hi, &key, NULL, &val);
name = key;
entry = val;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -