diff options
Diffstat (limited to 'subversion/libsvn_subr/config_file.c')
-rw-r--r-- | subversion/libsvn_subr/config_file.c | 302 |
1 files changed, 212 insertions, 90 deletions
diff --git a/subversion/libsvn_subr/config_file.c b/subversion/libsvn_subr/config_file.c index 185d990..9969b8e 100644 --- a/subversion/libsvn_subr/config_file.c +++ b/subversion/libsvn_subr/config_file.c @@ -50,25 +50,28 @@ /* File parsing context */ typedef struct parse_context_t { - /* This config struct and file */ + /* This config struct */ svn_config_t *cfg; - const char *file; - /* The file descriptor */ + /* The stream struct */ svn_stream_t *stream; /* The current line in the file */ int line; - /* Cached ungotten character - streams don't support ungetc() - [emulate it] */ + /* Emulate an ungetc */ int ungotten_char; - svn_boolean_t have_ungotten_char; - /* Temporary strings, allocated from the temp pool */ + /* Temporary strings */ svn_stringbuf_t *section; svn_stringbuf_t *option; svn_stringbuf_t *value; + + /* Parser buffer for getc() to avoid call overhead into several libraries + for every character */ + char parser_buffer[SVN__STREAM_CHUNK_SIZE]; /* Larger than most config files */ + size_t buffer_pos; /* Current position within parser_buffer */ + size_t buffer_size; /* parser_buffer contains this many bytes */ } parse_context_t; @@ -82,27 +85,61 @@ typedef struct parse_context_t static APR_INLINE svn_error_t * parser_getc(parse_context_t *ctx, int *c) { - if (ctx->have_ungotten_char) - { - *c = ctx->ungotten_char; - ctx->have_ungotten_char = FALSE; - } - else + do { - char char_buf; - apr_size_t readlen = 1; + if (ctx->ungotten_char != EOF) + { + *c = ctx->ungotten_char; + ctx->ungotten_char = EOF; + } + else if (ctx->buffer_pos < ctx->buffer_size) + { + *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos]; + ctx->buffer_pos++; + } + else + { + ctx->buffer_pos = 0; + ctx->buffer_size = sizeof(ctx->parser_buffer); - SVN_ERR(svn_stream_read(ctx->stream, &char_buf, &readlen)); + SVN_ERR(svn_stream_read(ctx->stream, ctx->parser_buffer, + &(ctx->buffer_size))); - if (readlen == 1) - *c = char_buf; - else - *c = EOF; + if (ctx->buffer_pos < ctx->buffer_size) + { + *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos]; + ctx->buffer_pos++; + } + else + *c = EOF; + } } + while (*c == '\r'); return SVN_NO_ERROR; } +/* Simplified version of parser_getc() to be used inside skipping loops. + * It will not check for 'ungotton' chars and may or may not ignore '\r'. + * + * In a 'while(cond) getc();' loop, the first iteration must call + * parser_getc to handle all the special cases. Later iterations should + * use parser_getc_plain for maximum performance. + */ +static APR_INLINE svn_error_t * +parser_getc_plain(parse_context_t *ctx, int *c) +{ + if (ctx->buffer_pos < ctx->buffer_size) + { + *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos]; + ctx->buffer_pos++; + + return SVN_NO_ERROR; + } + + return parser_getc(ctx, c); +} + /* Emulate ungetc() because streams don't support it. * * Use CTX to store the ungotten character C. @@ -111,7 +148,6 @@ static APR_INLINE svn_error_t * parser_ungetc(parse_context_t *ctx, int c) { ctx->ungotten_char = c; - ctx->have_ungotten_char = TRUE; return SVN_NO_ERROR; } @@ -123,14 +159,14 @@ parser_ungetc(parse_context_t *ctx, int c) static APR_INLINE svn_error_t * skip_whitespace(parse_context_t *ctx, int *c, int *pcount) { - int ch; + int ch = 0; int count = 0; SVN_ERR(parser_getc(ctx, &ch)); - while (ch != EOF && ch != '\n' && svn_ctype_isspace(ch)) + while (svn_ctype_isspace(ch) && ch != '\n' && ch != EOF) { ++count; - SVN_ERR(parser_getc(ctx, &ch)); + SVN_ERR(parser_getc_plain(ctx, &ch)); } *pcount = count; *c = ch; @@ -146,13 +182,39 @@ skip_to_eoln(parse_context_t *ctx, int *c) int ch; SVN_ERR(parser_getc(ctx, &ch)); - while (ch != EOF && ch != '\n') - SVN_ERR(parser_getc(ctx, &ch)); + while (ch != '\n' && ch != EOF) + SVN_ERR(parser_getc_plain(ctx, &ch)); *c = ch; return SVN_NO_ERROR; } +/* Skip a UTF-8 Byte Order Mark if found. */ +static APR_INLINE svn_error_t * +skip_bom(parse_context_t *ctx) +{ + int ch; + + SVN_ERR(parser_getc(ctx, &ch)); + if (ch == 0xEF) + { + const unsigned char *buf = (unsigned char *)ctx->parser_buffer; + /* This makes assumptions about the implementation of parser_getc and + * the use of skip_bom. Specifically that parser_getc() will get all + * of the BOM characters into the parse_context_t buffer. This can + * safely be assumed as long as we only try to use skip_bom() at the + * start of the stream and the buffer is longer than 3 characters. */ + SVN_ERR_ASSERT(ctx->buffer_size > ctx->buffer_pos + 1); + if (buf[ctx->buffer_pos] == 0xBB && buf[ctx->buffer_pos + 1] == 0xBF) + ctx->buffer_pos += 2; + else + SVN_ERR(parser_ungetc(ctx, ch)); + } + else + SVN_ERR(parser_ungetc(ctx, ch)); + + return SVN_NO_ERROR; +} /* Parse a single option value */ static svn_error_t * @@ -241,7 +303,7 @@ parse_value(int *pch, parse_context_t *ctx) /* Parse a single option */ static svn_error_t * -parse_option(int *pch, parse_context_t *ctx, apr_pool_t *pool) +parse_option(int *pch, parse_context_t *ctx, apr_pool_t *scratch_pool) { svn_error_t *err = SVN_NO_ERROR; int ch; @@ -259,8 +321,7 @@ parse_option(int *pch, parse_context_t *ctx, apr_pool_t *pool) { ch = EOF; err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, - "%s:%d: Option must end with ':' or '='", - svn_dirent_local_style(ctx->file, pool), + "line %d: Option must end with ':' or '='", ctx->line); } else @@ -284,7 +345,8 @@ parse_option(int *pch, parse_context_t *ctx, apr_pool_t *pool) * starts a section name. */ static svn_error_t * -parse_section_name(int *pch, parse_context_t *ctx, apr_pool_t *pool) +parse_section_name(int *pch, parse_context_t *ctx, + apr_pool_t *scratch_pool) { svn_error_t *err = SVN_NO_ERROR; int ch; @@ -302,8 +364,7 @@ parse_section_name(int *pch, parse_context_t *ctx, apr_pool_t *pool) { ch = EOF; err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, - "%s:%d: Section header must end with ']'", - svn_dirent_local_style(ctx->file, pool), + "line %d: Section header must end with ']'", ctx->line); } else @@ -363,91 +424,113 @@ svn_config__sys_config_path(const char **path_p, svn_error_t * svn_config__parse_file(svn_config_t *cfg, const char *file, - svn_boolean_t must_exist, apr_pool_t *pool) + svn_boolean_t must_exist, apr_pool_t *result_pool) { svn_error_t *err = SVN_NO_ERROR; - parse_context_t ctx; - int ch, count; svn_stream_t *stream; + apr_pool_t *scratch_pool = svn_pool_create(result_pool); - err = svn_stream_open_readonly(&stream, file, pool, pool); + err = svn_stream_open_readonly(&stream, file, scratch_pool, scratch_pool); if (! must_exist && err && APR_STATUS_IS_ENOENT(err->apr_err)) { svn_error_clear(err); + svn_pool_destroy(scratch_pool); return SVN_NO_ERROR; } else SVN_ERR(err); - ctx.cfg = cfg; - ctx.file = file; - ctx.stream = svn_subst_stream_translated(stream, "\n", TRUE, NULL, FALSE, - pool); - ctx.line = 1; - ctx.have_ungotten_char = FALSE; - ctx.section = svn_stringbuf_create("", pool); - ctx.option = svn_stringbuf_create("", pool); - ctx.value = svn_stringbuf_create("", pool); + err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool); + + if (err != SVN_NO_ERROR) + { + /* Add the filename to the error stack. */ + err = svn_error_createf(err->apr_err, err, + "Error while parsing config file: %s:", + svn_dirent_local_style(file, scratch_pool)); + } + + /* Close the streams (and other cleanup): */ + svn_pool_destroy(scratch_pool); + + return err; +} + +svn_error_t * +svn_config__parse_stream(svn_config_t *cfg, svn_stream_t *stream, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) +{ + parse_context_t *ctx; + int ch, count; + + ctx = apr_palloc(scratch_pool, sizeof(*ctx)); + + ctx->cfg = cfg; + ctx->stream = stream; + ctx->line = 1; + ctx->ungotten_char = EOF; + ctx->section = svn_stringbuf_create_empty(scratch_pool); + ctx->option = svn_stringbuf_create_empty(scratch_pool); + ctx->value = svn_stringbuf_create_empty(scratch_pool); + ctx->buffer_pos = 0; + ctx->buffer_size = 0; + + SVN_ERR(skip_bom(ctx)); do { - SVN_ERR(skip_whitespace(&ctx, &ch, &count)); + SVN_ERR(skip_whitespace(ctx, &ch, &count)); switch (ch) { case '[': /* Start of section header */ if (count == 0) - SVN_ERR(parse_section_name(&ch, &ctx, pool)); + SVN_ERR(parse_section_name(&ch, ctx, scratch_pool)); else return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, - "%s:%d: Section header" + "line %d: Section header" " must start in the first column", - svn_dirent_local_style(file, pool), - ctx.line); + ctx->line); break; case '#': /* Comment */ if (count == 0) { - SVN_ERR(skip_to_eoln(&ctx, &ch)); - ++ctx.line; + SVN_ERR(skip_to_eoln(ctx, &ch)); + ++(ctx->line); } else return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, - "%s:%d: Comment" + "line %d: Comment" " must start in the first column", - svn_dirent_local_style(file, pool), - ctx.line); + ctx->line); break; case '\n': /* Empty line */ - ++ctx.line; + ++(ctx->line); break; case EOF: /* End of file or read error */ break; default: - if (svn_stringbuf_isempty(ctx.section)) + if (svn_stringbuf_isempty(ctx->section)) return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, - "%s:%d: Section header expected", - svn_dirent_local_style(file, pool), - ctx.line); + "line %d: Section header expected", + ctx->line); else if (count != 0) return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, - "%s:%d: Option expected", - svn_dirent_local_style(file, pool), - ctx.line); + "line %d: Option expected", + ctx->line); else - SVN_ERR(parse_option(&ch, &ctx, pool)); + SVN_ERR(parse_option(&ch, ctx, scratch_pool)); break; } } while (ch != EOF); - /* Close the streams (and other cleanup): */ - return svn_stream_close(ctx.stream); + return SVN_NO_ERROR; } @@ -748,10 +831,12 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### http-timeout Timeout for HTTP requests in seconds" NL "### http-compression Whether to compress HTTP requests" NL + "### http-max-connections Maximum number of parallel server" NL + "### connections to use for any given" NL + "### HTTP operation." NL + "### http-chunked-requests Whether to use chunked transfer" NL + "### encoding for HTTP requests body." NL "### neon-debug-mask Debug mask for Neon HTTP library" NL -#ifdef SVN_NEON_0_26 - "### http-auth-types Auth types to use for HTTP library"NL -#endif "### ssl-authority-files List of files, each of a trusted CA" NL "### ssl-trust-default-ca Trust the system 'default' CAs" NL @@ -761,37 +846,42 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### ssl-pkcs11-provider Name of PKCS#11 provider to use." NL "### http-library Which library to use for http/https" NL - "### connections (neon or serf)" NL + "### connections." NL + "### http-bulk-updates Whether to request bulk update" NL + "### responses or to fetch each file" NL + "### in an individual request. " NL "### store-passwords Specifies whether passwords used" NL "### to authenticate against a" NL "### Subversion server may be cached" NL "### to disk in any way." NL +#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE "### store-plaintext-passwords Specifies whether passwords may" NL "### be cached on disk unencrypted." NL +#endif "### store-ssl-client-cert-pp Specifies whether passphrase used" NL "### to authenticate against a client" NL "### certificate may be cached to disk" NL "### in any way" NL +#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE "### store-ssl-client-cert-pp-plaintext" NL "### Specifies whether client cert" NL "### passphrases may be cached on disk" NL "### unencrypted (i.e., as plaintext)." NL +#endif "### store-auth-creds Specifies whether any auth info" NL - "### (passwords as well as server certs)" - NL + "### (passwords, server certs, etc.)" NL "### may be cached to disk." NL "### username Specifies the default username." NL "###" NL "### Set store-passwords to 'no' to avoid storing passwords on disk" NL - "### in any way, including in password stores. It defaults to 'yes'," - NL - "### but Subversion will never save your password to disk in plaintext" - NL - "### unless you tell it to." NL + "### in any way, including in password stores. It defaults to" NL + "### 'yes', but Subversion will never save your password to disk in" NL + "### plaintext unless explicitly configured to do so." NL "### Note that this option only prevents saving of *new* passwords;" NL "### it doesn't invalidate existing passwords. (To do that, remove" NL "### the cache files by hand as described in the Subversion book.)" NL "###" NL +#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE "### Set store-plaintext-passwords to 'no' to avoid storing" NL "### passwords in unencrypted form in the auth/ area of your config" NL "### directory. Set it to 'yes' to allow Subversion to store" NL @@ -801,11 +891,12 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### this option has no effect if either 'store-passwords' or " NL "### 'store-auth-creds' is set to 'no'." NL "###" NL +#endif "### Set store-ssl-client-cert-pp to 'no' to avoid storing ssl" NL "### client certificate passphrases in the auth/ area of your" NL "### config directory. It defaults to 'yes', but Subversion will" NL - "### never save your passphrase to disk in plaintext unless you tell"NL - "### it to via 'store-ssl-client-cert-pp-plaintext' (see below)." NL + "### never save your passphrase to disk in plaintext unless" NL + "### explicitly configured to do so." NL "###" NL "### Note store-ssl-client-cert-pp only prevents the saving of *new*"NL "### passphrases; it doesn't invalidate existing passphrases. To do"NL @@ -814,6 +905,7 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### svn.serverconfig.netmodel.html\\" NL "### #svn.serverconfig.netmodel.credcache" NL "###" NL +#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE "### Set store-ssl-client-cert-pp-plaintext to 'no' to avoid storing"NL "### passphrases in unencrypted form in the auth/ area of your" NL "### config directory. Set it to 'yes' to allow Subversion to" NL @@ -823,6 +915,7 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### this option has no effect if either 'store-auth-creds' or " NL "### 'store-ssl-client-cert-pp' is set to 'no'." NL "###" NL +#endif "### Set store-auth-creds to 'no' to avoid storing any Subversion" NL "### credentials in the auth/ area of your config directory." NL "### Note that this includes SSL server certificates." NL @@ -833,6 +926,13 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### HTTP timeouts, if given, are specified in seconds. A timeout" NL "### of 0, i.e. zero, causes a builtin default to be used." NL "###" NL + "### Most users will not need to explicitly set the http-library" NL + "### option, but valid values for the option include:" NL + "### 'serf': Serf-based module (Subversion 1.5 - present)" NL + "### 'neon': Neon-based module (Subversion 1.0 - 1.7)" NL + "### Availability of these modules may depend on your specific" NL + "### Subversion distribution." NL + "###" NL "### The commented-out examples below are intended only to" NL "### demonstrate how to use this file; any resemblance to actual" NL "### servers, living or dead, is entirely coincidental." NL @@ -854,11 +954,10 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "# http-proxy-username = blah" NL "# http-proxy-password = doubleblah" NL "# http-timeout = 60" NL -#ifdef SVN_NEON_0_26 - "# http-auth-types = basic;digest;negotiate" NL -#endif "# neon-debug-mask = 130" NL +#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE "# store-plaintext-passwords = no" NL +#endif "# username = harry" NL "" NL "### Information for the second group:" NL @@ -895,18 +994,18 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "# http-proxy-username = defaultusername" NL "# http-proxy-password = defaultpassword" NL "# http-compression = no" NL -#ifdef SVN_NEON_0_26 - "# http-auth-types = basic;digest;negotiate" NL -#endif "# No http-timeout, so just use the builtin default." NL "# No neon-debug-mask, so neon debugging is disabled." NL "# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem" NL "#" NL "# Password / passphrase caching parameters:" NL "# store-passwords = no" NL - "# store-plaintext-passwords = no" NL "# store-ssl-client-cert-pp = no" NL - "# store-ssl-client-cert-pp-plaintext = no" NL; +#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE + "# store-plaintext-passwords = no" NL + "# store-ssl-client-cert-pp-plaintext = no" NL +#endif + ; err = svn_io_file_open(&f, path, (APR_WRITE | APR_CREATE | APR_EXCL), @@ -954,6 +1053,7 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### Valid password stores:" NL "### gnome-keyring (Unix-like systems)" NL "### kwallet (Unix-like systems)" NL + "### gpg-agent (Unix-like systems)" NL "### keychain (Mac OS X)" NL "### windows-cryptoapi (Windows)" NL #ifdef SVN_HAVE_KEYCHAIN_SERVICES @@ -961,7 +1061,7 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) #elif defined(WIN32) && !defined(__MINGW32__) "# password-stores = windows-cryptoapi" NL #else - "# password-stores = gnome-keyring,kwallet" NL + "# password-stores = gpg-agent,gnome-keyring,kwallet" NL #endif "### To disable all password stores, use an empty list:" NL "# password-stores =" NL @@ -976,6 +1076,13 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "# kwallet-svn-application-name-with-pid = yes" NL #endif "###" NL + "### Set ssl-client-cert-file-prompt to 'yes' to cause the client" NL + "### to prompt for a path to a client cert file when the server" NL + "### requests a client cert but no client cert file is found in the" NL + "### expected place (see the 'ssl-client-cert-file' option in the" NL + "### 'servers' configuration file). Defaults to 'no'." NL + "# ssl-client-cert-file-prompt = no" NL + "###" NL "### The rest of the [auth] section in this file has been deprecated." NL "### Both 'store-passwords' and 'store-auth-creds' can now be" NL @@ -1038,7 +1145,7 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "### path separator. A single backslash will be treated as an" NL "### escape for the following character." NL "" NL - "### Section for configuring miscelleneous Subversion options." NL + "### Section for configuring miscellaneous Subversion options." NL "[miscellany]" NL "### Set global-ignores to a set of whitespace-delimited globs" NL "### which Subversion will ignore in its 'status' output, and" NL @@ -1095,7 +1202,22 @@ svn_config_ensure(const char *config_dir, apr_pool_t *pool) "# *.png = svn:mime-type=image/png" NL "# *.jpg = svn:mime-type=image/jpeg" NL "# Makefile = svn:eol-style=native" NL - "" NL; + "" NL + "### Section for configuring working copies." NL + "[working-copy]" NL + "### Set to a list of the names of specific clients that should use" NL + "### exclusive SQLite locking of working copies. This increases the"NL + "### performance of the client but prevents concurrent access by" NL + "### other clients. Third-party clients may also support this" NL + "### option." NL + "### Possible values:" NL + "### svn (the command line client)" NL + "# exclusive-locking-clients =" NL + "### Set to true to enable exclusive SQLite locking of working" NL + "### copies by all clients using the 1.8 APIs. Enabling this may" NL + "### cause some clients to fail to work properly. This does not have"NL + "### to be set for exclusive-locking-clients to work." NL + "# exclusive-locking = false" NL; err = svn_io_file_open(&f, path, (APR_WRITE | APR_CREATE | APR_EXCL), |