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);
205 return svn_error_createf(SVN_ERR_BAD_FILENAME,
206 svn_error_wrap_apr(apr_err, NULL),
207 _("Can't open registry key '%s'"),
208 svn_dirent_local_style(file, pool));
210 return svn_error_createf(SVN_ERR_BAD_FILENAME,
212 _("Can't open registry key '%s'"),
213 svn_dirent_local_style(file, pool));
219 subpool = svn_pool_create(pool);
220 section = svn_stringbuf_create_empty(subpool);
221 option = svn_stringbuf_create_empty(subpool);
222 value = svn_stringbuf_create_empty(subpool);
224 /* The top-level values belong to the [DEFAULT] section */
225 svn_err = parse_section(cfg, hkey, SVN_CONFIG__DEFAULT_SECTION,
230 /* Now enumerate the rest of the keys. */
231 svn_stringbuf_ensure(section, SVN_REG_DEFAULT_NAME_SIZE);
232 for (index = 0; ; ++index)
234 DWORD section_len = (DWORD)section->blocksize;
237 err = RegEnumKeyEx(hkey, index, section->data, §ion_len,
238 NULL, NULL, NULL, NULL);
239 if (err == ERROR_NO_MORE_ITEMS)
241 if (err == ERROR_MORE_DATA)
243 svn_stringbuf_ensure(section, section_len);
244 err = RegEnumKeyEx(hkey, index, section->data, §ion_len,
245 NULL, NULL, NULL, NULL);
247 if (err != ERROR_SUCCESS)
249 svn_err = svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
250 _("Can't enumerate registry keys"));
254 err = RegOpenKeyEx(hkey, section->data, 0,
255 KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
257 if (err != ERROR_SUCCESS)
259 svn_err = svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
260 _("Can't open existing subkey"));
264 svn_err = parse_section(cfg, sub_hkey, section->data, option, value);
265 RegCloseKey(sub_hkey);
272 svn_pool_destroy(subpool);
278 /* Silence OSX ranlib warnings about object files with no symbols. */
280 extern const apr_uint32_t svn__fake__config_win;
281 const apr_uint32_t svn__fake__config_win = 0xdeadbeef;