📄 entries.c
字号:
} } /* cachable-props string. */ entry->cachable_props = apr_hash_get(atts, SVN_WC__ENTRY_ATTR_CACHABLE_PROPS, APR_HASH_KEY_STRING); if (entry->cachable_props) { *modify_flags |= SVN_WC__ENTRY_MODIFY_CACHABLE_PROPS; entry->cachable_props = apr_pstrdup(pool, entry->cachable_props); } /* present-props string. */ entry->present_props = apr_hash_get(atts, SVN_WC__ENTRY_ATTR_PRESENT_PROPS, APR_HASH_KEY_STRING); if (entry->present_props) { *modify_flags |= SVN_WC__ENTRY_MODIFY_PRESENT_PROPS; entry->present_props = apr_pstrdup(pool, entry->present_props); } *new_entry = entry; return SVN_NO_ERROR;}/* Used when reading an entries file in XML format. */struct entries_accumulator{ /* Keys are entry names, vals are (struct svn_wc_entry_t *)'s. */ apr_hash_t *entries; /* The parser that's parsing it, for signal_expat_bailout(). */ svn_xml_parser_t *parser; /* Should we include 'deleted' entries in the hash? */ svn_boolean_t show_hidden; /* Don't leave home without one. */ apr_pool_t *pool; /* Cleared before handling each entry. */ apr_pool_t *scratch_pool;};/* Called whenever we find an <open> tag of some kind. */static voidhandle_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; svn_pool_clear(accum->scratch_pool); /* Make an entry from the attributes. */ attributes = svn_xml_make_att_hash(atts, accum->scratch_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);}/* Parse BUF of size SIZE as an entries file in XML format, storing the parsed entries in ENTRIES. Use pool for temporary allocations and the pool of ADM_ACCESS for the returned entries. */static svn_error_t *parse_entries_xml(svn_wc_adm_access_t *adm_access, apr_hash_t *entries, svn_boolean_t show_hidden, const char *buf, apr_size_t size, apr_pool_t *pool){ svn_xml_parser_t *svn_parser; struct entries_accumulator accum; /* Set up userData for the XML parser. */ accum.entries = entries; accum.show_hidden = show_hidden; accum.pool = svn_wc_adm_access_pool(adm_access); accum.scratch_pool = svn_pool_create(pool); /* 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. */ SVN_ERR_W(svn_xml_parse(svn_parser, buf, size, TRUE), apr_psprintf(pool, _("XML parser failed in '%s'"), svn_path_local_style (svn_wc_adm_access_path(adm_access), pool))); svn_pool_destroy(accum.scratch_pool); /* Clean up the XML parser */ svn_xml_free_parser(svn_parser); return SVN_NO_ERROR;}/* 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 voidtake_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->repos) dst->repos = src->repos; if ((! dst->uuid) && (! ((dst->schedule == svn_wc_schedule_add) || (dst->schedule == svn_wc_schedule_replace)))) { dst->uuid = src->uuid; } if (! dst->cachable_props) dst->cachable_props = src->cachable_props;}/* 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){ const char *path = svn_wc_adm_access_path(adm_access); apr_file_t *infile = NULL; svn_stringbuf_t *buf = svn_stringbuf_create("", pool); apr_hash_t *entries = apr_hash_make(svn_wc_adm_access_pool(adm_access)); char *curp, *endp; svn_wc_entry_t *entry; int entryno; /* Open the entries file. */ SVN_ERR(svn_wc__open_adm_file(&infile, path, SVN_WC__ADM_ENTRIES, APR_READ, pool)); SVN_ERR(svn_stringbuf_from_aprfile(&buf, infile, pool)); curp = buf->data; endp = buf->data + buf->len; /* If the first byte of the file is not a digit, then it is probably in XML format. */ if (curp != endp && !svn_ctype_isdigit(*curp)) SVN_ERR(parse_entries_xml(adm_access, entries, show_hidden, buf->data, buf->len, pool)); else { /* Skip format line. */ /* ### Could read it here and report it to caller if it wants it. */ curp = memchr(curp, '\n', buf->len); if (! curp) return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, _("Invalid version line in entries file " "of '%s'"), svn_path_local_style(path, pool)); ++curp; entryno = 1; while (curp != endp) { svn_error_t *err = read_entry(&entry, &curp, endp, svn_wc_adm_access_pool(adm_access)); if (! err) { /* We allow extra fields at the end of the line, for extensibility. */ curp = memchr(curp, '\f', endp - curp); if (! curp) err = svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Missing entry terminator")); if (! err && (curp == endp || *(++curp) != '\n')) err = svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Invalid entry terminator")); } if (err) return svn_error_createf(err->apr_err, err, _("Error at entry %d in entries file for " "'%s':"), entryno, svn_path_local_style(path, pool)); ++curp; ++entryno; if ((entry->deleted || entry->absent) && (entry->schedule != svn_wc_schedule_add) && (entry->schedule != svn_wc_schedule_replace) && (! show_hidden)) ; else apr_hash_set(entries, entry->name, APR_HASH_KEY_STRING, entry); } } /* 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)); /* 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 *//* Run a simple validity check on the ENTRIES (the list of entries associated with the directory PATH). */static svn_error_t *check_entries(apr_hash_t *entries, const char *path, apr_pool_t *pool){ svn_wc_entry_t *default_entry; apr_hash_index_t *hi; default_entry = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING); if (! default_entry) return svn_error_createf (SVN_ERR_WC_CORRUPT, NULL, _("Corrupt working copy: '%s' has no default entry"), svn_path_local_style(path, pool)); /* Validate DEFAULT_ENTRY's current schedule. */ switch (default_entry->schedule) { case svn_wc_schedule_normal: case svn_wc_schedule_add: case svn_wc_schedule_delete: case svn_wc_schedule_replace: /* These are all valid states */ break; default: /* This is an invalid state */ return svn_error_createf (SVN_ERR_WC_CORRUPT, NULL, _("Corrupt working copy: directory '%s' has an invalid schedule"), svn_path_local_style(path, pool)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -