2 * config_file.c : parsing configuration files
4 * ====================================================================
5 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
24 #include "config_impl.h"
26 #include "svn_types.h"
29 #include "svn_subst.h"
31 #include "svn_pools.h"
34 #include "svn_private_config.h"
36 /* Used to terminate lines in large multi-line string literals. */
37 #define NL APR_EOL_STR
40 /* File parsing context */
41 typedef struct parse_context_t
43 /* This config struct and file */
47 /* The file descriptor */
50 /* The current line in the file */
53 /* Cached ungotten character - streams don't support ungetc()
56 svn_boolean_t have_ungotten_char
;
58 /* Temporary strings, allocated from the temp pool */
59 svn_stringbuf_t
*section
;
60 svn_stringbuf_t
*option
;
61 svn_stringbuf_t
*value
;
66 /* Emulate getc() because streams don't support it.
68 * In order to be able to ungetc(), use the CXT instead of the stream
69 * to be able to store the 'ungotton' character.
72 static APR_INLINE svn_error_t
*
73 parser_getc(parse_context_t
*ctx
, int *c
)
75 if (ctx
->have_ungotten_char
)
77 *c
= ctx
->ungotten_char
;
78 ctx
->have_ungotten_char
= FALSE
;
83 apr_size_t readlen
= 1;
85 SVN_ERR(svn_stream_read(ctx
->stream
, &char_buf
, &readlen
));
96 /* Emulate ungetc() because streams don't support it.
98 * Use CTX to store the ungotten character C.
100 static APR_INLINE svn_error_t
*
101 parser_ungetc(parse_context_t
*ctx
, int c
)
103 ctx
->ungotten_char
= c
;
104 ctx
->have_ungotten_char
= TRUE
;
109 /* Eat chars from STREAM until encounter non-whitespace, newline, or EOF.
110 Set *PCOUNT to the number of characters eaten, not counting the
111 last one, and return the last char read (the one that caused the
113 static APR_INLINE svn_error_t
*
114 skip_whitespace(parse_context_t
*ctx
, int *c
, int *pcount
)
119 SVN_ERR(parser_getc(ctx
, &ch
));
120 while (ch
!= EOF
&& ch
!= '\n' && apr_isspace(ch
))
123 SVN_ERR(parser_getc(ctx
, &ch
));
131 /* Skip to the end of the line (or file). Returns the char that ended
132 the line; the char is either EOF or newline. */
133 static APR_INLINE svn_error_t
*
134 skip_to_eoln(parse_context_t
*ctx
, int *c
)
138 SVN_ERR(parser_getc(ctx
, &ch
));
139 while (ch
!= EOF
&& ch
!= '\n')
140 SVN_ERR(parser_getc(ctx
, &ch
));
147 /* Parse a single option value */
149 parse_value(int *pch
, parse_context_t
*ctx
)
151 svn_boolean_t end_of_val
= FALSE
;
154 /* Read the first line of the value */
155 svn_stringbuf_setempty(ctx
->value
);
156 SVN_ERR(parser_getc(ctx
, &ch
));
157 while (ch
!= EOF
&& ch
!= '\n')
158 /* last ch seen was ':' or '=' in parse_option. */
160 const char char_from_int
= ch
;
161 svn_stringbuf_appendbytes(ctx
->value
, &char_from_int
, 1);
162 SVN_ERR(parser_getc(ctx
, &ch
));
164 /* Leading and trailing whitespace is ignored. */
165 svn_stringbuf_strip_whitespace(ctx
->value
);
167 /* Look for any continuation lines. */
171 if (ch
== EOF
|| end_of_val
)
173 /* At end of file. The value is complete, there can't be
174 any continuation lines. */
175 svn_config_set(ctx
->cfg
, ctx
->section
->data
,
176 ctx
->option
->data
, ctx
->value
->data
);
183 SVN_ERR(skip_whitespace(ctx
, &ch
, &count
));
188 /* The next line was empty. Ergo, it can't be a
189 continuation line. */
195 /* This is also an empty line. */
202 /* This line starts in the first column. That means
203 it's either a section, option or comment. Put
204 the char back into the stream, because it doesn't
206 SVN_ERR(parser_ungetc(ctx
, ch
));
211 /* This is a continuation line. Read it. */
212 svn_stringbuf_appendbytes(ctx
->value
, " ", 1);
214 while (ch
!= EOF
&& ch
!= '\n')
216 const char char_from_int
= ch
;
217 svn_stringbuf_appendbytes(ctx
->value
,
219 SVN_ERR(parser_getc(ctx
, &ch
));
221 /* Trailing whitespace is ignored. */
222 svn_stringbuf_strip_whitespace(ctx
->value
);
233 /* Parse a single option */
235 parse_option(int *pch
, parse_context_t
*ctx
, apr_pool_t
*pool
)
237 svn_error_t
*err
= SVN_NO_ERROR
;
240 svn_stringbuf_setempty(ctx
->option
);
241 ch
= *pch
; /* Yes, the first char is relevant. */
242 while (ch
!= EOF
&& ch
!= ':' && ch
!= '=' && ch
!= '\n')
244 const char char_from_int
= ch
;
245 svn_stringbuf_appendbytes(ctx
->option
, &char_from_int
, 1);
246 SVN_ERR(parser_getc(ctx
, &ch
));
249 if (ch
!= ':' && ch
!= '=')
252 err
= svn_error_createf(SVN_ERR_MALFORMED_FILE
, NULL
,
253 "%s:%d: Option must end with ':' or '='",
254 svn_path_local_style(ctx
->file
, pool
),
259 /* Whitespace around the name separator is ignored. */
260 svn_stringbuf_strip_whitespace(ctx
->option
);
261 err
= parse_value(&ch
, ctx
);
269 /* Read chars until enounter ']', then skip everything to the end of
270 * the line. Set *PCH to the character that ended the line (either
271 * newline or EOF), and set CTX->section to the string of characters
274 * This is meant to be called immediately after reading the '[' that
275 * starts a section name.
278 parse_section_name(int *pch
, parse_context_t
*ctx
, apr_pool_t
*pool
)
280 svn_error_t
*err
= SVN_NO_ERROR
;
283 svn_stringbuf_setempty(ctx
->section
);
284 SVN_ERR(parser_getc(ctx
, &ch
));
285 while (ch
!= EOF
&& ch
!= ']' && ch
!= '\n')
287 const char char_from_int
= ch
;
288 svn_stringbuf_appendbytes(ctx
->section
, &char_from_int
, 1);
289 SVN_ERR(parser_getc(ctx
, &ch
));
295 err
= svn_error_createf(SVN_ERR_MALFORMED_FILE
, NULL
,
296 "%s:%d: Section header must end with ']'",
297 svn_path_local_style(ctx
->file
, pool
),
302 /* Everything from the ']' to the end of the line is ignored. */
303 SVN_ERR(skip_to_eoln(ctx
, &ch
));
314 svn_config__sys_config_path(const char **path_p
,
318 /* ### This never actually returns error in practice. Perhaps the
319 prototype should change? */
323 /* Note that even if fname is null, svn_path_join_many will DTRT. */
328 SVN_ERR(svn_config__win_config_path(&folder
, TRUE
, pool
));
329 *path_p
= svn_path_join_many(pool
, folder
,
330 SVN_CONFIG__SUBDIRECTORY
, fname
, NULL
);
335 *path_p
= svn_path_join_many(pool
, SVN_CONFIG__SYS_DIRECTORY
, fname
, NULL
);
344 svn_config__user_config_path(const char *config_dir
,
349 /* ### This never actually returns error in practice. Perhaps the
350 prototype should change? */
354 /* Note that even if fname is null, svn_path_join_many will DTRT. */
358 *path_p
= svn_path_join_many(pool
, config_dir
, fname
, NULL
);
365 SVN_ERR(svn_config__win_config_path(&folder
, FALSE
, pool
));
366 *path_p
= svn_path_join_many(pool
, folder
,
367 SVN_CONFIG__SUBDIRECTORY
, fname
, NULL
);
372 const char *homedir
= svn_user_get_homedir(pool
);
375 *path_p
= svn_path_join_many(pool
,
376 svn_path_canonicalize(homedir
, pool
),
377 SVN_CONFIG__USR_DIRECTORY
, fname
, NULL
);
386 /*** Exported interfaces. ***/
390 svn_config__parse_file(svn_config_t
*cfg
, const char *file
,
391 svn_boolean_t must_exist
, apr_pool_t
*pool
)
393 svn_error_t
*err
= SVN_NO_ERROR
;
398 /* No need for buffering; a translated stream buffers */
399 err
= svn_io_file_open(&f
, file
, APR_BINARY
| APR_READ
,
400 APR_OS_DEFAULT
, pool
);
402 if (! must_exist
&& err
&& APR_STATUS_IS_ENOENT(err
->apr_err
))
404 svn_error_clear(err
);
412 ctx
.stream
= svn_subst_stream_translated(svn_stream_from_aprfile(f
, pool
),
413 "\n", TRUE
, NULL
, FALSE
, pool
);
415 ctx
.have_ungotten_char
= FALSE
;
416 ctx
.section
= svn_stringbuf_create("", pool
);
417 ctx
.option
= svn_stringbuf_create("", pool
);
418 ctx
.value
= svn_stringbuf_create("", pool
);
422 SVN_ERR(skip_whitespace(&ctx
, &ch
, &count
));
426 case '[': /* Start of section header */
428 SVN_ERR(parse_section_name(&ch
, &ctx
, pool
));
430 return svn_error_createf(SVN_ERR_MALFORMED_FILE
, NULL
,
431 "%s:%d: Section header"
432 " must start in the first column",
433 svn_path_local_style(file
, pool
),
437 case '#': /* Comment */
440 SVN_ERR(skip_to_eoln(&ctx
, &ch
));
444 return svn_error_createf(SVN_ERR_MALFORMED_FILE
, NULL
,
446 " must start in the first column",
447 svn_path_local_style(file
, pool
),
451 case '\n': /* Empty line */
455 case EOF
: /* End of file or read error */
459 if (svn_stringbuf_isempty(ctx
.section
))
460 return svn_error_createf(SVN_ERR_MALFORMED_FILE
, NULL
,
461 "%s:%d: Section header expected",
462 svn_path_local_style(file
, pool
),
465 return svn_error_createf(SVN_ERR_MALFORMED_FILE
, NULL
,
466 "%s:%d: Option expected",
467 svn_path_local_style(file
, pool
),
470 SVN_ERR(parse_option(&ch
, &ctx
, pool
));
476 /* Close the file and streams (and other cleanup): */
477 SVN_ERR(svn_stream_close(ctx
.stream
));
478 SVN_ERR(svn_io_file_close(f
, pool
));
484 /* Helper for svn_config_ensure: see if ~/.subversion/auth/ and its
485 subdirs exist, try to create them, but don't throw errors on
486 failure. PATH is assumed to be a path to the user's private config
489 ensure_auth_dirs(const char *path
,
492 svn_node_kind_t kind
;
493 const char *auth_dir
, *auth_subdir
;
496 /* Ensure ~/.subversion/auth/ */
497 auth_dir
= svn_path_join_many(pool
, path
, SVN_CONFIG__AUTH_SUBDIR
, NULL
);
498 err
= svn_io_check_path(auth_dir
, &kind
, pool
);
499 if (err
|| kind
== svn_node_none
)
501 svn_error_clear(err
);
502 /* 'chmod 700' permissions: */
503 err
= svn_io_dir_make(auth_dir
,
504 (APR_UREAD
| APR_UWRITE
| APR_UEXECUTE
),
508 /* Don't try making subdirs if we can't make the top-level dir. */
509 svn_error_clear(err
);
514 /* If a provider exists that wants to store credentials in
515 ~/.subversion, a subdirectory for the cred_kind must exist. */
517 auth_subdir
= svn_path_join_many(pool
, auth_dir
,
518 SVN_AUTH_CRED_SIMPLE
, NULL
);
519 err
= svn_io_check_path(auth_subdir
, &kind
, pool
);
520 if (err
|| kind
== svn_node_none
)
522 svn_error_clear(err
);
523 svn_error_clear(svn_io_dir_make(auth_subdir
, APR_OS_DEFAULT
, pool
));
526 auth_subdir
= svn_path_join_many(pool
, auth_dir
,
527 SVN_AUTH_CRED_USERNAME
, NULL
);
528 err
= svn_io_check_path(auth_subdir
, &kind
, pool
);
529 if (err
|| kind
== svn_node_none
)
531 svn_error_clear(err
);
532 svn_error_clear(svn_io_dir_make(auth_subdir
, APR_OS_DEFAULT
, pool
));
535 auth_subdir
= svn_path_join_many(pool
, auth_dir
,
536 SVN_AUTH_CRED_SSL_SERVER_TRUST
, NULL
);
537 err
= svn_io_check_path(auth_subdir
, &kind
, pool
);
538 if (err
|| kind
== svn_node_none
)
540 svn_error_clear(err
);
541 svn_error_clear(svn_io_dir_make(auth_subdir
, APR_OS_DEFAULT
, pool
));
547 svn_config_ensure(const char *config_dir
, apr_pool_t
*pool
)
550 svn_node_kind_t kind
;
553 /* Ensure that the user-specific config directory exists. */
554 SVN_ERR(svn_config__user_config_path(config_dir
, &path
, NULL
, pool
));
559 err
= svn_io_check_path(path
, &kind
, pool
);
562 /* Don't throw an error, but don't continue. */
563 svn_error_clear(err
);
567 if (kind
== svn_node_none
)
569 err
= svn_io_dir_make(path
, APR_OS_DEFAULT
, pool
);
572 /* Don't throw an error, but don't continue. */
573 svn_error_clear(err
);
577 else if (kind
== svn_node_file
)
579 /* Somebody put a file where the config directory should be.
580 Wacky. Let's bail. */
584 /* Else, there's a configuration directory. */
586 /* If we get errors trying to do things below, just stop and return
587 success. There's no _need_ to init a config directory if
588 something's preventing it. */
590 /** If non-existent, try to create a number of auth/ subdirectories. */
591 ensure_auth_dirs(path
, pool
);
593 /** Ensure that the `README.txt' file exists. **/
594 SVN_ERR(svn_config__user_config_path
595 (config_dir
, &path
, SVN_CONFIG__USR_README_FILE
, pool
));
597 if (! path
) /* highly unlikely, since a previous call succeeded */
600 err
= svn_io_check_path(path
, &kind
, pool
);
603 svn_error_clear(err
);
607 if (kind
== svn_node_none
)
610 const char *contents
=
611 "This directory holds run-time configuration information for Subversion" NL
612 "clients. The configuration files all share the same syntax, but you" NL
613 "should examine a particular file to learn what configuration" NL
614 "directives are valid for that file." NL
616 "The syntax is standard INI format:" NL
618 " - Empty lines, and lines starting with '#', are ignored." NL
619 " The first significant line in a file must be a section header." NL
621 " - A section starts with a section header, which must start in" NL
622 " the first column:" NL
626 " - An option, which must always appear within a section, is a pair" NL
627 " (name, value). There are two valid forms for defining an" NL
628 " option, both of which must start in the first column:" NL
633 " Whitespace around the separator (:, =) is optional." NL
635 " - Section and option names are case-insensitive, but case is" NL
638 " - An option's value may be broken into several lines. The value" NL
639 " continuation lines must start with at least one whitespace." NL
640 " Trailing whitespace in the previous line, the newline character" NL
641 " and the leading whitespace in the continuation line is compressed" NL
642 " into a single space character." NL
644 " - All leading and trailing whitespace around a value is trimmed," NL
645 " but the whitespace within a value is preserved, with the" NL
646 " exception of whitespace around line continuations, as" NL
647 " described above." NL
649 " - When a value is a boolean, any of the following strings are" NL
650 " recognised as truth values (case does not matter):" NL
657 " - When a value is a list, it is comma-separated. Again, the" NL
658 " whitespace around each element of the list is trimmed." NL
660 " - Option values may be expanded within a value by enclosing the" NL
661 " option name in parentheses, preceded by a percent sign and" NL
662 " followed by an 's':" NL
666 " The expansion is performed recursively and on demand, during" NL
667 " svn_option_get. The name is first searched for in the same" NL
668 " section, then in the special [DEFAULT] section. If the name" NL
669 " is not found, the whole '%(name)s' placeholder is left" NL
672 " Any modifications to the configuration data invalidate all" NL
673 " previously expanded values, so that the next svn_option_get" NL
674 " will take the modifications into account." NL
676 "The syntax of the configuration files is a subset of the one used by" NL
677 "Python's ConfigParser module; see" NL
679 " http://www.python.org/doc/current/lib/module-ConfigParser.html" NL
681 "Configuration data in the Windows registry" NL
682 "==========================================" NL
684 "On Windows, configuration data may also be stored in the registry. The" NL
685 "functions svn_config_read and svn_config_merge will read from the" NL
686 "registry when passed file names of the form:" NL
688 " REGISTRY:<hive>/path/to/config-key" NL
690 "The REGISTRY: prefix must be in upper case. The <hive> part must be" NL
693 " HKLM for HKEY_LOCAL_MACHINE" NL
694 " HKCU for HKEY_CURRENT_USER" NL
696 "The values in config-key represent the options in the [DEFAULT] section."NL
697 "The keys below config-key represent other sections, and their values" NL
698 "represent the options. Only values of type REG_SZ whose name doesn't" NL
699 "start with a '#' will be used; other values, as well as the keys'" NL
700 "default values, will be ignored." NL
706 "Typically, Subversion uses two config directories, one for site-wide" NL
710 " /etc/subversion/servers" NL
711 " /etc/subversion/config" NL
712 " /etc/subversion/hairstyles" NL
714 " %ALLUSERSPROFILE%\\Application Data\\Subversion\\servers" NL
715 " %ALLUSERSPROFILE%\\Application Data\\Subversion\\config" NL
716 " %ALLUSERSPROFILE%\\Application Data\\Subversion\\hairstyles" NL
717 " REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Servers" NL
718 " REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Config" NL
719 " REGISTRY:HKLM\\Software\\Tigris.org\\Subversion\\Hairstyles" NL
721 "and one for per-user configuration:" NL
724 " ~/.subversion/servers" NL
725 " ~/.subversion/config" NL
726 " ~/.subversion/hairstyles" NL
728 " %APPDATA%\\Subversion\\servers" NL
729 " %APPDATA%\\Subversion\\config" NL
730 " %APPDATA%\\Subversion\\hairstyles" NL
731 " REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Servers" NL
732 " REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Config" NL
733 " REGISTRY:HKCU\\Software\\Tigris.org\\Subversion\\Hairstyles" NL
736 err
= svn_io_file_open(&f
, path
,
737 (APR_WRITE
| APR_CREATE
| APR_EXCL
),
743 SVN_ERR(svn_io_file_write_full(f
, contents
,
744 strlen(contents
), NULL
, pool
));
745 SVN_ERR(svn_io_file_close(f
, pool
));
748 svn_error_clear(err
);
751 /** Ensure that the `servers' file exists. **/
752 SVN_ERR(svn_config__user_config_path
753 (config_dir
, &path
, SVN_CONFIG_CATEGORY_SERVERS
, pool
));
755 if (! path
) /* highly unlikely, since a previous call succeeded */
758 err
= svn_io_check_path(path
, &kind
, pool
);
761 svn_error_clear(err
);
765 if (kind
== svn_node_none
)
768 const char *contents
=
769 "### This file specifies server-specific protocol parameters," NL
770 "### including HTTP proxy information, and HTTP timeout settings." NL
772 "### The currently defined server options are:" NL
773 "### http-proxy-host Proxy host for HTTP connection" NL
774 "### http-proxy-port Port number of proxy host service" NL
775 "### http-proxy-username Username for auth to proxy service"NL
776 "### http-proxy-password Password for auth to proxy service"NL
777 "### http-proxy-exceptions List of sites that do not use proxy"
779 "### http-timeout Timeout for HTTP requests in seconds"
781 "### http-compression Whether to compress HTTP requests" NL
782 "### neon-debug-mask Debug mask for Neon HTTP library" NL
784 "### http-auth-types Auth types to use for HTTP library"NL
786 "### ssl-authority-files List of files, each of a trusted CAs"
788 "### ssl-trust-default-ca Trust the system 'default' CAs" NL
789 "### ssl-client-cert-file PKCS#12 format client certificate file"
791 "### ssl-client-cert-password Client Key password, if needed." NL
792 "### http-library Which library to use for http/https"
794 "### connections (neon or serf)" NL
796 "### HTTP timeouts, if given, are specified in seconds. A timeout" NL
797 "### of 0, i.e. zero, causes a builtin default to be used." NL
799 "### The commented-out examples below are intended only to" NL
800 "### demonstrate how to use this file; any resemblance to actual" NL
801 "### servers, living or dead, is entirely coincidental." NL
803 "### In this section, the URL of the repository you're trying to" NL
804 "### access is matched against the patterns on the right. If a" NL
805 "### match is found, the server info is from the section with the" NL
806 "### corresponding name." NL
809 "# group1 = *.collab.net" NL
810 "# othergroup = repository.blarggitywhoomph.com" NL
811 "# thirdgroup = *.example.com" NL
813 "### Information for the first group:" NL
815 "# http-proxy-host = proxy1.some-domain-name.com" NL
816 "# http-proxy-port = 80" NL
817 "# http-proxy-username = blah" NL
818 "# http-proxy-password = doubleblah" NL
819 "# http-timeout = 60" NL
821 "# http-auth-types = basic;digest;negotiate" NL
823 "# neon-debug-mask = 130" NL
825 "### Information for the second group:" NL
827 "# http-proxy-host = proxy2.some-domain-name.com" NL
828 "# http-proxy-port = 9000" NL
829 "# No username and password, so use the defaults below." NL
831 "### You can set default parameters in the 'global' section." NL
832 "### These parameters apply if no corresponding parameter is set in" NL
833 "### a specifically matched group as shown above. Thus, if you go" NL
834 "### through the same proxy server to reach every site on the" NL
835 "### Internet, you probably just want to put that server's" NL
836 "### information in the 'global' section and not bother with" NL
837 "### 'groups' or any other sections." NL
839 "### If you go through a proxy for all but a few sites, you can" NL
840 "### list those exceptions under 'http-proxy-exceptions'. This only"NL
841 "### overrides defaults, not explicitly matched server names." NL
843 "### 'ssl-authority-files' is a semicolon-delimited list of files," NL
844 "### each pointing to a PEM-encoded Certificate Authority (CA) " NL
845 "### SSL certificate. See details above for overriding security " NL
848 "# http-proxy-exceptions = *.exception.com, www.internal-site.org" NL
849 "# http-proxy-host = defaultproxy.whatever.com" NL
850 "# http-proxy-port = 7000" NL
851 "# http-proxy-username = defaultusername" NL
852 "# http-proxy-password = defaultpassword" NL
853 "# http-compression = no" NL
855 "# http-auth-types = basic;digest;negotiate" NL
857 "# No http-timeout, so just use the builtin default." NL
858 "# No neon-debug-mask, so neon debugging is disabled." NL
859 "# ssl-authority-files = /path/to/CAcert.pem;/path/to/CAcert2.pem" NL
;
861 err
= svn_io_file_open(&f
, path
,
862 (APR_WRITE
| APR_CREATE
| APR_EXCL
),
868 SVN_ERR(svn_io_file_write_full(f
, contents
,
869 strlen(contents
), NULL
, pool
));
870 SVN_ERR(svn_io_file_close(f
, pool
));
873 svn_error_clear(err
);
876 /** Ensure that the `config' file exists. **/
877 SVN_ERR(svn_config__user_config_path
878 (config_dir
, &path
, SVN_CONFIG_CATEGORY_CONFIG
, pool
));
880 if (! path
) /* highly unlikely, since a previous call succeeded */
883 err
= svn_io_check_path(path
, &kind
, pool
);
886 svn_error_clear(err
);
890 if (kind
== svn_node_none
)
893 const char *contents
=
894 "### This file configures various client-side behaviors." NL
896 "### The commented-out examples below are intended to demonstrate" NL
897 "### how to use this file." NL
899 "### Section for authentication and authorization customizations." NL
901 "### Set store-passwords to 'no' to avoid storing passwords in the" NL
902 "### auth/ area of your config directory. It defaults to 'yes'." NL
903 "### Note that this option only prevents saving of *new* passwords;" NL
904 "### it doesn't invalidate existing passwords. (To do that, remove" NL
905 "### the cache files by hand as described in the Subversion book.)" NL
906 "# store-passwords = no" NL
907 "### Set store-auth-creds to 'no' to avoid storing any subversion" NL
908 "### credentials in the auth/ area of your config directory." NL
909 "### It defaults to 'yes'. Note that this option only prevents" NL
910 "### saving of *new* credentials; it doesn't invalidate existing" NL
911 "### caches. (To do that, remove the cache files by hand.)" NL
912 "# store-auth-creds = no" NL
914 "### Section for configuring external helper applications." NL
916 "### Set editor to the command used to invoke your text editor." NL
917 "### This will override the environment variables that Subversion" NL
918 "### examines by default to find this information ($EDITOR, " NL
920 "# editor-cmd = editor (vi, emacs, notepad, etc.)" NL
921 "### Set diff-cmd to the absolute path of your 'diff' program." NL
922 "### This will override the compile-time default, which is to use" NL
923 "### Subversion's internal diff implementation." NL
924 "# diff-cmd = diff_program (diff, gdiff, etc.)" NL
925 "### Set diff3-cmd to the absolute path of your 'diff3' program." NL
926 "### This will override the compile-time default, which is to use" NL
927 "### Subversion's internal diff3 implementation." NL
928 "# diff3-cmd = diff3_program (diff3, gdiff3, etc.)" NL
929 "### Set diff3-has-program-arg to 'true' or 'yes' if your 'diff3'" NL
930 "### program accepts the '--diff-program' option." NL
931 "# diff3-has-program-arg = [true | false]" NL
932 "### Set merge-tool-cmd to the command used to invoke your external" NL
933 "### merging tool of choice. Subversion will pass 4 arguments to" NL
934 "### the specified command: base theirs mine merged" NL
935 "# merge-tool-cmd = merge_command" NL
937 "### Section for configuring tunnel agents." NL
939 "### Configure svn protocol tunnel schemes here. By default, only" NL
940 "### the 'ssh' scheme is defined. You can define other schemes to" NL
941 "### be used with 'svn+scheme://hostname/path' URLs. A scheme" NL
942 "### definition is simply a command, optionally prefixed by an" NL
943 "### environment variable name which can override the command if it" NL
944 "### is defined. The command (or environment variable) may contain" NL
945 "### arguments, using standard shell quoting for arguments with" NL
946 "### spaces. The command will be invoked as:" NL
947 "### <command> <hostname> svnserve -t" NL
948 "### (If the URL includes a username, then the hostname will be" NL
949 "### passed to the tunnel agent as <user>@<hostname>.) If the" NL
950 "### built-in ssh scheme were not predefined, it could be defined" NL
952 "# ssh = $SVN_SSH ssh" NL
953 "### If you wanted to define a new 'rsh' scheme, to be used with" NL
954 "### 'svn+rsh:' URLs, you could do so as follows:" NL
956 "### Or, if you wanted to specify a full path and arguments:" NL
957 "# rsh = /path/to/rsh -l myusername" NL
958 "### On Windows, if you are specifying a full path to a command," NL
959 "### use a forward slash (/) or a paired backslash (\\\\) as the" NL
960 "### path separator. A single backslash will be treated as an" NL
961 "### escape for the following character." NL
963 "### Section for configuring miscelleneous Subversion options." NL
965 "### Set global-ignores to a set of whitespace-delimited globs" NL
966 "### which Subversion will ignore in its 'status' output, and" NL
967 "### while importing or adding files and directories." NL
968 "### '*' matches leading dots, e.g. '*.rej' matches '.foo.rej'." NL
969 "# global-ignores = " SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_1 NL
970 "# " SVN_CONFIG__DEFAULT_GLOBAL_IGNORES_LINE_2 NL
971 "### Set log-encoding to the default encoding for log messages" NL
972 "# log-encoding = latin1" NL
973 "### Set use-commit-times to make checkout/update/switch/revert" NL
974 "### put last-committed timestamps on every file touched." NL
975 "# use-commit-times = yes" NL
976 "### Set no-unlock to prevent 'svn commit' from automatically" NL
977 "### releasing locks on files." NL
978 "# no-unlock = yes" NL
979 "### Set mime-types-file to a MIME type registry file, used to" NL
980 "### provide hints to Subversion's MIME type auto-detection" NL
982 "# mime-types-file = /path/to/mime.types" NL
983 "### Set preserved-conflict-file-exts to a whitespace-delimited" NL
984 "### list of patterns matching file extensions which should be" NL
985 "### preserved in generated conflict file names. By default," NL
986 "### conflict files use custom extensions." NL
987 "# preserved-conflict-file-exts = doc ppt xls od?" NL
988 "### Set enable-auto-props to 'yes' to enable automatic properties" NL
989 "### for 'svn add' and 'svn import', it defaults to 'no'." NL
990 "### Automatic properties are defined in the section 'auto-props'." NL
991 "# enable-auto-props = yes" NL
992 "### Set interactive-conflicts to 'no' to disable interactive" NL
993 "### confict resolution prompting. It defaults to 'yes'." NL
994 "# interactive-conflicts = no" NL
996 "### Section for configuring automatic properties." NL
998 "### The format of the entries is:" NL
999 "### file-name-pattern = propname[=value][;propname[=value]...]" NL
1000 "### The file-name-pattern can contain wildcards (such as '*' and" NL
1001 "### '?'). All entries which match (case-insensitively) will be" NL
1002 "### applied to the file. Note that auto-props functionality" NL
1003 "### must be enabled, which is typically done by setting the" NL
1004 "### 'enable-auto-props' option." NL
1005 "# *.c = svn:eol-style=native" NL
1006 "# *.cpp = svn:eol-style=native" NL
1007 "# *.h = svn:eol-style=native" NL
1008 "# *.dsp = svn:eol-style=CRLF" NL
1009 "# *.dsw = svn:eol-style=CRLF" NL
1010 "# *.sh = svn:eol-style=native;svn:executable" NL
1011 "# *.txt = svn:eol-style=native" NL
1012 "# *.png = svn:mime-type=image/png" NL
1013 "# *.jpg = svn:mime-type=image/jpeg" NL
1014 "# Makefile = svn:eol-style=native" NL
1017 err
= svn_io_file_open(&f
, path
,
1018 (APR_WRITE
| APR_CREATE
| APR_EXCL
),
1024 SVN_ERR(svn_io_file_write_full(f
, contents
,
1025 strlen(contents
), NULL
, pool
));
1026 SVN_ERR(svn_io_file_close(f
, pool
));
1029 svn_error_clear(err
);
1032 return SVN_NO_ERROR
;