[install] Update driver version to match package version
[sanbootconf.git] / installer / registry.c
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <windows.h>
23 #include "registry.h"
24
25 #define eprintf(...) fprintf ( stderr, __VA_ARGS__ )
26 #define array_size(x) ( sizeof ( (x) ) / sizeof ( (x)[0] ) )
27
28 #pragma warning(disable: 4702) /* Unreachable code */
29
30 /*****************************************************************************
31  *
32  * Generic routines for registry access
33  *
34  *****************************************************************************
35  */
36
37 /**
38  * Open registry key
39  *
40  * @v key               Registry key
41  * @v subkey_name       Registry subkey name, or NULL
42  * @v subkey            Opened key
43  * @ret err             Error status
44  */
45 LONG reg_open ( HKEY key, LPCWSTR subkey_name, PHKEY subkey ) {
46         LONG err;
47
48         err = RegOpenKeyExW ( key, subkey_name, 0, ( KEY_READ | KEY_WRITE ),
49                               subkey );
50         if ( err != ERROR_SUCCESS ) {
51                 eprintf ( "Could not open \"%S\": %x\n", subkey_name, err );
52                 return err;
53         }
54
55         return ERROR_SUCCESS;
56 }
57
58 /**
59  * Close registry key
60  *
61  * @v key               Registry key
62  */
63 VOID reg_close ( HKEY key ) {
64         RegCloseKey ( key );
65 }
66
67 /**
68  * Check existence of registry key
69  *
70  * @v key               Registry key
71  * @v subkey_name       Registry subkey name, or NULL
72  * @ret err             Error status
73  */
74 LONG reg_key_exists ( HKEY key, LPCWSTR subkey_name ) {
75         HKEY subkey;
76         LONG err;
77
78         err = reg_open ( key, subkey_name, &subkey );
79         if ( err != ERROR_SUCCESS )
80                 return err;
81
82         reg_close ( subkey );
83         return ERROR_SUCCESS;
84 }
85
86 /**
87  * Read raw registry value
88  *
89  * @v key               Registry key
90  * @v subkey_name       Registry subkey name, or NULL
91  * @v value_name        Registry value name
92  * @v buffer            Buffer to allocate and fill in
93  * @v len               Length of buffer to fill in
94  * @ret err             Error status
95  *
96  * The caller must free() the returned value.
97  */
98 LONG reg_query_value ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
99                        LPBYTE *buffer, LPDWORD len ) {
100         HKEY subkey;
101         LONG err;
102
103         /* Open subkey */
104         err = reg_open ( key, subkey_name, &subkey );
105         if ( err != ERROR_SUCCESS )
106                 goto err_open_subkey;
107
108         /* Determine length */
109         err = RegQueryValueExW ( subkey, value_name, NULL, NULL, NULL, len );
110         if ( err != ERROR_SUCCESS ) {
111                 if ( err != ERROR_FILE_NOT_FOUND ) {
112                         eprintf ( "Could not determine length of \"%S\": %x\n",
113                                   value_name, err );
114                 }
115                 goto err_get_length;
116         }
117
118         /* Allocate buffer for string + extra NUL (for safety) */
119         *buffer = malloc ( *len );
120         if ( ! *buffer ) {
121                 eprintf ( "Could not allocate buffer for \"%S\": %x\n",
122                           value_name, err );
123                 err = ERROR_NOT_ENOUGH_MEMORY;
124                 goto err_malloc;
125         }
126         memset ( *buffer, 0, *len );
127
128         /* Read data */
129         err = RegQueryValueExW ( subkey, value_name, NULL, NULL,
130                                  *buffer, len );
131         if ( err != ERROR_SUCCESS ) {
132                 eprintf ( "Could not read data for \"%S\": %x\n",
133                           value_name, err );
134                 goto err_read_data;
135         }
136
137         reg_close ( subkey );
138         return ERROR_SUCCESS;
139
140  err_read_data:
141         free ( *buffer );
142         *buffer = NULL;
143  err_malloc:
144  err_get_length:
145         reg_close ( subkey );
146  err_open_subkey:
147         return err;
148 }
149
150 /**
151  * Write raw registry value
152  *
153  * @v key               Registry key
154  * @v subkey_name       Registry subkey name, or NULL
155  * @v value_name        Registry value name
156  * @v data              Data to store
157  * @v len               Length of data
158  * @ret err             Error status
159  */
160 LONG reg_set_value ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
161                      DWORD type, LPBYTE data, DWORD len ) {
162         HKEY subkey;
163         LONG err;
164
165         /* Open subkey */
166         err = reg_open ( key, subkey_name, &subkey );
167         if ( err != ERROR_SUCCESS )
168                 goto err_open_subkey;
169
170         /* Store value */
171         err = RegSetValueExW ( subkey, value_name, 0, type, data, len );
172         if ( err != ERROR_SUCCESS ) {
173                 eprintf ( "Could not write data for \"%S\": %x\n",
174                           value_name, err );
175                 goto err_write_data;
176         }
177
178         /* Success */
179         err = 0;
180
181  err_write_data:
182         reg_close ( subkey );
183  err_open_subkey:
184         return err;
185 }
186
187 /**
188  * Check existence of registry value
189  *
190  * @v key               Registry key
191  * @v subkey_name       Registry subkey name, or NULL
192  * @v value_name        Registry value name
193  * @ret err             Error status
194  */
195 LONG reg_value_exists ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name ) {
196         LPBYTE buffer;
197         DWORD len;
198         LONG err;
199
200         err = reg_query_value ( key, subkey_name, value_name, &buffer, &len );
201         if ( err != ERROR_SUCCESS )
202                 return err;
203         free ( buffer );
204         return ERROR_SUCCESS;
205 }
206
207 /**
208  * Read REG_SZ value
209  *
210  * @v key               Registry key
211  * @v subkey_name       Registry subkey name, or NULL
212  * @v value_name        Registry value name
213  * @v sz                String to allocate and fill in
214  * @ret err             Error status
215  *
216  * The caller must free() the returned value "sz".
217  */
218 LONG reg_query_sz ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
219                     LPWSTR *sz ) {
220         LPBYTE buffer;
221         DWORD len;
222         DWORD sz_len;
223         LONG err;
224
225         /* Read raw data */
226         err = reg_query_value ( key, subkey_name, value_name, &buffer, &len );
227         if ( err != ERROR_SUCCESS )
228                 goto err_query_raw;
229
230         /* Allocate buffer for string + extra NUL (for safety) */
231         sz_len = ( len + sizeof ( sz[0] ) );
232         *sz = malloc ( sz_len );
233         if ( ! *sz ) {
234                 eprintf ( "Could not allocate string for \"%S\": %x\n",
235                           value_name, err );
236                 err = ERROR_NOT_ENOUGH_MEMORY;
237                 goto err_malloc;
238         }
239         memset ( *sz, 0, sz_len );
240
241         /* Copy string data */
242         memcpy ( *sz, buffer, len );
243
244         /* Success */
245         free ( buffer );
246         return ERROR_SUCCESS;
247
248         free ( *sz );
249         *sz = NULL;
250  err_malloc:
251         free ( buffer );
252  err_query_raw:
253         return err;
254 }
255
256 /**
257  * Write REG_SZ value
258  *
259  * @v key               Registry key
260  * @v subkey_name       Registry subkey name, or NULL
261  * @v value_name        Registry value name
262  * @v sz                String
263  * @ret err             Error status
264  */
265 LONG reg_set_sz ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
266                   LPWSTR sz ) {
267         SIZE_T len;
268
269         len = ( ( wcslen ( sz ) + 1 ) * sizeof ( sz[0] ) );
270         return reg_set_value ( key, subkey_name, value_name, REG_SZ,
271                                ( ( LPBYTE ) sz ), ( ( DWORD ) len ) );
272 }
273
274 /**
275  * Read REG_MULTI_SZ value
276  *
277  * @v key               Registry key
278  * @v subkey_name       Registry subkey name, or NULL
279  * @v value_name        Registry value name
280  * @v multi_sz          String array to allocate and fill in
281  * @ret err             Error status
282  *
283  * The caller must free() the returned value "multi_sz".
284  */
285 LONG reg_query_multi_sz ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
286                           LPWSTR **multi_sz ) {
287         LPBYTE buffer;
288         DWORD len;
289         DWORD num_szs;
290         LPWSTR sz;
291         DWORD multi_sz_len;
292         DWORD i;
293         LONG err;
294
295         /* Read raw data */
296         err = reg_query_value ( key, subkey_name, value_name, &buffer, &len );
297         if ( err != ERROR_SUCCESS )
298                 goto err_query_raw;
299
300         /* Count number of strings in the array.  This is a
301          * potential(ly harmless) overestimate.
302          */
303         num_szs = 0;
304         for ( sz = ( ( LPWSTR ) buffer ) ;
305               sz < ( ( LPWSTR ) ( buffer + len ) ) ; sz++ ) {
306                 if ( ! *sz )
307                         num_szs++;
308         }
309         
310         /* Allocate and populate string array */
311         multi_sz_len = ( ( ( num_szs + 1 ) * sizeof ( multi_sz[0] ) ) +
312                          len + sizeof ( multi_sz[0][0] ) );
313         *multi_sz = malloc ( multi_sz_len );
314         if ( ! *multi_sz ) {
315                 eprintf ( "Could not allocate string array for \"%S\"\n",
316                            value_name );
317                 err = ERROR_NOT_ENOUGH_MEMORY;
318                 goto err_malloc;
319         }
320         memset ( *multi_sz, 0, multi_sz_len );
321         sz = ( ( LPWSTR ) ( *multi_sz + num_szs + 1 ) );
322         memcpy ( sz, buffer, len );
323         for ( i = 0 ; i < num_szs ; i++ ) {
324                 if ( ! *sz )
325                         break;
326                 (*multi_sz)[i] = sz;
327                 while ( *sz )
328                         sz++;
329                 sz++;
330         }
331
332         /* Success */
333         free ( buffer );
334         return ERROR_SUCCESS;
335
336         free ( *multi_sz );
337         *multi_sz = NULL;
338  err_malloc:
339         free ( buffer );
340  err_query_raw:
341         return err;
342 }
343
344 /**
345  * Write REG_MULTI_SZ value
346  *
347  * @v key               Registry key
348  * @v subkey_name       Registry subkey name, or NULL
349  * @v value_name        Registry value name
350  * @v multi_sz          String array to allocate and fill in
351  * @ret err             Error status
352  *
353  * The caller must free() the returned value "multi_sz".
354  */
355 LONG reg_set_multi_sz ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
356                         LPWSTR *multi_sz ) {
357         LPWSTR *sz;
358         SIZE_T sz_len;
359         SIZE_T len;
360         LPBYTE buffer;
361         SIZE_T used;
362         LONG err;
363
364         /* Calculate total length and allocate block */
365         len = sizeof ( sz[0][0] ); /* List-terminating NUL */
366         for ( sz = multi_sz ; *sz ; sz++ ) {
367                 sz_len = ( ( wcslen ( *sz ) + 1 ) * sizeof ( sz[0][0] ) );
368                 len += sz_len;
369         }
370         buffer = malloc ( len );
371         if ( ! buffer ) {
372                 eprintf ( "Could not allocate string array for \"%S\"\n",
373                           value_name );
374                 err = ERROR_NOT_ENOUGH_MEMORY;
375                 goto err_malloc;
376         }
377
378         /* Populate block */
379         memset ( buffer, 0, len );
380         used = 0;
381         for ( sz = multi_sz ; *sz ; sz++ ) {
382                 sz_len = ( ( wcslen ( *sz ) + 1 ) * sizeof ( sz[0][0] ) );
383                 memcpy ( ( buffer + used ), *sz, sz_len );
384                 used += sz_len;
385         }
386
387         /* Write block to registry */
388         err = reg_set_value ( key, subkey_name, value_name, REG_MULTI_SZ,
389                               buffer, ( ( DWORD ) len ) );
390         if ( err != ERROR_SUCCESS )
391                 goto err_set_value;
392
393         /* Success */
394         err = ERROR_SUCCESS;
395
396  err_set_value:
397         free ( buffer );
398  err_malloc:
399         return err;
400 }
401
402 /**
403  * Read REG_DWORD value
404  *
405  * @v key               Registry key
406  * @v subkey_name       Registry subkey name, or NULL
407  * @v value_name        Registry value name
408  * @v dword             Dword to fill in
409  * @ret err             Error status
410  */
411 LONG reg_query_dword ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
412                        PDWORD dword ) {
413         LPBYTE buffer;
414         DWORD len;
415         LONG err;
416
417         /* Read raw data */
418         err = reg_query_value ( key, subkey_name, value_name, &buffer, &len );
419         if ( err != ERROR_SUCCESS )
420                 goto err_query_raw;
421
422         /* Sanity check */
423         if ( len != sizeof ( *dword ) ) {
424                 eprintf ( "Bad size for dword \"%S\"\n", value_name );
425                 goto err_bad_size;
426         }
427
428         /* Copy dword data */
429         memcpy ( dword, buffer, sizeof ( *dword ) );
430
431         /* Success */
432         err = ERROR_SUCCESS;
433
434  err_bad_size:
435         free ( buffer );
436  err_query_raw:
437         return err;
438 }
439
440 /**
441  * Write REG_DWORD value
442  *
443  * @v key               Registry key
444  * @v subkey_name       Registry subkey name, or NULL
445  * @v value_name        Registry value name
446  * @v dword             Dword
447  * @ret err             Error status
448  */
449 LONG reg_set_dword ( HKEY key, LPCWSTR subkey_name, LPCWSTR value_name,
450                      DWORD dword ) {
451         return reg_set_value ( key, subkey_name, value_name, REG_DWORD,
452                                ( ( LPBYTE ) &dword ), sizeof ( dword ) );
453 }