📄 entries.c
字号:
/* Is this entry incomplete? */
{
const char *incompletestr;
incompletestr = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_INCOMPLETE,
APR_HASH_KEY_STRING);
entry->incomplete = FALSE;
if (incompletestr)
{
if (! strcmp (incompletestr, "true"))
entry->incomplete = TRUE;
else if (! strcmp (incompletestr, "false"))
entry->incomplete = FALSE;
else if (! strcmp (incompletestr, ""))
entry->incomplete = FALSE;
else
return svn_error_createf
(SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL,
_("Entry '%s' has invalid '%s' value"),
(name ? name : SVN_WC_ENTRY_THIS_DIR),
SVN_WC__ENTRY_ATTR_INCOMPLETE);
*modify_flags |= SVN_WC__ENTRY_MODIFY_INCOMPLETE;
}
}
/* Attempt to set up timestamps. */
{
const char *text_timestr, *prop_timestr;
text_timestr = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_TEXT_TIME,
APR_HASH_KEY_STRING);
if (text_timestr)
{
if (! strcmp (text_timestr, SVN_WC_TIMESTAMP_WC))
{
/* Special case: a magic string that means 'get this value
from the working copy' -- we ignore it here, trusting
that the caller of this function know what to do about
it. */
}
else
SVN_ERR (svn_time_from_cstring (&entry->text_time, text_timestr,
pool));
*modify_flags |= SVN_WC__ENTRY_MODIFY_TEXT_TIME;
}
prop_timestr = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_PROP_TIME,
APR_HASH_KEY_STRING);
if (prop_timestr)
{
if (! strcmp (prop_timestr, SVN_WC_TIMESTAMP_WC))
{
/* Special case: a magic string that means 'get this value
from the working copy' -- we ignore it here, trusting
that the caller of this function know what to do about
it. */
}
else
SVN_ERR (svn_time_from_cstring (&entry->prop_time, prop_timestr,
pool));
*modify_flags |= SVN_WC__ENTRY_MODIFY_PROP_TIME;
}
}
/* Checksum. */
{
entry->checksum = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_CHECKSUM,
APR_HASH_KEY_STRING);
if (entry->checksum)
*modify_flags |= SVN_WC__ENTRY_MODIFY_CHECKSUM;
}
/* UUID. */
{
entry->uuid = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_UUID,
APR_HASH_KEY_STRING);
if (entry->uuid)
*modify_flags |= SVN_WC__ENTRY_MODIFY_UUID;
}
/* Setup last-committed values. */
{
const char *cmt_datestr, *cmt_revstr;
cmt_datestr = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_CMT_DATE,
APR_HASH_KEY_STRING);
if (cmt_datestr)
{
SVN_ERR (svn_time_from_cstring (&entry->cmt_date, cmt_datestr, pool));
*modify_flags |= SVN_WC__ENTRY_MODIFY_CMT_DATE;
}
else
entry->cmt_date = 0;
cmt_revstr = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_CMT_REV,
APR_HASH_KEY_STRING);
if (cmt_revstr)
{
entry->cmt_rev = SVN_STR_TO_REV (cmt_revstr);
*modify_flags |= SVN_WC__ENTRY_MODIFY_CMT_REV;
}
else
entry->cmt_rev = SVN_INVALID_REVNUM;
entry->cmt_author = apr_hash_get (atts, SVN_WC__ENTRY_ATTR_CMT_AUTHOR,
APR_HASH_KEY_STRING);
if (entry->cmt_author)
*modify_flags |= SVN_WC__ENTRY_MODIFY_CMT_AUTHOR;
}
*new_entry = entry;
return SVN_NO_ERROR;
}
/* Called whenever we find an <open> tag of some kind. */
static void
handle_start_tag (void *userData, const char *tagname, const char **atts)
{
struct entries_accumulator *accum = userData;
apr_hash_t *attributes;
svn_wc_entry_t *entry;
svn_error_t *err;
apr_uint32_t modify_flags = 0;
/* We only care about the `entry' tag; all other tags, such as `xml'
and `wc-entries', are ignored. */
if (strcmp (tagname, SVN_WC__ENTRIES_ENTRY))
return;
/* Make an entry from the attributes. */
attributes = svn_xml_make_att_hash (atts, accum->pool);
err = svn_wc__atts_to_entry (&entry, &modify_flags, attributes, accum->pool);
if (err)
{
svn_xml_signal_bailout (err, accum->parser);
return;
}
/* Find the name and set up the entry under that name. This
should *NOT* be NULL, since svn_wc__atts_to_entry() should
have made it into SVN_WC_ENTRY_THIS_DIR. (Note that technically,
an entry can't be both absent and scheduled for addition, but we
don't need a sanity check for that here.) */
if ((entry->deleted || entry->absent)
&& (entry->schedule != svn_wc_schedule_add)
&& (entry->schedule != svn_wc_schedule_replace)
&& (! accum->show_hidden))
;
else
apr_hash_set (accum->entries, entry->name, APR_HASH_KEY_STRING, entry);
}
/* Use entry SRC to fill in blank portions of entry DST. SRC itself
may not have any blanks, of course.
Typically, SRC is a parent directory's own entry, and DST is some
child in that directory. */
static void
take_from_entry (svn_wc_entry_t *src, svn_wc_entry_t *dst, apr_pool_t *pool)
{
/* Inherits parent's revision if doesn't have a revision of one's
own, unless this is a subdirectory. */
if ((dst->revision == SVN_INVALID_REVNUM) && (dst->kind != svn_node_dir))
dst->revision = src->revision;
/* Inherits parent's url if doesn't have a url of one's own. */
if (! dst->url)
dst->url = svn_path_url_add_component (src->url, dst->name, pool);
if ((! dst->uuid)
&& (! ((dst->schedule == svn_wc_schedule_add)
|| (dst->schedule == svn_wc_schedule_replace))))
{
dst->uuid = src->uuid;
}
}
/* Resolve any missing information in ENTRIES by deducing from the
directory's own entry (which must already be present in ENTRIES). */
static svn_error_t *
resolve_to_defaults (apr_hash_t *entries,
apr_pool_t *pool)
{
apr_hash_index_t *hi;
svn_wc_entry_t *default_entry
= apr_hash_get (entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING);
/* First check the dir's own entry for consistency. */
if (! default_entry)
return svn_error_create (SVN_ERR_ENTRY_NOT_FOUND,
NULL,
_("Missing default entry"));
if (default_entry->revision == SVN_INVALID_REVNUM)
return svn_error_create (SVN_ERR_ENTRY_MISSING_REVISION,
NULL,
_("Default entry has no revision number"));
if (! default_entry->url)
return svn_error_create (SVN_ERR_ENTRY_MISSING_URL,
NULL,
_("Default entry is missing URL"));
/* Then use it to fill in missing information in other entries. */
for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
{
void *val;
svn_wc_entry_t *this_entry;
apr_hash_this (hi, NULL, NULL, &val);
this_entry = val;
if (this_entry == default_entry)
/* THIS_DIR already has all the information it can possibly
have. */
continue;
if (this_entry->kind == svn_node_dir)
/* Entries that are directories have everything but their
name, kind, and state stored in the THIS_DIR entry of the
directory itself. However, we are disallowing the perusing
of any entries outside of the current entries file. If a
caller wants more info about a directory, it should look in
the entries file in the directory. */
continue;
if (this_entry->kind == svn_node_file)
/* For file nodes that do not explicitly have their ancestry
stated, this can be derived from the default entry of the
directory in which those files reside. */
take_from_entry (default_entry, this_entry, pool);
}
return SVN_NO_ERROR;
}
/* Fill the entries cache in ADM_ACCESS. Either the full hash cache will be
populated, if SHOW_HIDDEN is TRUE, or the truncated hash cache will be
populated if SHOW_HIDDEN is FALSE. POOL is used for local memory
allocation, the access baton pool is used for the cache. */
static svn_error_t *
read_entries (svn_wc_adm_access_t *adm_access,
svn_boolean_t show_hidden,
apr_pool_t *pool)
{
svn_error_t *err;
svn_boolean_t is_final;
apr_file_t *infile = NULL;
svn_xml_parser_t *svn_parser;
char buf[BUFSIZ];
apr_size_t bytes_read;
struct entries_accumulator accum;
apr_hash_t *entries = apr_hash_make (svn_wc_adm_access_pool (adm_access));
/* Open the entries file. */
SVN_ERR (svn_wc__open_adm_file (&infile,
svn_wc_adm_access_path (adm_access),
SVN_WC__ADM_ENTRIES, APR_READ, pool));
/* Set up userData for the XML parser. */
accum.entries = entries;
accum.show_hidden = show_hidden;
accum.pool = svn_wc_adm_access_pool (adm_access);
/* Create the XML parser */
svn_parser = svn_xml_make_parser (&accum,
handle_start_tag,
NULL,
NULL,
pool);
/* Store parser in its own userdata, so callbacks can call
svn_xml_signal_bailout() */
accum.parser = svn_parser;
/* Parse. */
do {
err = svn_io_file_read_full (infile, buf, sizeof(buf), &bytes_read, pool);
if (err && !APR_STATUS_IS_EOF(err->apr_err))
return err;
is_final = (err != NULL); /* EOF is only possible error */
svn_error_clear (err);
SVN_ERR_W (svn_xml_parse (svn_parser, buf, bytes_read, is_final),
apr_psprintf (pool,
_("XML parser failed in '%s'"),
svn_wc_adm_access_path (adm_access)));
} while (! is_final);
/* Close the entries file. */
SVN_ERR (svn_wc__close_adm_file (infile, svn_wc_adm_access_path (adm_access),
SVN_WC__ADM_ENTRIES, 0, pool));
/* Clean up the XML parser */
svn_xml_free_parser (svn_parser);
/* Fill in any implied fields. */
SVN_ERR (resolve_to_defaults (entries, svn_wc_adm_access_pool (adm_access)));
svn_wc__adm_access_set_entries (adm_access, show_hidden, entries);
return SVN_NO_ERROR;
}
/* For non-directory PATHs full entry information is obtained by reading
* the entries for the parent directory of PATH and then extracting PATH's
* entry. If PATH is a directory then only abrieviated information is
* available in the parent directory, more complete information is
* available by reading the entries for PATH itself.
*
* Note: There is one bit of information about directories that is only
* available in the parent directory, that is the "deleted" state. If PATH
* is a versioned directory then the "deleted" state information will not
* be returned in ENTRY. This means some bits of the code (e.g. revert)
* need to obtain it by directly extracting the directory entry from the
* parent directory's entries. I wonder if this function should handle
* that?
*/
svn_error_t *
svn_wc_entry (const svn_wc_entry_t **entry,
const char *path,
svn_wc_adm_access_t *adm_access,
svn_boolean_t show_hidden,
apr_pool_t *pool)
{
const char *entry_name;
svn_wc_adm_access_t *dir_access;
SVN_ERR (svn_wc__adm_retrieve_internal (&dir_access, adm_access, path, pool));
if (! dir_access)
{
const char *dir_path, *base_name;
svn_path_split (path, &dir_path, &base_name, pool);
SVN_ERR (svn_wc__adm_retrieve_internal (&dir_access, adm_access, dir_path,
pool));
entry_name = base_name;
}
else
entry_name = SVN_WC_ENTRY_THIS_DIR;
if (dir_access)
{
apr_hash_t *entries;
SVN_ERR (svn_wc_entries_read (&entries, dir_access, show_hidden, pool));
*entry = apr_hash_get (entries, entry_name, APR_HASH_KEY_STRING);
}
else
*entry = NULL;
return SVN_NO_ERROR;
}
#if 0
/* This is #if 0'd out until I decide where to use it. --cmpilato */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -