📄 update_editor.c
字号:
const char *path,
svn_boolean_t is_root_dir,
apr_pool_t *pool)
{
svn_wc_adm_access_t *adm_access;
apr_hash_t *entries;
svn_wc_entry_t *entry;
apr_hash_index_t *hi;
apr_pool_t *subpool;
svn_wc_entry_t *current_entry;
const char *name;
/* If this is the root directory and there is a target, we can't
mark this directory complete. */
if (is_root_dir && *eb->target)
return SVN_NO_ERROR;
/* All operations are on the in-memory entries hash. */
SVN_ERR (svn_wc_adm_retrieve (&adm_access, eb->adm_access, path, pool));
SVN_ERR (svn_wc_entries_read (&entries, adm_access, TRUE, pool));
/* Mark THIS_DIR complete. */
entry = apr_hash_get (entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING);
if (! entry)
return svn_error_createf (SVN_ERR_ENTRY_NOT_FOUND, NULL,
_("No '.' entry in: '%s'"), path);
entry->incomplete = FALSE;
/* Remove any deleted or missing entries. */
subpool = svn_pool_create (pool);
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
{
const void *key;
void *val;
svn_pool_clear (subpool);
apr_hash_this (hi, &key, NULL, &val);
name = key;
current_entry = val;
/* Any entry still marked as deleted (and not schedule add) can now
be removed -- if it wasn't undeleted by the update, then it
shouldn't stay in the updated working set. Schedule add items
should remain.
*/
if (current_entry->deleted)
{
if (current_entry->schedule != svn_wc_schedule_add)
svn_wc__entry_remove (entries, name);
else
{
svn_wc_entry_t tmpentry;
tmpentry.deleted = FALSE;
SVN_ERR (svn_wc__entry_modify (adm_access, current_entry->name,
&tmpentry,
SVN_WC__ENTRY_MODIFY_DELETED,
FALSE, subpool));
}
}
/* An absent entry might have been reconfirmed as absent, and the way
we can tell is by looking at its revision number: a revision
number different from the target revision of the update means the
update never mentioned the item, so the entry should be
removed. */
else if (current_entry->absent
&& (current_entry->revision != *(eb->target_revision)))
{
svn_wc__entry_remove (entries, name);
}
else if (current_entry->kind == svn_node_dir)
{
const char *child_path = svn_path_join (path, name, subpool);
if ((svn_wc__adm_missing (adm_access, child_path))
&& (! current_entry->absent)
&& (current_entry->schedule != svn_wc_schedule_add))
{
svn_wc__entry_remove (entries, name);
if (eb->notify_func)
(* eb->notify_func) (eb->notify_baton, child_path,
svn_wc_notify_update_delete,
current_entry->kind, NULL,
svn_wc_notify_state_unknown,
svn_wc_notify_state_unknown,
SVN_INVALID_REVNUM);
}
}
}
/* An atomic write of the whole entries file. */
SVN_ERR (svn_wc__entries_write (entries, adm_access, pool));
return SVN_NO_ERROR;
}
/* Decrement the bump_dir_info's reference count. If it hits zero,
then this directory is "done". This means it is safe to remove the
'incomplete' flag attached to the THIS_DIR entry.
In addition, when the directory is "done", we loop onto the parent's
bump information to possibly mark it as done, too.
*/
static svn_error_t *
maybe_bump_dir_info (struct edit_baton *eb,
struct bump_dir_info *bdi,
apr_pool_t *pool)
{
/* Keep moving up the tree of directories until we run out of parents,
or a directory is not yet "done". */
for ( ; bdi != NULL; bdi = bdi->parent)
{
if (--bdi->ref_count > 0)
return SVN_NO_ERROR; /* directory isn't done yet */
/* The refcount is zero, so we remove any 'dead' entries from
the directory and mark it 'complete'. */
SVN_ERR (complete_directory (eb, bdi->path,
bdi->parent ? FALSE : TRUE, pool));
}
/* we exited the for loop because there are no more parents */
return SVN_NO_ERROR;
}
struct file_baton
{
/* The global edit baton. */
struct edit_baton *edit_baton;
/* The parent directory of this file. */
struct dir_baton *dir_baton;
/* Pool specific to this file_baton. */
apr_pool_t *pool;
/* Name of this file (its entry in the directory). */
const char *name;
/* Path to this file, either abs or relative to the change-root. */
const char *path;
/* The repository URL this file will correspond to. */
const char *new_URL;
/* Set if this file is new. */
svn_boolean_t added;
/* This gets set if the file underwent a text change, which guides
the code that syncs up the adm dir and working copy. */
svn_boolean_t text_changed;
/* This gets set if the file underwent a prop change, which guides
the code that syncs up the adm dir and working copy. */
svn_boolean_t prop_changed;
/* An array of svn_prop_t structures, representing all the property
changes to be applied to this file. */
apr_array_header_t *propchanges;
/* The last-changed-date of the file. This is actually a property
that comes through as an 'entry prop', and will be used to set
the working file's timestamp if it's added. */
const char *last_changed_date;
/* Bump information for the directory this file lives in */
struct bump_dir_info *bump_info;
/* This is initialized to all zeroes when the baton is created, then
populated with the MD5 digest of the resultant fulltext after the
last window is handled by the handler returned from
apply_textdelta(). */
unsigned char digest[APR_MD5_DIGESTSIZE];
};
/* Make a new file baton in the provided POOL, with PB as the parent baton.
PATH is relative to the root of the edit. */
static struct file_baton *
make_file_baton (struct dir_baton *pb,
const char *path,
svn_boolean_t adding,
apr_pool_t *pool)
{
struct file_baton *f = apr_pcalloc (pool, sizeof (*f));
/* I rather need this information, yes. */
if (! path)
abort();
/* Make the file's on-disk name. */
f->path = svn_path_join (pb->edit_baton->anchor, path, pool);
f->name = svn_path_basename (path, pool);
/* Figure out the new_URL for this file. */
if (pb->edit_baton->switch_url)
{
f->new_URL = svn_path_url_add_component (pb->new_URL, f->name, pool);
}
else
{
f->new_URL = get_entry_url (pb->edit_baton->adm_access,
pb->path, f->name, pool);
}
f->pool = pool;
f->edit_baton = pb->edit_baton;
f->propchanges = apr_array_make (pool, 1, sizeof (svn_prop_t));
f->bump_info = pb->bump_info;
f->added = adding;
f->dir_baton = pb;
/* No need to initialize f->digest, since we used pcalloc(). */
/* the directory's bump info has one more referer now */
++f->bump_info->ref_count;
return f;
}
/*** Helpers for the editor callbacks. ***/
static svn_error_t *
window_handler (svn_txdelta_window_t *window, void *baton)
{
struct handler_baton *hb = baton;
struct file_baton *fb = hb->fb;
svn_error_t *err = SVN_NO_ERROR, *err2 = SVN_NO_ERROR;
/* Apply this window. We may be done at that point. */
err = hb->apply_handler (window, hb->apply_baton);
if (window != NULL && err == SVN_NO_ERROR)
return err;
/* Either we're done (window is NULL) or we had an error. In either
case, clean up the handler. */
if (hb->source)
{
err2 = svn_wc__close_text_base (hb->source, fb->path, 0, fb->pool);
if (err2 != SVN_NO_ERROR && err == SVN_NO_ERROR)
err = err2;
}
err2 = svn_wc__close_text_base (hb->dest, fb->path, 0, fb->pool);
if (err2 != SVN_NO_ERROR)
{
if (err == SVN_NO_ERROR)
err = err2;
else
svn_error_clear (err2);
}
svn_pool_destroy (hb->pool);
if (err != SVN_NO_ERROR)
{
/* We failed to apply the patch; clean up the temporary file. */
const char *tmppath = svn_wc__text_base_path (fb->path, TRUE, fb->pool);
apr_file_remove (tmppath, fb->pool);
}
else
{
/* Leave a note in the baton indicating that there's new text to
sync up. */
fb->text_changed = 1;
}
return err;
}
/* Prepare directory for dir_baton DB for updating or checking out.
*
* If the path already exists, but is not a working copy for
* ANCESTOR_URL and ANCESTOR_REVISION, then an error will be returned.
*/
static svn_error_t *
prep_directory (struct dir_baton *db,
const char *ancestor_url,
svn_revnum_t ancestor_revision,
apr_pool_t *pool)
{
/* Make sure the directory exists. */
SVN_ERR (svn_wc__ensure_directory (db->path, pool));
/* Make sure it's the right working copy, either by creating it so,
or by checking that it is so already. */
SVN_ERR (svn_wc_ensure_adm (db->path, NULL,
ancestor_url, ancestor_revision, pool));
if (! db->edit_baton->adm_access
|| strcmp (svn_wc_adm_access_path (db->edit_baton->adm_access),
db->path))
{
svn_wc_adm_access_t *adm_access;
apr_pool_t *adm_access_pool
= db->edit_baton->adm_access
? svn_wc_adm_access_pool (db->edit_baton->adm_access)
: db->edit_baton->pool;
SVN_ERR (svn_wc_adm_open2 (&adm_access, db->edit_baton->adm_access,
db->path, TRUE, 0, adm_access_pool));
if (!db->edit_baton->adm_access)
db->edit_baton->adm_access = adm_access;
}
return SVN_NO_ERROR;
}
/* Accumulate tags in LOG_ACCUM to set ENTRY_PROPS for BASE_NAME.
ENTRY_PROPS is an array of svn_prop_t* entry props. */
static void
accumulate_entry_props (svn_stringbuf_t *log_accum,
const char *base_name,
apr_array_header_t *entry_props,
apr_pool_t *pool)
{
int i;
for (i = 0; i < entry_props->nelts; ++i)
{
const svn_prop_t *prop = &APR_ARRAY_IDX (entry_props, i, svn_prop_t);
const char *entry_field = NULL;
/* A prop value of NULL means the information was not
available. We don't remove this field from the entries
file; we have convention just leave it empty. So let's
just skip those entry props that have no values. */
if (! prop->value)
continue;
if (! strcmp (prop->name, SVN_PROP_ENTRY_LAST_AUTHOR))
entry_field = SVN_WC__ENTRY_ATTR_CMT_AUTHOR;
else if (! strcmp (prop->name, SVN_PROP_ENTRY_COMMITTED_REV))
entry_field = SVN_WC__ENTRY_ATTR_CMT_REV;
else if (! strcmp (prop->name, SVN_PROP_ENTRY_COMMITTED_DATE))
entry_field = SVN_WC__ENTRY_ATTR_CMT_DATE;
else if (! strcmp (prop->name, SVN_PROP_ENTRY_UUID))
entry_field = SVN_WC__ENTRY_ATTR_UUID;
else
continue;
svn_xml_make_open_tag (&log_accum, pool, svn_xml_self_closing,
SVN_WC__LOG_MODIFY_ENTRY,
SVN_WC__LOG_ATTR_NAME, base_name,
entry_field, prop->value->data,
NULL);
}
}
/* Accumulate tags in LOG_ACCUM to set WCPROPS for BASE_NAME. WCPROPS is
an array of svn_prop_t* wc props. */
static void
accumulate_wcprops (svn_stringbuf_t *log_accum,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -