upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / os / win32 / ap_regkey.c
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #ifdef WIN32
18
19 #include "apr.h"
20 #include "arch/win32/apr_arch_file_io.h"
21 #include "arch/win32/apr_arch_misc.h"
22 #include "ap_regkey.h"
23
24 struct ap_regkey_t {
25     apr_pool_t *pool;
26     HKEY        hkey;
27 };
28
29
30 AP_DECLARE(const ap_regkey_t *) ap_regkey_const(int i)
31 {
32     static struct ap_regkey_t ap_regkey_consts[7] = 
33     {
34         {NULL, HKEY_CLASSES_ROOT},
35         {NULL, HKEY_CURRENT_CONFIG},
36         {NULL, HKEY_CURRENT_USER},
37         {NULL, HKEY_LOCAL_MACHINE},
38         {NULL, HKEY_USERS},
39         {NULL, HKEY_PERFORMANCE_DATA},
40         {NULL, HKEY_DYN_DATA}
41     };
42     return ap_regkey_consts + i;
43 }
44
45
46 apr_status_t regkey_cleanup(void *key)
47 {
48     ap_regkey_t *regkey = key;
49
50     if (regkey->hkey && regkey->hkey != INVALID_HANDLE_VALUE) {
51         RegCloseKey(regkey->hkey);
52         regkey->hkey = INVALID_HANDLE_VALUE;
53     }
54     return APR_SUCCESS;
55 }
56
57
58 AP_DECLARE(apr_status_t) ap_regkey_open(ap_regkey_t **newkey, 
59                                         const ap_regkey_t *parentkey,
60                                         const char *keyname,
61                                         apr_int32_t flags, 
62                                         apr_pool_t *pool)
63 {
64     DWORD access = KEY_QUERY_VALUE;
65     DWORD exists;
66     HKEY hkey;
67     LONG rc;
68
69     if (flags & APR_READ)
70         access |= KEY_READ;
71     if (flags & APR_WRITE)
72         access |= KEY_WRITE; 
73
74 #if APR_HAS_UNICODE_FS
75     IF_WIN_OS_IS_UNICODE 
76     {
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)
82             return rv;
83         else if (keylen)
84             return APR_ENAMETOOLONG;
85
86         if (flags & APR_CREATE)
87             rc = RegCreateKeyExW(parentkey->hkey, wkeyname, 0, NULL, 0, 
88                                  access, NULL, &hkey, &exists);
89         else
90             rc = RegOpenKeyExW(parentkey->hkey, wkeyname, 0, access, &hkey);
91     }
92 #endif /* APR_HAS_UNICODE_FS */
93 #if APR_HAS_ANSI_FS
94     ELSE_WIN_OS_IS_ANSI
95     {
96         if (flags & APR_CREATE)
97             rc = RegCreateKeyEx(parentkey->hkey, keyname, 0, NULL, 0, 
98                                 access, NULL, &hkey, &exists);
99         else
100             rc = RegOpenKeyEx(parentkey->hkey, keyname, 0, access, &hkey);
101     }
102 #endif
103     if (rc != ERROR_SUCCESS) {
104         return APR_FROM_OS_ERROR(rc);
105     }
106     if ((flags & APR_EXCL) && (exists == REG_OPENED_EXISTING_KEY)) {
107         RegCloseKey(hkey);
108         return APR_EEXIST;
109     }
110
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);
116     return APR_SUCCESS;
117 }
118
119
120 AP_DECLARE(apr_status_t) ap_regkey_close(ap_regkey_t *regkey)
121 {
122     apr_status_t stat;
123     if ((stat = regkey_cleanup(regkey)) == APR_SUCCESS) {
124         apr_pool_cleanup_kill(regkey->pool, regkey, regkey_cleanup);
125     }
126     return stat;
127 }
128
129
130 AP_DECLARE(apr_status_t) ap_regkey_remove(const ap_regkey_t *parent, 
131                                           const char *keyname,
132                                           apr_pool_t *pool)
133 {
134     LONG rc;
135
136 #if APR_HAS_UNICODE_FS
137     IF_WIN_OS_IS_UNICODE 
138     {
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)
144             return rv;
145         else if (keylen)
146             return APR_ENAMETOOLONG;
147         rc = RegDeleteKeyW(parent->hkey, wkeyname);
148     }
149 #endif /* APR_HAS_UNICODE_FS */
150 #if APR_HAS_ANSI_FS
151     ELSE_WIN_OS_IS_ANSI
152     {
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.
156          */
157         DWORD subkeys;
158         HKEY hkey;
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);
164         RegCloseKey(hkey);
165         if (rc != ERROR_SUCCESS)
166             return APR_FROM_OS_ERROR(rc);
167         else if (subkeys)
168             return APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED);
169         rc = RegDeleteKey(parent->hkey, keyname);
170     }
171 #endif
172     if (rc != ERROR_SUCCESS) {
173         return APR_FROM_OS_ERROR(rc);
174     }
175     return APR_SUCCESS;
176 }
177
178
179 AP_DECLARE(apr_status_t) ap_regkey_value_get(char **result, 
180                                              ap_regkey_t *key, 
181                                              const char *valuename, 
182                                              apr_pool_t *pool)
183 {
184     /* Retrieve a registry string value, and explode any envvars
185      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
186      */
187     LONG rc;
188     DWORD type;
189     DWORD size = 0;
190     
191 #if APR_HAS_UNICODE_FS
192     IF_WIN_OS_IS_UNICODE 
193     {
194         apr_size_t valuelen = strlen(valuename) + 1;
195         apr_size_t wvallen = 256;
196         apr_wchar_t wvalname[256];
197         apr_wchar_t *wvalue;
198         apr_status_t rv;
199         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
200         if (rv != APR_SUCCESS)
201             return rv;
202         else if (valuelen)
203             return APR_ENAMETOOLONG;
204         /* Read to NULL buffer to determine value size */
205         rc = RegQueryValueExW(key->hkey, wvalname, 0, &type, NULL, &size);
206         if (rc != ERROR_SUCCESS) {
207             return APR_FROM_OS_ERROR(rc);
208         }
209         if ((size < 2) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
210             return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
211         }
212
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, &size);
217         if (rc != ERROR_SUCCESS) {
218             return APR_FROM_OS_ERROR(rc);
219         }
220         if (type == REG_EXPAND_SZ) {
221             apr_wchar_t zbuf[1];
222             size = ExpandEnvironmentStringsW(wvalue, zbuf, 0);
223             if (size) {
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, size);
228             }
229         }
230         else {
231             /* count wchars from RegQueryValueExW, rather than bytes */
232             size /= 2;
233         }
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.
237          */
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)
242             return rv;
243         else if (size)
244             return APR_ENAMETOOLONG;
245     }
246 #endif /* APR_HAS_UNICODE_FS */
247 #if APR_HAS_ANSI_FS
248     ELSE_WIN_OS_IS_ANSI
249     {
250         /* Read to NULL buffer to determine value size */
251         rc = RegQueryValueEx(key->hkey, valuename, 0, &type, NULL, &size);
252         if (rc != ERROR_SUCCESS)
253             return APR_FROM_OS_ERROR(rc);
254
255         if ((size < 1) || (type != REG_SZ && type != REG_EXPAND_SZ)) {
256             return APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER);
257         }
258
259         *result = apr_palloc(pool, size);
260         /* Read value based on size query above */
261         rc = RegQueryValueEx(key->hkey, valuename, 0, &type, *result, &size);
262         if (rc != ERROR_SUCCESS)
263             return APR_FROM_OS_ERROR(rc);
264
265         if (type == REG_EXPAND_SZ) {
266             /* Advise ExpandEnvironmentStrings that we have a zero char
267              * buffer to force computation of the required length.
268              */
269             char zbuf[1];
270             size = ExpandEnvironmentStrings(*result, zbuf, 0);
271             if (size) {
272                 char *tmp = *result;
273                 *result = apr_palloc(pool, size);
274                 size = ExpandEnvironmentStrings(tmp, *result, size);
275             }
276         }
277     }
278 #endif
279     return APR_SUCCESS;
280 }
281
282
283 AP_DECLARE(apr_status_t) ap_regkey_value_set(ap_regkey_t *key, 
284                                              const char *valuename, 
285                                              const char *value, 
286                                              apr_int32_t flags, 
287                                              apr_pool_t *pool)
288 {
289     /* Retrieve a registry string value, and explode any envvars
290      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
291      */
292     LONG rc;
293     DWORD size = strlen(value) + 1;
294     DWORD type = (flags & AP_REGKEY_EXPAND) ? REG_EXPAND_SZ : REG_SZ;
295     
296 #if APR_HAS_UNICODE_FS
297     IF_WIN_OS_IS_UNICODE 
298     {
299         apr_size_t alloclen;
300         apr_size_t valuelen = strlen(valuename) + 1;
301         apr_size_t wvallen = 256;
302         apr_wchar_t wvalname[256];
303         apr_wchar_t *wvalue;
304         apr_status_t rv;
305         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
306         if (rv != APR_SUCCESS)
307             return rv;
308         else if (valuelen)
309             return APR_ENAMETOOLONG;
310         
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)
315             return rv;
316         else if (size)
317             return APR_ENAMETOOLONG;
318
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.
321          */
322         size = (alloclen - wvallen) * 2;
323         rc = RegSetValueExW(key->hkey, wvalname, 0, type, 
324                             (LPBYTE)wvalue, size);
325         if (rc != ERROR_SUCCESS)
326             return APR_FROM_OS_ERROR(rc);
327     }
328 #endif /* APR_HAS_UNICODE_FS */
329 #if APR_HAS_ANSI_FS
330     ELSE_WIN_OS_IS_ANSI
331     {
332         rc = RegSetValueEx(key->hkey, valuename, 0, type, value, size);
333         if (rc != ERROR_SUCCESS)
334             return APR_FROM_OS_ERROR(rc);
335     }
336 #endif
337     return APR_SUCCESS;
338 }
339
340
341 AP_DECLARE(apr_status_t) ap_regkey_value_raw_get(void **result, 
342                                                  apr_size_t *resultsize,
343                                                  apr_int32_t *resulttype,
344                                                  ap_regkey_t *key, 
345                                                  const char *valuename, 
346                                                  apr_pool_t *pool)
347 {
348     /* Retrieve a registry string value, and explode any envvars
349      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
350      */
351     LONG rc;
352     
353 #if APR_HAS_UNICODE_FS
354     IF_WIN_OS_IS_UNICODE 
355     {
356         apr_size_t valuelen = strlen(valuename) + 1;
357         apr_size_t wvallen = 256;
358         apr_wchar_t wvalname[256];
359         apr_status_t rv;
360         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
361         if (rv != APR_SUCCESS)
362             return rv;
363         else if (valuelen)
364             return APR_ENAMETOOLONG;
365         /* Read to NULL buffer to determine value size */
366         rc = RegQueryValueExW(key->hkey, wvalname, 0, resulttype, 
367                               NULL, resultsize);
368         if (rc != ERROR_SUCCESS) {
369             return APR_FROM_OS_ERROR(rc);
370         }
371
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, resultsize);
376     }
377 #endif /* APR_HAS_UNICODE_FS */
378 #if APR_HAS_ANSI_FS
379     ELSE_WIN_OS_IS_ANSI
380     {
381         /* Read to NULL buffer to determine value size */
382         rc = RegQueryValueEx(key->hkey, valuename, 0, resulttype, 
383                              NULL, resultsize);
384         if (rc != ERROR_SUCCESS)
385             return APR_FROM_OS_ERROR(rc);
386
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, resultsize);
391         if (rc != ERROR_SUCCESS)
392             return APR_FROM_OS_ERROR(rc);
393     }
394 #endif
395     if (rc != ERROR_SUCCESS) {
396         return APR_FROM_OS_ERROR(rc);
397     }
398
399     return APR_SUCCESS;
400 }
401
402
403 AP_DECLARE(apr_status_t) ap_regkey_value_raw_set(ap_regkey_t *key, 
404                                                  const char *valuename, 
405                                                  const void *value, 
406                                                  apr_size_t valuesize,
407                                                  apr_int32_t valuetype,
408                                                  apr_pool_t *pool)
409 {
410     LONG rc;
411     
412 #if APR_HAS_UNICODE_FS
413     IF_WIN_OS_IS_UNICODE 
414     {
415         apr_size_t valuelen = strlen(valuename) + 1;
416         apr_size_t wvallen = 256;
417         apr_wchar_t wvalname[256];
418         apr_status_t rv;
419         rv = apr_conv_utf8_to_ucs2(valuename, &valuelen, wvalname, &wvallen);
420         if (rv != APR_SUCCESS)
421             return rv;
422         else if (valuelen)
423             return APR_ENAMETOOLONG;
424
425         rc = RegSetValueExW(key->hkey, wvalname, 0, valuetype, 
426                             (LPBYTE)value, valuesize);
427     }
428 #endif /* APR_HAS_UNICODE_FS */
429 #if APR_HAS_ANSI_FS
430     ELSE_WIN_OS_IS_ANSI
431     {
432         rc = RegSetValueEx(key->hkey, valuename, 0, valuetype, 
433                             (LPBYTE)value, valuesize);
434     }
435 #endif
436     if (rc != ERROR_SUCCESS) {
437         return APR_FROM_OS_ERROR(rc);
438     }
439     return APR_SUCCESS;
440 }
441
442
443 AP_DECLARE(apr_status_t) ap_regkey_value_array_get(apr_array_header_t **result, 
444                                                    ap_regkey_t *key,
445                                                    const char *valuename, 
446                                                    apr_pool_t *pool)
447 {
448     /* Retrieve a registry string value, and explode any envvars
449      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
450      */
451     apr_status_t rv;
452     void *value;
453     char *buf;
454     char *tmp;
455     DWORD type;
456     DWORD size = 0;
457
458     rv = ap_regkey_value_raw_get(&value, &size, &type, key, valuename, pool);
459     if (rv != APR_SUCCESS) {
460         return rv;
461     }
462     else if (type != REG_MULTI_SZ) {
463         return APR_EINVAL;
464     }
465
466 #if APR_HAS_UNICODE_FS
467     IF_WIN_OS_IS_UNICODE 
468     {
469         apr_size_t alloclen;
470         apr_size_t valuelen = strlen(valuename) + 1;
471         apr_size_t wvallen = 256;
472         apr_wchar_t *wvalue = (apr_wchar_t *)value;
473
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.
477          */
478         size /= 2;
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)
483             return rv;
484         else if (size)
485             return APR_ENAMETOOLONG;
486         buf[(alloclen - valuelen)] = '\0';
487         buf[(alloclen - valuelen) + 1] = '\0';
488     }
489 #endif /* APR_HAS_UNICODE_FS */
490 #if APR_HAS_ANSI_FS
491     ELSE_WIN_OS_IS_ANSI
492     {
493         /* Small possiblity the array is either unterminated 
494          * or single NULL terminated.  Avert.
495          */
496         buf = (char *)value;
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';
501             buf[size] = '\0';
502         }
503     }
504 #endif
505
506     size = 0;    /* Element Count */
507     for (tmp = buf; *tmp; ++tmp) {
508         ++size;
509         while (*tmp) {
510             ++tmp;
511         }
512     }
513
514     *result = apr_array_make(pool, size, sizeof(char *));
515     for (tmp = buf; *tmp; ++tmp) {
516         char **newelem = (char **) apr_array_push(*result);
517         *newelem = tmp;
518         while (*tmp) {
519             ++tmp;
520         }
521     }
522
523    return APR_SUCCESS;
524 }
525
526
527 AP_DECLARE(apr_status_t) ap_regkey_value_array_set(ap_regkey_t *key, 
528                                                    const char *valuename, 
529                                                    int nelts, 
530                                                    const char * const * elts,
531                                                    apr_pool_t *pool)
532 {
533     /* Retrieve a registry string value, and explode any envvars
534      * that the system has configured (e.g. %SystemRoot%/someapp.exe)
535      */
536     int i;
537     const void *value;
538     apr_size_t bufsize;
539     
540 #if APR_HAS_UNICODE_FS
541     IF_WIN_OS_IS_UNICODE 
542     {
543         apr_status_t rv;
544         apr_wchar_t *buf;
545         apr_wchar_t *tmp;
546         apr_size_t bufrem;
547
548         bufsize = 1; /* For trailing second null */
549         for (i = 0; i < nelts; ++i) {
550             bufsize += strlen(elts[i]) + 1;
551         }
552         if (!nelts) {
553             ++bufsize;
554         }
555
556         bufrem = bufsize;
557         buf = apr_palloc(pool, bufsize * 2);
558         tmp = buf;
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)
564                 return rv;
565             else if (size)
566                 return APR_ENAMETOOLONG;
567             tmp += eltsize;
568         }
569         if (!nelts) {
570             --bufrem;
571             (*tmp++) = L'\0';
572         }
573         --bufrem;
574         *tmp = L'\0'; /* Trailing second null */
575
576         bufsize = (bufsize - bufrem) * 2;
577         value = (void*)buf;
578     }
579 #endif /* APR_HAS_UNICODE_FS */
580 #if APR_HAS_ANSI_FS
581     ELSE_WIN_OS_IS_ANSI
582     {
583         char *buf;
584         char *tmp;
585
586         bufsize = 1; /* For trailing second null */
587         for (i = 0; i < nelts; ++i) {
588             bufsize += strlen(elts[i]) + 1;
589         }
590         if (!nelts) {
591             ++bufsize;
592         }
593         buf = apr_palloc(pool, bufsize);
594         tmp = buf;
595         for (i = 0; i < nelts; ++i) {
596             apr_size_t len = strlen(elts[i]) + 1;
597             memcpy(tmp, elts[i], len);
598             tmp += len;
599         }
600         if (!nelts) {
601             (*tmp++) = '\0';
602         }
603         *tmp = '\0'; /* Trailing second null */
604         value = buf;
605     }
606 #endif
607     return ap_regkey_value_raw_set(key, valuename, value, 
608                                    bufsize, REG_MULTI_SZ, pool);
609 }
610
611
612 AP_DECLARE(apr_status_t) ap_regkey_value_remove(const ap_regkey_t *key, 
613                                                 const char *valuename,
614                                                 apr_pool_t *pool)
615 {
616     LONG rc;
617
618 #if APR_HAS_UNICODE_FS
619     IF_WIN_OS_IS_UNICODE 
620     {
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)
626             return rv;
627         else if (valuelen)
628             return APR_ENAMETOOLONG;
629         rc = RegDeleteValueW(key->hkey, wvalname);
630     }
631 #endif /* APR_HAS_UNICODE_FS */
632 #if APR_HAS_ANSI_FS
633     ELSE_WIN_OS_IS_ANSI
634     {
635         rc = RegDeleteValue(key->hkey, valuename);
636     }
637 #endif
638     if (rc != ERROR_SUCCESS) {
639         return APR_FROM_OS_ERROR(rc);
640     }
641     return APR_SUCCESS;
642 }
643
644 #endif /* defined WIN32 */