📄 props.c
字号:
{
if (! APR_STATUS_IS_ENOENT (err->apr_err)
&& ! APR_STATUS_IS_ENOTDIR (err->apr_err))
return err;
/* nonexistent */
svn_error_clear (err);
*empty_p = TRUE;
}
else
{
/* If we remove props from a propfile, eventually the file will
contain nothing but "END\n" */
if (finfo.filetype == APR_REG && finfo.size == 4)
*empty_p = TRUE;
else
*empty_p = FALSE;
/* If the size is < 4, then something is corrupt.
If the size is between 4 and 16, then something is corrupt,
because 16 is the -smallest- the file can possibly be if it
contained only one property. So long as we say it is "not
empty", we will discover such corruption later when we try
to read the properties from the file. */
}
return SVN_NO_ERROR;
}
/* Simple wrapper around empty_props_p, and inversed. */
svn_error_t *
svn_wc__has_props (svn_boolean_t *has_props,
const char *path,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
svn_boolean_t is_empty;
const char *prop_path;
SVN_ERR (svn_wc__prop_path (&prop_path, path, adm_access, FALSE, pool));
SVN_ERR (empty_props_p (&is_empty, prop_path, pool));
if (is_empty)
*has_props = FALSE;
else
*has_props = TRUE;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_props_modified_p (svn_boolean_t *modified_p,
const char *path,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
svn_boolean_t bempty, wempty;
const char *prop_path;
const char *prop_base_path;
svn_boolean_t different_filesizes, equal_timestamps;
const svn_wc_entry_t *entry;
apr_pool_t *subpool = svn_pool_create (pool);
/* First, get the paths of the working and 'base' prop files. */
SVN_ERR (svn_wc__prop_path (&prop_path, path, adm_access, FALSE, subpool));
SVN_ERR (svn_wc__prop_base_path (&prop_base_path, path, adm_access, FALSE,
subpool));
/* Decide if either path is "empty" of properties. */
SVN_ERR (empty_props_p (&wempty, prop_path, subpool));
SVN_ERR (empty_props_p (&bempty, prop_base_path, subpool));
/* If something is scheduled for replacement, we do *not* want to
pay attention to any base-props; they might be residual from the
old deleted file. */
SVN_ERR (svn_wc_entry (&entry, path, adm_access, TRUE, subpool));
if (entry && (entry->schedule == svn_wc_schedule_replace))
{
*modified_p = wempty ? FALSE : TRUE;
goto cleanup;
}
/* Easy out: if the base file is empty, we know the answer
immediately. */
if (bempty)
{
if (! wempty)
{
/* base is empty, but working is not */
*modified_p = TRUE;
goto cleanup;
}
else
{
/* base and working are both empty */
*modified_p = FALSE;
goto cleanup;
}
}
/* OK, so the base file is non-empty. One more easy out: */
if (wempty)
{
/* base exists, working is empty */
*modified_p = TRUE;
goto cleanup;
}
/* At this point, we know both files exists. Therefore we have no
choice but to start checking their contents. */
/* There are at least three tests we can try in succession. */
/* Easy-answer attempt #1: (### this stat's the files again) */
/* Check if the local and prop-base file have *definitely* different
filesizes. */
SVN_ERR (svn_io_filesizes_different_p (&different_filesizes,
prop_path,
prop_base_path,
subpool));
if (different_filesizes)
{
*modified_p = TRUE;
goto cleanup;
}
/* Easy-answer attempt #2: (### this stat's the files again) */
/* See if the local file's prop timestamp is the same as the one
recorded in the administrative directory. */
SVN_ERR (svn_wc__timestamps_equal_p (&equal_timestamps, path, adm_access,
svn_wc__prop_time, subpool));
if (equal_timestamps)
{
*modified_p = FALSE;
goto cleanup;
}
/* Last ditch attempt: */
/* If we get here, then we know that the filesizes are the same,
but the timestamps are different. That's still not enough
evidence to make a correct decision; we need to look at the
files' contents directly.
However, doing a byte-for-byte comparison won't work. The two
properties files may have the *exact* same name/value pairs, but
arranged in a different order. (Our hashdump format makes no
guarantees about ordering.)
Therefore, rather than use contents_identical_p(), we use
svn_prop_diffs(). */
{
apr_array_header_t *local_propchanges;
apr_hash_t *localprops = apr_hash_make (subpool);
apr_hash_t *baseprops = apr_hash_make (subpool);
/* ### Amazingly, this stats the files again! */
SVN_ERR (svn_wc__load_prop_file (prop_path, localprops, subpool));
SVN_ERR (svn_wc__load_prop_file (prop_base_path,
baseprops,
subpool));
SVN_ERR (svn_prop_diffs (&local_propchanges, localprops,
baseprops, subpool));
if (local_propchanges->nelts > 0)
*modified_p = TRUE;
else
*modified_p = FALSE;
/* If it turns out that there are no differences then we might be able
to "repair" the prop-time in the entries file and avoid the
expensive file contents comparison next time.
### Unlike the text-time in svn_wc_text_modified_p the only
### "legitimate" way to produce a prop-time variation with no
### corresponding property variation, is by using the Subversion
### property interface. Perhaps those functions should detect the
### change that restores the pristine values and reset the
### prop-time? This code would still be needed, to handle someone
### or something manually changing the timestamp on the
### prop-base. */
if (! *modified_p && svn_wc_adm_locked (adm_access))
{
svn_wc_entry_t tmp;
SVN_ERR (svn_io_file_affected_time (&tmp.prop_time, prop_path, pool));
SVN_ERR (svn_wc__entry_modify (adm_access,
(entry->kind == svn_node_dir
? SVN_WC_ENTRY_THIS_DIR
: svn_path_basename (path, pool)),
&tmp, SVN_WC__ENTRY_MODIFY_PROP_TIME,
TRUE, pool));
}
}
cleanup:
svn_pool_destroy (subpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_get_prop_diffs (apr_array_header_t **propchanges,
apr_hash_t **original_props,
const char *path,
svn_wc_adm_access_t *adm_access,
apr_pool_t *pool)
{
const char *prop_path, *prop_base_path;
apr_array_header_t *local_propchanges;
apr_hash_t *localprops = apr_hash_make (pool);
apr_hash_t *baseprops = apr_hash_make (pool);
SVN_ERR (svn_wc__prop_path (&prop_path, path, adm_access, FALSE, pool));
SVN_ERR (svn_wc__prop_base_path (&prop_base_path, path, adm_access, FALSE,
pool));
SVN_ERR (svn_wc__load_prop_file (prop_path, localprops, pool));
SVN_ERR (svn_wc__load_prop_file (prop_base_path, baseprops, pool));
if (original_props != NULL)
*original_props = baseprops;
/* At this point, if either of the propfiles are non-existent, then
the corresponding hash is simply empty. */
if (propchanges != NULL)
{
SVN_ERR (svn_prop_diffs (&local_propchanges, localprops,
baseprops, pool));
*propchanges = local_propchanges;
}
return SVN_NO_ERROR;
}
/** Externals **/
svn_error_t *
svn_wc_parse_externals_description2 (apr_array_header_t **externals_p,
const char *parent_directory,
const char *desc,
apr_pool_t *pool)
{
apr_array_header_t *lines = svn_cstring_split (desc, "\n\r", TRUE, pool);
int i;
if (externals_p)
*externals_p = apr_array_make (pool, 1, sizeof (svn_wc_external_item_t *));
for (i = 0; i < lines->nelts; i++)
{
const char *line = APR_ARRAY_IDX (lines, i, const char *);
apr_array_header_t *line_parts;
svn_wc_external_item_t *item;
if ((! line) || (line[0] == '#'))
continue;
/* else proceed */
line_parts = svn_cstring_split (line, " \t", TRUE, pool);
item = apr_palloc (pool, sizeof (*item));
if (line_parts->nelts < 2)
goto parse_error;
else if (line_parts->nelts == 2)
{
/* No "-r REV" given. */
item->target_dir = APR_ARRAY_IDX (line_parts, 0, const char *);
item->url = APR_ARRAY_IDX (line_parts, 1, const char *);
item->revision.kind = svn_opt_revision_head;
}
else if ((line_parts->nelts == 3) || (line_parts->nelts == 4))
{
/* We're dealing with one of these two forms:
*
* TARGET_DIR -rN URL
* TARGET_DIR -r N URL
*
* Handle either way.
*/
const char *r_part_1 = NULL, *r_part_2 = NULL;
item->target_dir = APR_ARRAY_IDX (line_parts, 0, const char *);
item->revision.kind = svn_opt_revision_number;
if (line_parts->nelts == 3)
{
r_part_1 = APR_ARRAY_IDX (line_parts, 1, const char *);
item->url = APR_ARRAY_IDX (line_parts, 2, const char *);
}
else /* nelts == 4 */
{
r_part_1 = APR_ARRAY_IDX (line_parts, 1, const char *);
r_part_2 = APR_ARRAY_IDX (line_parts, 2, const char *);
item->url = APR_ARRAY_IDX (line_parts, 3, const char *);
}
if ((! r_part_1) || (r_part_1[0] != '-') || (r_part_1[1] != 'r'))
goto parse_error;
if (! r_part_2) /* "-rN" */
{
if (strlen (r_part_1) < 3)
goto parse_error;
else
item->revision.value.number = SVN_STR_TO_REV (r_part_1 + 2);
}
else /* "-r N" */
{
if (strlen (r_part_2) < 1)
goto parse_error;
else
item->revision.value.number = SVN_STR_TO_REV (r_part_2);
}
}
else /* too many items on line */
goto parse_error;
if (0)
{
parse_error:
return svn_error_createf
(SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL,
_("Error parsing %s property on '%s': '%s'"),
SVN_PROP_EXTERNALS, parent_directory, line);
}
item->target_dir = svn_path_canonicalize
(svn_path_internal_style (item->target_dir, pool), pool);
{
if (item->target_dir[0] == '\0' || item->target_dir[0] == '/'
|| svn_path_is_backpath_present (item->target_dir))
return svn_error_createf
(SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL,
_("Invalid %s property on '%s': "
"target involves '.' or '..' or is an absolute path"),
SVN_PROP_EXTERNALS, parent_directory);
}
item->url = svn_path_canonicalize (item->url, pool);
if (externals_p)
APR_ARRAY_PUSH (*externals_p, svn_wc_external_item_t *) = item;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_parse_externals_description (apr_hash_t **externals_p,
const char *parent_directory,
const char *desc,
apr_pool_t *pool)
{
apr_array_header_t *list;
int i;
SVN_ERR (svn_wc_parse_externals_description2 (externals_p ? &list : NULL,
parent_directory, desc, pool));
/* Store all of the items into the hash if that was requested. */
if (externals_p)
{
*externals_p = apr_hash_make (pool);
for (i = 0; i < list->nelts; i++)
{
svn_wc_external_item_t *item;
item = APR_ARRAY_IDX (list, i, svn_wc_external_item_t *);
apr_hash_set (*externals_p, item->target_dir,
APR_HASH_KEY_STRING, item);
}
}
return SVN_NO_ERROR;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -