📄 entries.c
字号:
/* * entries.c : manipulating the administrative `entries' file. * * ==================================================================== * Copyright (c) 2000-2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#include <string.h>#include <assert.h>#include <apr_strings.h>#include "svn_xml.h"#include "svn_error.h"#include "svn_types.h"#include "svn_time.h"#include "svn_pools.h"#include "svn_path.h"#include "svn_ctype.h"#include "wc.h"#include "adm_files.h"#include "adm_ops.h"#include "entries.h"#include "lock.h"#include "svn_private_config.h"/** Overview **//* The administrative `entries' file tracks information about files and subdirs within a particular directory. See the section on the `entries' file in libsvn_wc/README, for concrete information about the XML format.*//*--------------------------------------------------------------- *//*** reading and writing the entries file ***/static svn_wc_entry_t *alloc_entry(apr_pool_t *pool){ svn_wc_entry_t *entry = apr_pcalloc(pool, sizeof(*entry)); entry->revision = SVN_INVALID_REVNUM; entry->copyfrom_rev = SVN_INVALID_REVNUM; entry->cmt_rev = SVN_INVALID_REVNUM; entry->kind = svn_node_none; return entry;}/* If attribute ATTR_NAME appears in hash ATTS, set *ENTRY_FLAG to its * boolean value and add MODIFY_FLAG into *MODIFY_FLAGS, else set *ENTRY_FLAG * false. ENTRY_NAME is the name of the WC-entry. */static svn_error_t *do_bool_attr(svn_boolean_t *entry_flag, apr_uint32_t *modify_flags, apr_uint32_t modify_flag, apr_hash_t *atts, const char *attr_name, const char *entry_name){ const char *str = apr_hash_get(atts, attr_name, APR_HASH_KEY_STRING); *entry_flag = FALSE; if (str) { if (strcmp(str, "true") == 0) *entry_flag = TRUE; else if (strcmp(str, "false") == 0 || strcmp(str, "") == 0) *entry_flag = FALSE; else return svn_error_createf (SVN_ERR_ENTRY_ATTRIBUTE_INVALID, NULL, _("Entry '%s' has invalid '%s' value"), (entry_name ? entry_name : SVN_WC_ENTRY_THIS_DIR), attr_name); *modify_flags |= modify_flag; } return SVN_NO_ERROR;}/* Read an escaped byte on the form 'xHH' from [*BUF, END), placing the byte in *RESULT. Advance *BUF to point after the escape sequence. */static svn_error_t *read_escaped(char *result, char **buf, const char *end){ apr_uint64_t val; char digits[3]; if (end - *buf < 3 || **buf != 'x' || ! svn_ctype_isxdigit((*buf)[1]) || ! svn_ctype_isxdigit((*buf)[2])) return svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Invalid escape sequence")); (*buf)++; digits[0] = *((*buf)++); digits[1] = *((*buf)++); digits[2] = 0; if ((val = apr_strtoi64(digits, NULL, 16)) == 0) return svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Invalid escaped character")); *result = val; return SVN_NO_ERROR;}/* Read a field, possibly with escaped bytes, from [*BUF, END), stopping at the terminator. Place the read string in *RESULT, or set *RESULT to NULL if it is the empty string. Allocate the returned string in POOL. Advance *BUF to point after the terminator. */static svn_error_t *read_str(const char **result, char **buf, const char *end, apr_pool_t *pool){ svn_stringbuf_t *s = NULL; const char *start; if (*buf == end) return svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Unexpected end of entry")); if (**buf == '\n') { *result = NULL; (*buf)++; return SVN_NO_ERROR; } start = *buf; while (*buf != end && **buf != '\n') { if (**buf == '\\') { char c; if (! s) s = svn_stringbuf_ncreate(start, *buf - start, pool); else svn_stringbuf_appendbytes(s, start, *buf - start); (*buf)++; SVN_ERR(read_escaped(&c, buf, end)); svn_stringbuf_appendbytes(s, &c, 1); start = *buf; } else (*buf)++; } if (*buf == end) return svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Unexpected end of entry")); if (s) { svn_stringbuf_appendbytes(s, start, *buf - start); *result = s->data; } else *result = apr_pstrndup(pool, start, *buf - start); (*buf)++; return SVN_NO_ERROR;}/* Read a field from [*BUF, END), terminated by a newline character. The field may not contain escape sequences. The field is not copyed and the buffer is modified in place, by replacing the terminator with a NUL byte. Make *BUF point after the original terminator. */static svn_error_t *read_val(const char **result, char **buf, const char *end){ const char *start = *buf; if (*buf == end) return svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Unexpected end of entry")); if (**buf == '\n') { (*buf)++; *result = NULL; return SVN_NO_ERROR; } while (*buf != end && **buf != '\n') (*buf)++; if (*buf == end) return svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Unexpected end of entry")); **buf = '\0'; *result = start; (*buf)++; return SVN_NO_ERROR;} /* Read a boolean field from [*BUF, END), placing the result in *RESULT. If there is no boolean value (just a terminator), it defaults to false. Else, the value must match FIELD_NAME, in which case *RESULT will be set to true. Advance *BUF to point after the terminator. */static svn_error_t *read_bool(svn_boolean_t *result, const char *field_name, char **buf, const char *end){ const char *val; SVN_ERR(read_val(&val, buf, end)); if (val) { if (strcmp(val, field_name) != 0) return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, _("Invalid value for field '%s'"), field_name); *result = TRUE; } else *result = FALSE; return SVN_NO_ERROR;}/* Read a revision number from [*BUF, END) stopping at the terminator. Set *RESULT to the revision number, or SVN_INVALID_REVNUM if there is none. Use POOL for temporary allocations. Make *BUF point after the terminator. */static svn_error_t *read_revnum(svn_revnum_t *result, char **buf, const char *end, apr_pool_t *pool){ const char *val; SVN_ERR(read_val(&val, buf, end)); if (val) *result = SVN_STR_TO_REV(val); else *result = SVN_INVALID_REVNUM; return SVN_NO_ERROR;}/* Read a timestamp from [*BUF, END) stopping at the terminator. Set *RESULT to the resulting timestamp, or 0 if there is none. Use POOL for temporary allocations. Make *BUF point after the terminator. */static svn_error_t *read_time(apr_time_t *result, char **buf, const char *end, apr_pool_t *pool){ const char *val; SVN_ERR(read_val(&val, buf, end)); if (val) SVN_ERR(svn_time_from_cstring(result, val, pool)); else *result = 0; return SVN_NO_ERROR;}/* Allocate an entry from POOL and read it from [*BUF, END). The buffer may be modified in place while parsing. Return the new entry in *NEW_ENTRY. Advance *BUF to point at the end of the entry record. */static svn_error_t *read_entry(svn_wc_entry_t **new_entry, char **buf, const char *end, apr_pool_t *pool){ svn_wc_entry_t *entry = alloc_entry(pool); const char *name; #define MAYBE_DONE if (**buf == '\f') goto done /* Find the name and set up the entry under that name. */ SVN_ERR(read_str(&name, buf, end, pool)); entry->name = name ? name : SVN_WC_ENTRY_THIS_DIR; /* Set up kind. */ { const char *kindstr; SVN_ERR(read_val(&kindstr, buf, end)); if (kindstr) { if (! strcmp(kindstr, SVN_WC__ENTRIES_ATTR_FILE_STR)) entry->kind = svn_node_file; else if (! strcmp(kindstr, SVN_WC__ENTRIES_ATTR_DIR_STR)) entry->kind = svn_node_dir; else return svn_error_createf (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Entry '%s' has invalid node kind"), (name ? name : SVN_WC_ENTRY_THIS_DIR)); } else entry->kind = svn_node_none; } MAYBE_DONE; /* Attempt to set revision (resolve_to_defaults may do it later, too) */ SVN_ERR(read_revnum(&entry->revision, buf, end, pool)); MAYBE_DONE; /* Attempt to set up url path (again, see resolve_to_defaults). */ SVN_ERR(read_str(&entry->url, buf, end, pool)); MAYBE_DONE; /* Set up repository root. Make sure it is a prefix of url. */ SVN_ERR(read_str(&entry->repos, buf, end, pool)); if (entry->repos && entry->url && ! svn_path_is_ancestor(entry->repos, entry->url)) return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, _("Entry for '%s' has invalid repository " "root"), name ? name : SVN_WC_ENTRY_THIS_DIR); MAYBE_DONE; /* Look for a schedule attribute on this entry. */ { const char *schedulestr; SVN_ERR(read_val(&schedulestr, buf, end)); entry->schedule = svn_wc_schedule_normal; if (schedulestr) { if (! strcmp(schedulestr, SVN_WC__ENTRY_VALUE_ADD)) entry->schedule = svn_wc_schedule_add; else if (! strcmp(schedulestr, SVN_WC__ENTRY_VALUE_DELETE)) entry->schedule = svn_wc_schedule_delete; else if (! strcmp(schedulestr, SVN_WC__ENTRY_VALUE_REPLACE)) entry->schedule = svn_wc_schedule_replace; 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_SCHEDULE); } } MAYBE_DONE; /* Attempt to set up text timestamp. */ SVN_ERR(read_time(&entry->text_time, buf, end, pool)); MAYBE_DONE; /* Checksum. */ SVN_ERR(read_str(&entry->checksum, buf, end, pool)); MAYBE_DONE; /* Setup last-committed values. */ SVN_ERR(read_time(&entry->cmt_date, buf, end, pool)); MAYBE_DONE; SVN_ERR(read_revnum(&entry->cmt_rev, buf, end, pool)); MAYBE_DONE; SVN_ERR(read_str(&entry->cmt_author, buf, end, pool)); MAYBE_DONE; /* has-props flag. */ SVN_ERR(read_bool(&entry->has_props, SVN_WC__ENTRY_ATTR_HAS_PROPS, buf, end)); MAYBE_DONE; /* has-prop-mods flag. */ SVN_ERR(read_bool(&entry->has_prop_mods, SVN_WC__ENTRY_ATTR_HAS_PROP_MODS, buf, end)); MAYBE_DONE; /* cachable-props string. */ SVN_ERR(read_val(&entry->cachable_props, buf, end)); if (entry->cachable_props) entry->cachable_props = apr_pstrdup(pool, entry->cachable_props); MAYBE_DONE; /* present-props string. */ SVN_ERR(read_val(&entry->present_props, buf, end)); if (entry->present_props) entry->present_props = apr_pstrdup(pool, entry->present_props); MAYBE_DONE; /* Is this entry in a state of mental torment (conflict)? */ { SVN_ERR(read_str(&entry->prejfile, buf, end, pool)); MAYBE_DONE; SVN_ERR(read_str(&entry->conflict_old, buf, end, pool)); MAYBE_DONE; SVN_ERR(read_str(&entry->conflict_new, buf, end, pool)); MAYBE_DONE; SVN_ERR(read_str(&entry->conflict_wrk, buf, end, pool)); MAYBE_DONE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -