📄 log.c
字号:
left_label, right_label, target_label,
FALSE, &merge_outcome, loggy->diff3_cmd,
loggy->pool));
return SVN_NO_ERROR;
}
static svn_error_t *
log_do_file_xfer (struct log_runner *loggy,
const char *name,
enum svn_wc__xfer_action action,
const char **atts)
{
svn_error_t *err;
const char *dest = NULL;
/* We have the name (src), and the destination is absolutely required. */
dest = svn_xml_get_attr_value (SVN_WC__LOG_ATTR_DEST, atts);
if (! dest)
return svn_error_createf (pick_error_code (loggy), NULL,
_("Missing 'dest' attribute in '%s'"),
svn_wc_adm_access_path (loggy->adm_access));
err = file_xfer_under_path (loggy->adm_access, name, dest, action,
loggy->pool);
if (err)
signal_error (loggy, err);
return SVN_NO_ERROR;
}
/* Make file NAME in log's CWD readonly */
static svn_error_t *
log_do_file_readonly (struct log_runner *loggy,
const char *name)
{
const char *full_path
= svn_path_join (svn_wc_adm_access_path (loggy->adm_access), name,
loggy->pool);
SVN_ERR (svn_io_set_file_read_only (full_path, FALSE, loggy->pool));
return SVN_NO_ERROR;
}
/* Set file NAME in log's CWD to timestamp value in ATTS. */
static svn_error_t *
log_do_file_timestamp (struct log_runner *loggy,
const char *name,
const char **atts)
{
apr_time_t timestamp;
svn_node_kind_t kind;
const char *full_path
= svn_path_join (svn_wc_adm_access_path (loggy->adm_access), name,
loggy->pool);
const char *timestamp_string
= svn_xml_get_attr_value (SVN_WC__LOG_ATTR_TIMESTAMP, atts);
svn_boolean_t is_special;
if (! timestamp_string)
return svn_error_createf (pick_error_code (loggy), NULL,
_("Missing 'timestamp' attribute in '%s'"),
svn_wc_adm_access_path (loggy->adm_access));
/* Do not set the timestamp on special files. */
SVN_ERR (svn_io_check_special_path (full_path, &kind, &is_special,
loggy->pool));
if (! is_special)
{
SVN_ERR (svn_time_from_cstring (×tamp, timestamp_string,
loggy->pool));
SVN_ERR (svn_io_set_file_affected_time (timestamp, full_path,
loggy->pool));
}
return SVN_NO_ERROR;
}
/* Remove file NAME in log's CWD. */
static svn_error_t *
log_do_rm (struct log_runner *loggy, const char *name)
{
const char *full_path
= svn_path_join (svn_wc_adm_access_path (loggy->adm_access),
name, loggy->pool);
SVN_ERR (svn_io_remove_file (full_path, loggy->pool));
return SVN_NO_ERROR;
}
static svn_error_t *
log_do_modify_entry (struct log_runner *loggy,
const char *name,
const char **atts)
{
svn_error_t *err;
apr_hash_t *ah = svn_xml_make_att_hash (atts, loggy->pool);
const char *tfile;
svn_wc_entry_t *entry;
apr_uint32_t modify_flags;
const char *valuestr;
/* Convert the attributes into an entry structure. */
SVN_ERR (svn_wc__atts_to_entry (&entry, &modify_flags, ah, loggy->pool));
/* Make TFILE the path of the thing being modified. */
tfile = svn_path_join (svn_wc_adm_access_path (loggy->adm_access),
strcmp (name, SVN_WC_ENTRY_THIS_DIR) ? name : "",
loggy->pool);
/* Did the log command give us any timestamps? There are three
possible scenarios here. We must check both text_time
and prop_time for each of the three scenarios. */
/* TEXT_TIME: */
valuestr = apr_hash_get (ah, SVN_WC__ENTRY_ATTR_TEXT_TIME,
APR_HASH_KEY_STRING);
if ((modify_flags & SVN_WC__ENTRY_MODIFY_TEXT_TIME)
&& (! strcmp (valuestr, SVN_WC_TIMESTAMP_WC)))
{
svn_node_kind_t tfile_kind;
apr_time_t text_time;
err = svn_io_check_path (tfile, &tfile_kind, loggy->pool);
if (err)
return svn_error_createf
(pick_error_code (loggy), err,
_("Error checking path '%s'"), tfile);
err = svn_io_file_affected_time (&text_time, tfile, loggy->pool);
if (err)
return svn_error_createf
(pick_error_code (loggy), err,
_("Error getting 'affected time' on '%s'"), tfile);
entry->text_time = text_time;
}
/* PROP_TIME: */
valuestr = apr_hash_get (ah, SVN_WC__ENTRY_ATTR_PROP_TIME,
APR_HASH_KEY_STRING);
if ((modify_flags & SVN_WC__ENTRY_MODIFY_PROP_TIME)
&& (! strcmp (valuestr, SVN_WC_TIMESTAMP_WC)))
{
const char *pfile;
svn_node_kind_t pfile_kind;
apr_time_t prop_time;
err = svn_wc__prop_path (&pfile, tfile, loggy->adm_access, FALSE,
loggy->pool);
if (err)
signal_error (loggy, err);
err = svn_io_check_path (pfile, &pfile_kind, loggy->pool);
if (err)
return svn_error_createf
(pick_error_code (loggy), err,
_("Error checking path '%s'"), pfile);
err = svn_io_file_affected_time (&prop_time, pfile, loggy->pool);
if (err)
return svn_error_createf
(pick_error_code (loggy), NULL,
_("Error getting 'affected time' on '%s'"), pfile);
entry->prop_time = prop_time;
}
/* Now write the new entry out */
err = svn_wc__entry_modify (loggy->adm_access, name,
entry, modify_flags, FALSE, loggy->pool);
if (err)
return svn_error_createf (pick_error_code (loggy), err,
_("Error modifying entry for '%s'"), name);
loggy->entries_modified = TRUE;
return SVN_NO_ERROR;
}
/* Ben sez: this log command is (at the moment) only executed by the
update editor. It attempts to forcefully remove working data. */
static svn_error_t *
log_do_delete_entry (struct log_runner *loggy, const char *name)
{
svn_wc_adm_access_t *adm_access;
const svn_wc_entry_t *entry;
svn_error_t *err = SVN_NO_ERROR;
const char *full_path
= svn_path_join (svn_wc_adm_access_path (loggy->adm_access), name,
loggy->pool);
/* Figure out if 'name' is a dir or a file */
SVN_ERR (svn_wc_adm_probe_retrieve (&adm_access, loggy->adm_access, full_path,
loggy->pool));
SVN_ERR (svn_wc_entry (&entry, full_path, adm_access, FALSE, loggy->pool));
if (! entry)
/* Hmm....this entry is already absent from the revision control
system. Chances are good that this item was removed via a
commit from this working copy. */
return SVN_NO_ERROR;
/* Remove the object from revision control -- whether it's a
single file or recursive directory removal. Attempt
attempt to destroy all working files & dirs too.
### We pass NULL, NULL for cancel_func and cancel_baton below.
### If they were available, it would be nice to use them. */
if (entry->kind == svn_node_dir)
{
svn_wc_adm_access_t *ignored;
/* If we get the right kind of error, it means the directory is
already missing, so all we need to do is delete its entry in
the parent directory. */
err = svn_wc_adm_retrieve (&ignored, adm_access, full_path, loggy->pool);
if (err)
{
if (err->apr_err == SVN_ERR_WC_NOT_LOCKED)
{
apr_hash_t *entries;
svn_error_clear (err);
err = SVN_NO_ERROR;
if (entry->schedule != svn_wc_schedule_add)
{
SVN_ERR (svn_wc_entries_read (&entries, loggy->adm_access,
TRUE, loggy->pool));
svn_wc__entry_remove (entries, name);
SVN_ERR (svn_wc__entries_write (entries, loggy->adm_access,
loggy->pool));
}
}
else
{
return err;
}
}
else
{
err = svn_wc_remove_from_revision_control (adm_access,
SVN_WC_ENTRY_THIS_DIR,
TRUE, /* destroy */
FALSE, /* instant_error */
NULL, NULL,
loggy->pool);
}
}
else if (entry->kind == svn_node_file)
{
err = svn_wc_remove_from_revision_control (loggy->adm_access, name,
TRUE, /* destroy */
FALSE, /* instant_error */
NULL, NULL,
loggy->pool);
}
if ((err) && (err->apr_err == SVN_ERR_WC_LEFT_LOCAL_MOD))
{
svn_error_clear (err);
return SVN_NO_ERROR;
}
else
return err;
}
/* Note: assuming that svn_wc__log_commit() is what created all of
the <committed...> commands, the `name' attribute will either be a
file or SVN_WC_ENTRY_THIS_DIR. */
static svn_error_t *
log_do_committed (struct log_runner *loggy,
const char *name,
const char **atts)
{
svn_error_t *err;
apr_pool_t *pool = loggy->pool;
int is_this_dir = (strcmp (name, SVN_WC_ENTRY_THIS_DIR) == 0);
const char *rev = svn_xml_get_attr_value (SVN_WC__LOG_ATTR_REVISION, atts);
svn_boolean_t wc_root, overwrote_working = FALSE, remove_executable = FALSE;
const char *full_path;
const char *pdir, *base_name;
apr_hash_t *entries;
const svn_wc_entry_t *orig_entry;
svn_wc_entry_t *entry;
apr_time_t text_time = 0; /* By default, don't override old stamp. */
apr_time_t prop_time = 0; /* By default, don't override old stamp. */
svn_node_kind_t kind;
svn_wc_adm_access_t *adm_access;
/* Determine the actual full path of the affected item. */
if (! is_this_dir)
full_path = svn_path_join (svn_wc_adm_access_path (loggy->adm_access),
name, pool);
else
full_path = apr_pstrdup (pool, svn_wc_adm_access_path (loggy->adm_access));
/*** Perform sanity checking operations ***/
/* If no new post-commit revision was given us, bail with an error. */
if (! rev)
return svn_error_createf (pick_error_code (loggy), NULL,
_("Missing 'revision' attribute for '%s'"),
name);
/* Read the entry for the affected item. If we can't find the
entry, or if the entry states that our item is not either "this
dir" or a file kind, perhaps this isn't really the entry our log
creator was expecting. */
SVN_ERR (svn_wc_adm_probe_retrieve (&adm_access, loggy->adm_access, full_path,
pool));
SVN_ERR (svn_wc_entry (&orig_entry, full_path, adm_access, TRUE, pool));
if ((! orig_entry)
|| ((! is_this_dir) && (orig_entry->kind != svn_node_file)))
return svn_error_createf
(pick_error_code (loggy), NULL,
_("Log command for directory '%s' is mislocated"), name);
entry = svn_wc_entry_dup (orig_entry, pool);
/*** Handle the committed deletion case ***/
/* If the committed item was scheduled for deletion, it needs to
now be removed from revision control. Once that is accomplished,
we are finished handling this item. */
if (entry->schedule == svn_wc_schedule_delete)
{
svn_revnum_t new_rev = SVN_STR_TO_REV(rev);
/* If we are suppose to delete "this dir", drop a 'killme' file
into my own administrative dir as a signal for svn_wc__run_log()
to blow away the administrative area after it is finished
processing this logfile. */
if (is_this_dir)
{
/* Bump the revision number of this_dir anyway, so that it
might be higher than its parent's revnum. If it's
higher, then the process that sees KILLME and destroys
the directory can also place a 'deleted' dir entry in the
parent. */
svn_wc_entry_t tmpentry;
tmpentry.revision = new_rev;
tmpentry.kind = svn_node_dir;
SVN_ERR (svn_wc__entry_modify
(loggy->adm_access, NULL, &tmpentry,
SVN_WC__ENTRY_MODIFY_REVISION | SVN_WC__ENTRY_MODIFY_KIND,
FALSE, pool));
loggy->entries_modified = TRUE;
/* Drop the 'killme' file. */
return svn_wc__make_adm_thing (loggy->adm_access, SVN_WC__ADM_KILLME,
svn_node_file, APR_OS_DEFAULT,
0, pool);
}
/* Else, we're deleting a file, and we can safely remove files
from revision control without screwing something else up.
### We pass NULL, NULL for cancel_func and cancel_baton below.
### If they were available, it would be nice to use them. */
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -