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