📄 props.c
字号:
basehash = apr_hash_make (pool);
SVN_ERR (svn_wc__load_prop_file (base_propfile_path, basehash, pool));
SVN_ERR (svn_wc__load_prop_file (local_propfile_path, localhash, pool));
/* Deduce any local propchanges the user has made since the last
update. */
SVN_ERR (svn_prop_diffs (&local_propchanges, localhash, basehash, pool));
if (state)
{
/* Start out assuming no conflicts. Don't bother to examine
propchanges->nelts yet; even if we knew there were
propchanges, we wouldn't yet know if they are "normal" props,
as opposed wc or entry props. */
if (local_propchanges->nelts > 0)
*state = svn_wc_notify_state_changed;
else
*state = svn_wc_notify_state_unchanged;
}
/* Looping over the array of `update' propchanges we want to apply: */
for (i = 0; i < propchanges->nelts; i++)
{
int j;
int found_match = 0;
const svn_string_t *conflict_description;
const svn_prop_t *update_change;
const svn_prop_t *local_change = NULL;
const svn_string_t *value;
svn_boolean_t is_normal;
update_change = &APR_ARRAY_IDX (propchanges, i, svn_prop_t);
is_normal = svn_wc_is_normal_prop (update_change->name);
value = update_change->value
? svn_string_dup (update_change->value, pool)
: NULL;
/* Apply the update_change to the pristine hash, no questions
asked. */
apr_hash_set (basehash, update_change->name, APR_HASH_KEY_STRING, value);
/* We already know that state is at least `modified', so mark
that, but remember that we may later upgrade to `merged' or
even `conflicted'. */
if (state && is_normal)
*state = svn_wc_notify_state_changed;
/* Now, does the update_change conflict with some local change? */
/* First check if the property name even exists in our list
of local changes... */
for (j = 0; j < local_propchanges->nelts; j++)
{
local_change = &APR_ARRAY_IDX (local_propchanges, j, svn_prop_t);
if (strcmp (local_change->name, update_change->name) == 0)
{
found_match = 1;
break;
}
}
if (found_match)
{
svn_boolean_t conflict
= svn_wc__conflicting_propchanges_p (&conflict_description,
local_change,
update_change,
pool);
/* Now see if the two changes actually conflict */
if (conflict)
{
/* Found one! Reflect the conflict in the notification state. */
if (state && is_normal)
*state = svn_wc_notify_state_conflicted;
if (dry_run)
continue;
if (! reject_tmp_fp)
{
/* This is the very first prop conflict found on this
node. */
const char *tmppath;
const char *tmpname;
/* Get path to /temporary/ local prop file */
SVN_ERR (svn_wc__prop_path (&tmppath, full_path, adm_access,
TRUE, pool));
/* Reserve a .prej file based on it. */
SVN_ERR (svn_io_open_unique_file (&reject_tmp_fp,
&reject_tmp_path,
tmppath,
SVN_WC__PROP_REJ_EXT,
FALSE,
pool));
/* reject_tmp_path is an absolute path at this point,
but that's no good for us. We need to convert this
path to a *relative* path to use in the logfile. */
tmpname = svn_path_basename (reject_tmp_path, pool);
if (is_dir)
{
/* Dealing with directory "path" */
reject_tmp_path =
svn_wc__adm_path ("",
TRUE, /* use tmp */
pool,
tmpname,
NULL);
}
else
{
/* Dealing with file "path/name" */
reject_tmp_path =
svn_wc__adm_path ("",
TRUE,
pool,
SVN_WC__ADM_PROPS,
tmpname,
NULL);
}
}
/* Append the conflict to the open tmp/PROPS/---.prej file */
SVN_ERR (append_prop_conflict (reject_tmp_fp,
conflict_description,
pool));
continue; /* skip to the next update_change */
}
else /* not a conflict */
{
/* Reflect the merge in the notification state, but
don't override any previous conflicted state. */
if (state && is_normal
&& (*state != svn_wc_notify_state_conflicted))
*state = svn_wc_notify_state_merged;
}
}
/* Every time we reach this point, it's not a conflict, so we
can safely apply the update_change to our working property hash. */
apr_hash_set (localhash,
update_change->name, APR_HASH_KEY_STRING,
value);
}
if (dry_run)
return SVN_NO_ERROR;
/* Done merging property changes into both pristine and working
hashes. Now we write them to temporary files. Notice that the
paths computed are ABSOLUTE pathnames, which is what our disk
routines require.*/
SVN_ERR (svn_wc__prop_path (&local_prop_tmp_path, full_path, adm_access, TRUE,
pool));
/* Write the merged local prop hash to path/.svn/tmp/props/name or
path/.svn/tmp/dir-props */
SVN_ERR (svn_wc__save_prop_file (local_prop_tmp_path, localhash, pool));
/* Compute pathnames for the "mv" log entries. Notice that these
paths are RELATIVE pathnames (each beginning with ".svn/"), so
that each .svn subdir remains separable when executing run_log(). */
tmp_props = apr_pstrdup (pool, local_prop_tmp_path + access_len + slash);
real_props = apr_pstrdup (pool, local_propfile_path + access_len + slash);
/* Write log entry to move working tmp copy to real working area. */
svn_xml_make_open_tag (entry_accum,
pool,
svn_xml_self_closing,
SVN_WC__LOG_MV,
SVN_WC__LOG_ATTR_NAME,
tmp_props,
SVN_WC__LOG_ATTR_DEST,
real_props,
NULL);
/* Make props readonly */
svn_xml_make_open_tag (entry_accum,
pool,
svn_xml_self_closing,
SVN_WC__LOG_READONLY,
SVN_WC__LOG_ATTR_NAME,
real_props,
NULL);
/* Repeat the above steps for the base properties if required */
if (base_merge)
{
SVN_ERR (svn_wc__prop_base_path (&base_prop_tmp_path, full_path,
adm_access, TRUE, pool));
SVN_ERR (svn_wc__save_prop_file (base_prop_tmp_path, basehash, pool));
tmp_prop_base = apr_pstrdup (pool,
base_prop_tmp_path + access_len + slash);
real_prop_base = apr_pstrdup (pool,
base_propfile_path + access_len + slash);
svn_xml_make_open_tag (entry_accum,
pool,
svn_xml_self_closing,
SVN_WC__LOG_MV,
SVN_WC__LOG_ATTR_NAME,
tmp_prop_base,
SVN_WC__LOG_ATTR_DEST,
real_prop_base,
NULL);
svn_xml_make_open_tag (entry_accum,
pool,
svn_xml_self_closing,
SVN_WC__LOG_READONLY,
SVN_WC__LOG_ATTR_NAME,
real_prop_base,
NULL);
}
if (reject_tmp_fp)
{
/* There's a .prej file sitting in .svn/tmp/ somewhere. Deal
with the conflicts. */
/* First, _close_ this temporary conflicts file. We've been
appending to it all along. */
SVN_ERR (svn_io_file_close (reject_tmp_fp, pool));
/* Now try to get the name of a pre-existing .prej file from the
entries file */
SVN_ERR (svn_wc__get_existing_prop_reject_file (&reject_path,
adm_access,
entryname,
pool));
if (! reject_path)
{
/* Reserve a new .prej file *above* the .svn/ directory by
opening and closing it. */
const char *reserved_path;
const char *full_reject_path;
full_reject_path
= svn_path_join (access_path,
is_dir ? SVN_WC__THIS_DIR_PREJ : name,
pool);
SVN_ERR (svn_io_open_unique_file (&reject_fp,
&reserved_path,
full_reject_path,
SVN_WC__PROP_REJ_EXT,
FALSE,
pool));
SVN_ERR (svn_io_file_close (reject_fp, pool));
/* This file will be overwritten when the log is run; that's
ok, because at least now we have a reservation on
disk. */
/* Now just get the name of the reserved file. This is the
"relative" path we will use in the log entry. */
reject_path = svn_path_basename (reserved_path, pool);
}
/* We've now guaranteed that some kind of .prej file exists
above the .svn/ dir. We write log entries to append our
conflicts to it. */
svn_xml_make_open_tag (entry_accum,
pool,
svn_xml_self_closing,
SVN_WC__LOG_APPEND,
SVN_WC__LOG_ATTR_NAME,
reject_tmp_path,
SVN_WC__LOG_ATTR_DEST,
reject_path,
NULL);
/* And of course, delete the temporary reject file. */
svn_xml_make_open_tag (entry_accum,
pool,
svn_xml_self_closing,
SVN_WC__LOG_RM,
SVN_WC__LOG_ATTR_NAME,
reject_tmp_path,
NULL);
/* Mark entry as "conflicted" with a particular .prej file. */
svn_xml_make_open_tag (entry_accum,
pool,
svn_xml_self_closing,
SVN_WC__LOG_MODIFY_ENTRY,
SVN_WC__LOG_ATTR_NAME,
entryname,
SVN_WC__ENTRY_ATTR_PREJFILE,
reject_path,
NULL);
} /* if (reject_tmp_fp) */
/* At this point, we need to write log entries that bump revision
number and set new entry timestamps. The caller of this function
should (hopefully) add those commands to the log accumulator. */
return SVN_NO_ERROR;
}
/*------------------------------------------------------------------*/
/*** Private 'wc prop' functions ***/
/* A clone of svn_wc_prop_list, for the most part, except that it
returns 'wc' props instead of normal props. */
static svn_error_t *
wcprop_list (apr_hash_t **props,
const char *path,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
svn_node_kind_t kind, pkind;
const char *prop_path;
*props = apr_hash_make (pool);
/* Check validity of PATH */
SVN_ERR( svn_io_check_path (path, &kind, pool) );
#if 0
if (kind == svn_node_none)
return svn_error_createf (SVN_ERR_BAD_FILENAME, NULL,
_("'%s' does not exist"),
path);
if (kind == svn_node_unknown)
return svn_error_createf (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
_("Unknown node kind: '%s'"),
path);
#endif
/* Construct a path to the relevant property file */
SVN_ERR( svn_wc__wcprop_path (&prop_path, path, adm_access, FALSE, pool) );
/* Does the property file exist? */
SVN_ERR( svn_io_check_path (prop_path, &pkind, pool) );
if (pkind == svn_node_none)
/* No property file exists. Just go home, with an empty hash. */
return SVN_NO_ERROR;
/* else... */
SVN_ERR( svn_wc__load_prop_file (prop_path, *props, pool) );
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__wcprop_get (const svn_string_t **value,
const char *name,
const char *path,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
svn_error_t *err;
apr_hash_t *prophash;
err = wcprop_list (&prophash, path, adm_access, pool);
if (err)
return
svn_error_quick_wrap
(err, _("Failed to load properties from disk"));
*value = apr_hash_get (prophash, name, APR_HASH_KEY_STRING);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__wcprop_set (const char *name,
const svn_string_t *value,
const char *path,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
svn_error_t *err;
apr_hash_t *prophash;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -