config_file.c revision 309512
1/*
2 * config_file.c :  parsing configuration files
3 *
4 * ====================================================================
5 *    Licensed to the Apache Software Foundation (ASF) under one
6 *    or more contributor license agreements.  See the NOTICE file
7 *    distributed with this work for additional information
8 *    regarding copyright ownership.  The ASF licenses this file
9 *    to you under the Apache License, Version 2.0 (the
10 *    "License"); you may not use this file except in compliance
11 *    with the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 *    Unless required by applicable law or agreed to in writing,
16 *    software distributed under the License is distributed on an
17 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 *    KIND, either express or implied.  See the License for the
19 *    specific language governing permissions and limitations
20 *    under the License.
21 * ====================================================================
22 */
23
24
25
26#include <apr_lib.h>
27#include <apr_env.h>
28#include "config_impl.h"
29#include "svn_io.h"
30#include "svn_types.h"
31#include "svn_dirent_uri.h"
32#include "svn_auth.h"
33#include "svn_hash.h"
34#include "svn_subst.h"
35#include "svn_utf.h"
36#include "svn_pools.h"
37#include "svn_user.h"
38#include "svn_ctype.h"
39
40#include "svn_private_config.h"
41#include "private/svn_subr_private.h"
42
43#ifdef __HAIKU__
44#  include <FindDirectory.h>
45#  include <StorageDefs.h>
46#endif
47
48/* Used to terminate lines in large multi-line string literals. */
49#define NL APR_EOL_STR
50
51
52/* File parsing context */
53typedef struct parse_context_t
54{
55  /* This config struct */
56  svn_config_t *cfg;
57
58  /* The stream struct */
59  svn_stream_t *stream;
60
61  /* The current line in the file */
62  int line;
63
64  /* Emulate an ungetc */
65  int ungotten_char;
66
67  /* Temporary strings */
68  svn_stringbuf_t *section;
69  svn_stringbuf_t *option;
70  svn_stringbuf_t *value;
71
72  /* Parser buffer for getc() to avoid call overhead into several libraries
73     for every character */
74  char parser_buffer[SVN__STREAM_CHUNK_SIZE]; /* Larger than most config files */
75  size_t buffer_pos; /* Current position within parser_buffer */
76  size_t buffer_size; /* parser_buffer contains this many bytes */
77
78  /* Non-zero if we hit EOF on the stream. */
79  svn_boolean_t hit_stream_eof;
80} parse_context_t;
81
82
83
84/* Emulate getc() because streams don't support it.
85 *
86 * In order to be able to ungetc(), use the CXT instead of the stream
87 * to be able to store the 'ungotton' character.
88 *
89 */
90static APR_INLINE svn_error_t *
91parser_getc(parse_context_t *ctx, int *c)
92{
93  do
94    {
95      if (ctx->ungotten_char != EOF)
96        {
97          *c = ctx->ungotten_char;
98          ctx->ungotten_char = EOF;
99        }
100      else if (ctx->buffer_pos < ctx->buffer_size)
101        {
102          *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos];
103          ctx->buffer_pos++;
104        }
105      else
106        {
107          if (!ctx->hit_stream_eof)
108            {
109              ctx->buffer_pos = 0;
110              ctx->buffer_size = sizeof(ctx->parser_buffer);
111
112              SVN_ERR(svn_stream_read_full(ctx->stream, ctx->parser_buffer,
113                                           &(ctx->buffer_size)));
114              ctx->hit_stream_eof = (ctx->buffer_size != sizeof(ctx->parser_buffer));
115            }
116
117          if (ctx->buffer_pos < ctx->buffer_size)
118            {
119              *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos];
120              ctx->buffer_pos++;
121            }
122          else
123            *c = EOF;
124        }
125    }
126  while (*c == '\r');
127
128  return SVN_NO_ERROR;
129}
130
131/* Simplified version of parser_getc() to be used inside skipping loops.
132 * It will not check for 'ungotton' chars and may or may not ignore '\r'.
133 *
134 * In a 'while(cond) getc();' loop, the first iteration must call
135 * parser_getc to handle all the special cases.  Later iterations should
136 * use parser_getc_plain for maximum performance.
137 */
138static APR_INLINE svn_error_t *
139parser_getc_plain(parse_context_t *ctx, int *c)
140{
141  if (ctx->buffer_pos < ctx->buffer_size)
142    {
143      *c = (unsigned char)ctx->parser_buffer[ctx->buffer_pos];
144      ctx->buffer_pos++;
145
146      return SVN_NO_ERROR;
147    }
148
149  return parser_getc(ctx, c);
150}
151
152/* Emulate ungetc() because streams don't support it.
153 *
154 * Use CTX to store the ungotten character C.
155 */
156static APR_INLINE svn_error_t *
157parser_ungetc(parse_context_t *ctx, int c)
158{
159  ctx->ungotten_char = c;
160
161  return SVN_NO_ERROR;
162}
163
164/* Eat chars from STREAM until encounter non-whitespace, newline, or EOF.
165   Set *PCOUNT to the number of characters eaten, not counting the
166   last one, and return the last char read (the one that caused the
167   break).  */
168static APR_INLINE svn_error_t *
169skip_whitespace(parse_context_t *ctx, int *c, int *pcount)
170{
171  int ch = 0;
172  int count = 0;
173
174  SVN_ERR(parser_getc(ctx, &ch));
175  while (svn_ctype_isspace(ch) && ch != '\n' && ch != EOF)
176    {
177      ++count;
178      SVN_ERR(parser_getc_plain(ctx, &ch));
179    }
180  *pcount = count;
181  *c = ch;
182  return SVN_NO_ERROR;
183}
184
185
186/* Skip to the end of the line (or file).  Returns the char that ended
187   the line; the char is either EOF or newline. */
188static APR_INLINE svn_error_t *
189skip_to_eoln(parse_context_t *ctx, int *c)
190{
191  int ch;
192
193  SVN_ERR(parser_getc(ctx, &ch));
194  while (ch != '\n' && ch != EOF)
195    {
196      /* This is much faster than checking individual bytes.
197       * We use this function a lot when skipping comment lines.
198       *
199       * This assumes that the ungetc buffer is empty, but that is a
200       * safe assumption right after reading a character (which would
201       * clear the buffer. */
202      const char *newline = memchr(ctx->parser_buffer + ctx->buffer_pos, '\n',
203                                   ctx->buffer_size - ctx->buffer_pos);
204      if (newline)
205        {
206          ch = '\n';
207          ctx->buffer_pos = newline - ctx->parser_buffer + 1;
208          break;
209        }
210
211      /* refill buffer, check for EOF */
212      SVN_ERR(parser_getc_plain(ctx, &ch));
213    }
214
215  *c = ch;
216  return SVN_NO_ERROR;
217}
218
219/* Skip a UTF-8 Byte Order Mark if found. */
220static APR_INLINE svn_error_t *
221skip_bom(parse_context_t *ctx)
222{
223  int ch;
224
225  SVN_ERR(parser_getc(ctx, &ch));
226  if (ch == 0xEF)
227    {
228      const unsigned char *buf = (unsigned char *)ctx->parser_buffer;
229      /* This makes assumptions about the implementation of parser_getc and
230       * the use of skip_bom.  Specifically that parser_getc() will get all
231       * of the BOM characters into the parse_context_t buffer.  This can
232       * safely be assumed as long as we only try to use skip_bom() at the
233       * start of the stream and the buffer is longer than 3 characters. */
234      SVN_ERR_ASSERT(ctx->buffer_size > ctx->buffer_pos + 1 ||
235                     ctx->hit_stream_eof);
236      if (ctx->buffer_size > ctx->buffer_pos + 1 &&
237          buf[ctx->buffer_pos] == 0xBB && buf[ctx->buffer_pos + 1] == 0xBF)
238        ctx->buffer_pos += 2;
239      else
240        SVN_ERR(parser_ungetc(ctx, ch));
241    }
242  else
243    SVN_ERR(parser_ungetc(ctx, ch));
244
245  return SVN_NO_ERROR;
246}
247
248/* Parse a single option value */
249static svn_error_t *
250parse_value(int *pch, parse_context_t *ctx)
251{
252  svn_boolean_t end_of_val = FALSE;
253  int ch;
254
255  /* Read the first line of the value */
256  svn_stringbuf_setempty(ctx->value);
257  SVN_ERR(parser_getc(ctx, &ch));
258  while (ch != EOF && ch != '\n')
259    /* last ch seen was ':' or '=' in parse_option. */
260    {
261      const char char_from_int = (char)ch;
262      svn_stringbuf_appendbyte(ctx->value, char_from_int);
263      SVN_ERR(parser_getc(ctx, &ch));
264    }
265  /* Leading and trailing whitespace is ignored. */
266  svn_stringbuf_strip_whitespace(ctx->value);
267
268  /* Look for any continuation lines. */
269  for (;;)
270    {
271
272      if (ch == EOF || end_of_val)
273        {
274          /* At end of file. The value is complete, there can't be
275             any continuation lines. */
276          svn_config_set(ctx->cfg, ctx->section->data,
277                         ctx->option->data, ctx->value->data);
278          break;
279        }
280      else
281        {
282          int count;
283          ++ctx->line;
284          SVN_ERR(skip_whitespace(ctx, &ch, &count));
285
286          switch (ch)
287            {
288            case '\n':
289              /* The next line was empty. Ergo, it can't be a
290                 continuation line. */
291              ++ctx->line;
292              end_of_val = TRUE;
293              continue;
294
295            case EOF:
296              /* This is also an empty line. */
297              end_of_val = TRUE;
298              continue;
299
300            default:
301              if (count == 0)
302                {
303                  /* This line starts in the first column.  That means
304                     it's either a section, option or comment.  Put
305                     the char back into the stream, because it doesn't
306                     belong to us. */
307                  SVN_ERR(parser_ungetc(ctx, ch));
308                  end_of_val = TRUE;
309                }
310              else
311                {
312                  /* This is a continuation line. Read it. */
313                  svn_stringbuf_appendbyte(ctx->value, ' ');
314
315                  while (ch != EOF && ch != '\n')
316                    {
317                      const char char_from_int = (char)ch;
318                      svn_stringbuf_appendbyte(ctx->value, char_from_int);
319                      SVN_ERR(parser_getc(ctx, &ch));
320                    }
321                  /* Trailing whitespace is ignored. */
322                  svn_stringbuf_strip_whitespace(ctx->value);
323                }
324            }
325        }
326    }
327
328  *pch = ch;
329  return SVN_NO_ERROR;
330}
331
332
333/* Parse a single option */
334static svn_error_t *
335parse_option(int *pch, parse_context_t *ctx, apr_pool_t *scratch_pool)
336{
337  svn_error_t *err = SVN_NO_ERROR;
338  int ch;
339
340  svn_stringbuf_setempty(ctx->option);
341  ch = *pch;   /* Yes, the first char is relevant. */
342  while (ch != EOF && ch != ':' && ch != '=' && ch != '\n')
343    {
344      const char char_from_int = (char)ch;
345      svn_stringbuf_appendbyte(ctx->option, char_from_int);
346      SVN_ERR(parser_getc(ctx, &ch));
347    }
348
349  if (ch != ':' && ch != '=')
350    {
351      ch = EOF;
352      err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
353                              _("line %d: Option must end with ':' or '='"),
354                              ctx->line);
355    }
356  else
357    {
358      /* Whitespace around the name separator is ignored. */
359      svn_stringbuf_strip_whitespace(ctx->option);
360      err = parse_value(&ch, ctx);
361    }
362
363  *pch = ch;
364  return err;
365}
366
367
368/* Read chars until enounter ']', then skip everything to the end of
369 * the line.  Set *PCH to the character that ended the line (either
370 * newline or EOF), and set CTX->section to the string of characters
371 * seen before ']'.
372 *
373 * This is meant to be called immediately after reading the '[' that
374 * starts a section name.
375 */
376static svn_error_t *
377parse_section_name(int *pch, parse_context_t *ctx,
378                   apr_pool_t *scratch_pool)
379{
380  svn_error_t *err = SVN_NO_ERROR;
381  int ch;
382
383  svn_stringbuf_setempty(ctx->section);
384  SVN_ERR(parser_getc(ctx, &ch));
385  while (ch != EOF && ch != ']' && ch != '\n')
386    {
387      const char char_from_int = (char)ch;
388      svn_stringbuf_appendbyte(ctx->section, char_from_int);
389      SVN_ERR(parser_getc(ctx, &ch));
390    }
391
392  if (ch != ']')
393    {
394      ch = EOF;
395      err = svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
396                              _("line %d: Section header must end with ']'"),
397                              ctx->line);
398    }
399  else
400    {
401      /* Everything from the ']' to the end of the line is ignored. */
402      SVN_ERR(skip_to_eoln(ctx, &ch));
403      if (ch != EOF)
404        ++ctx->line;
405    }
406
407  *pch = ch;
408  return err;
409}
410
411
412svn_error_t *
413svn_config__sys_config_path(const char **path_p,
414                            const char *fname,
415                            apr_pool_t *pool)
416{
417  *path_p = NULL;
418
419  /* Note that even if fname is null, svn_dirent_join_many will DTRT. */
420
421#ifdef WIN32
422  {
423    const char *folder;
424    SVN_ERR(svn_config__win_config_path(&folder, TRUE, pool, pool));
425    *path_p = svn_dirent_join_many(pool, folder,
426                                   SVN_CONFIG__SUBDIRECTORY, fname,
427                                   SVN_VA_NULL);
428  }
429
430#elif defined(__HAIKU__)
431  {
432    char folder[B_PATH_NAME_LENGTH];
433
434    status_t error = find_directory(B_COMMON_SETTINGS_DIRECTORY, -1, false,
435                                    folder, sizeof(folder));
436    if (error)
437      return SVN_NO_ERROR;
438
439    *path_p = svn_dirent_join_many(pool, folder,
440                                   SVN_CONFIG__SYS_DIRECTORY, fname,
441                                   SVN_VA_NULL);
442  }
443#else  /* ! WIN32 && !__HAIKU__ */
444
445  *path_p = svn_dirent_join_many(pool, SVN_CONFIG__SYS_DIRECTORY, fname,
446                                 SVN_VA_NULL);
447
448#endif /* WIN32 */
449
450  return SVN_NO_ERROR;
451}
452
453/* Callback for svn_config_enumerate2: Continue to next value. */
454static svn_boolean_t
455expand_value(const char *name,
456             const char *value,
457             void *baton,
458             apr_pool_t *pool)
459{
460  return TRUE;
461}
462
463/* Callback for svn_config_enumerate_sections2:
464 * Enumerate and implicitly expand all values in this section.
465 */
466static svn_boolean_t
467expand_values_in_section(const char *name,
468                         void *baton,
469                         apr_pool_t *pool)
470{
471  svn_config_t *cfg = baton;
472  svn_config_enumerate2(cfg, name, expand_value, NULL, pool);
473
474  return TRUE;
475}
476
477
478/*** Exported interfaces. ***/
479
480void
481svn_config__set_read_only(svn_config_t *cfg,
482                          apr_pool_t *scratch_pool)
483{
484  /* expand all items such that later calls to getters won't need to
485   * change internal state */
486  svn_config_enumerate_sections2(cfg, expand_values_in_section,
487                                 cfg, scratch_pool);
488
489  /* now, any modification attempt will be ignored / trigger an assertion
490   * in debug mode */
491  cfg->read_only = TRUE;
492}
493
494svn_boolean_t
495svn_config__is_read_only(svn_config_t *cfg)
496{
497  return cfg->read_only;
498}
499
500svn_config_t *
501svn_config__shallow_copy(svn_config_t *src,
502                         apr_pool_t *pool)
503{
504  svn_config_t *cfg = apr_palloc(pool, sizeof(*cfg));
505
506  cfg->sections = src->sections;
507  cfg->pool = pool;
508
509  /* r/o configs are fully expanded and don't need the x_pool anymore */
510  cfg->x_pool = src->read_only ? NULL : svn_pool_create(pool);
511  cfg->x_values = src->x_values;
512  cfg->tmp_key = svn_stringbuf_create_empty(pool);
513  cfg->tmp_value = svn_stringbuf_create_empty(pool);
514  cfg->section_names_case_sensitive = src->section_names_case_sensitive;
515  cfg->option_names_case_sensitive = src->option_names_case_sensitive;
516  cfg->read_only = src->read_only;
517
518  return cfg;
519}
520
521void
522svn_config__shallow_replace_section(svn_config_t *target,
523                                    svn_config_t *source,
524                                    const char *section)
525{
526  if (target->read_only)
527    target->sections = apr_hash_copy(target->pool, target->sections);
528
529  svn_hash_sets(target->sections, section,
530                svn_hash_gets(source->sections, section));
531}
532
533
534svn_error_t *
535svn_config__parse_file(svn_config_t *cfg, const char *file,
536                       svn_boolean_t must_exist, apr_pool_t *result_pool)
537{
538  svn_error_t *err = SVN_NO_ERROR;
539  apr_file_t *apr_file;
540  svn_stream_t *stream;
541  apr_pool_t *scratch_pool = svn_pool_create(result_pool);
542
543  /* Use unbuffered IO since we use our own buffering. */
544  err = svn_io_file_open(&apr_file, file, APR_READ, APR_OS_DEFAULT,
545                         scratch_pool);
546
547  if (! must_exist && err && APR_STATUS_IS_ENOENT(err->apr_err))
548    {
549      svn_error_clear(err);
550      svn_pool_destroy(scratch_pool);
551      return SVN_NO_ERROR;
552    }
553  else
554    SVN_ERR(err);
555
556  stream = svn_stream_from_aprfile2(apr_file, FALSE, scratch_pool);
557  err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
558
559  if (err != SVN_NO_ERROR)
560    {
561      /* Add the filename to the error stack. */
562      err = svn_error_createf(err->apr_err, err,
563                              _("Error while parsing config file: %s:"),
564                              svn_dirent_local_style(file, scratch_pool));
565    }
566
567  /* Close the streams (and other cleanup): */
568  svn_pool_destroy(scratch_pool);
569
570  return err;
571}
572
573svn_error_t *
574svn_config__parse_stream(svn_config_t *cfg, svn_stream_t *stream,
575                         apr_pool_t *result_pool, apr_pool_t *scratch_pool)
576{
577  parse_context_t *ctx;
578  int ch, count;
579
580  ctx = apr_palloc(scratch_pool, sizeof(*ctx));
581
582  ctx->cfg = cfg;
583  ctx->stream = stream;
584  ctx->line = 1;
585  ctx->ungotten_char = EOF;
586  ctx->section = svn_stringbuf_create_empty(scratch_pool);
587  ctx->option = svn_stringbuf_create_empty(scratch_pool);
588  ctx->value = svn_stringbuf_create_empty(scratch_pool);
589  ctx->buffer_pos = 0;
590  ctx->buffer_size = 0;
591  ctx->hit_stream_eof = FALSE;
592
593  SVN_ERR(skip_bom(ctx));
594
595  do
596    {
597      SVN_ERR(skip_whitespace(ctx, &ch, &count));
598
599      switch (ch)
600        {
601        case '[':               /* Start of section header */
602          if (count == 0)
603            SVN_ERR(parse_section_name(&ch, ctx, scratch_pool));
604          else
605            return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
606                                     _("line %d: Section header"
607                                       " must start in the first column"),
608                                     ctx->line);
609          break;
610
611        case '#':               /* Comment */
612          if (count == 0)
613            {
614              SVN_ERR(skip_to_eoln(ctx, &ch));
615              ++(ctx->line);
616            }
617          else
618            return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
619                                     _("line %d: Comment"
620                                       " must start in the first column"),
621                                     ctx->line);
622          break;
623
624        case '\n':              /* Empty line */
625          ++(ctx->line);
626          break;
627
628        case EOF:               /* End of file or read error */
629          break;
630
631        default:
632          if (svn_stringbuf_isempty(ctx->section))
633            return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
634                                     _("line %d: Section header expected"),
635                                     ctx->line);
636          else if (count != 0)
637            return svn_error_createf(SVN_ERR_MALFORMED_FILE, NULL,
638                                     _("line %d: Option expected"),
639                                     ctx->line);
640          else
641            SVN_ERR(parse_option(&ch, ctx, scratch_pool));
642          break;
643        }
644    }
645  while (ch != EOF);
646
647  return SVN_NO_ERROR;
648}
649
650
651/* Helper for ensure_auth_dirs: create SUBDIR under AUTH_DIR, iff
652   SUBDIR does not already exist, but ignore any errors.  Use POOL for
653   temporary allocation. */
654static void
655ensure_auth_subdir(const char *auth_dir,
656                   const char *subdir,
657                   apr_pool_t *pool)
658{
659  svn_error_t *err;
660  const char *subdir_full_path;
661  svn_node_kind_t kind;
662
663  subdir_full_path = svn_dirent_join(auth_dir, subdir, pool);
664  err = svn_io_check_path(subdir_full_path, &kind, pool);
665  if (err || kind == svn_node_none)
666    {
667      svn_error_clear(err);
668      svn_error_clear(svn_io_dir_make(subdir_full_path, APR_OS_DEFAULT, pool));
669    }
670}
671
672/* Helper for svn_config_ensure:  see if ~/.subversion/auth/ and its
673   subdirs exist, try to create them, but don't throw errors on
674   failure.  PATH is assumed to be a path to the user's private config
675   directory. */
676static void
677ensure_auth_dirs(const char *path,
678                 apr_pool_t *pool)
679{
680  svn_node_kind_t kind;
681  const char *auth_dir;
682  svn_error_t *err;
683
684  /* Ensure ~/.subversion/auth/ */
685  auth_dir = svn_dirent_join(path, SVN_CONFIG__AUTH_SUBDIR, pool);
686  err = svn_io_check_path(auth_dir, &kind, pool);
687  if (err || kind == svn_node_none)
688    {
689      svn_error_clear(err);
690      /* 'chmod 700' permissions: */
691      err = svn_io_dir_make(auth_dir,
692                            (APR_UREAD | APR_UWRITE | APR_UEXECUTE),
693                            pool);
694      if (err)
695        {
696          /* Don't try making subdirs if we can't make the top-level dir. */
697          svn_error_clear(err);
698          return;
699        }
700    }
701
702  /* If a provider exists that wants to store credentials in
703     ~/.subversion, a subdirectory for the cred_kind must exist. */
704  ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_SIMPLE, pool);
705  ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_USERNAME, pool);
706  ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_SSL_SERVER_TRUST, pool);
707  ensure_auth_subdir(auth_dir, SVN_AUTH_CRED_SSL_CLIENT_CERT_PW, pool);
708}
709
710
711svn_error_t *
712svn_config_ensure(const char *config_dir, apr_pool_t *pool)
713{
714  const char *path;
715  svn_node_kind_t kind;
716  svn_error_t *err;
717
718  /* Ensure that the user-specific config directory exists.  */
719  SVN_ERR(svn_config_get_user_config_path(&path, config_dir, NULL, pool));
720
721  if (! path)
722    return SVN_NO_ERROR;
723
724  err = svn_io_check_resolved_path(path, &kind, pool);
725  if (err)
726    {
727      /* Don't throw an error, but don't continue. */
728      svn_error_clear(err);
729      return SVN_NO_ERROR;
730    }
731
732  if (kind == svn_node_none)
733    {
734      err = svn_io_dir_make(path, APR_OS_DEFAULT, pool);
735      if (err)
736        {
737          /* Don't throw an error, but don't continue. */
738          svn_error_clear(err);
739          return SVN_NO_ERROR;
740        }
741    }
742  else if (kind == svn_node_file)
743    {
744      /* Somebody put a file where the config directory should be.
745         Wacky.  Let's bail. */
746      return SVN_NO_ERROR;
747    }
748
749  /* Else, there's a configuration directory. */
750
751  /* If we get errors trying to do things below, just stop and return
752     success.  There's no _need_ to init a config directory if
753     something's preventing it. */
754
755  /** If non-existent, try to create a number of auth/ subdirectories. */
756  ensure_auth_dirs(path, pool);
757
758  /** Ensure that the `README.txt' file exists. **/
759  SVN_ERR(svn_config_get_user_config_path
760          (&path, config_dir, SVN_CONFIG__USR_README_FILE, pool));
761
762  if (! path)  /* highly unlikely, since a previous call succeeded */
763    return SVN_NO_ERROR;
764
765  err = svn_io_check_path(path, &kind, pool);
766  if (err)
767    {
768      svn_error_clear(err);
769      return SVN_NO_ERROR;
770    }
771
772  if (kind == svn_node_none)
773    {
774      apr_file_t *f;
775      const char *contents =
776   "This directory holds run-time configuration information for Subversion"  NL
777   "clients.  The configuration files all share the same syntax, but you"    NL
778   "should examine a particular file to learn what configuration"            NL
779   "directives are valid for that file."                                     NL
780   ""                                                                        NL
781   "The syntax is standard INI format:"                                      NL
782   ""                                                                        NL
783   "   - Empty lines, and lines starting with '#', are ignored."             NL
784   "     The first significant line in a file must be a section header."     NL
785   ""                                                                        NL
786   "   - A section starts with a section header, which must start in"        NL
787   "     the first column:"                                                  NL
788   ""                                                                        NL
789   "       [section-name]"                                                   NL
790   ""                                                                        NL
791   "   - An option, which must always appear within a section, is a pair"    NL
792   "     (name, value).  There are two valid forms for defining an"          NL
793   "     option, both of which must start in the first column:"              NL
794   ""                                                                        NL
795   "       name: value"                                                      NL
796   "       name = value"                                                     NL
797   ""                                                                        NL
798   "     Whitespace around the separator (:, =) is optional."                NL
799   ""                                                                        NL
800   "   - Section and option names are case-insensitive, but case is"         NL
801   "     preserved."                                                         NL
802   ""                                                                        NL
803   "   - An option's value may be broken into several lines.  The value"     NL
804   "     continuation lines must start with at least one whitespace."        NL
805   "     Trailing whitespace in the previous line, the newline character"    NL
806   "     and the leading whitespace in the continuation line is compressed"  NL
807   "     into a single space character."                                     NL
808   ""                                                                        NL
809   "   - All leading and trailing whitespace around a value is trimmed,"     NL
810   "     but the whitespace within a value is preserved, with the"           NL
811   "     exception of whitespace around line continuations, as"              NL
812   "     described above."                                                   NL
813   ""                                                                        NL
814   "   - When a value is a boolean, any of the following strings are"        NL
815   "     recognised as truth values (case does not matter):"                 NL
816   ""                                                                        NL
817   "       true      false"                                                  NL
818   "       yes       no"                                                     NL
819   "       on        off"                                                    NL
820   "       1         0"                                                      NL
821   ""                                                                        NL
822   "   - When a value is a list, it is comma-separated.  Again, the"         NL
823   "     whitespace around each element of the list is trimmed."             NL
824   ""                                                                        NL
825   "   - Option values may be expanded within a value by enclosing the"      NL
826   "     option name in parentheses, preceded by a percent sign and"         NL
827   "     followed by an 's':"                                                NL
828   ""                                                                        NL
829   "       %(name)s"                                                         NL
830   ""                                                                        NL
831   "     The expansion is performed recursively and on demand, during"       NL
832   "     svn_option_get.  The name is first searched for in the same"        NL
833   "     section, then in the special [DEFAULT] section. If the name"        NL
834   "     is not found, the whole '%(name)s' placeholder is left"             NL
835   "     unchanged."                                                         NL
836   ""                                                                        NL
837   "     Any modifications to the configuration data invalidate all"         NL
838   "     previously expanded values, so that the next svn_option_get"        NL
839   "     will take the modifications into account."                          NL
840   ""                                                                        NL
841   "The syntax of the configuration files is a subset of the one used by"    NL
842   "Python's ConfigParser module; see"                                       NL
843   ""                                                                        NL
844   "   http://www.python.org/doc/current/lib/module-ConfigParser.html"       NL
845   ""                                                                        NL
846   "Configuration data in the Windows registry"                              NL
847   "=========================================="                              NL
848   ""                                                                        NL
849   "On Windows, configuration data may also be stored in the registry. The"  NL
850   "functions svn_config_read and svn_config_merge will read from the"       NL
851   "registry when passed file names of the form:"                            NL
852   ""                                                                        NL
853   "   REGISTRY:<hive>/path/to/config-key"                                   NL
854   ""                                                                        NL
855   "The REGISTRY: prefix must be in upper case. The <hive> part must be"     NL
856   "one of:"                                                                 NL
857   ""                                                                        NL
858   "   HKLM for HKEY_LOCAL_MACHINE"                                          NL
859   "   HKCU for HKEY_CURRENT_USER"                                           NL
860   ""                                                                        NL
861   "The values in config-key represent the options in the [DEFAULT] section."NL
862   "The keys below config-key represent other sections, and their values"    NL
863   "represent the options. Only values of type REG_SZ whose name doesn't"    NL
864   "start with a '#' will be used; other values, as well as the keys'"       NL
865   "default values, will be ignored."                                        NL
866   ""                                                                        NL
867   ""                                                                        NL
868   "File locations"                                                          NL
869   "=============="                                                          NL
870   ""                                                                        NL
871   "Typically, Subversion uses two config directories, one for site-wide"    NL
872   "configuration,"                                                          NL
873   ""                                                                        NL
874   "  Unix:"                                                                 NL
875   "    /etc/subversion/servers"                                             NL
876   "    /etc/subversion/config"                                              NL
877   "    /etc/subversion/hairstyles"                                          NL
878   "  Windows:"                                                              NL
879   "    %ALLUSERSPROFILE%\\Application Data\\Subversion\\servers"            NL
880   "    %ALLUSERSPROFILE%\\Application Data\\Subversion\\config"             NL
881   "    %ALLUSERSPROFILE%\\Application Data\\Subversion\\hairstyles"         NL
882   "    REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Servers"            NL
883   "    REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Config"             NL
884   "    REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Hairstyles"         NL
885   ""                                                                        NL
886   "and one for per-user configuration:"                                     NL
887   ""                                                                        NL
888   "  Unix:"                                                                 NL
889   "    ~/.subversion/servers"                                               NL
890   "    ~/.subversion/config"                                                NL
891   "    ~/.subversion/hairstyles"                                            NL
892   "  Windows:"                                                              NL
893   "    %APPDATA%\\Subversion\\servers"                                      NL
894   "    %APPDATA%\\Subversion\\config"                                       NL
895   "    %APPDATA%\\Subversion\\hairstyles"                                   NL
896   "    REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Servers"            NL
897   "    REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Config"             NL
898   "    REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Hairstyles"         NL
899   ""                                                                        NL;
900
901      err = svn_io_file_open(&f, path,
902                             (APR_WRITE | APR_CREATE | APR_EXCL),
903                             APR_OS_DEFAULT,
904                             pool);
905
906      if (! err)
907        {
908          SVN_ERR(svn_io_file_write_full(f, contents,
909                                         strlen(contents), NULL, pool));
910          SVN_ERR(svn_io_file_close(f, pool));
911        }
912
913      svn_error_clear(err);
914    }
915
916  /** Ensure that the `servers' file exists. **/
917  SVN_ERR(svn_config_get_user_config_path
918          (&path, config_dir, SVN_CONFIG_CATEGORY_SERVERS, pool));
919
920  if (! path)  /* highly unlikely, since a previous call succeeded */
921    return SVN_NO_ERROR;
922
923  err = svn_io_check_path(path, &kind, pool);
924  if (err)
925    {
926      svn_error_clear(err);
927      return SVN_NO_ERROR;
928    }
929
930  if (kind == svn_node_none)
931    {
932      apr_file_t *f;
933      const char *contents =
934        "### This file specifies server-specific parameters,"                NL
935        "### including HTTP proxy information, HTTP timeout settings,"       NL
936        "### and authentication settings."                                   NL
937        "###"                                                                NL
938        "### The currently defined server options are:"                      NL
939        "###   http-proxy-host            Proxy host for HTTP connection"    NL
940        "###   http-proxy-port            Port number of proxy host service" NL
941        "###   http-proxy-username        Username for auth to proxy service"NL
942        "###   http-proxy-password        Password for auth to proxy service"NL
943        "###   http-proxy-exceptions      List of sites that do not use proxy"
944                                                                             NL
945        "###   http-timeout               Timeout for HTTP requests in seconds"
946                                                                             NL
947        "###   http-compression           Whether to compress HTTP requests" NL
948        "###   http-max-connections       Maximum number of parallel server" NL
949        "###                              connections to use for any given"  NL
950        "###                              HTTP operation."                   NL
951        "###   http-chunked-requests      Whether to use chunked transfer"   NL
952        "###                              encoding for HTTP requests body."  NL
953        "###   neon-debug-mask            Debug mask for Neon HTTP library"  NL
954        "###   ssl-authority-files        List of files, each of a trusted CA"
955                                                                             NL
956        "###   ssl-trust-default-ca       Trust the system 'default' CAs"    NL
957        "###   ssl-client-cert-file       PKCS#12 format client certificate file"
958                                                                             NL
959        "###   ssl-client-cert-password   Client Key password, if needed."   NL
960        "###   ssl-pkcs11-provider        Name of PKCS#11 provider to use."  NL
961        "###   http-library               Which library to use for http/https"
962                                                                             NL
963        "###                              connections."                      NL
964        "###   http-bulk-updates          Whether to request bulk update"    NL
965        "###                              responses or to fetch each file"   NL
966        "###                              in an individual request. "        NL
967        "###   store-passwords            Specifies whether passwords used"  NL
968        "###                              to authenticate against a"         NL
969        "###                              Subversion server may be cached"   NL
970        "###                              to disk in any way."               NL
971#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
972        "###   store-plaintext-passwords  Specifies whether passwords may"   NL
973        "###                              be cached on disk unencrypted."    NL
974#endif
975        "###   store-ssl-client-cert-pp   Specifies whether passphrase used" NL
976        "###                              to authenticate against a client"  NL
977        "###                              certificate may be cached to disk" NL
978        "###                              in any way"                        NL
979#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
980        "###   store-ssl-client-cert-pp-plaintext"                           NL
981        "###                              Specifies whether client cert"     NL
982        "###                              passphrases may be cached on disk" NL
983        "###                              unencrypted (i.e., as plaintext)." NL
984#endif
985        "###   store-auth-creds           Specifies whether any auth info"   NL
986        "###                              (passwords, server certs, etc.)"   NL
987        "###                              may be cached to disk."            NL
988        "###   username                   Specifies the default username."   NL
989        "###"                                                                NL
990        "### Set store-passwords to 'no' to avoid storing passwords on disk" NL
991        "### in any way, including in password stores.  It defaults to"      NL
992        "### 'yes', but Subversion will never save your password to disk in" NL
993        "### plaintext unless explicitly configured to do so."               NL
994        "### Note that this option only prevents saving of *new* passwords;" NL
995        "### it doesn't invalidate existing passwords.  (To do that, remove" NL
996        "### the cache files by hand as described in the Subversion book.)"  NL
997        "###"                                                                NL
998#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
999        "### Set store-plaintext-passwords to 'no' to avoid storing"         NL
1000        "### passwords in unencrypted form in the auth/ area of your config" NL
1001        "### directory. Set it to 'yes' to allow Subversion to store"        NL
1002        "### unencrypted passwords in the auth/ area.  The default is"       NL
1003        "### 'ask', which means that Subversion will ask you before"         NL
1004        "### saving a password to disk in unencrypted form.  Note that"      NL
1005        "### this option has no effect if either 'store-passwords' or "      NL
1006        "### 'store-auth-creds' is set to 'no'."                             NL
1007        "###"                                                                NL
1008#endif
1009        "### Set store-ssl-client-cert-pp to 'no' to avoid storing ssl"      NL
1010        "### client certificate passphrases in the auth/ area of your"       NL
1011        "### config directory.  It defaults to 'yes', but Subversion will"   NL
1012        "### never save your passphrase to disk in plaintext unless"         NL
1013        "### explicitly configured to do so."                                NL
1014        "###"                                                                NL
1015        "### Note store-ssl-client-cert-pp only prevents the saving of *new*"NL
1016        "### passphrases; it doesn't invalidate existing passphrases.  To do"NL
1017        "### that, remove the cache files by hand as described in the"       NL
1018        "### Subversion book at http://svnbook.red-bean.com/nightly/en/\\"   NL
1019        "###                    svn.serverconfig.netmodel.html\\"            NL
1020        "###                    #svn.serverconfig.netmodel.credcache"        NL
1021        "###"                                                                NL
1022#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
1023        "### Set store-ssl-client-cert-pp-plaintext to 'no' to avoid storing"NL
1024        "### passphrases in unencrypted form in the auth/ area of your"      NL
1025        "### config directory.  Set it to 'yes' to allow Subversion to"      NL
1026        "### store unencrypted passphrases in the auth/ area.  The default"  NL
1027        "### is 'ask', which means that Subversion will prompt before"       NL
1028        "### saving a passphrase to disk in unencrypted form.  Note that"    NL
1029        "### this option has no effect if either 'store-auth-creds' or "     NL
1030        "### 'store-ssl-client-cert-pp' is set to 'no'."                     NL
1031        "###"                                                                NL
1032#endif
1033        "### Set store-auth-creds to 'no' to avoid storing any Subversion"   NL
1034        "### credentials in the auth/ area of your config directory."        NL
1035        "### Note that this includes SSL server certificates."               NL
1036        "### It defaults to 'yes'.  Note that this option only prevents"     NL
1037        "### saving of *new* credentials;  it doesn't invalidate existing"   NL
1038        "### caches.  (To do that, remove the cache files by hand.)"         NL
1039        "###"                                                                NL
1040        "### HTTP timeouts, if given, are specified in seconds.  A timeout"  NL
1041        "### of 0, i.e. zero, causes a builtin default to be used."          NL
1042        "###"                                                                NL
1043        "### Most users will not need to explicitly set the http-library"    NL
1044        "### option, but valid values for the option include:"               NL
1045        "###    'serf': Serf-based module (Subversion 1.5 - present)"        NL
1046        "###    'neon': Neon-based module (Subversion 1.0 - 1.7)"            NL
1047        "### Availability of these modules may depend on your specific"      NL
1048        "### Subversion distribution."                                       NL
1049        "###"                                                                NL
1050        "### The commented-out examples below are intended only to"          NL
1051        "### demonstrate how to use this file; any resemblance to actual"    NL
1052        "### servers, living or dead, is entirely coincidental."             NL
1053        ""                                                                   NL
1054        "### In the 'groups' section, the URL of the repository you're"      NL
1055        "### trying to access is matched against the patterns on the right." NL
1056        "### If a match is found, the server options are taken from the"     NL
1057        "### section with the corresponding name on the left."               NL
1058        ""                                                                   NL
1059        "[groups]"                                                           NL
1060        "# group1 = *.collab.net"                                            NL
1061        "# othergroup = repository.blarggitywhoomph.com"                     NL
1062        "# thirdgroup = *.example.com"                                       NL
1063        ""                                                                   NL
1064        "### Information for the first group:"                               NL
1065        "# [group1]"                                                         NL
1066        "# http-proxy-host = proxy1.some-domain-name.com"                    NL
1067        "# http-proxy-port = 80"                                             NL
1068        "# http-proxy-username = blah"                                       NL
1069        "# http-proxy-password = doubleblah"                                 NL
1070        "# http-timeout = 60"                                                NL
1071        "# neon-debug-mask = 130"                                            NL
1072#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
1073        "# store-plaintext-passwords = no"                                   NL
1074#endif
1075        "# username = harry"                                                 NL
1076        ""                                                                   NL
1077        "### Information for the second group:"                              NL
1078        "# [othergroup]"                                                     NL
1079        "# http-proxy-host = proxy2.some-domain-name.com"                    NL
1080        "# http-proxy-port = 9000"                                           NL
1081        "# No username and password for the proxy, so use the defaults below."
1082                                                                             NL
1083        ""                                                                   NL
1084        "### You can set default parameters in the 'global' section."        NL
1085        "### These parameters apply if no corresponding parameter is set in" NL
1086        "### a specifically matched group as shown above.  Thus, if you go"  NL
1087        "### through the same proxy server to reach every site on the"       NL
1088        "### Internet, you probably just want to put that server's"          NL
1089        "### information in the 'global' section and not bother with"        NL
1090        "### 'groups' or any other sections."                                NL
1091        "###"                                                                NL
1092        "### Most people might want to configure password caching"           NL
1093        "### parameters here, but you can also configure them per server"    NL
1094        "### group (per-group settings override global settings)."           NL
1095        "###"                                                                NL
1096        "### If you go through a proxy for all but a few sites, you can"     NL
1097        "### list those exceptions under 'http-proxy-exceptions'.  This only"NL
1098        "### overrides defaults, not explicitly matched server names."       NL
1099        "###"                                                                NL
1100        "### 'ssl-authority-files' is a semicolon-delimited list of files,"  NL
1101        "### each pointing to a PEM-encoded Certificate Authority (CA) "     NL
1102        "### SSL certificate.  See details above for overriding security "   NL
1103        "### due to SSL."                                                    NL
1104        "[global]"                                                           NL
1105        "# http-proxy-exceptions = *.exception.com, www.internal-site.org"   NL
1106        "# http-proxy-host = defaultproxy.whatever.com"                      NL
1107        "# http-proxy-port = 7000"                                           NL
1108        "# http-proxy-username = defaultusername"                            NL
1109        "# http-proxy-password = defaultpassword"                            NL
1110        "# http-compression = no"                                            NL
1111        "# No http-timeout, so just use the builtin default."                NL
1112        "# No neon-debug-mask, so neon debugging is disabled."               NL
1113        "# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem"   NL
1114        "#"                                                                  NL
1115        "# Password / passphrase caching parameters:"                        NL
1116        "# store-passwords = no"                                             NL
1117        "# store-ssl-client-cert-pp = no"                                    NL
1118#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE
1119        "# store-plaintext-passwords = no"                                   NL
1120        "# store-ssl-client-cert-pp-plaintext = no"                          NL
1121#endif
1122        ;
1123
1124      err = svn_io_file_open(&f, path,
1125                             (APR_WRITE | APR_CREATE | APR_EXCL),
1126                             APR_OS_DEFAULT,
1127                             pool);
1128
1129      if (! err)
1130        {
1131          SVN_ERR(svn_io_file_write_full(f, contents,
1132                                         strlen(contents), NULL, pool));
1133          SVN_ERR(svn_io_file_close(f, pool));
1134        }
1135
1136      svn_error_clear(err);
1137    }
1138
1139  /** Ensure that the `config' file exists. **/
1140  SVN_ERR(svn_config_get_user_config_path
1141          (&path, config_dir, SVN_CONFIG_CATEGORY_CONFIG, pool));
1142
1143  if (! path)  /* highly unlikely, since a previous call succeeded */
1144    return SVN_NO_ERROR;
1145
1146  err = svn_io_check_path(path, &kind, pool);
1147  if (err)
1148    {
1149      svn_error_clear(err);
1150      return SVN_NO_ERROR;
1151    }
1152
1153  if (kind == svn_node_none)
1154    {
1155      apr_file_t *f;
1156      const char *contents =
1157        "### This file configures various client-side behaviors."            NL
1158        "###"                                                                NL
1159        "### The commented-out examples below are intended to demonstrate"   NL
1160        "### how to use this file."                                          NL
1161        ""                                                                   NL
1162        "### Section for authentication and authorization customizations."   NL
1163        "[auth]"                                                             NL
1164        "### Set password stores used by Subversion. They should be"         NL
1165        "### delimited by spaces or commas. The order of values determines"  NL
1166        "### the order in which password stores are used."                   NL
1167        "### Valid password stores:"                                         NL
1168        "###   gnome-keyring        (Unix-like systems)"                     NL
1169        "###   kwallet              (Unix-like systems)"                     NL
1170        "###   gpg-agent            (Unix-like systems)"                     NL
1171        "###   keychain             (Mac OS X)"                              NL
1172        "###   windows-cryptoapi    (Windows)"                               NL
1173#ifdef SVN_HAVE_KEYCHAIN_SERVICES
1174        "# password-stores = keychain"                                       NL
1175#elif defined(WIN32) && !defined(__MINGW32__)
1176        "# password-stores = windows-cryptoapi"                              NL
1177#else
1178        "# password-stores = gpg-agent,gnome-keyring,kwallet"                NL
1179#endif
1180        "### To disable all password stores, use an empty list:"             NL
1181        "# password-stores ="                                                NL
1182#ifdef SVN_HAVE_KWALLET
1183        "###"                                                                NL
1184        "### Set KWallet wallet used by Subversion. If empty or unset,"      NL
1185        "### then the default network wallet will be used."                  NL
1186        "# kwallet-wallet ="                                                 NL
1187        "###"                                                                NL
1188        "### Include PID (Process ID) in Subversion application name when"   NL
1189        "### using KWallet. It defaults to 'no'."                            NL
1190        "# kwallet-svn-application-name-with-pid = yes"                      NL
1191#endif
1192        "###"                                                                NL
1193        "### Set ssl-client-cert-file-prompt to 'yes' to cause the client"   NL
1194        "### to prompt for a path to a client cert file when the server"     NL
1195        "### requests a client cert but no client cert file is found in the" NL
1196        "### expected place (see the 'ssl-client-cert-file' option in the"   NL
1197        "### 'servers' configuration file). Defaults to 'no'."               NL
1198        "# ssl-client-cert-file-prompt = no"                                 NL
1199        "###"                                                                NL
1200        "### The rest of the [auth] section in this file has been deprecated."
1201                                                                             NL
1202        "### Both 'store-passwords' and 'store-auth-creds' can now be"       NL
1203        "### specified in the 'servers' file in your config directory"       NL
1204        "### and are documented there. Anything specified in this section "  NL
1205        "### is overridden by settings specified in the 'servers' file."     NL
1206        "# store-passwords = no"                                             NL
1207        "# store-auth-creds = no"                                            NL
1208        ""                                                                   NL
1209        "### Section for configuring external helper applications."          NL
1210        "[helpers]"                                                          NL
1211        "### Set editor-cmd to the command used to invoke your text editor." NL
1212        "###   This will override the environment variables that Subversion" NL
1213        "###   examines by default to find this information ($EDITOR, "      NL
1214        "###   et al)."                                                      NL
1215        "# editor-cmd = editor (vi, emacs, notepad, etc.)"                   NL
1216        "### Set diff-cmd to the absolute path of your 'diff' program."      NL
1217        "###   This will override the compile-time default, which is to use" NL
1218        "###   Subversion's internal diff implementation."                   NL
1219        "# diff-cmd = diff_program (diff, gdiff, etc.)"                      NL
1220        "### Diff-extensions are arguments passed to an external diff"       NL
1221        "### program or to Subversion's internal diff implementation."       NL
1222        "### Set diff-extensions to override the default arguments ('-u')."  NL
1223        "# diff-extensions = -u -p"                                          NL
1224        "### Set diff3-cmd to the absolute path of your 'diff3' program."    NL
1225        "###   This will override the compile-time default, which is to use" NL
1226        "###   Subversion's internal diff3 implementation."                  NL
1227        "# diff3-cmd = diff3_program (diff3, gdiff3, etc.)"                  NL
1228        "### Set diff3-has-program-arg to 'yes' if your 'diff3' program"     NL
1229        "###   accepts the '--diff-program' option."                         NL
1230        "# diff3-has-program-arg = [yes | no]"                               NL
1231        "### Set merge-tool-cmd to the command used to invoke your external" NL
1232        "### merging tool of choice. Subversion will pass 5 arguments to"    NL
1233        "### the specified command: base theirs mine merged wcfile"          NL
1234        "# merge-tool-cmd = merge_command"                                   NL
1235        ""                                                                   NL
1236        "### Section for configuring tunnel agents."                         NL
1237        "[tunnels]"                                                          NL
1238        "### Configure svn protocol tunnel schemes here.  By default, only"  NL
1239        "### the 'ssh' scheme is defined.  You can define other schemes to"  NL
1240        "### be used with 'svn+scheme://hostname/path' URLs.  A scheme"      NL
1241        "### definition is simply a command, optionally prefixed by an"      NL
1242        "### environment variable name which can override the command if it" NL
1243        "### is defined.  The command (or environment variable) may contain" NL
1244        "### arguments, using standard shell quoting for arguments with"     NL
1245        "### spaces.  The command will be invoked as:"                       NL
1246        "###   <command> <hostname> svnserve -t"                             NL
1247        "### (If the URL includes a username, then the hostname will be"     NL
1248        "### passed to the tunnel agent as <user>@<hostname>.)  If the"      NL
1249        "### built-in ssh scheme were not predefined, it could be defined"   NL
1250        "### as:"                                                            NL
1251        "# ssh = $SVN_SSH ssh -q"                                            NL
1252        "### If you wanted to define a new 'rsh' scheme, to be used with"    NL
1253        "### 'svn+rsh:' URLs, you could do so as follows:"                   NL
1254        "# rsh = rsh"                                                        NL
1255        "### Or, if you wanted to specify a full path and arguments:"        NL
1256        "# rsh = /path/to/rsh -l myusername"                                 NL
1257        "### On Windows, if you are specifying a full path to a command,"    NL
1258        "### use a forward slash (/) or a paired backslash (\\\\) as the"    NL
1259        "### path separator.  A single backslash will be treated as an"      NL
1260        "### escape for the following character."                            NL
1261        ""                                                                   NL
1262        "### Section for configuring miscellaneous Subversion options."      NL
1263        "[miscellany]"                                                       NL
1264        "### Set global-ignores to a set of whitespace-delimited globs"      NL
1265        "### which Subversion will ignore in its 'status' output, and"       NL
1266        "### while importing or adding files and directories."               NL
1267        "### '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'."     NL
1268        "# global-ignores = " SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_1      NL
1269        "#   " SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_2                     NL
1270        "### Set log-encoding to the default encoding for log messages"      NL
1271        "# log-encoding = latin1"                                            NL
1272        "### Set use-commit-times to make checkout/update/switch/revert"     NL
1273        "### put last-committed timestamps on every file touched."           NL
1274        "# use-commit-times = yes"                                           NL
1275        "### Set no-unlock to prevent 'svn commit' from automatically"       NL
1276        "### releasing locks on files."                                      NL
1277        "# no-unlock = yes"                                                  NL
1278        "### Set mime-types-file to a MIME type registry file, used to"      NL
1279        "### provide hints to Subversion's MIME type auto-detection"         NL
1280        "### algorithm."                                                     NL
1281        "# mime-types-file = /path/to/mime.types"                            NL
1282        "### Set preserved-conflict-file-exts to a whitespace-delimited"     NL
1283        "### list of patterns matching file extensions which should be"      NL
1284        "### preserved in generated conflict file names.  By default,"       NL
1285        "### conflict files use custom extensions."                          NL
1286        "# preserved-conflict-file-exts = doc ppt xls od?"                   NL
1287        "### Set enable-auto-props to 'yes' to enable automatic properties"  NL
1288        "### for 'svn add' and 'svn import', it defaults to 'no'."           NL
1289        "### Automatic properties are defined in the section 'auto-props'."  NL
1290        "# enable-auto-props = yes"                                          NL
1291#ifdef SVN_HAVE_LIBMAGIC
1292        "### Set enable-magic-file to 'no' to disable magic file detection"  NL
1293        "### of the file type when automatically setting svn:mime-type. It"  NL
1294        "### defaults to 'yes' if magic file support is possible."           NL
1295        "# enable-magic-file = yes"                                          NL
1296#endif
1297        "### Set interactive-conflicts to 'no' to disable interactive"       NL
1298        "### conflict resolution prompting.  It defaults to 'yes'."          NL
1299        "# interactive-conflicts = no"                                       NL
1300        "### Set memory-cache-size to define the size of the memory cache"   NL
1301        "### used by the client when accessing a FSFS repository via"        NL
1302        "### ra_local (the file:// scheme). The value represents the number" NL
1303        "### of MB used by the cache."                                       NL
1304        "# memory-cache-size = 16"                                           NL
1305        "### Set diff-ignore-content-type to 'yes' to cause 'svn diff' to"   NL
1306        "### attempt to show differences of all modified files regardless"   NL
1307        "### of their MIME content type.  By default, Subversion will only"  NL
1308        "### attempt to show differences for files believed to have human-"  NL
1309        "### readable (non-binary) content.  This option is especially"      NL
1310        "### useful when Subversion is configured (via the 'diff-cmd'"       NL
1311        "### option) to employ an external differencing tool which is able"  NL
1312        "### to show meaningful differences for binary file formats.  [New"  NL
1313        "### in 1.9]"                                                        NL
1314        "# diff-ignore-content-type = no"                                    NL
1315        ""                                                                   NL
1316        "### Section for configuring automatic properties."                  NL
1317        "[auto-props]"                                                       NL
1318        "### The format of the entries is:"                                  NL
1319        "###   file-name-pattern = propname[=value][;propname[=value]...]"   NL
1320        "### The file-name-pattern can contain wildcards (such as '*' and"   NL
1321        "### '?').  All entries which match (case-insensitively) will be"    NL
1322        "### applied to the file.  Note that auto-props functionality"       NL
1323        "### must be enabled, which is typically done by setting the"        NL
1324        "### 'enable-auto-props' option."                                    NL
1325        "# *.c = svn:eol-style=native"                                       NL
1326        "# *.cpp = svn:eol-style=native"                                     NL
1327        "# *.h = svn:keywords=Author Date Id Rev URL;svn:eol-style=native"   NL
1328        "# *.dsp = svn:eol-style=CRLF"                                       NL
1329        "# *.dsw = svn:eol-style=CRLF"                                       NL
1330        "# *.sh = svn:eol-style=native;svn:executable"                       NL
1331        "# *.txt = svn:eol-style=native;svn:keywords=Author Date Id Rev URL;"NL
1332        "# *.png = svn:mime-type=image/png"                                  NL
1333        "# *.jpg = svn:mime-type=image/jpeg"                                 NL
1334        "# Makefile = svn:eol-style=native"                                  NL
1335        ""                                                                   NL
1336        "### Section for configuring working copies."                        NL
1337        "[working-copy]"                                                     NL
1338        "### Set to a list of the names of specific clients that should use" NL
1339        "### exclusive SQLite locking of working copies.  This increases the"NL
1340        "### performance of the client but prevents concurrent access by"    NL
1341        "### other clients.  Third-party clients may also support this"      NL
1342        "### option."                                                        NL
1343        "### Possible values:"                                               NL
1344        "###   svn                (the command line client)"                 NL
1345        "# exclusive-locking-clients ="                                      NL
1346        "### Set to true to enable exclusive SQLite locking of working"      NL
1347        "### copies by all clients using the 1.8 APIs.  Enabling this may"   NL
1348        "### cause some clients to fail to work properly. This does not have"NL
1349        "### to be set for exclusive-locking-clients to work."               NL
1350        "# exclusive-locking = false"                                        NL
1351        "### Set the SQLite busy timeout in milliseconds: the maximum time"  NL
1352        "### the client waits to get access to the SQLite database before"   NL
1353        "### returning an error.  The default is 10000, i.e. 10 seconds."    NL
1354        "### Longer values may be useful when exclusive locking is enabled." NL
1355        "# busy-timeout = 10000"                                             NL
1356        ;
1357
1358      err = svn_io_file_open(&f, path,
1359                             (APR_WRITE | APR_CREATE | APR_EXCL),
1360                             APR_OS_DEFAULT,
1361                             pool);
1362
1363      if (! err)
1364        {
1365          SVN_ERR(svn_io_file_write_full(f, contents,
1366                                         strlen(contents), NULL, pool));
1367          SVN_ERR(svn_io_file_close(f, pool));
1368        }
1369
1370      svn_error_clear(err);
1371    }
1372
1373  return SVN_NO_ERROR;
1374}
1375
1376svn_error_t *
1377svn_config_get_user_config_path(const char **path,
1378                                const char *config_dir,
1379                                const char *fname,
1380                                apr_pool_t *pool)
1381{
1382  *path= NULL;
1383
1384  /* Note that even if fname is null, svn_dirent_join_many will DTRT. */
1385
1386  if (config_dir)
1387    {
1388      *path = svn_dirent_join_many(pool, config_dir, fname, SVN_VA_NULL);
1389      return SVN_NO_ERROR;
1390    }
1391
1392#ifdef WIN32
1393  {
1394    const char *folder;
1395    SVN_ERR(svn_config__win_config_path(&folder, FALSE, pool, pool));
1396
1397    if (! folder)
1398      return SVN_NO_ERROR;
1399
1400    *path = svn_dirent_join_many(pool, folder,
1401                                 SVN_CONFIG__SUBDIRECTORY, fname, SVN_VA_NULL);
1402  }
1403
1404#elif defined(__HAIKU__)
1405  {
1406    char folder[B_PATH_NAME_LENGTH];
1407
1408    status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, -1, false,
1409                                    folder, sizeof(folder));
1410    if (error)
1411      return SVN_NO_ERROR;
1412
1413    *path = svn_dirent_join_many(pool, folder,
1414                                 SVN_CONFIG__USR_DIRECTORY, fname,
1415                                 SVN_VA_NULL);
1416  }
1417#else  /* ! WIN32 && !__HAIKU__ */
1418
1419  {
1420    const char *homedir = svn_user_get_homedir(pool);
1421    if (! homedir)
1422      return SVN_NO_ERROR;
1423    *path = svn_dirent_join_many(pool,
1424                               svn_dirent_canonicalize(homedir, pool),
1425                               SVN_CONFIG__USR_DIRECTORY, fname, SVN_VA_NULL);
1426  }
1427#endif /* WIN32 */
1428
1429  return SVN_NO_ERROR;
1430}
1431
1432