1251881Speter/* 2251881Speter * config_file.c : parsing configuration files 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26251881Speter#include <apr_lib.h> 27251881Speter#include <apr_env.h> 28251881Speter#include "config_impl.h" 29251881Speter#include "svn_io.h" 30251881Speter#include "svn_types.h" 31251881Speter#include "svn_dirent_uri.h" 32251881Speter#include "svn_auth.h" 33251881Speter#include "svn_subst.h" 34251881Speter#include "svn_utf.h" 35251881Speter#include "svn_pools.h" 36251881Speter#include "svn_user.h" 37251881Speter#include "svn_ctype.h" 38251881Speter 39251881Speter#include "svn_private_config.h" 40251881Speter 41251881Speter#ifdef __HAIKU__ 42251881Speter# include <FindDirectory.h> 43251881Speter# include <StorageDefs.h> 44251881Speter#endif 45251881Speter 46251881Speter/* Used to terminate lines in large multi-line string literals. */ 47251881Speter#define NL APR_EOL_STR 48251881Speter 49251881Speter 50251881Speter/* File parsing context */ 51251881Spetertypedef struct parse_context_t 52251881Speter{ 53251881Speter /* This config struct */ 54251881Speter svn_config_t *cfg; 55251881Speter 56251881Speter /* The stream struct */ 57251881Speter svn_stream_t *stream; 58251881Speter 59251881Speter /* The current line in the file */ 60251881Speter int line; 61251881Speter 62251881Speter /* Emulate an ungetc */ 63251881Speter int ungotten_char; 64251881Speter 65251881Speter /* Temporary strings */ 66251881Speter svn_stringbuf_t *section; 67251881Speter svn_stringbuf_t *option; 68251881Speter svn_stringbuf_t *value; 69251881Speter 70251881Speter /* Parser buffer for getc() to avoid call overhead into several libraries 71251881Speter for every character */ 72251881Speter char parser_buffer[SVN_STREAM_CHUNK_SIZE]; /* Larger than most config files */ 73251881Speter size_t buffer_pos; /* Current position within parser_buffer */ 74251881Speter size_t buffer_size; /* parser_buffer contains this many bytes */ 75251881Speter} parse_context_t; 76251881Speter 77251881Speter 78251881Speter 79251881Speter/* Emulate getc() because streams don't support it. 80251881Speter * 81251881Speter * In order to be able to ungetc(), use the CXT instead of the stream 82251881Speter * to be able to store the 'ungotton' character. 83251881Speter * 84251881Speter */ 85251881Speterstatic APR_INLINE svn_error_t * 86251881Speterparser_getc(parse_context_t *ctx, int *c) 87251881Speter{ 88251881Speter do 89251881Speter { 90251881Speter if (ctx->ungotten_char != EOF) 91251881Speter { 92251881Speter *c = ctx->ungotten_char; 93251881Speter ctx->ungotten_char = EOF; 94251881Speter } 95251881Speter else if (ctx->buffer_pos < ctx->buffer_size) 96251881Speter { 97253734Speter *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos]; 98251881Speter ctx->buffer_pos++; 99251881Speter } 100251881Speter else 101251881Speter { 102251881Speter ctx->buffer_pos = 0; 103251881Speter ctx->buffer_size = sizeof(ctx->parser_buffer); 104251881Speter 105251881Speter SVN_ERR(svn_stream_read(ctx->stream, ctx->parser_buffer, 106251881Speter &(ctx->buffer_size))); 107251881Speter 108251881Speter if (ctx->buffer_pos < ctx->buffer_size) 109251881Speter { 110253734Speter *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos]; 111251881Speter ctx->buffer_pos++; 112251881Speter } 113251881Speter else 114251881Speter *c = EOF; 115251881Speter } 116251881Speter } 117251881Speter while (*c == '\r'); 118251881Speter 119251881Speter return SVN_NO_ERROR; 120251881Speter} 121251881Speter 122251881Speter/* Simplified version of parser_getc() to be used inside skipping loops. 123251881Speter * It will not check for 'ungotton' chars and may or may not ignore '\r'. 124251881Speter * 125251881Speter * In a 'while(cond) getc();' loop, the first iteration must call 126251881Speter * parser_getc to handle all the special cases. Later iterations should 127251881Speter * use parser_getc_plain for maximum performance. 128251881Speter */ 129251881Speterstatic APR_INLINE svn_error_t * 130251881Speterparser_getc_plain(parse_context_t *ctx, int *c) 131251881Speter{ 132251881Speter if (ctx->buffer_pos < ctx->buffer_size) 133251881Speter { 134253734Speter *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos]; 135251881Speter ctx->buffer_pos++; 136251881Speter 137251881Speter return SVN_NO_ERROR; 138251881Speter } 139251881Speter 140251881Speter return parser_getc(ctx, c); 141251881Speter} 142251881Speter 143251881Speter/* Emulate ungetc() because streams don't support it. 144251881Speter * 145251881Speter * Use CTX to store the ungotten character C. 146251881Speter */ 147251881Speterstatic APR_INLINE svn_error_t * 148251881Speterparser_ungetc(parse_context_t *ctx, int c) 149251881Speter{ 150251881Speter ctx->ungotten_char = c; 151251881Speter 152251881Speter return SVN_NO_ERROR; 153251881Speter} 154251881Speter 155251881Speter/* Eat chars from STREAM until encounter non-whitespace, newline, or EOF. 156251881Speter Set *PCOUNT to the number of characters eaten, not counting the 157251881Speter last one, and return the last char read (the one that caused the 158251881Speter break). */ 159251881Speterstatic APR_INLINE svn_error_t * 160251881Speterskip_whitespace(parse_context_t *ctx, int *c, int *pcount) 161251881Speter{ 162251881Speter int ch = 0; 163251881Speter int count = 0; 164251881Speter 165251881Speter SVN_ERR(parser_getc(ctx, &ch)); 166251881Speter while (svn_ctype_isspace(ch) && ch != '\n' && ch != EOF) 167251881Speter { 168251881Speter ++count; 169251881Speter SVN_ERR(parser_getc_plain(ctx, &ch)); 170251881Speter } 171251881Speter *pcount = count; 172251881Speter *c = ch; 173251881Speter return SVN_NO_ERROR; 174251881Speter} 175251881Speter 176251881Speter 177251881Speter/* Skip to the end of the line (or file). Returns the char that ended 178251881Speter the line; the char is either EOF or newline. */ 179251881Speterstatic APR_INLINE svn_error_t * 180251881Speterskip_to_eoln(parse_context_t *ctx, int *c) 181251881Speter{ 182251881Speter int ch; 183251881Speter 184251881Speter SVN_ERR(parser_getc(ctx, &ch)); 185251881Speter while (ch != '\n' && ch != EOF) 186251881Speter SVN_ERR(parser_getc_plain(ctx, &ch)); 187251881Speter 188251881Speter *c = ch; 189251881Speter return SVN_NO_ERROR; 190251881Speter} 191251881Speter 192253734Speter/* Skip a UTF-8 Byte Order Mark if found. */ 193253734Speterstatic APR_INLINE svn_error_t * 194253734Speterskip_bom(parse_context_t *ctx) 195253734Speter{ 196253734Speter int ch; 197251881Speter 198253734Speter SVN_ERR(parser_getc(ctx, &ch)); 199253734Speter if (ch == 0xEF) 200253734Speter { 201253734Speter const unsigned char *buf = (unsigned char *)ctx->parser_buffer; 202253734Speter /* This makes assumptions about the implementation of parser_getc and 203253734Speter * the use of skip_bom. Specifically that parser_getc() will get all 204253734Speter * of the BOM characters into the parse_context_t buffer. This can 205253734Speter * safely be assumed as long as we only try to use skip_bom() at the 206253734Speter * start of the stream and the buffer is longer than 3 characters. */ 207253734Speter SVN_ERR_ASSERT(ctx->buffer_size > ctx->buffer_pos + 1); 208253734Speter if (buf[ctx->buffer_pos] == 0xBB && buf[ctx->buffer_pos + 1] == 0xBF) 209253734Speter ctx->buffer_pos += 2; 210253734Speter else 211253734Speter SVN_ERR(parser_ungetc(ctx, ch)); 212253734Speter } 213253734Speter else 214253734Speter SVN_ERR(parser_ungetc(ctx, ch)); 215253734Speter 216253734Speter return SVN_NO_ERROR; 217253734Speter} 218253734Speter 219251881Speter/* Parse a single option value */ 220251881Speterstatic svn_error_t * 221251881Speterparse_value(int *pch, parse_context_t *ctx) 222251881Speter{ 223251881Speter svn_boolean_t end_of_val = FALSE; 224251881Speter int ch; 225251881Speter 226251881Speter /* Read the first line of the value */ 227251881Speter svn_stringbuf_setempty(ctx->value); 228251881Speter SVN_ERR(parser_getc(ctx, &ch)); 229251881Speter while (ch != EOF && ch != '\n') 230251881Speter /* last ch seen was ':' or '=' in parse_option. */ 231251881Speter { 232251881Speter const char char_from_int = (char)ch; 233251881Speter svn_stringbuf_appendbyte(ctx->value, char_from_int); 234251881Speter SVN_ERR(parser_getc(ctx, &ch)); 235251881Speter } 236251881Speter /* Leading and trailing whitespace is ignored. */ 237251881Speter svn_stringbuf_strip_whitespace(ctx->value); 238251881Speter 239251881Speter /* Look for any continuation lines. */ 240251881Speter for (;;) 241251881Speter { 242251881Speter 243251881Speter if (ch == EOF || end_of_val) 244251881Speter { 245251881Speter /* At end of file. The value is complete, there can't be 246251881Speter any continuation lines. */ 247251881Speter svn_config_set(ctx->cfg, ctx->section->data, 248251881Speter ctx->option->data, ctx->value->data); 249251881Speter break; 250251881Speter } 251251881Speter else 252251881Speter { 253251881Speter int count; 254251881Speter ++ctx->line; 255251881Speter SVN_ERR(skip_whitespace(ctx, &ch, &count)); 256251881Speter 257251881Speter switch (ch) 258251881Speter { 259251881Speter case '\n': 260251881Speter /* The next line was empty. Ergo, it can't be a 261251881Speter continuation line. */ 262251881Speter ++ctx->line; 263251881Speter end_of_val = TRUE; 264251881Speter continue; 265251881Speter 266251881Speter case EOF: 267251881Speter /* This is also an empty line. */ 268251881Speter end_of_val = TRUE; 269251881Speter continue; 270251881Speter 271251881Speter default: 272251881Speter if (count == 0) 273251881Speter { 274251881Speter /* This line starts in the first column. That means 275251881Speter it's either a section, option or comment. Put 276251881Speter the char back into the stream, because it doesn't 277251881Speter belong to us. */ 278251881Speter SVN_ERR(parser_ungetc(ctx, ch)); 279251881Speter end_of_val = TRUE; 280251881Speter } 281251881Speter else 282251881Speter { 283251881Speter /* This is a continuation line. Read it. */ 284251881Speter svn_stringbuf_appendbyte(ctx->value, ' '); 285251881Speter 286251881Speter while (ch != EOF && ch != '\n') 287251881Speter { 288251881Speter const char char_from_int = (char)ch; 289251881Speter svn_stringbuf_appendbyte(ctx->value, char_from_int); 290251881Speter SVN_ERR(parser_getc(ctx, &ch)); 291251881Speter } 292251881Speter /* Trailing whitespace is ignored. */ 293251881Speter svn_stringbuf_strip_whitespace(ctx->value); 294251881Speter } 295251881Speter } 296251881Speter } 297251881Speter } 298251881Speter 299251881Speter *pch = ch; 300251881Speter return SVN_NO_ERROR; 301251881Speter} 302251881Speter 303251881Speter 304251881Speter/* Parse a single option */ 305251881Speterstatic svn_error_t * 306251881Speterparse_option(int *pch, parse_context_t *ctx, apr_pool_t *scratch_pool) 307251881Speter{ 308251881Speter svn_error_t *err = SVN_NO_ERROR; 309251881Speter int ch; 310251881Speter 311251881Speter svn_stringbuf_setempty(ctx->option); 312251881Speter ch = *pch; /* Yes, the first char is relevant. */ 313251881Speter while (ch != EOF && ch != ':' && ch != '=' && ch != '\n') 314251881Speter { 315251881Speter const char char_from_int = (char)ch; 316251881Speter svn_stringbuf_appendbyte(ctx->option, char_from_int); 317251881Speter SVN_ERR(parser_getc(ctx, &ch)); 318251881Speter } 319251881Speter 320251881Speter if (ch != ':' && ch != '=') 321251881Speter { 322251881Speter ch = EOF; 323251881Speter err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, 324251881Speter "line %d: Option must end with ':' or '='", 325251881Speter ctx->line); 326251881Speter } 327251881Speter else 328251881Speter { 329251881Speter /* Whitespace around the name separator is ignored. */ 330251881Speter svn_stringbuf_strip_whitespace(ctx->option); 331251881Speter err = parse_value(&ch, ctx); 332251881Speter } 333251881Speter 334251881Speter *pch = ch; 335251881Speter return err; 336251881Speter} 337251881Speter 338251881Speter 339251881Speter/* Read chars until enounter ']', then skip everything to the end of 340251881Speter * the line. Set *PCH to the character that ended the line (either 341251881Speter * newline or EOF), and set CTX->section to the string of characters 342251881Speter * seen before ']'. 343251881Speter * 344251881Speter * This is meant to be called immediately after reading the '[' that 345251881Speter * starts a section name. 346251881Speter */ 347251881Speterstatic svn_error_t * 348251881Speterparse_section_name(int *pch, parse_context_t *ctx, 349251881Speter apr_pool_t *scratch_pool) 350251881Speter{ 351251881Speter svn_error_t *err = SVN_NO_ERROR; 352251881Speter int ch; 353251881Speter 354251881Speter svn_stringbuf_setempty(ctx->section); 355251881Speter SVN_ERR(parser_getc(ctx, &ch)); 356251881Speter while (ch != EOF && ch != ']' && ch != '\n') 357251881Speter { 358251881Speter const char char_from_int = (char)ch; 359251881Speter svn_stringbuf_appendbyte(ctx->section, char_from_int); 360251881Speter SVN_ERR(parser_getc(ctx, &ch)); 361251881Speter } 362251881Speter 363251881Speter if (ch != ']') 364251881Speter { 365251881Speter ch = EOF; 366251881Speter err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, 367251881Speter "line %d: Section header must end with ']'", 368251881Speter ctx->line); 369251881Speter } 370251881Speter else 371251881Speter { 372251881Speter /* Everything from the ']' to the end of the line is ignored. */ 373251881Speter SVN_ERR(skip_to_eoln(ctx, &ch)); 374251881Speter if (ch != EOF) 375251881Speter ++ctx->line; 376251881Speter } 377251881Speter 378251881Speter *pch = ch; 379251881Speter return err; 380251881Speter} 381251881Speter 382251881Speter 383251881Spetersvn_error_t * 384251881Spetersvn_config__sys_config_path(const char **path_p, 385251881Speter const char *fname, 386251881Speter apr_pool_t *pool) 387251881Speter{ 388251881Speter *path_p = NULL; 389251881Speter 390251881Speter /* Note that even if fname is null, svn_dirent_join_many will DTRT. */ 391251881Speter 392251881Speter#ifdef WIN32 393251881Speter { 394251881Speter const char *folder; 395251881Speter SVN_ERR(svn_config__win_config_path(&folder, TRUE, pool)); 396251881Speter *path_p = svn_dirent_join_many(pool, folder, 397251881Speter SVN_CONFIG__SUBDIRECTORY, fname, NULL); 398251881Speter } 399251881Speter 400251881Speter#elif defined(__HAIKU__) 401251881Speter { 402251881Speter char folder[B_PATH_NAME_LENGTH]; 403251881Speter 404251881Speter status_t error = find_directory(B_COMMON_SETTINGS_DIRECTORY, -1, false, 405251881Speter folder, sizeof(folder)); 406251881Speter if (error) 407251881Speter return SVN_NO_ERROR; 408251881Speter 409251881Speter *path_p = svn_dirent_join_many(pool, folder, 410251881Speter SVN_CONFIG__SYS_DIRECTORY, fname, NULL); 411251881Speter } 412251881Speter#else /* ! WIN32 && !__HAIKU__ */ 413251881Speter 414251881Speter *path_p = svn_dirent_join_many(pool, SVN_CONFIG__SYS_DIRECTORY, fname, NULL); 415251881Speter 416251881Speter#endif /* WIN32 */ 417251881Speter 418251881Speter return SVN_NO_ERROR; 419251881Speter} 420251881Speter 421251881Speter 422251881Speter/*** Exported interfaces. ***/ 423251881Speter 424251881Speter 425251881Spetersvn_error_t * 426251881Spetersvn_config__parse_file(svn_config_t *cfg, const char *file, 427251881Speter svn_boolean_t must_exist, apr_pool_t *result_pool) 428251881Speter{ 429251881Speter svn_error_t *err = SVN_NO_ERROR; 430251881Speter svn_stream_t *stream; 431251881Speter apr_pool_t *scratch_pool = svn_pool_create(result_pool); 432251881Speter 433251881Speter err = svn_stream_open_readonly(&stream, file, scratch_pool, scratch_pool); 434251881Speter 435251881Speter if (! must_exist && err && APR_STATUS_IS_ENOENT(err->apr_err)) 436251881Speter { 437251881Speter svn_error_clear(err); 438251881Speter svn_pool_destroy(scratch_pool); 439251881Speter return SVN_NO_ERROR; 440251881Speter } 441251881Speter else 442251881Speter SVN_ERR(err); 443251881Speter 444251881Speter err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool); 445251881Speter 446251881Speter if (err != SVN_NO_ERROR) 447251881Speter { 448251881Speter /* Add the filename to the error stack. */ 449251881Speter err = svn_error_createf(err->apr_err, err, 450251881Speter "Error while parsing config file: %s:", 451251881Speter svn_dirent_local_style(file, scratch_pool)); 452251881Speter } 453251881Speter 454251881Speter /* Close the streams (and other cleanup): */ 455251881Speter svn_pool_destroy(scratch_pool); 456251881Speter 457251881Speter return err; 458251881Speter} 459251881Speter 460251881Spetersvn_error_t * 461251881Spetersvn_config__parse_stream(svn_config_t *cfg, svn_stream_t *stream, 462251881Speter apr_pool_t *result_pool, apr_pool_t *scratch_pool) 463251881Speter{ 464251881Speter parse_context_t *ctx; 465251881Speter int ch, count; 466251881Speter 467251881Speter ctx = apr_palloc(scratch_pool, sizeof(*ctx)); 468251881Speter 469251881Speter ctx->cfg = cfg; 470251881Speter ctx->stream = stream; 471251881Speter ctx->line = 1; 472251881Speter ctx->ungotten_char = EOF; 473251881Speter ctx->section = svn_stringbuf_create_empty(scratch_pool); 474251881Speter ctx->option = svn_stringbuf_create_empty(scratch_pool); 475251881Speter ctx->value = svn_stringbuf_create_empty(scratch_pool); 476251881Speter ctx->buffer_pos = 0; 477251881Speter ctx->buffer_size = 0; 478251881Speter 479253734Speter SVN_ERR(skip_bom(ctx)); 480253734Speter 481251881Speter do 482251881Speter { 483251881Speter SVN_ERR(skip_whitespace(ctx, &ch, &count)); 484251881Speter 485251881Speter switch (ch) 486251881Speter { 487251881Speter case '[': /* Start of section header */ 488251881Speter if (count == 0) 489251881Speter SVN_ERR(parse_section_name(&ch, ctx, scratch_pool)); 490251881Speter else 491251881Speter return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, 492251881Speter "line %d: Section header" 493251881Speter " must start in the first column", 494251881Speter ctx->line); 495251881Speter break; 496251881Speter 497251881Speter case '#': /* Comment */ 498251881Speter if (count == 0) 499251881Speter { 500251881Speter SVN_ERR(skip_to_eoln(ctx, &ch)); 501251881Speter ++(ctx->line); 502251881Speter } 503251881Speter else 504251881Speter return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, 505251881Speter "line %d: Comment" 506251881Speter " must start in the first column", 507251881Speter ctx->line); 508251881Speter break; 509251881Speter 510251881Speter case '\n': /* Empty line */ 511251881Speter ++(ctx->line); 512251881Speter break; 513251881Speter 514251881Speter case EOF: /* End of file or read error */ 515251881Speter break; 516251881Speter 517251881Speter default: 518251881Speter if (svn_stringbuf_isempty(ctx->section)) 519251881Speter return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, 520251881Speter "line %d: Section header expected", 521251881Speter ctx->line); 522251881Speter else if (count != 0) 523251881Speter return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL, 524251881Speter "line %d: Option expected", 525251881Speter ctx->line); 526251881Speter else 527251881Speter SVN_ERR(parse_option(&ch, ctx, scratch_pool)); 528251881Speter break; 529251881Speter } 530251881Speter } 531251881Speter while (ch != EOF); 532251881Speter 533251881Speter return SVN_NO_ERROR; 534251881Speter} 535251881Speter 536251881Speter 537251881Speter/* Helper for ensure_auth_dirs: create SUBDIR under AUTH_DIR, iff 538251881Speter SUBDIR does not already exist, but ignore any errors. Use POOL for 539251881Speter temporary allocation. */ 540251881Speterstatic void 541251881Speterensure_auth_subdir(const char *auth_dir, 542251881Speter const char *subdir, 543251881Speter apr_pool_t *pool) 544251881Speter{ 545251881Speter svn_error_t *err; 546251881Speter const char *subdir_full_path; 547251881Speter svn_node_kind_t kind; 548251881Speter 549251881Speter subdir_full_path = svn_dirent_join(auth_dir, subdir, pool); 550251881Speter err = svn_io_check_path(subdir_full_path, &kind, pool); 551251881Speter if (err || kind == svn_node_none) 552251881Speter { 553251881Speter svn_error_clear(err); 554251881Speter svn_error_clear(svn_io_dir_make(subdir_full_path, APR_OS_DEFAULT, pool)); 555251881Speter } 556251881Speter} 557251881Speter 558251881Speter/* Helper for svn_config_ensure: see if ~/.subversion/auth/ and its 559251881Speter subdirs exist, try to create them, but don't throw errors on 560251881Speter failure. PATH is assumed to be a path to the user's private config 561251881Speter directory. */ 562251881Speterstatic void 563251881Speterensure_auth_dirs(const char *path, 564251881Speter apr_pool_t *pool) 565251881Speter{ 566251881Speter svn_node_kind_t kind; 567251881Speter const char *auth_dir; 568251881Speter svn_error_t *err; 569251881Speter 570251881Speter /* Ensure ~/.subversion/auth/ */ 571251881Speter auth_dir = svn_dirent_join(path, SVN_CONFIG__AUTH_SUBDIR, pool); 572251881Speter err = svn_io_check_path(auth_dir, &kind, pool); 573251881Speter if (err || kind == svn_node_none) 574251881Speter { 575251881Speter svn_error_clear(err); 576251881Speter /* 'chmod 700' permissions: */ 577251881Speter err = svn_io_dir_make(auth_dir, 578251881Speter (APR_UREAD | APR_UWRITE | APR_UEXECUTE), 579251881Speter pool); 580251881Speter if (err) 581251881Speter { 582251881Speter /* Don't try making subdirs if we can't make the top-level dir. */ 583251881Speter svn_error_clear(err); 584251881Speter return; 585251881Speter } 586251881Speter } 587251881Speter 588251881Speter /* If a provider exists that wants to store credentials in 589251881Speter ~/.subversion, a subdirectory for the cred_kind must exist. */ 590251881Speter ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_SIMPLE, pool); 591251881Speter ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_USERNAME, pool); 592251881Speter ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_SSL_SERVER_TRUST, pool); 593251881Speter ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_SSL_CLIENT_CERT_PW, pool); 594251881Speter} 595251881Speter 596251881Speter 597251881Spetersvn_error_t * 598251881Spetersvn_config_ensure(const char *config_dir, apr_pool_t *pool) 599251881Speter{ 600251881Speter const char *path; 601251881Speter svn_node_kind_t kind; 602251881Speter svn_error_t *err; 603251881Speter 604251881Speter /* Ensure that the user-specific config directory exists. */ 605251881Speter SVN_ERR(svn_config_get_user_config_path(&path, config_dir, NULL, pool)); 606251881Speter 607251881Speter if (! path) 608251881Speter return SVN_NO_ERROR; 609251881Speter 610251881Speter err = svn_io_check_resolved_path(path, &kind, pool); 611251881Speter if (err) 612251881Speter { 613251881Speter /* Don't throw an error, but don't continue. */ 614251881Speter svn_error_clear(err); 615251881Speter return SVN_NO_ERROR; 616251881Speter } 617251881Speter 618251881Speter if (kind == svn_node_none) 619251881Speter { 620251881Speter err = svn_io_dir_make(path, APR_OS_DEFAULT, pool); 621251881Speter if (err) 622251881Speter { 623251881Speter /* Don't throw an error, but don't continue. */ 624251881Speter svn_error_clear(err); 625251881Speter return SVN_NO_ERROR; 626251881Speter } 627251881Speter } 628251881Speter else if (kind == svn_node_file) 629251881Speter { 630251881Speter /* Somebody put a file where the config directory should be. 631251881Speter Wacky. Let's bail. */ 632251881Speter return SVN_NO_ERROR; 633251881Speter } 634251881Speter 635251881Speter /* Else, there's a configuration directory. */ 636251881Speter 637251881Speter /* If we get errors trying to do things below, just stop and return 638251881Speter success. There's no _need_ to init a config directory if 639251881Speter something's preventing it. */ 640251881Speter 641251881Speter /** If non-existent, try to create a number of auth/ subdirectories. */ 642251881Speter ensure_auth_dirs(path, pool); 643251881Speter 644251881Speter /** Ensure that the `README.txt' file exists. **/ 645251881Speter SVN_ERR(svn_config_get_user_config_path 646251881Speter (&path, config_dir, SVN_CONFIG__USR_README_FILE, pool)); 647251881Speter 648251881Speter if (! path) /* highly unlikely, since a previous call succeeded */ 649251881Speter return SVN_NO_ERROR; 650251881Speter 651251881Speter err = svn_io_check_path(path, &kind, pool); 652251881Speter if (err) 653251881Speter { 654251881Speter svn_error_clear(err); 655251881Speter return SVN_NO_ERROR; 656251881Speter } 657251881Speter 658251881Speter if (kind == svn_node_none) 659251881Speter { 660251881Speter apr_file_t *f; 661251881Speter const char *contents = 662251881Speter "This directory holds run-time configuration information for Subversion" NL 663251881Speter "clients. The configuration files all share the same syntax, but you" NL 664251881Speter "should examine a particular file to learn what configuration" NL 665251881Speter "directives are valid for that file." NL 666251881Speter "" NL 667251881Speter "The syntax is standard INI format:" NL 668251881Speter "" NL 669251881Speter " - Empty lines, and lines starting with '#', are ignored." NL 670251881Speter " The first significant line in a file must be a section header." NL 671251881Speter "" NL 672251881Speter " - A section starts with a section header, which must start in" NL 673251881Speter " the first column:" NL 674251881Speter "" NL 675251881Speter " [section-name]" NL 676251881Speter "" NL 677251881Speter " - An option, which must always appear within a section, is a pair" NL 678251881Speter " (name, value). There are two valid forms for defining an" NL 679251881Speter " option, both of which must start in the first column:" NL 680251881Speter "" NL 681251881Speter " name: value" NL 682251881Speter " name = value" NL 683251881Speter "" NL 684251881Speter " Whitespace around the separator (:, =) is optional." NL 685251881Speter "" NL 686251881Speter " - Section and option names are case-insensitive, but case is" NL 687251881Speter " preserved." NL 688251881Speter "" NL 689251881Speter " - An option's value may be broken into several lines. The value" NL 690251881Speter " continuation lines must start with at least one whitespace." NL 691251881Speter " Trailing whitespace in the previous line, the newline character" NL 692251881Speter " and the leading whitespace in the continuation line is compressed" NL 693251881Speter " into a single space character." NL 694251881Speter "" NL 695251881Speter " - All leading and trailing whitespace around a value is trimmed," NL 696251881Speter " but the whitespace within a value is preserved, with the" NL 697251881Speter " exception of whitespace around line continuations, as" NL 698251881Speter " described above." NL 699251881Speter "" NL 700251881Speter " - When a value is a boolean, any of the following strings are" NL 701251881Speter " recognised as truth values (case does not matter):" NL 702251881Speter "" NL 703251881Speter " true false" NL 704251881Speter " yes no" NL 705251881Speter " on off" NL 706251881Speter " 1 0" NL 707251881Speter "" NL 708251881Speter " - When a value is a list, it is comma-separated. Again, the" NL 709251881Speter " whitespace around each element of the list is trimmed." NL 710251881Speter "" NL 711251881Speter " - Option values may be expanded within a value by enclosing the" NL 712251881Speter " option name in parentheses, preceded by a percent sign and" NL 713251881Speter " followed by an 's':" NL 714251881Speter "" NL 715251881Speter " %(name)s" NL 716251881Speter "" NL 717251881Speter " The expansion is performed recursively and on demand, during" NL 718251881Speter " svn_option_get. The name is first searched for in the same" NL 719251881Speter " section, then in the special [DEFAULT] section. If the name" NL 720251881Speter " is not found, the whole '%(name)s' placeholder is left" NL 721251881Speter " unchanged." NL 722251881Speter "" NL 723251881Speter " Any modifications to the configuration data invalidate all" NL 724251881Speter " previously expanded values, so that the next svn_option_get" NL 725251881Speter " will take the modifications into account." NL 726251881Speter "" NL 727251881Speter "The syntax of the configuration files is a subset of the one used by" NL 728251881Speter "Python's ConfigParser module; see" NL 729251881Speter "" NL 730251881Speter " http://www.python.org/doc/current/lib/module-ConfigParser.html" NL 731251881Speter "" NL 732251881Speter "Configuration data in the Windows registry" NL 733251881Speter "==========================================" NL 734251881Speter "" NL 735251881Speter "On Windows, configuration data may also be stored in the registry. The" NL 736251881Speter "functions svn_config_read and svn_config_merge will read from the" NL 737251881Speter "registry when passed file names of the form:" NL 738251881Speter "" NL 739251881Speter " REGISTRY:<hive>/path/to/config-key" NL 740251881Speter "" NL 741251881Speter "The REGISTRY: prefix must be in upper case. The <hive> part must be" NL 742251881Speter "one of:" NL 743251881Speter "" NL 744251881Speter " HKLM for HKEY_LOCAL_MACHINE" NL 745251881Speter " HKCU for HKEY_CURRENT_USER" NL 746251881Speter "" NL 747251881Speter "The values in config-key represent the options in the [DEFAULT] section."NL 748251881Speter "The keys below config-key represent other sections, and their values" NL 749251881Speter "represent the options. Only values of type REG_SZ whose name doesn't" NL 750251881Speter "start with a '#' will be used; other values, as well as the keys'" NL 751251881Speter "default values, will be ignored." NL 752251881Speter "" NL 753251881Speter "" NL 754251881Speter "File locations" NL 755251881Speter "==============" NL 756251881Speter "" NL 757251881Speter "Typically, Subversion uses two config directories, one for site-wide" NL 758251881Speter "configuration," NL 759251881Speter "" NL 760251881Speter " Unix:" NL 761251881Speter " /etc/subversion/servers" NL 762251881Speter " /etc/subversion/config" NL 763251881Speter " /etc/subversion/hairstyles" NL 764251881Speter " Windows:" NL 765251881Speter " %ALLUSERSPROFILE%\\Application Data\\Subversion\\servers" NL 766251881Speter " %ALLUSERSPROFILE%\\Application Data\\Subversion\\config" NL 767251881Speter " %ALLUSERSPROFILE%\\Application Data\\Subversion\\hairstyles" NL 768251881Speter " REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Servers" NL 769251881Speter " REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Config" NL 770251881Speter " REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Hairstyles" NL 771251881Speter "" NL 772251881Speter "and one for per-user configuration:" NL 773251881Speter "" NL 774251881Speter " Unix:" NL 775251881Speter " ~/.subversion/servers" NL 776251881Speter " ~/.subversion/config" NL 777251881Speter " ~/.subversion/hairstyles" NL 778251881Speter " Windows:" NL 779251881Speter " %APPDATA%\\Subversion\\servers" NL 780251881Speter " %APPDATA%\\Subversion\\config" NL 781251881Speter " %APPDATA%\\Subversion\\hairstyles" NL 782251881Speter " REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Servers" NL 783251881Speter " REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Config" NL 784251881Speter " REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Hairstyles" NL 785251881Speter "" NL; 786251881Speter 787251881Speter err = svn_io_file_open(&f, path, 788251881Speter (APR_WRITE | APR_CREATE | APR_EXCL), 789251881Speter APR_OS_DEFAULT, 790251881Speter pool); 791251881Speter 792251881Speter if (! err) 793251881Speter { 794251881Speter SVN_ERR(svn_io_file_write_full(f, contents, 795251881Speter strlen(contents), NULL, pool)); 796251881Speter SVN_ERR(svn_io_file_close(f, pool)); 797251881Speter } 798251881Speter 799251881Speter svn_error_clear(err); 800251881Speter } 801251881Speter 802251881Speter /** Ensure that the `servers' file exists. **/ 803251881Speter SVN_ERR(svn_config_get_user_config_path 804251881Speter (&path, config_dir, SVN_CONFIG_CATEGORY_SERVERS, pool)); 805251881Speter 806251881Speter if (! path) /* highly unlikely, since a previous call succeeded */ 807251881Speter return SVN_NO_ERROR; 808251881Speter 809251881Speter err = svn_io_check_path(path, &kind, pool); 810251881Speter if (err) 811251881Speter { 812251881Speter svn_error_clear(err); 813251881Speter return SVN_NO_ERROR; 814251881Speter } 815251881Speter 816251881Speter if (kind == svn_node_none) 817251881Speter { 818251881Speter apr_file_t *f; 819251881Speter const char *contents = 820251881Speter "### This file specifies server-specific parameters," NL 821251881Speter "### including HTTP proxy information, HTTP timeout settings," NL 822251881Speter "### and authentication settings." NL 823251881Speter "###" NL 824251881Speter "### The currently defined server options are:" NL 825251881Speter "### http-proxy-host Proxy host for HTTP connection" NL 826251881Speter "### http-proxy-port Port number of proxy host service" NL 827251881Speter "### http-proxy-username Username for auth to proxy service"NL 828251881Speter "### http-proxy-password Password for auth to proxy service"NL 829251881Speter "### http-proxy-exceptions List of sites that do not use proxy" 830251881Speter NL 831251881Speter "### http-timeout Timeout for HTTP requests in seconds" 832251881Speter NL 833251881Speter "### http-compression Whether to compress HTTP requests" NL 834251881Speter "### http-max-connections Maximum number of parallel server" NL 835251881Speter "### connections to use for any given" NL 836251881Speter "### HTTP operation." NL 837253734Speter "### http-chunked-requests Whether to use chunked transfer" NL 838253734Speter "### encoding for HTTP requests body." NL 839251881Speter "### neon-debug-mask Debug mask for Neon HTTP library" NL 840251881Speter "### ssl-authority-files List of files, each of a trusted CA" 841251881Speter NL 842251881Speter "### ssl-trust-default-ca Trust the system 'default' CAs" NL 843251881Speter "### ssl-client-cert-file PKCS#12 format client certificate file" 844251881Speter NL 845251881Speter "### ssl-client-cert-password Client Key password, if needed." NL 846251881Speter "### ssl-pkcs11-provider Name of PKCS#11 provider to use." NL 847251881Speter "### http-library Which library to use for http/https" 848251881Speter NL 849251881Speter "### connections." NL 850251881Speter "### http-bulk-updates Whether to request bulk update" NL 851251881Speter "### responses or to fetch each file" NL 852251881Speter "### in an individual request. " NL 853251881Speter "### store-passwords Specifies whether passwords used" NL 854251881Speter "### to authenticate against a" NL 855251881Speter "### Subversion server may be cached" NL 856251881Speter "### to disk in any way." NL 857251881Speter#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE 858251881Speter "### store-plaintext-passwords Specifies whether passwords may" NL 859251881Speter "### be cached on disk unencrypted." NL 860251881Speter#endif 861251881Speter "### store-ssl-client-cert-pp Specifies whether passphrase used" NL 862251881Speter "### to authenticate against a client" NL 863251881Speter "### certificate may be cached to disk" NL 864251881Speter "### in any way" NL 865251881Speter#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE 866251881Speter "### store-ssl-client-cert-pp-plaintext" NL 867251881Speter "### Specifies whether client cert" NL 868251881Speter "### passphrases may be cached on disk" NL 869251881Speter "### unencrypted (i.e., as plaintext)." NL 870251881Speter#endif 871251881Speter "### store-auth-creds Specifies whether any auth info" NL 872251881Speter "### (passwords, server certs, etc.)" NL 873251881Speter "### may be cached to disk." NL 874251881Speter "### username Specifies the default username." NL 875251881Speter "###" NL 876251881Speter "### Set store-passwords to 'no' to avoid storing passwords on disk" NL 877251881Speter "### in any way, including in password stores. It defaults to" NL 878251881Speter "### 'yes', but Subversion will never save your password to disk in" NL 879251881Speter "### plaintext unless explicitly configured to do so." NL 880251881Speter "### Note that this option only prevents saving of *new* passwords;" NL 881251881Speter "### it doesn't invalidate existing passwords. (To do that, remove" NL 882251881Speter "### the cache files by hand as described in the Subversion book.)" NL 883251881Speter "###" NL 884251881Speter#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE 885251881Speter "### Set store-plaintext-passwords to 'no' to avoid storing" NL 886251881Speter "### passwords in unencrypted form in the auth/ area of your config" NL 887251881Speter "### directory. Set it to 'yes' to allow Subversion to store" NL 888251881Speter "### unencrypted passwords in the auth/ area. The default is" NL 889251881Speter "### 'ask', which means that Subversion will ask you before" NL 890251881Speter "### saving a password to disk in unencrypted form. Note that" NL 891251881Speter "### this option has no effect if either 'store-passwords' or " NL 892251881Speter "### 'store-auth-creds' is set to 'no'." NL 893251881Speter "###" NL 894251881Speter#endif 895251881Speter "### Set store-ssl-client-cert-pp to 'no' to avoid storing ssl" NL 896251881Speter "### client certificate passphrases in the auth/ area of your" NL 897251881Speter "### config directory. It defaults to 'yes', but Subversion will" NL 898251881Speter "### never save your passphrase to disk in plaintext unless" NL 899251881Speter "### explicitly configured to do so." NL 900251881Speter "###" NL 901251881Speter "### Note store-ssl-client-cert-pp only prevents the saving of *new*"NL 902251881Speter "### passphrases; it doesn't invalidate existing passphrases. To do"NL 903251881Speter "### that, remove the cache files by hand as described in the" NL 904251881Speter "### Subversion book at http://svnbook.red-bean.com/nightly/en/\\" NL 905251881Speter "### svn.serverconfig.netmodel.html\\" NL 906251881Speter "### #svn.serverconfig.netmodel.credcache" NL 907251881Speter "###" NL 908251881Speter#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE 909251881Speter "### Set store-ssl-client-cert-pp-plaintext to 'no' to avoid storing"NL 910251881Speter "### passphrases in unencrypted form in the auth/ area of your" NL 911251881Speter "### config directory. Set it to 'yes' to allow Subversion to" NL 912251881Speter "### store unencrypted passphrases in the auth/ area. The default" NL 913251881Speter "### is 'ask', which means that Subversion will prompt before" NL 914251881Speter "### saving a passphrase to disk in unencrypted form. Note that" NL 915251881Speter "### this option has no effect if either 'store-auth-creds' or " NL 916251881Speter "### 'store-ssl-client-cert-pp' is set to 'no'." NL 917251881Speter "###" NL 918251881Speter#endif 919251881Speter "### Set store-auth-creds to 'no' to avoid storing any Subversion" NL 920251881Speter "### credentials in the auth/ area of your config directory." NL 921251881Speter "### Note that this includes SSL server certificates." NL 922251881Speter "### It defaults to 'yes'. Note that this option only prevents" NL 923251881Speter "### saving of *new* credentials; it doesn't invalidate existing" NL 924251881Speter "### caches. (To do that, remove the cache files by hand.)" NL 925251881Speter "###" NL 926251881Speter "### HTTP timeouts, if given, are specified in seconds. A timeout" NL 927251881Speter "### of 0, i.e. zero, causes a builtin default to be used." NL 928251881Speter "###" NL 929251881Speter "### Most users will not need to explicitly set the http-library" NL 930251881Speter "### option, but valid values for the option include:" NL 931251881Speter "### 'serf': Serf-based module (Subversion 1.5 - present)" NL 932251881Speter "### 'neon': Neon-based module (Subversion 1.0 - 1.7)" NL 933251881Speter "### Availability of these modules may depend on your specific" NL 934251881Speter "### Subversion distribution." NL 935251881Speter "###" NL 936251881Speter "### The commented-out examples below are intended only to" NL 937251881Speter "### demonstrate how to use this file; any resemblance to actual" NL 938251881Speter "### servers, living or dead, is entirely coincidental." NL 939251881Speter "" NL 940251881Speter "### In the 'groups' section, the URL of the repository you're" NL 941251881Speter "### trying to access is matched against the patterns on the right." NL 942251881Speter "### If a match is found, the server options are taken from the" NL 943251881Speter "### section with the corresponding name on the left." NL 944251881Speter "" NL 945251881Speter "[groups]" NL 946251881Speter "# group1 = *.collab.net" NL 947251881Speter "# othergroup = repository.blarggitywhoomph.com" NL 948251881Speter "# thirdgroup = *.example.com" NL 949251881Speter "" NL 950251881Speter "### Information for the first group:" NL 951251881Speter "# [group1]" NL 952251881Speter "# http-proxy-host = proxy1.some-domain-name.com" NL 953251881Speter "# http-proxy-port = 80" NL 954251881Speter "# http-proxy-username = blah" NL 955251881Speter "# http-proxy-password = doubleblah" NL 956251881Speter "# http-timeout = 60" NL 957251881Speter "# neon-debug-mask = 130" NL 958251881Speter#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE 959251881Speter "# store-plaintext-passwords = no" NL 960251881Speter#endif 961251881Speter "# username = harry" NL 962251881Speter "" NL 963251881Speter "### Information for the second group:" NL 964251881Speter "# [othergroup]" NL 965251881Speter "# http-proxy-host = proxy2.some-domain-name.com" NL 966251881Speter "# http-proxy-port = 9000" NL 967251881Speter "# No username and password for the proxy, so use the defaults below." 968251881Speter NL 969251881Speter "" NL 970251881Speter "### You can set default parameters in the 'global' section." NL 971251881Speter "### These parameters apply if no corresponding parameter is set in" NL 972251881Speter "### a specifically matched group as shown above. Thus, if you go" NL 973251881Speter "### through the same proxy server to reach every site on the" NL 974251881Speter "### Internet, you probably just want to put that server's" NL 975251881Speter "### information in the 'global' section and not bother with" NL 976251881Speter "### 'groups' or any other sections." NL 977251881Speter "###" NL 978251881Speter "### Most people might want to configure password caching" NL 979251881Speter "### parameters here, but you can also configure them per server" NL 980251881Speter "### group (per-group settings override global settings)." NL 981251881Speter "###" NL 982251881Speter "### If you go through a proxy for all but a few sites, you can" NL 983251881Speter "### list those exceptions under 'http-proxy-exceptions'. This only"NL 984251881Speter "### overrides defaults, not explicitly matched server names." NL 985251881Speter "###" NL 986251881Speter "### 'ssl-authority-files' is a semicolon-delimited list of files," NL 987251881Speter "### each pointing to a PEM-encoded Certificate Authority (CA) " NL 988251881Speter "### SSL certificate. See details above for overriding security " NL 989251881Speter "### due to SSL." NL 990251881Speter "[global]" NL 991251881Speter "# http-proxy-exceptions = *.exception.com, www.internal-site.org" NL 992251881Speter "# http-proxy-host = defaultproxy.whatever.com" NL 993251881Speter "# http-proxy-port = 7000" NL 994251881Speter "# http-proxy-username = defaultusername" NL 995251881Speter "# http-proxy-password = defaultpassword" NL 996251881Speter "# http-compression = no" NL 997251881Speter "# No http-timeout, so just use the builtin default." NL 998251881Speter "# No neon-debug-mask, so neon debugging is disabled." NL 999251881Speter "# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem" NL 1000251881Speter "#" NL 1001251881Speter "# Password / passphrase caching parameters:" NL 1002251881Speter "# store-passwords = no" NL 1003251881Speter "# store-ssl-client-cert-pp = no" NL 1004251881Speter#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE 1005251881Speter "# store-plaintext-passwords = no" NL 1006251881Speter "# store-ssl-client-cert-pp-plaintext = no" NL 1007251881Speter#endif 1008251881Speter ; 1009251881Speter 1010251881Speter err = svn_io_file_open(&f, path, 1011251881Speter (APR_WRITE | APR_CREATE | APR_EXCL), 1012251881Speter APR_OS_DEFAULT, 1013251881Speter pool); 1014251881Speter 1015251881Speter if (! err) 1016251881Speter { 1017251881Speter SVN_ERR(svn_io_file_write_full(f, contents, 1018251881Speter strlen(contents), NULL, pool)); 1019251881Speter SVN_ERR(svn_io_file_close(f, pool)); 1020251881Speter } 1021251881Speter 1022251881Speter svn_error_clear(err); 1023251881Speter } 1024251881Speter 1025251881Speter /** Ensure that the `config' file exists. **/ 1026251881Speter SVN_ERR(svn_config_get_user_config_path 1027251881Speter (&path, config_dir, SVN_CONFIG_CATEGORY_CONFIG, pool)); 1028251881Speter 1029251881Speter if (! path) /* highly unlikely, since a previous call succeeded */ 1030251881Speter return SVN_NO_ERROR; 1031251881Speter 1032251881Speter err = svn_io_check_path(path, &kind, pool); 1033251881Speter if (err) 1034251881Speter { 1035251881Speter svn_error_clear(err); 1036251881Speter return SVN_NO_ERROR; 1037251881Speter } 1038251881Speter 1039251881Speter if (kind == svn_node_none) 1040251881Speter { 1041251881Speter apr_file_t *f; 1042251881Speter const char *contents = 1043251881Speter "### This file configures various client-side behaviors." NL 1044251881Speter "###" NL 1045251881Speter "### The commented-out examples below are intended to demonstrate" NL 1046251881Speter "### how to use this file." NL 1047251881Speter "" NL 1048251881Speter "### Section for authentication and authorization customizations." NL 1049251881Speter "[auth]" NL 1050251881Speter "### Set password stores used by Subversion. They should be" NL 1051251881Speter "### delimited by spaces or commas. The order of values determines" NL 1052251881Speter "### the order in which password stores are used." NL 1053251881Speter "### Valid password stores:" NL 1054251881Speter "### gnome-keyring (Unix-like systems)" NL 1055251881Speter "### kwallet (Unix-like systems)" NL 1056251881Speter "### gpg-agent (Unix-like systems)" NL 1057251881Speter "### keychain (Mac OS X)" NL 1058251881Speter "### windows-cryptoapi (Windows)" NL 1059251881Speter#ifdef SVN_HAVE_KEYCHAIN_SERVICES 1060251881Speter "# password-stores = keychain" NL 1061251881Speter#elif defined(WIN32) && !defined(__MINGW32__) 1062251881Speter "# password-stores = windows-cryptoapi" NL 1063251881Speter#else 1064251881Speter "# password-stores = gpg-agent,gnome-keyring,kwallet" NL 1065251881Speter#endif 1066251881Speter "### To disable all password stores, use an empty list:" NL 1067251881Speter "# password-stores =" NL 1068251881Speter#ifdef SVN_HAVE_KWALLET 1069251881Speter "###" NL 1070251881Speter "### Set KWallet wallet used by Subversion. If empty or unset," NL 1071251881Speter "### then the default network wallet will be used." NL 1072251881Speter "# kwallet-wallet =" NL 1073251881Speter "###" NL 1074251881Speter "### Include PID (Process ID) in Subversion application name when" NL 1075251881Speter "### using KWallet. It defaults to 'no'." NL 1076251881Speter "# kwallet-svn-application-name-with-pid = yes" NL 1077251881Speter#endif 1078251881Speter "###" NL 1079251881Speter "### Set ssl-client-cert-file-prompt to 'yes' to cause the client" NL 1080251881Speter "### to prompt for a path to a client cert file when the server" NL 1081251881Speter "### requests a client cert but no client cert file is found in the" NL 1082251881Speter "### expected place (see the 'ssl-client-cert-file' option in the" NL 1083251881Speter "### 'servers' configuration file). Defaults to 'no'." NL 1084251881Speter "# ssl-client-cert-file-prompt = no" NL 1085251881Speter "###" NL 1086251881Speter "### The rest of the [auth] section in this file has been deprecated." 1087251881Speter NL 1088251881Speter "### Both 'store-passwords' and 'store-auth-creds' can now be" NL 1089251881Speter "### specified in the 'servers' file in your config directory" NL 1090251881Speter "### and are documented there. Anything specified in this section " NL 1091251881Speter "### is overridden by settings specified in the 'servers' file." NL 1092251881Speter "# store-passwords = no" NL 1093251881Speter "# store-auth-creds = no" NL 1094251881Speter "" NL 1095251881Speter "### Section for configuring external helper applications." NL 1096251881Speter "[helpers]" NL 1097251881Speter "### Set editor-cmd to the command used to invoke your text editor." NL 1098251881Speter "### This will override the environment variables that Subversion" NL 1099251881Speter "### examines by default to find this information ($EDITOR, " NL 1100251881Speter "### et al)." NL 1101251881Speter "# editor-cmd = editor (vi, emacs, notepad, etc.)" NL 1102251881Speter "### Set diff-cmd to the absolute path of your 'diff' program." NL 1103251881Speter "### This will override the compile-time default, which is to use" NL 1104251881Speter "### Subversion's internal diff implementation." NL 1105251881Speter "# diff-cmd = diff_program (diff, gdiff, etc.)" NL 1106251881Speter "### Diff-extensions are arguments passed to an external diff" NL 1107251881Speter "### program or to Subversion's internal diff implementation." NL 1108251881Speter "### Set diff-extensions to override the default arguments ('-u')." NL 1109251881Speter "# diff-extensions = -u -p" NL 1110251881Speter "### Set diff3-cmd to the absolute path of your 'diff3' program." NL 1111251881Speter "### This will override the compile-time default, which is to use" NL 1112251881Speter "### Subversion's internal diff3 implementation." NL 1113251881Speter "# diff3-cmd = diff3_program (diff3, gdiff3, etc.)" NL 1114251881Speter "### Set diff3-has-program-arg to 'yes' if your 'diff3' program" NL 1115251881Speter "### accepts the '--diff-program' option." NL 1116251881Speter "# diff3-has-program-arg = [yes | no]" NL 1117251881Speter "### Set merge-tool-cmd to the command used to invoke your external" NL 1118251881Speter "### merging tool of choice. Subversion will pass 5 arguments to" NL 1119251881Speter "### the specified command: base theirs mine merged wcfile" NL 1120251881Speter "# merge-tool-cmd = merge_command" NL 1121251881Speter "" NL 1122251881Speter "### Section for configuring tunnel agents." NL 1123251881Speter "[tunnels]" NL 1124251881Speter "### Configure svn protocol tunnel schemes here. By default, only" NL 1125251881Speter "### the 'ssh' scheme is defined. You can define other schemes to" NL 1126251881Speter "### be used with 'svn+scheme://hostname/path' URLs. A scheme" NL 1127251881Speter "### definition is simply a command, optionally prefixed by an" NL 1128251881Speter "### environment variable name which can override the command if it" NL 1129251881Speter "### is defined. The command (or environment variable) may contain" NL 1130251881Speter "### arguments, using standard shell quoting for arguments with" NL 1131251881Speter "### spaces. The command will be invoked as:" NL 1132251881Speter "### <command> <hostname> svnserve -t" NL 1133251881Speter "### (If the URL includes a username, then the hostname will be" NL 1134251881Speter "### passed to the tunnel agent as <user>@<hostname>.) If the" NL 1135251881Speter "### built-in ssh scheme were not predefined, it could be defined" NL 1136251881Speter "### as:" NL 1137251881Speter "# ssh = $SVN_SSH ssh -q" NL 1138251881Speter "### If you wanted to define a new 'rsh' scheme, to be used with" NL 1139251881Speter "### 'svn+rsh:' URLs, you could do so as follows:" NL 1140251881Speter "# rsh = rsh" NL 1141251881Speter "### Or, if you wanted to specify a full path and arguments:" NL 1142251881Speter "# rsh = /path/to/rsh -l myusername" NL 1143251881Speter "### On Windows, if you are specifying a full path to a command," NL 1144251881Speter "### use a forward slash (/) or a paired backslash (\\\\) as the" NL 1145251881Speter "### path separator. A single backslash will be treated as an" NL 1146251881Speter "### escape for the following character." NL 1147251881Speter "" NL 1148251881Speter "### Section for configuring miscellaneous Subversion options." NL 1149251881Speter "[miscellany]" NL 1150251881Speter "### Set global-ignores to a set of whitespace-delimited globs" NL 1151251881Speter "### which Subversion will ignore in its 'status' output, and" NL 1152251881Speter "### while importing or adding files and directories." NL 1153251881Speter "### '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'." NL 1154251881Speter "# global-ignores = " SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_1 NL 1155251881Speter "# " SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_2 NL 1156251881Speter "### Set log-encoding to the default encoding for log messages" NL 1157251881Speter "# log-encoding = latin1" NL 1158251881Speter "### Set use-commit-times to make checkout/update/switch/revert" NL 1159251881Speter "### put last-committed timestamps on every file touched." NL 1160251881Speter "# use-commit-times = yes" NL 1161251881Speter "### Set no-unlock to prevent 'svn commit' from automatically" NL 1162251881Speter "### releasing locks on files." NL 1163251881Speter "# no-unlock = yes" NL 1164251881Speter "### Set mime-types-file to a MIME type registry file, used to" NL 1165251881Speter "### provide hints to Subversion's MIME type auto-detection" NL 1166251881Speter "### algorithm." NL 1167251881Speter "# mime-types-file = /path/to/mime.types" NL 1168251881Speter "### Set preserved-conflict-file-exts to a whitespace-delimited" NL 1169251881Speter "### list of patterns matching file extensions which should be" NL 1170251881Speter "### preserved in generated conflict file names. By default," NL 1171251881Speter "### conflict files use custom extensions." NL 1172251881Speter "# preserved-conflict-file-exts = doc ppt xls od?" NL 1173251881Speter "### Set enable-auto-props to 'yes' to enable automatic properties" NL 1174251881Speter "### for 'svn add' and 'svn import', it defaults to 'no'." NL 1175251881Speter "### Automatic properties are defined in the section 'auto-props'." NL 1176251881Speter "# enable-auto-props = yes" NL 1177251881Speter "### Set interactive-conflicts to 'no' to disable interactive" NL 1178251881Speter "### conflict resolution prompting. It defaults to 'yes'." NL 1179251881Speter "# interactive-conflicts = no" NL 1180251881Speter "### Set memory-cache-size to define the size of the memory cache" NL 1181251881Speter "### used by the client when accessing a FSFS repository via" NL 1182251881Speter "### ra_local (the file:// scheme). The value represents the number" NL 1183251881Speter "### of MB used by the cache." NL 1184251881Speter "# memory-cache-size = 16" NL 1185251881Speter "" NL 1186251881Speter "### Section for configuring automatic properties." NL 1187251881Speter "[auto-props]" NL 1188251881Speter "### The format of the entries is:" NL 1189251881Speter "### file-name-pattern = propname[=value][;propname[=value]...]" NL 1190251881Speter "### The file-name-pattern can contain wildcards (such as '*' and" NL 1191251881Speter "### '?'). All entries which match (case-insensitively) will be" NL 1192251881Speter "### applied to the file. Note that auto-props functionality" NL 1193251881Speter "### must be enabled, which is typically done by setting the" NL 1194251881Speter "### 'enable-auto-props' option." NL 1195251881Speter "# *.c = svn:eol-style=native" NL 1196251881Speter "# *.cpp = svn:eol-style=native" NL 1197251881Speter "# *.h = svn:keywords=Author Date Id Rev URL;svn:eol-style=native" NL 1198251881Speter "# *.dsp = svn:eol-style=CRLF" NL 1199251881Speter "# *.dsw = svn:eol-style=CRLF" NL 1200251881Speter "# *.sh = svn:eol-style=native;svn:executable" NL 1201251881Speter "# *.txt = svn:eol-style=native;svn:keywords=Author Date Id Rev URL;"NL 1202251881Speter "# *.png = svn:mime-type=image/png" NL 1203251881Speter "# *.jpg = svn:mime-type=image/jpeg" NL 1204251881Speter "# Makefile = svn:eol-style=native" NL 1205251881Speter "" NL 1206251881Speter "### Section for configuring working copies." NL 1207251881Speter "[working-copy]" NL 1208251881Speter "### Set to a list of the names of specific clients that should use" NL 1209251881Speter "### exclusive SQLite locking of working copies. This increases the"NL 1210251881Speter "### performance of the client but prevents concurrent access by" NL 1211251881Speter "### other clients. Third-party clients may also support this" NL 1212251881Speter "### option." NL 1213251881Speter "### Possible values:" NL 1214251881Speter "### svn (the command line client)" NL 1215251881Speter "# exclusive-locking-clients =" NL 1216251881Speter "### Set to true to enable exclusive SQLite locking of working" NL 1217251881Speter "### copies by all clients using the 1.8 APIs. Enabling this may" NL 1218251881Speter "### cause some clients to fail to work properly. This does not have"NL 1219251881Speter "### to be set for exclusive-locking-clients to work." NL 1220251881Speter "# exclusive-locking = false" NL; 1221251881Speter 1222251881Speter err = svn_io_file_open(&f, path, 1223251881Speter (APR_WRITE | APR_CREATE | APR_EXCL), 1224251881Speter APR_OS_DEFAULT, 1225251881Speter pool); 1226251881Speter 1227251881Speter if (! err) 1228251881Speter { 1229251881Speter SVN_ERR(svn_io_file_write_full(f, contents, 1230251881Speter strlen(contents), NULL, pool)); 1231251881Speter SVN_ERR(svn_io_file_close(f, pool)); 1232251881Speter } 1233251881Speter 1234251881Speter svn_error_clear(err); 1235251881Speter } 1236251881Speter 1237251881Speter return SVN_NO_ERROR; 1238251881Speter} 1239251881Speter 1240251881Spetersvn_error_t * 1241251881Spetersvn_config_get_user_config_path(const char **path, 1242251881Speter const char *config_dir, 1243251881Speter const char *fname, 1244251881Speter apr_pool_t *pool) 1245251881Speter{ 1246251881Speter *path= NULL; 1247251881Speter 1248251881Speter /* Note that even if fname is null, svn_dirent_join_many will DTRT. */ 1249251881Speter 1250251881Speter if (config_dir) 1251251881Speter { 1252251881Speter *path = svn_dirent_join_many(pool, config_dir, fname, NULL); 1253251881Speter return SVN_NO_ERROR; 1254251881Speter } 1255251881Speter 1256251881Speter#ifdef WIN32 1257251881Speter { 1258251881Speter const char *folder; 1259251881Speter SVN_ERR(svn_config__win_config_path(&folder, FALSE, pool)); 1260251881Speter *path = svn_dirent_join_many(pool, folder, 1261251881Speter SVN_CONFIG__SUBDIRECTORY, fname, NULL); 1262251881Speter } 1263251881Speter 1264251881Speter#elif defined(__HAIKU__) 1265251881Speter { 1266251881Speter char folder[B_PATH_NAME_LENGTH]; 1267251881Speter 1268251881Speter status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, 1269251881Speter folder, sizeof(folder)); 1270251881Speter if (error) 1271251881Speter return SVN_NO_ERROR; 1272251881Speter 1273251881Speter *path = svn_dirent_join_many(pool, folder, 1274251881Speter SVN_CONFIG__USR_DIRECTORY, fname, NULL); 1275251881Speter } 1276251881Speter#else /* ! WIN32 && !__HAIKU__ */ 1277251881Speter 1278251881Speter { 1279251881Speter const char *homedir = svn_user_get_homedir(pool); 1280251881Speter if (! homedir) 1281251881Speter return SVN_NO_ERROR; 1282251881Speter *path = svn_dirent_join_many(pool, 1283251881Speter svn_dirent_canonicalize(homedir, pool), 1284251881Speter SVN_CONFIG__USR_DIRECTORY, fname, NULL); 1285251881Speter } 1286251881Speter#endif /* WIN32 */ 1287251881Speter 1288251881Speter return SVN_NO_ERROR; 1289251881Speter} 1290251881Speter 1291