summaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr/config_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_subr/config_file.c')
-rw-r--r--subversion/libsvn_subr/config_file.c302
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),