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