Converted all m_free to xfree etc.
[gnupg.git] / util / w32reg.c
1 /* w32reg.c -  MS-Windows Registry access
2  *      Copyright (C) 1999, 2002, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #if defined (_WIN32) || defined (__CYGWIN32__)
24  /* This module is only used in this environment */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <windows.h>
31 #include "util.h"
32 #include "memory.h"
33
34 static HKEY
35 get_root_key(const char *root)
36 {
37     HKEY root_key;
38         
39     if( !root )
40         root_key = HKEY_CURRENT_USER;
41     else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
42         root_key = HKEY_CLASSES_ROOT;
43     else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
44         root_key = HKEY_CURRENT_USER;
45     else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
46         root_key = HKEY_LOCAL_MACHINE;
47     else if( !strcmp( root, "HKEY_USERS" ) )
48         root_key = HKEY_USERS;
49     else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
50         root_key = HKEY_PERFORMANCE_DATA;
51     else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
52         root_key = HKEY_CURRENT_CONFIG;
53     else
54         return NULL;
55         
56     return root_key;
57 }
58
59
60 /****************
61  * Return a string from the Win32 Registry or NULL in case of
62  * error.  Caller must release the return value.   A NULL for root
63  * is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.
64  * NOTE: The value is allocated with a plain malloc() - use free() and not
65  * the usual xfree()!!!
66  */
67 char *
68 read_w32_registry_string( const char *root, const char *dir, const char *name )
69 {
70     HKEY root_key, key_handle;
71     DWORD n1, nbytes, type;
72     char *result = NULL;
73
74     if ( !(root_key = get_root_key(root) ) )
75         return NULL;
76
77     if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
78       {
79         if (root)
80           return NULL; /* no need for a RegClose, so return direct */
81         /* It seems to be common practise to fall back to HKLM. */
82         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
83           return NULL; /* still no need for a RegClose, so return direct */
84       }
85
86     nbytes = 1;
87     if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) {
88         if (root)
89             goto leave;
90         /* Try to fallback to HKLM also vor a missing value.  */
91         RegCloseKey (key_handle);
92         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
93             return NULL; /* Nope.  */
94         if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes))
95             goto leave;
96     }
97     result = malloc( (n1=nbytes+1) );
98     if( !result )
99         goto leave;
100     if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
101         free(result); result = NULL;
102         goto leave;
103     }
104     result[nbytes] = 0; /* make sure it is really a string  */
105     if (type == REG_EXPAND_SZ && strchr (result, '%')) {
106         char *tmp;
107         
108         n1 += 1000;
109         tmp = malloc (n1+1);
110         if (!tmp)
111             goto leave;
112         nbytes = ExpandEnvironmentStrings (result, tmp, n1);
113         if (nbytes && nbytes > n1) {
114             free (tmp);
115             n1 = nbytes;
116             tmp = malloc (n1 + 1);
117             if (!tmp)
118                 goto leave;
119             nbytes = ExpandEnvironmentStrings (result, tmp, n1);
120             if (nbytes && nbytes > n1) {
121                 free (tmp); /* oops - truncated, better don't expand at all */
122                 goto leave;
123             }
124             tmp[nbytes] = 0;
125             free (result);
126             result = tmp;
127         }
128         else if (nbytes) { /* okay, reduce the length */
129             tmp[nbytes] = 0;
130             free (result);
131             result = malloc (strlen (tmp)+1);
132             if (!result)
133                 result = tmp;
134             else {
135                 strcpy (result, tmp);
136                 free (tmp);
137             }
138         }
139         else {  /* error - don't expand */
140             free (tmp);
141         }
142     }
143
144   leave:
145     RegCloseKey( key_handle );
146     return result;
147 }
148
149
150 int
151 write_w32_registry_string(const char *root, const char *dir, 
152                           const char *name, const char *value)
153 {
154     HKEY root_key, reg_key;
155         
156     if ( !(root_key = get_root_key(root) ) )
157         return -1;
158
159     if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, &reg_key ) 
160          != ERROR_SUCCESS )
161         return -1;
162         
163     if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value, 
164                         strlen( value ) ) != ERROR_SUCCESS ) {
165         if ( RegCreateKey( root_key, name, &reg_key ) != ERROR_SUCCESS ) {
166             RegCloseKey(reg_key);
167             return -1;
168         }
169         if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value,
170                             strlen( value ) ) != ERROR_SUCCESS ) {
171             RegCloseKey(reg_key);
172             return -1;
173         }
174     }
175
176     RegCloseKey( reg_key );
177         
178     return 0;
179 }
180
181 #endif /* __MINGW32__ || __CYGWIN32__ */