📄 status.c
字号:
/* If the item is ignored, and we don't want ignores, skip it. */
if ((status->text_status == svn_wc_status_ignored) && (! eb->no_ignore))
return FALSE;
/* If we want everything, we obviously want this single-item subset
of everything. */
if (eb->get_all)
return TRUE;
/* If the item is unversioned, display it. */
if (status->text_status == svn_wc_status_unversioned)
return TRUE;
/* If the text or property states are interesting, send it. */
if ((status->text_status != svn_wc_status_none)
&& (status->text_status != svn_wc_status_normal))
return TRUE;
if ((status->prop_status != svn_wc_status_none)
&& (status->prop_status != svn_wc_status_normal))
return TRUE;
/* If it's locked or switched, send it. */
if (status->locked)
return TRUE;
if (status->switched)
return TRUE;
/* Otherwise, don't send it. */
return FALSE;
}
/* Baton for mark_status. */
struct status_baton
{
svn_wc_status_func_t real_status_func; /* real status function */
void *real_status_baton; /* real status baton */
};
/* A status callback function which wraps the *real* status
function/baton. It simply sets the "repos_text_status" field of the
STATUS to svn_wc_status_deleted and passes it off to the real
status func/baton. */
static void
mark_deleted (void *baton,
const char *path,
svn_wc_status_t *status)
{
struct status_baton *sb = baton;
status->repos_text_status = svn_wc_status_deleted;
sb->real_status_func (sb->real_status_baton, path, status);
}
/* Handle a directory's STATII hash. EB is the edit baton. DIR_PATH
and DIR_ENTRY are the on-disk path and entry, respectively, for the
directory itself. If DESCEND is set, this function will recurse
into subdirectories. Also, if DIR_WAS_DELETED is set, each status
that is reported through this function will have its
repos_text_status field showing a deletion. Use POOL for all
allocations. */
static svn_error_t *
handle_statii (struct edit_baton *eb,
svn_wc_entry_t *dir_entry,
const char *dir_path,
apr_hash_t *statii,
svn_boolean_t dir_was_deleted,
svn_boolean_t descend,
apr_pool_t *pool)
{
apr_array_header_t *ignores = eb->ignores;
apr_hash_index_t *hi;
apr_pool_t *subpool = svn_pool_create (pool);
svn_wc_status_func_t status_func = eb->status_func;
void *status_baton = eb->status_baton;
struct status_baton sb;
if (dir_was_deleted)
{
sb.real_status_func = eb->status_func;
sb.real_status_baton = eb->status_baton;
status_func = mark_deleted;
status_baton = &sb;
}
/* Loop over all the statuses still in our hash, handling each one. */
for (hi = apr_hash_first (pool, statii); hi; hi = apr_hash_next (hi))
{
const void *key;
void *val;
svn_wc_status_t *status;
apr_hash_this (hi, &key, NULL, &val);
status = val;
/* Clear the subpool. */
svn_pool_clear (subpool);
/* Now, handle the status. */
if (svn_wc__adm_missing (eb->adm_access, key))
status->text_status = svn_wc_status_missing;
else if (descend && status->entry && status->entry->kind == svn_node_dir)
{
svn_wc_adm_access_t *dir_access;
SVN_ERR (svn_wc_adm_retrieve (&dir_access, eb->adm_access,
key, subpool));
SVN_ERR (get_dir_status (eb, dir_entry, dir_access, NULL,
ignores, TRUE, eb->get_all,
eb->no_ignore, TRUE, status_func,
status_baton, eb->cancel_func,
eb->cancel_baton, subpool));
}
if (dir_was_deleted)
status->repos_text_status = svn_wc_status_deleted;
if (is_sendable_status (status, eb))
(eb->status_func)(eb->status_baton, key, status);
}
/* Destroy the subpool. */
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
/*----------------------------------------------------------------------*/
/*** The callbacks we'll plug into an svn_delta_editor_t structure. ***/
static svn_error_t *
set_target_revision (void *edit_baton,
svn_revnum_t target_revision,
apr_pool_t *pool)
{
struct edit_baton *eb = edit_baton;
*(eb->target_revision) = target_revision;
return SVN_NO_ERROR;
}
static svn_error_t *
open_root (void *edit_baton,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **dir_baton)
{
struct edit_baton *eb = edit_baton;
eb->root_opened = TRUE;
return make_dir_baton (dir_baton, NULL, eb, NULL, pool);
}
static svn_error_t *
delete_entry (const char *path,
svn_revnum_t revision,
void *parent_baton,
apr_pool_t *pool)
{
struct dir_baton *db = parent_baton;
struct edit_baton *eb = db->edit_baton;
apr_hash_t *entries;
const char *name = svn_path_basename (path, pool);
const char *full_path = svn_path_join (eb->anchor, path, pool);
const char *dir_path;
svn_node_kind_t kind;
svn_wc_adm_access_t *adm_access;
const char *hash_key;
/* Note: when something is deleted, it's okay to tweak the
statushash immediately. No need to wait until close_file or
close_dir, because there's no risk of having to honor the 'added'
flag. We already know this item exists in the working copy. */
/* Read the parent's entries file. If the deleted thing is not
versioned in this working copy, it was probably deleted via this
working copy. No need to report such a thing. */
/* ### use svn_wc_entry() instead? */
SVN_ERR (svn_io_check_path (full_path, &kind, pool));
if (kind == svn_node_dir)
{
dir_path = full_path;
hash_key = SVN_WC_ENTRY_THIS_DIR;
}
else
{
dir_path = svn_path_dirname (full_path, pool);
hash_key = name;
}
SVN_ERR (svn_wc_adm_retrieve (&adm_access, eb->adm_access, dir_path, pool));
SVN_ERR (svn_wc_entries_read (&entries, adm_access, FALSE, pool));
if (apr_hash_get (entries, hash_key, APR_HASH_KEY_STRING))
SVN_ERR (tweak_statushash (db->statii, eb->adm_access,
full_path, kind == svn_node_dir,
svn_wc_status_deleted, 0));
/* Mark the parent dir -- it lost an entry (unless that parent dir
is the root node and we're not supposed to report on the root
node). */
if (db->parent_baton && (! *eb->target))
SVN_ERR (tweak_statushash (db->parent_baton->statii, eb->adm_access,
db->path, kind == svn_node_dir,
svn_wc_status_modified, 0));
return SVN_NO_ERROR;
}
static svn_error_t *
add_directory (const char *path,
void *parent_baton,
const char *copyfrom_path,
svn_revnum_t copyfrom_revision,
apr_pool_t *pool,
void **child_baton)
{
struct dir_baton *pb = parent_baton;
struct edit_baton *eb = pb->edit_baton;
struct dir_baton *new_db;
SVN_ERR (make_dir_baton (child_baton, path, eb, pb, pool));
/* Make this dir as added. */
new_db = *child_baton;
new_db->added = TRUE;
/* Mark the parent as changed; it gained an entry. */
pb->text_changed = TRUE;
return SVN_NO_ERROR;
}
static svn_error_t *
open_directory (const char *path,
void *parent_baton,
svn_revnum_t base_revision,
apr_pool_t *pool,
void **child_baton)
{
struct dir_baton *pb = parent_baton;
return make_dir_baton (child_baton, path, pb->edit_baton, pb, pool);
}
static svn_error_t *
change_dir_prop (void *dir_baton,
const char *name,
const svn_string_t *value,
apr_pool_t *pool)
{
struct dir_baton *db = dir_baton;
if (svn_wc_is_normal_prop (name))
db->prop_changed = TRUE;
return SVN_NO_ERROR;
}
static svn_error_t *
close_directory (void *dir_baton,
apr_pool_t *pool)
{
struct dir_baton *db = dir_baton;
struct dir_baton *pb = db->parent_baton;
struct edit_baton *eb = db->edit_baton;
svn_wc_status_t *dir_status = NULL;
/* If nothing has changed, return. */
if (db->added || db->prop_changed || db->text_changed)
{
enum svn_wc_status_kind repos_text_status;
enum svn_wc_status_kind repos_prop_status;
/* If this is a new file, add it to the statushash. */
if (db->added)
{
repos_text_status = svn_wc_status_added;
repos_prop_status = db->prop_changed ? svn_wc_status_added : 0;
}
else
{
repos_text_status = db->text_changed ? svn_wc_status_modified : 0;
repos_prop_status = db->prop_changed ? svn_wc_status_modified : 0;
}
/* If this directory was added, add it to its parent's status hash. */
if (pb)
SVN_ERR (tweak_statushash (pb->statii,
eb->adm_access,
db->path, TRUE,
repos_text_status,
repos_prop_status));
}
/* Handle this directory's statuses, and then note in the parent
that this has been done. */
if (pb && eb->descend)
{
svn_boolean_t was_deleted = FALSE;
/* See if the directory was deleted or replaced. */
dir_status = apr_hash_get (pb->statii, db->path, APR_HASH_KEY_STRING);
if (dir_status &&
((dir_status->repos_text_status == svn_wc_status_deleted)
|| (dir_status->repos_text_status == svn_wc_status_replaced)))
was_deleted = TRUE;
/* Now do the status reporting. */
SVN_ERR (handle_statii (eb, dir_status ? dir_status->entry : NULL,
db->path, db->statii, was_deleted, TRUE, pool));
if (is_sendable_status (dir_status, eb))
(eb->status_func) (eb->status_baton, db->path, dir_status);
apr_hash_set (pb->statii, db->path, APR_HASH_KEY_STRING, NULL);
}
else if (! pb)
{
/* If this is the top-most directory, and the operation had a
target, we should only report the target. */
if (*eb->target)
{
svn_wc_status_t *tgt_status;
const char *path = svn_path_join (eb->anchor, eb->target, pool);
dir_status = eb->anchor_status;
tgt_status = apr_hash_get (db->statii, path, APR_HASH_KEY_STRING);
if (tgt_status)
{
if ((eb->descend)
&& (tgt_status->entry)
&& (tgt_status->entry->kind == svn_node_dir))
{
svn_wc_adm_access_t *dir_access;
SVN_ERR (svn_wc_adm_retrieve (&dir_access, eb->adm_access,
path, pool));
SVN_ERR (get_dir_status
(eb, tgt_status->entry, dir_access, NULL,
eb->ignores, TRUE, eb->get_all, eb->no_ignore,
TRUE, eb->status_func, eb->status_baton,
eb->cancel_func, eb->cancel_baton, pool));
}
if (is_sendable_status (tgt_status, eb))
(eb->status_func) (eb->status_baton, path, tgt_status);
}
}
else
{
/* Otherwise, we report on all our children and ourself.
Note that our directory couldn't have been deleted,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -