]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/subversion/subversion/libsvn_subr/config_win.c
Update svn-1.9.7 to 1.10.0.
[FreeBSD/FreeBSD.git] / contrib / subversion / subversion / libsvn_subr / config_win.c
1 /*
2  * config_win.c :  parsing configuration data from the registry
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 \f
26 #include "svn_private_config.h"
27
28 #ifdef WIN32
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. */
33
34 #define WIN32_LEAN_AND_MEAN
35 /* winsock2.h includes windows.h */
36 #include <winsock2.h>
37 #include <Ws2tcpip.h>
38
39 #include <shlobj.h>
40
41 #include <apr_file_info.h>
42
43 #include "svn_error.h"
44 #include "svn_path.h"
45 #include "svn_pools.h"
46 #include "svn_utf.h"
47 #include "private/svn_utf_private.h"
48
49 #include "config_impl.h"
50
51 svn_error_t *
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)
56 {
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)
61                      | CSIDL_FLAG_CREATE);
62
63   WCHAR folder_ucs2[MAX_PATH];
64   const char *folder_utf8;
65
66   if (! system_path)
67     {
68       HKEY hkey_tmp;
69
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 */
73       else
74         {
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.
81
82              We just answer that there is no user configuration directory. */
83
84           *folder = NULL;
85           return SVN_NO_ERROR;
86         }
87     }
88
89   if (S_OK != SHGetFolderPathW(NULL, csidl, NULL, SHGFP_TYPE_CURRENT,
90                                folder_ucs2))
91     return svn_error_create(SVN_ERR_BAD_FILENAME, NULL,
92                           (system_path
93                            ? _("Can't determine the system config path")
94                            : _("Can't determine the user's config path")));
95
96   SVN_ERR(svn_utf__win32_utf16_to_utf8(&folder_utf8, folder_ucs2,
97                                        NULL, scratch_pool));
98   *folder = svn_dirent_internal_style(folder_utf8, result_pool);
99
100   return SVN_NO_ERROR;
101 }
102
103 \f
104
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
109
110 /* ### This function should be converted to use the unicode functions
111    ### instead of the ansi functions */
112 static svn_error_t *
113 parse_section(svn_config_t *cfg, HKEY hkey, const char *section,
114               svn_stringbuf_t *option, svn_stringbuf_t *value)
115 {
116   DWORD option_len, type, index;
117   LONG err;
118
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)
123     {
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)
128           break;
129       if (err == ERROR_INSUFFICIENT_BUFFER)
130         {
131           svn_stringbuf_ensure(option, option_len);
132           err = RegEnumValue(hkey, index, option->data, &option_len,
133                              NULL, &type, NULL, NULL);
134         }
135       if (err != ERROR_SUCCESS)
136         return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
137                                 _("Can't enumerate registry values"));
138
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] != '#')
142         {
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)
147             {
148               svn_stringbuf_ensure(value, value_len);
149               err = RegQueryValueEx(hkey, option->data, NULL, NULL,
150                                     (LPBYTE)value->data, &value_len);
151             }
152           if (err != ERROR_SUCCESS)
153             return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
154                                     _("Can't read registry value data"));
155
156           svn_config_set(cfg, section, option->data, value->data);
157         }
158     }
159
160   return SVN_NO_ERROR;
161 }
162
163
164 \f
165 /*** Exported interface. ***/
166
167 svn_error_t *
168 svn_config__parse_registry(svn_config_t *cfg, const char *file,
169                            svn_boolean_t must_exist, apr_pool_t *pool)
170 {
171   apr_pool_t *subpool;
172   svn_stringbuf_t *section, *option, *value;
173   svn_error_t *svn_err = SVN_NO_ERROR;
174   HKEY base_hkey, hkey;
175   DWORD index;
176   LONG err;
177
178   if (0 == strncmp(file, SVN_REGISTRY_HKLM, SVN_REGISTRY_HKLM_LEN))
179     {
180       base_hkey = HKEY_LOCAL_MACHINE;
181       file += SVN_REGISTRY_HKLM_LEN;
182     }
183   else if (0 == strncmp(file, SVN_REGISTRY_HKCU, SVN_REGISTRY_HKCU_LEN))
184     {
185       base_hkey = HKEY_CURRENT_USER;
186       file += SVN_REGISTRY_HKCU_LEN;
187     }
188   else
189     {
190       return svn_error_createf(SVN_ERR_BAD_FILENAME, NULL,
191                                _("Unrecognised registry path '%s'"),
192                                svn_dirent_local_style(file, pool));
193     }
194
195   err = RegOpenKeyEx(base_hkey, file, 0,
196                      KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
197                      &hkey);
198   if (err != ERROR_SUCCESS)
199     {
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);
203
204       if (!is_enoent)
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));
209       else if (must_exist)
210         return svn_error_createf(SVN_ERR_BAD_FILENAME,
211                                  NULL,
212                                  _("Can't open registry key '%s'"),
213                                  svn_dirent_local_style(file, pool));
214       else
215         return SVN_NO_ERROR;
216     }
217
218
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);
223
224   /* The top-level values belong to the [DEFAULT] section */
225   svn_err = parse_section(cfg, hkey, SVN_CONFIG__DEFAULT_SECTION,
226                           option, value);
227   if (svn_err)
228     goto cleanup;
229
230   /* Now enumerate the rest of the keys. */
231   svn_stringbuf_ensure(section, SVN_REG_DEFAULT_NAME_SIZE);
232   for (index = 0; ; ++index)
233     {
234       DWORD section_len = (DWORD)section->blocksize;
235       HKEY sub_hkey;
236
237       err = RegEnumKeyEx(hkey, index, section->data, &section_len,
238                          NULL, NULL, NULL, NULL);
239       if (err == ERROR_NO_MORE_ITEMS)
240           break;
241       if (err == ERROR_MORE_DATA)
242         {
243           svn_stringbuf_ensure(section, section_len);
244           err = RegEnumKeyEx(hkey, index, section->data, &section_len,
245                              NULL, NULL, NULL, NULL);
246         }
247       if (err != ERROR_SUCCESS)
248         {
249           svn_err =  svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
250                                       _("Can't enumerate registry keys"));
251           goto cleanup;
252         }
253
254       err = RegOpenKeyEx(hkey, section->data, 0,
255                          KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
256                          &sub_hkey);
257       if (err != ERROR_SUCCESS)
258         {
259           svn_err =  svn_error_create(SVN_ERR_MALFORMED_FILE, NULL,
260                                       _("Can't open existing subkey"));
261           goto cleanup;
262         }
263
264       svn_err = parse_section(cfg, sub_hkey, section->data, option, value);
265       RegCloseKey(sub_hkey);
266       if (svn_err)
267         goto cleanup;
268     }
269
270  cleanup:
271   RegCloseKey(hkey);
272   svn_pool_destroy(subpool);
273   return svn_err;
274 }
275
276 #else  /* !WIN32 */
277
278 /* Silence OSX ranlib warnings about object files with no symbols. */
279 #include <apr.h>
280 extern const apr_uint32_t svn__fake__config_win;
281 const apr_uint32_t svn__fake__config_win = 0xdeadbeef;
282
283 #endif /* WIN32 */