2 * config_win.c : parsing configuration data from the registry
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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
21 * ====================================================================
26 #include "svn_private_config.h"
29 /* We must include windows.h ourselves or apr.h includes it for us with
30 many ignore options set. Including Winsock is required to resolve IPv6
31 compilation errors. APR_HAVE_IPV6 is only defined after including
32 apr.h, so we can't detect this case here. */
34 #define WIN32_LEAN_AND_MEAN
35 /* winsock2.h includes windows.h */
41 #include <apr_file_info.h>
43 #include "svn_error.h"
45 #include "svn_pools.h"
47 #include "private/svn_utf_private.h"
49 #include "config_impl.h"
52 svn_config__win_config_path(const char **folder,
53 svn_boolean_t system_path,
54 apr_pool_t *result_pool,
55 apr_pool_t *scratch_pool)
57 /* ### Adding CSIDL_FLAG_CREATE here, because those folders really
58 must exist. I'm not too sure about the SHGFP_TYPE_CURRENT
59 semancics, though; maybe we should use ..._DEFAULT instead? */
60 const int csidl = ((system_path ? CSIDL_COMMON_APPDATA : CSIDL_APPDATA)
63 WCHAR folder_ucs2[MAX_PATH];
64 const char *folder_utf8;
70 /* Verify if we actually have a *per user* profile to read from */
71 if (ERROR_SUCCESS == RegOpenCurrentUser(KEY_SET_VALUE, &hkey_tmp))
72 RegCloseKey(hkey_tmp); /* We have a profile */
75 /* The user is not properly logged in. (Most likely we are running
76 in a service process). In this case Windows will return a default
77 read only 'roaming profile' directory, which we assume to be
78 writable. We will then spend many seconds trying to create a
79 configuration and then fail, because we are not allowed to write
80 there, but the retry loop in io.c doesn't know that.
82 We just answer that there is no user configuration directory. */
89 if (S_OK != SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT,
91 return svn_error_create(SVN_ERR_BAD_FILENAME, NULL,
93 ? _("Can't determine the system config path")
94 : _("Can't determine the user's config path")));
96 SVN_ERR(svn_utf__win32_utf16_to_utf8(&folder_utf8, folder_ucs2,
98 *folder = svn_dirent_internal_style(folder_utf8, result_pool);
105 /* ### These constants are insanely large, but we want to avoid
106 reallocating strings if possible. */
107 #define SVN_REG_DEFAULT_NAME_SIZE 2048
108 #define SVN_REG_DEFAULT_VALUE_SIZE 8192
110 /* ### This function should be converted to use the unicode functions
111 ### instead of the ansi functions */
113 parse_section(svn_config_t *cfg, HKEY hkey, const char *section,
114 svn_stringbuf_t *option, svn_stringbuf_t *value)
116 DWORD option_len, type, index;
119 /* Start with a reasonable size for the buffers. */
120 svn_stringbuf_ensure(option, SVN_REG_DEFAULT_NAME_SIZE);
121 svn_stringbuf_ensure(value, SVN_REG_DEFAULT_VALUE_SIZE);
122 for (index = 0; ; ++index)
124 option_len = (DWORD)option->blocksize;
125 err = RegEnumValue(hkey, index, option->data, &option_len,
126 NULL, &type, NULL, NULL);
127 if (err == ERROR_NO_MORE_ITEMS)
129 if (err == ERROR_INSUFFICIENT_BUFFER)
131 svn_stringbuf_ensure(option, option_len);
132 err = RegEnumValue(hkey, index, option->data, &option_len,
133 NULL, &type, NULL, NULL);
135 if (err != ERROR_SUCCESS)
136 return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
137 _("Can't enumerate registry values"));
139 /* Ignore option names that start with '#', see
140 http://subversion.tigris.org/issues/show_bug.cgi?id=671 */
141 if (type == REG_SZ && option->data[0] != '#')
143 DWORD value_len = (DWORD)value->blocksize;
144 err = RegQueryValueEx(hkey, option->data, NULL, NULL,
145 (LPBYTE)value->data, &value_len);
146 if (err == ERROR_MORE_DATA)
148 svn_stringbuf_ensure(value, value_len);
149 err = RegQueryValueEx(hkey, option->data, NULL, NULL,
150 (LPBYTE)value->data, &value_len);
152 if (err != ERROR_SUCCESS)
153 return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
154 _("Can't read registry value data"));
156 svn_config_set(cfg, section, option->data, value->data);
165 /*** Exported interface. ***/
168 svn_config__parse_registry(svn_config_t *cfg, const char *file,
169 svn_boolean_t must_exist, apr_pool_t *pool)
172 svn_stringbuf_t *section, *option, *value;
173 svn_error_t *svn_err = SVN_NO_ERROR;
174 HKEY base_hkey, hkey;
178 if (0 == strncmp(file, SVN_REGISTRY_HKLM, SVN_REGISTRY_HKLM_LEN))
180 base_hkey = HKEY_LOCAL_MACHINE;
181 file += SVN_REGISTRY_HKLM_LEN;
183 else if (0 == strncmp(file, SVN_REGISTRY_HKCU, SVN_REGISTRY_HKCU_LEN))
185 base_hkey = HKEY_CURRENT_USER;
186 file += SVN_REGISTRY_HKCU_LEN;
190 return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
191 _("Unrecognised registry path '%s'"),
192 svn_dirent_local_style(file, pool));
195 err = RegOpenKeyEx(base_hkey, file, 0,
196 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
198 if (err != ERROR_SUCCESS)
200 apr_status_t apr_err = APR_FROM_OS_ERROR(err);
201 svn_boolean_t is_enoent = APR_STATUS_IS_ENOENT(apr_err)
202 || (err == ERROR_INVALID_HANDLE);
204 if (must_exist || !is_enoent)
205 return svn_error_createf(SVN_ERR_BAD_FILENAME,
207 : svn_error_wrap_apr(apr_err, NULL),
208 _("Can't open registry key '%s'"),
209 svn_dirent_local_style(file, pool));
215 subpool = svn_pool_create(pool);
216 section = svn_stringbuf_create_empty(subpool);
217 option = svn_stringbuf_create_empty(subpool);
218 value = svn_stringbuf_create_empty(subpool);
220 /* The top-level values belong to the [DEFAULT] section */
221 svn_err = parse_section(cfg, hkey, SVN_CONFIG__DEFAULT_SECTION,
226 /* Now enumerate the rest of the keys. */
227 svn_stringbuf_ensure(section, SVN_REG_DEFAULT_NAME_SIZE);
228 for (index = 0; ; ++index)
230 DWORD section_len = (DWORD)section->blocksize;
233 err = RegEnumKeyEx(hkey, index, section->data, §ion_len,
234 NULL, NULL, NULL, NULL);
235 if (err == ERROR_NO_MORE_ITEMS)
237 if (err == ERROR_MORE_DATA)
239 svn_stringbuf_ensure(section, section_len);
240 err = RegEnumKeyEx(hkey, index, section->data, §ion_len,
241 NULL, NULL, NULL, NULL);
243 if (err != ERROR_SUCCESS)
245 svn_err = svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
246 _("Can't enumerate registry keys"));
250 err = RegOpenKeyEx(hkey, section->data, 0,
251 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
253 if (err != ERROR_SUCCESS)
255 svn_err = svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
256 _("Can't open existing subkey"));
260 svn_err = parse_section(cfg, sub_hkey, section->data, option, value);
261 RegCloseKey(sub_hkey);
268 svn_pool_destroy(subpool);