1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
* contributor license agreements. See the NOTICE file distributed with
3
* this work for additional information regarding copyright ownership.
4
* The ASF licenses this file to You under the Apache License, Version 2.0
5
* (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
20
#include "arch/win32/apr_arch_file_io.h"
21
#include "arch/win32/apr_arch_misc.h"
22
#include "ap_regkey.h"
30
AP_DECLARE(const ap_regkey_t *) ap_regkey_const(int i)
32
static struct ap_regkey_t ap_regkey_consts[7] =
34
{NULL, HKEY_CLASSES_ROOT},
35
{NULL, HKEY_CURRENT_CONFIG},
36
{NULL, HKEY_CURRENT_USER},
37
{NULL, HKEY_LOCAL_MACHINE},
39
{NULL, HKEY_PERFORMANCE_DATA},
42
return ap_regkey_consts + i;
46
apr_status_t regkey_cleanup(void *key)
48
ap_regkey_t *regkey = key;
50
if (regkey->hkey && regkey->hkey != INVALID_HANDLE_VALUE) {
51
RegCloseKey(regkey->hkey);
52
regkey->hkey = INVALID_HANDLE_VALUE;
58
AP_DECLARE(apr_status_t) ap_regkey_open(ap_regkey_t **newkey,
59
const ap_regkey_t *parentkey,
64
DWORD access = KEY_QUERY_VALUE;
71
if (flags & APR_WRITE)
74
#if APR_HAS_UNICODE_FS
77
apr_size_t keylen = strlen(keyname) + 1;
78
apr_size_t wkeylen = 256;
79
apr_wchar_t wkeyname[256];
80
apr_status_t rv = apr_conv_utf8_to_ucs2(keyname, &keylen, wkeyname, &wkeylen);
81
if (rv != APR_SUCCESS)
84
return APR_ENAMETOOLONG;
86
if (flags & APR_CREATE)
87
rc = RegCreateKeyExW(parentkey->hkey, wkeyname, 0, NULL, 0,
88
access, NULL, &hkey, &exists);
90
rc = RegOpenKeyExW(parentkey->hkey, wkeyname, 0, access, &hkey);
92
#endif /* APR_HAS_UNICODE_FS */
96
if (flags & APR_CREATE)
97
rc = RegCreateKeyEx(parentkey->hkey, keyname, 0, NULL, 0,
98
access, NULL, &hkey, &exists);
100
rc = RegOpenKeyEx(parentkey->hkey, keyname, 0, access, &hkey);
103
if (rc != ERROR_SUCCESS) {
104
return APR_FROM_OS_ERROR(rc);
106
if ((flags & APR_EXCL) && (exists == REG_OPENED_EXISTING_KEY)) {
111
*newkey = apr_palloc(pool, sizeof(**newkey));
112
(*newkey)->pool = pool;
113
(*newkey)->hkey = hkey;
114
apr_pool_cleanup_register((*newkey)->pool, (void *)(*newkey),
115
regkey_cleanup, apr_pool_cleanup_null);
120
AP_DECLARE(apr_status_t) ap_regkey_close(ap_regkey_t *regkey)
123
if ((stat = regkey_cleanup(regkey)) == APR_SUCCESS) {
124
apr_pool_cleanup_kill(regkey->pool, regkey, regkey_cleanup);
130
AP_DECLARE(apr_status_t) ap_regkey_remove(const ap_regkey_t *parent,
136
#if APR_HAS_UNICODE_FS
139
apr_size_t keylen = strlen(keyname) + 1;
140
apr_size_t wkeylen = 256;
141
apr_wchar_t wkeyname[256];
142
apr_status_t rv = apr_conv_utf8_to_ucs2(keyname, &keylen, wkeyname, &wkeylen);
143
if (rv != APR_SUCCESS)
146
return APR_ENAMETOOLONG;
147
rc = RegDeleteKeyW(parent->hkey, wkeyname);
149
#endif /* APR_HAS_UNICODE_FS */
153
/* We need to determine if subkeys exist on Win9x, to provide
154
* consistent behavior with NT, which returns access denied
155
* if subkeys exist when attempting to delete a key.
159
rc = RegOpenKeyEx(parent->hkey, keyname, 0, KEY_READ, &hkey);
160
if (rc != ERROR_SUCCESS)
161
return APR_FROM_OS_ERROR(rc);
162
rc = RegQueryInfoKey(hkey, NULL, NULL, NULL, &subkeys, NULL, NULL,
163
NULL, NULL, NULL, NULL, NULL);
165
if (rc != ERROR_SUCCESS)
166
return APR_FROM_OS_ERROR(rc);
168
return APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED);
169
rc = RegDeleteKey(parent->hkey, keyname);
172
if (rc != ERROR_SUCCESS) {
173
return APR_FROM_OS_ERROR(rc);
179
AP_DECLARE(apr_status_t) ap_regkey_value_get(char **result,
181
const char *valuename,
184
/* Retrieve a registry string value, and explode any envvars
185
* that the system has configured (e.g. %SystemRoot%/someapp.exe)
191
#if APR_HAS_UNICODE_FS
194
apr_size_t valuelen = strlen(valuename) + 1;
195
apr_size_t wvallen = 256;
196
apr_wchar_t wvalname[256];
199
rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
200
if (rv != APR_SUCCESS)
203
return APR_ENAMETOOLONG;
204
/* Read to NULL buffer to determine value size */
205
rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, NULL, (DWORD *)&size);
206
if (rc != ERROR_SUCCESS) {
207
return APR_FROM_OS_ERROR(rc);
209
if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
210
return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
213
wvalue = apr_palloc(pool, size);
214
/* Read value based on size query above */
215
rc = RegQueryValueExW(key->hkey, wvalname, 0, &type,
216
(LPBYTE)wvalue, (DWORD *)&size);
217
if (rc != ERROR_SUCCESS) {
218
return APR_FROM_OS_ERROR(rc);
220
if (type == REG_EXPAND_SZ) {
222
size = ExpandEnvironmentStringsW(wvalue, zbuf, 0);
224
apr_wchar_t *tmp = wvalue;
225
/* The size returned by ExpandEnvironmentStringsW is wchars */
226
wvalue = apr_palloc(pool, size * 2);
227
size = ExpandEnvironmentStringsW(tmp, wvalue, (DWORD)size);
231
/* count wchars from RegQueryValueExW, rather than bytes */
234
/* ###: deliberately overallocate all but the trailing null.
235
* We could precalculate the exact buffer here instead, the question
236
* is a matter of storage v.s. cpu cycles.
238
valuelen = (size - 1) * 3 + 1;
239
*result = apr_palloc(pool, valuelen);
240
rv = apr_conv_ucs2_to_utf8(wvalue, &size, *result, &valuelen);
241
if (rv != APR_SUCCESS)
244
return APR_ENAMETOOLONG;
246
#endif /* APR_HAS_UNICODE_FS */
250
/* Read to NULL buffer to determine value size */
251
rc = RegQueryValueEx(key->hkey, valuename, 0, &type, NULL, (DWORD *)&size);
252
if (rc != ERROR_SUCCESS)
253
return APR_FROM_OS_ERROR(rc);
255
if ((size < 1) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
256
return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
259
*result = apr_palloc(pool, size);
260
/* Read value based on size query above */
261
rc = RegQueryValueEx(key->hkey, valuename, 0, &type, *result, (DWORD *)&size);
262
if (rc != ERROR_SUCCESS)
263
return APR_FROM_OS_ERROR(rc);
265
if (type == REG_EXPAND_SZ) {
266
/* Advise ExpandEnvironmentStrings that we have a zero char
267
* buffer to force computation of the required length.
270
size = ExpandEnvironmentStrings(*result, zbuf, 0);
273
*result = apr_palloc(pool, size);
274
size = ExpandEnvironmentStrings(tmp, *result, (DWORD)size);
283
AP_DECLARE(apr_status_t) ap_regkey_value_set(ap_regkey_t *key,
284
const char *valuename,
289
/* Retrieve a registry string value, and explode any envvars
290
* that the system has configured (e.g. %SystemRoot%/someapp.exe)
293
apr_size_t size = strlen(value) + 1;
294
DWORD type = (flags & AP_REGKEY_EXPAND) ? REG_EXPAND_SZ : REG_SZ;
296
#if APR_HAS_UNICODE_FS
300
apr_size_t valuelen = strlen(valuename) + 1;
301
apr_size_t wvallen = 256;
302
apr_wchar_t wvalname[256];
305
rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
306
if (rv != APR_SUCCESS)
309
return APR_ENAMETOOLONG;
311
wvallen = alloclen = size;
312
wvalue = apr_palloc(pool, alloclen * 2);
313
rv = apr_conv_utf8_to_ucs2(value, &size, wvalue, &wvallen);
314
if (rv != APR_SUCCESS)
317
return APR_ENAMETOOLONG;
319
/* The size is the number of wchars consumed by apr_conv_utf8_to_ucs2
320
* converted to bytes; the trailing L'\0' continues to be counted.
322
size = (alloclen - wvallen) * 2;
323
rc = RegSetValueExW(key->hkey, wvalname, 0, type,
324
(LPBYTE)wvalue, (DWORD)size);
325
if (rc != ERROR_SUCCESS)
326
return APR_FROM_OS_ERROR(rc);
328
#endif /* APR_HAS_UNICODE_FS */
332
rc = RegSetValueEx(key->hkey, valuename, 0, type, value, (DWORD)size);
333
if (rc != ERROR_SUCCESS)
334
return APR_FROM_OS_ERROR(rc);
341
AP_DECLARE(apr_status_t) ap_regkey_value_raw_get(void **result,
342
apr_size_t *resultsize,
343
apr_int32_t *resulttype,
345
const char *valuename,
348
/* Retrieve a registry string value, and explode any envvars
349
* that the system has configured (e.g. %SystemRoot%/someapp.exe)
353
#if APR_HAS_UNICODE_FS
356
apr_size_t valuelen = strlen(valuename) + 1;
357
apr_size_t wvallen = 256;
358
apr_wchar_t wvalname[256];
360
rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
361
if (rv != APR_SUCCESS)
364
return APR_ENAMETOOLONG;
365
/* Read to NULL buffer to determine value size */
366
rc = RegQueryValueExW(key->hkey, wvalname, 0, resulttype,
367
NULL, (LPDWORD)resultsize);
368
if (rc != ERROR_SUCCESS) {
369
return APR_FROM_OS_ERROR(rc);
372
/* Read value based on size query above */
373
*result = apr_palloc(pool, *resultsize);
374
rc = RegQueryValueExW(key->hkey, wvalname, 0, resulttype,
375
(LPBYTE)*result, (LPDWORD)resultsize);
377
#endif /* APR_HAS_UNICODE_FS */
381
/* Read to NULL buffer to determine value size */
382
rc = RegQueryValueEx(key->hkey, valuename, 0, resulttype,
383
NULL, (LPDWORD)resultsize);
384
if (rc != ERROR_SUCCESS)
385
return APR_FROM_OS_ERROR(rc);
387
/* Read value based on size query above */
388
*result = apr_palloc(pool, *resultsize);
389
rc = RegQueryValueEx(key->hkey, valuename, 0, resulttype,
390
(LPBYTE)*result, (LPDWORD)resultsize);
391
if (rc != ERROR_SUCCESS)
392
return APR_FROM_OS_ERROR(rc);
395
if (rc != ERROR_SUCCESS) {
396
return APR_FROM_OS_ERROR(rc);
403
AP_DECLARE(apr_status_t) ap_regkey_value_raw_set(ap_regkey_t *key,
404
const char *valuename,
406
apr_size_t valuesize,
407
apr_int32_t valuetype,
412
#if APR_HAS_UNICODE_FS
415
apr_size_t valuelen = strlen(valuename) + 1;
416
apr_size_t wvallen = 256;
417
apr_wchar_t wvalname[256];
419
rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
420
if (rv != APR_SUCCESS)
423
return APR_ENAMETOOLONG;
425
rc = RegSetValueExW(key->hkey, wvalname, 0, valuetype,
426
(LPBYTE)value, (DWORD)valuesize);
428
#endif /* APR_HAS_UNICODE_FS */
432
rc = RegSetValueEx(key->hkey, valuename, 0, valuetype,
433
(LPBYTE)value, (DWORD)valuesize);
436
if (rc != ERROR_SUCCESS) {
437
return APR_FROM_OS_ERROR(rc);
443
AP_DECLARE(apr_status_t) ap_regkey_value_array_get(apr_array_header_t **result,
445
const char *valuename,
448
/* Retrieve a registry string value, and explode any envvars
449
* that the system has configured (e.g. %SystemRoot%/someapp.exe)
458
rv = ap_regkey_value_raw_get(&value, &size, &type, key, valuename, pool);
459
if (rv != APR_SUCCESS) {
462
else if (type != REG_MULTI_SZ) {
466
#if APR_HAS_UNICODE_FS
470
apr_size_t valuelen = strlen(valuename) + 1;
471
apr_size_t wvallen = 256;
472
apr_wchar_t *wvalue = (apr_wchar_t *)value;
474
/* ###: deliberately overallocate plus two extra nulls.
475
* We could precalculate the exact buffer here instead, the question
476
* is a matter of storage v.s. cpu cycles.
479
alloclen = valuelen = size * 3 + 2;
480
buf = apr_palloc(pool, valuelen);
481
rv = apr_conv_ucs2_to_utf8(value, &size, buf, &valuelen);
482
if (rv != APR_SUCCESS)
485
return APR_ENAMETOOLONG;
486
buf[(alloclen - valuelen)] = '\0';
487
buf[(alloclen - valuelen) + 1] = '\0';
489
#endif /* APR_HAS_UNICODE_FS */
493
/* Small possiblity the array is either unterminated
494
* or single NULL terminated. Avert.
497
if (size < 2 || buf[size - 1] != '\0' || buf[size - 2] != '\0') {
498
buf = apr_palloc(pool, size + 2);
499
memcpy(buf, value, size);
500
buf[size + 1] = '\0';
506
size = 0; /* Element Count */
507
for (tmp = buf; *tmp; ++tmp) {
514
*result = apr_array_make(pool, (int)size, sizeof(char *));
515
for (tmp = buf; *tmp; ++tmp) {
516
char **newelem = (char **) apr_array_push(*result);
527
AP_DECLARE(apr_status_t) ap_regkey_value_array_set(ap_regkey_t *key,
528
const char *valuename,
530
const char * const * elts,
533
/* Retrieve a registry string value, and explode any envvars
534
* that the system has configured (e.g. %SystemRoot%/someapp.exe)
540
#if APR_HAS_UNICODE_FS
548
bufsize = 1; /* For trailing second null */
549
for (i = 0; i < nelts; ++i) {
550
bufsize += strlen(elts[i]) + 1;
557
buf = apr_palloc(pool, bufsize * 2);
559
for (i = 0; i < nelts; ++i) {
560
apr_size_t eltsize = strlen(elts[i]) + 1;
561
apr_size_t size = eltsize;
562
rv = apr_conv_utf8_to_ucs2(elts[i], &size, tmp, &bufrem);
563
if (rv != APR_SUCCESS)
566
return APR_ENAMETOOLONG;
574
*tmp = L'\0'; /* Trailing second null */
576
bufsize = (bufsize - bufrem) * 2;
579
#endif /* APR_HAS_UNICODE_FS */
586
bufsize = 1; /* For trailing second null */
587
for (i = 0; i < nelts; ++i) {
588
bufsize += strlen(elts[i]) + 1;
593
buf = apr_palloc(pool, bufsize);
595
for (i = 0; i < nelts; ++i) {
596
apr_size_t len = strlen(elts[i]) + 1;
597
memcpy(tmp, elts[i], len);
603
*tmp = '\0'; /* Trailing second null */
607
return ap_regkey_value_raw_set(key, valuename, value,
608
bufsize, REG_MULTI_SZ, pool);
612
AP_DECLARE(apr_status_t) ap_regkey_value_remove(const ap_regkey_t *key,
613
const char *valuename,
618
#if APR_HAS_UNICODE_FS
621
apr_size_t valuelen = strlen(valuename) + 1;
622
apr_size_t wvallen = 256;
623
apr_wchar_t wvalname[256];
624
apr_status_t rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
625
if (rv != APR_SUCCESS)
628
return APR_ENAMETOOLONG;
629
rc = RegDeleteValueW(key->hkey, wvalname);
631
#endif /* APR_HAS_UNICODE_FS */
635
rc = RegDeleteValue(key->hkey, valuename);
638
if (rc != ERROR_SUCCESS) {
639
return APR_FROM_OS_ERROR(rc);
644
#endif /* defined WIN32 */