xref: /reactos/base/applications/cmdutils/reg/query.c (revision 1a6f523e)
1761c3c98Swinesync /*
2761c3c98Swinesync  * Copyright 2016-2017, 2021 Hugh McMaster
3761c3c98Swinesync  *
4761c3c98Swinesync  * This library is free software; you can redistribute it and/or
5761c3c98Swinesync  * modify it under the terms of the GNU Lesser General Public
6761c3c98Swinesync  * License as published by the Free Software Foundation; either
7761c3c98Swinesync  * version 2.1 of the License, or (at your option) any later version.
8761c3c98Swinesync  *
9761c3c98Swinesync  * This library is distributed in the hope that it will be useful,
10761c3c98Swinesync  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11761c3c98Swinesync  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12761c3c98Swinesync  * Lesser General Public License for more details.
13761c3c98Swinesync  *
14761c3c98Swinesync  * You should have received a copy of the GNU Lesser General Public
15761c3c98Swinesync  * License along with this library; if not, write to the Free Software
16761c3c98Swinesync  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17761c3c98Swinesync  */
18761c3c98Swinesync 
19761c3c98Swinesync #include <stdio.h>
20761c3c98Swinesync #include "reg.h"
21761c3c98Swinesync 
reg_type_to_wchar(DWORD type)22761c3c98Swinesync static const WCHAR *reg_type_to_wchar(DWORD type)
23761c3c98Swinesync {
24761c3c98Swinesync     int i, array_size = ARRAY_SIZE(type_rels);
25761c3c98Swinesync 
26761c3c98Swinesync     for (i = 0; i < array_size; i++)
27761c3c98Swinesync     {
28761c3c98Swinesync         if (type == type_rels[i].type)
29761c3c98Swinesync             return type_rels[i].name;
30761c3c98Swinesync     }
31761c3c98Swinesync 
32761c3c98Swinesync     return NULL;
33761c3c98Swinesync }
34761c3c98Swinesync 
reg_data_to_wchar(DWORD type,const BYTE * src,DWORD size_bytes)35761c3c98Swinesync static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes)
36761c3c98Swinesync {
37761c3c98Swinesync     WCHAR *buffer = NULL;
38761c3c98Swinesync     int i;
39761c3c98Swinesync 
40761c3c98Swinesync     switch (type)
41761c3c98Swinesync     {
42761c3c98Swinesync         case REG_SZ:
43761c3c98Swinesync         case REG_EXPAND_SZ:
4468d5548fSwinesync             buffer = malloc(size_bytes);
45761c3c98Swinesync             lstrcpyW(buffer, (WCHAR *)src);
46761c3c98Swinesync             break;
47761c3c98Swinesync         case REG_NONE:
48761c3c98Swinesync         case REG_BINARY:
49761c3c98Swinesync         {
50761c3c98Swinesync             WCHAR *ptr;
51761c3c98Swinesync 
5268d5548fSwinesync             buffer = malloc((size_bytes * 2 + 1) * sizeof(WCHAR));
5364312c4fSwinesync 
5464312c4fSwinesync             if (!size_bytes)
5564312c4fSwinesync             {
5664312c4fSwinesync                 *buffer = 0;
5764312c4fSwinesync                 break;
5864312c4fSwinesync             }
5964312c4fSwinesync 
60761c3c98Swinesync             ptr = buffer;
6164312c4fSwinesync 
62761c3c98Swinesync             for (i = 0; i < size_bytes; i++)
63*1a6f523eSThomas Csovcsity                 ptr += swprintf(ptr, L"%02X", src[i]);
64761c3c98Swinesync             break;
65761c3c98Swinesync         }
66761c3c98Swinesync         case REG_DWORD:
67761c3c98Swinesync      /* case REG_DWORD_LITTLE_ENDIAN: */
68761c3c98Swinesync         case REG_DWORD_BIG_ENDIAN:
69761c3c98Swinesync         {
70761c3c98Swinesync             const int zero_x_dword = 10;
71761c3c98Swinesync 
7268d5548fSwinesync             buffer = malloc((zero_x_dword + 1) * sizeof(WCHAR));
73*1a6f523eSThomas Csovcsity             swprintf(buffer, L"0x%x", *(DWORD *)src);
74761c3c98Swinesync             break;
75761c3c98Swinesync         }
76761c3c98Swinesync         case REG_MULTI_SZ:
77761c3c98Swinesync         {
78761c3c98Swinesync             const int two_wchars = 2 * sizeof(WCHAR);
79761c3c98Swinesync             DWORD tmp_size;
80761c3c98Swinesync             const WCHAR *tmp = (const WCHAR *)src;
81761c3c98Swinesync             int len, destindex;
82761c3c98Swinesync 
83761c3c98Swinesync             if (size_bytes <= two_wchars)
84761c3c98Swinesync             {
8568d5548fSwinesync                 buffer = malloc(sizeof(WCHAR));
86761c3c98Swinesync                 *buffer = 0;
87761c3c98Swinesync                 return buffer;
88761c3c98Swinesync             }
89761c3c98Swinesync 
90761c3c98Swinesync             tmp_size = size_bytes - two_wchars; /* exclude both null terminators */
9168d5548fSwinesync             buffer = malloc(tmp_size * 2 + sizeof(WCHAR));
92761c3c98Swinesync             len = tmp_size / sizeof(WCHAR);
93761c3c98Swinesync 
94761c3c98Swinesync             for (i = 0, destindex = 0; i < len; i++, destindex++)
95761c3c98Swinesync             {
96761c3c98Swinesync                 if (tmp[i])
97761c3c98Swinesync                     buffer[destindex] = tmp[i];
98761c3c98Swinesync                 else
99761c3c98Swinesync                 {
100761c3c98Swinesync                     buffer[destindex++] = '\\';
101761c3c98Swinesync                     buffer[destindex] = '0';
102761c3c98Swinesync                 }
103761c3c98Swinesync             }
104761c3c98Swinesync             buffer[destindex] = 0;
105761c3c98Swinesync             break;
106761c3c98Swinesync         }
107761c3c98Swinesync     }
108761c3c98Swinesync     return buffer;
109761c3c98Swinesync }
110761c3c98Swinesync 
1115eb878feSwinesync static const WCHAR *newlineW = L"\n";
112761c3c98Swinesync 
output_value(const WCHAR * value_name,DWORD type,BYTE * data,DWORD data_size)113761c3c98Swinesync static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size)
114761c3c98Swinesync {
1155eb878feSwinesync     static const WCHAR *fmt = L"    %1";
116761c3c98Swinesync     WCHAR defval[32];
117761c3c98Swinesync     WCHAR *reg_data;
118761c3c98Swinesync 
119761c3c98Swinesync     if (value_name && value_name[0])
120761c3c98Swinesync         output_string(fmt, value_name);
121761c3c98Swinesync     else
122761c3c98Swinesync     {
123761c3c98Swinesync         LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
124761c3c98Swinesync         output_string(fmt, defval);
125761c3c98Swinesync     }
126761c3c98Swinesync     output_string(fmt, reg_type_to_wchar(type));
127761c3c98Swinesync 
128761c3c98Swinesync     if (data)
129761c3c98Swinesync     {
130761c3c98Swinesync         reg_data = reg_data_to_wchar(type, data, data_size);
131761c3c98Swinesync         output_string(fmt, reg_data);
13268d5548fSwinesync         free(reg_data);
133761c3c98Swinesync     }
134761c3c98Swinesync     else
135761c3c98Swinesync     {
136761c3c98Swinesync         LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval));
137761c3c98Swinesync         output_string(fmt, defval);
138761c3c98Swinesync     }
139761c3c98Swinesync     output_string(newlineW);
140761c3c98Swinesync }
141761c3c98Swinesync 
142761c3c98Swinesync static unsigned int num_values_found = 0;
143c6993373Swinesync static REGSAM sam = 0;
144761c3c98Swinesync 
query_value(HKEY hkey,WCHAR * value_name,WCHAR * path,BOOL recurse)145f0c76942Swinesync static int query_value(HKEY hkey, WCHAR *value_name, WCHAR *path, BOOL recurse)
146761c3c98Swinesync {
147761c3c98Swinesync     LONG rc;
148761c3c98Swinesync     DWORD max_data_bytes = 2048, data_size;
149761c3c98Swinesync     DWORD subkey_len;
150761c3c98Swinesync     DWORD type, path_len, i;
151761c3c98Swinesync     BYTE *data;
1525eb878feSwinesync     static const WCHAR *fmt = L"%1\n";
153761c3c98Swinesync     WCHAR *subkey_name, *subkey_path;
154761c3c98Swinesync     HKEY subkey;
155761c3c98Swinesync 
15668d5548fSwinesync     data = malloc(max_data_bytes);
157761c3c98Swinesync 
158761c3c98Swinesync     for (;;)
159761c3c98Swinesync     {
160761c3c98Swinesync         data_size = max_data_bytes;
161f0c76942Swinesync         rc = RegQueryValueExW(hkey, value_name, NULL, &type, data, &data_size);
162761c3c98Swinesync         if (rc == ERROR_MORE_DATA)
163761c3c98Swinesync         {
164761c3c98Swinesync             max_data_bytes = data_size;
16568d5548fSwinesync             data = realloc(data, max_data_bytes);
166761c3c98Swinesync         }
167761c3c98Swinesync         else break;
168761c3c98Swinesync     }
169761c3c98Swinesync 
170761c3c98Swinesync     if (rc == ERROR_SUCCESS)
171761c3c98Swinesync     {
172761c3c98Swinesync         output_string(fmt, path);
173761c3c98Swinesync         output_value(value_name, type, data, data_size);
174761c3c98Swinesync         output_string(newlineW);
175761c3c98Swinesync         num_values_found++;
176761c3c98Swinesync     }
177761c3c98Swinesync 
17868d5548fSwinesync     free(data);
179761c3c98Swinesync 
180761c3c98Swinesync     if (!recurse)
181761c3c98Swinesync     {
182761c3c98Swinesync         if (rc == ERROR_FILE_NOT_FOUND)
183761c3c98Swinesync         {
184761c3c98Swinesync             if (value_name && *value_name)
185761c3c98Swinesync             {
1866c0f70dbSwinesync                 output_message(STRING_VALUE_NONEXIST);
187761c3c98Swinesync                 return 1;
188761c3c98Swinesync             }
189761c3c98Swinesync             output_string(fmt, path);
190761c3c98Swinesync             output_value(NULL, REG_SZ, NULL, 0);
191761c3c98Swinesync         }
192761c3c98Swinesync         return 0;
193761c3c98Swinesync     }
194761c3c98Swinesync 
19568d5548fSwinesync     subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
196761c3c98Swinesync 
197761c3c98Swinesync     path_len = lstrlenW(path);
198761c3c98Swinesync 
199761c3c98Swinesync     i = 0;
200761c3c98Swinesync     for (;;)
201761c3c98Swinesync     {
202761c3c98Swinesync         subkey_len = MAX_SUBKEY_LEN;
203f0c76942Swinesync         rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
204761c3c98Swinesync         if (rc == ERROR_SUCCESS)
205761c3c98Swinesync         {
206761c3c98Swinesync             subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
207c6993373Swinesync             if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
208761c3c98Swinesync             {
209761c3c98Swinesync                 query_value(subkey, value_name, subkey_path, recurse);
210761c3c98Swinesync                 RegCloseKey(subkey);
211761c3c98Swinesync             }
21268d5548fSwinesync             free(subkey_path);
213761c3c98Swinesync             i++;
214761c3c98Swinesync         }
215761c3c98Swinesync         else break;
216761c3c98Swinesync     }
217761c3c98Swinesync 
21868d5548fSwinesync     free(subkey_name);
219761c3c98Swinesync     return 0;
220761c3c98Swinesync }
221761c3c98Swinesync 
query_all(HKEY hkey,WCHAR * path,BOOL recurse,BOOL recursing)22214b77379Swinesync static int query_all(HKEY hkey, WCHAR *path, BOOL recurse, BOOL recursing)
223761c3c98Swinesync {
224761c3c98Swinesync     LONG rc;
225d9ac7716Swinesync     DWORD num_subkeys, num_values;
226761c3c98Swinesync     DWORD max_value_len = 256, value_len;
227761c3c98Swinesync     DWORD max_data_bytes = 2048, data_size;
228761c3c98Swinesync     DWORD subkey_len;
229761c3c98Swinesync     DWORD i, type, path_len;
230761c3c98Swinesync     WCHAR *value_name, *subkey_name, *subkey_path;
231761c3c98Swinesync     BYTE *data;
232761c3c98Swinesync     HKEY subkey;
233761c3c98Swinesync 
234d9ac7716Swinesync     rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, &num_subkeys, NULL,
235d9ac7716Swinesync                           NULL, &num_values, NULL, NULL, NULL, NULL);
23614b77379Swinesync     if (rc) return 1;
23714b77379Swinesync 
23814b77379Swinesync     if (num_values || recursing)
2395eb878feSwinesync         output_string(L"%1\n", path);
240761c3c98Swinesync 
24168d5548fSwinesync     value_name = malloc(max_value_len * sizeof(WCHAR));
24268d5548fSwinesync     data = malloc(max_data_bytes);
243761c3c98Swinesync 
244761c3c98Swinesync     i = 0;
245761c3c98Swinesync     for (;;)
246761c3c98Swinesync     {
247761c3c98Swinesync         value_len = max_value_len;
248761c3c98Swinesync         data_size = max_data_bytes;
249f0c76942Swinesync         rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, data, &data_size);
250761c3c98Swinesync         if (rc == ERROR_SUCCESS)
251761c3c98Swinesync         {
252761c3c98Swinesync             output_value(value_name, type, data, data_size);
253761c3c98Swinesync             i++;
254761c3c98Swinesync         }
255761c3c98Swinesync         else if (rc == ERROR_MORE_DATA)
256761c3c98Swinesync         {
257761c3c98Swinesync             if (data_size > max_data_bytes)
258761c3c98Swinesync             {
259761c3c98Swinesync                 max_data_bytes = data_size;
26068d5548fSwinesync                 data = realloc(data, max_data_bytes);
261761c3c98Swinesync             }
262761c3c98Swinesync             else
263761c3c98Swinesync             {
264761c3c98Swinesync                 max_value_len *= 2;
26568d5548fSwinesync                 value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
266761c3c98Swinesync             }
267761c3c98Swinesync         }
268761c3c98Swinesync         else break;
269761c3c98Swinesync     }
270761c3c98Swinesync 
27168d5548fSwinesync     free(data);
27268d5548fSwinesync     free(value_name);
273761c3c98Swinesync 
2743dbd4208Swinesync     if (i || recursing)
275761c3c98Swinesync         output_string(newlineW);
276761c3c98Swinesync 
277d9ac7716Swinesync     if (!num_subkeys)
278d9ac7716Swinesync         return 0;
279d9ac7716Swinesync 
28068d5548fSwinesync     subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
281761c3c98Swinesync 
282761c3c98Swinesync     path_len = lstrlenW(path);
283761c3c98Swinesync 
284761c3c98Swinesync     i = 0;
285761c3c98Swinesync     for (;;)
286761c3c98Swinesync     {
287761c3c98Swinesync         subkey_len = MAX_SUBKEY_LEN;
288f0c76942Swinesync         rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
289761c3c98Swinesync         if (rc == ERROR_SUCCESS)
290761c3c98Swinesync         {
291761c3c98Swinesync             if (recurse)
292761c3c98Swinesync             {
293761c3c98Swinesync                 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
294c6993373Swinesync                 if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
295761c3c98Swinesync                 {
29614b77379Swinesync                     query_all(subkey, subkey_path, recurse, TRUE);
297761c3c98Swinesync                     RegCloseKey(subkey);
298761c3c98Swinesync                 }
29968d5548fSwinesync                 free(subkey_path);
300761c3c98Swinesync             }
3015eb878feSwinesync             else output_string(L"%1\\%2\n", path, subkey_name);
302761c3c98Swinesync             i++;
303761c3c98Swinesync         }
304761c3c98Swinesync         else break;
305761c3c98Swinesync     }
306761c3c98Swinesync 
30768d5548fSwinesync     free(subkey_name);
308761c3c98Swinesync     return 0;
309761c3c98Swinesync }
310761c3c98Swinesync 
run_query(HKEY root,WCHAR * path,WCHAR * key_name,WCHAR * value_name,BOOL value_empty,BOOL recurse)311354e1582Swinesync static int run_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name,
312761c3c98Swinesync                      BOOL value_empty, BOOL recurse)
313761c3c98Swinesync {
314f0c76942Swinesync     HKEY hkey;
315761c3c98Swinesync     int ret;
316761c3c98Swinesync 
317c6993373Swinesync     if (RegOpenKeyExW(root, path, 0, KEY_READ|sam, &hkey))
318761c3c98Swinesync     {
319e11511daSwinesync         output_message(STRING_KEY_NONEXIST);
320761c3c98Swinesync         return 1;
321761c3c98Swinesync     }
322761c3c98Swinesync 
323761c3c98Swinesync     output_string(newlineW);
324761c3c98Swinesync 
325761c3c98Swinesync     if (value_name || value_empty)
326761c3c98Swinesync     {
327f0c76942Swinesync         ret = query_value(hkey, value_name, key_name, recurse);
328761c3c98Swinesync         if (recurse)
329761c3c98Swinesync             output_message(STRING_MATCHES_FOUND, num_values_found);
330761c3c98Swinesync     }
331761c3c98Swinesync     else
33214b77379Swinesync         ret = query_all(hkey, key_name, recurse, FALSE);
333761c3c98Swinesync 
334f0c76942Swinesync     RegCloseKey(hkey);
335761c3c98Swinesync 
336761c3c98Swinesync     return ret;
337761c3c98Swinesync }
338354e1582Swinesync 
reg_query(int argc,WCHAR * argvW[])339354e1582Swinesync int reg_query(int argc, WCHAR *argvW[])
340354e1582Swinesync {
341354e1582Swinesync     HKEY root;
342354e1582Swinesync     WCHAR *path, *key_name, *value_name = NULL;
343354e1582Swinesync     BOOL value_empty = FALSE, recurse = FALSE;
344354e1582Swinesync     int i;
345354e1582Swinesync 
346a1c74056Swinesync     if (!parse_registry_key(argvW[2], &root, &path))
347354e1582Swinesync         return 1;
348354e1582Swinesync 
349354e1582Swinesync     for (i = 3; i < argc; i++)
350354e1582Swinesync     {
351091880d2Swinesync         WCHAR *str;
352091880d2Swinesync 
353091880d2Swinesync         if (argvW[i][0] != '/' && argvW[i][0] != '-')
354091880d2Swinesync             goto invalid;
355091880d2Swinesync 
356091880d2Swinesync         str = &argvW[i][1];
357354e1582Swinesync 
358354e1582Swinesync         if (!lstrcmpiW(str, L"ve"))
359354e1582Swinesync         {
3608dc46f32Swinesync             if (value_empty) goto invalid;
361354e1582Swinesync             value_empty = TRUE;
362354e1582Swinesync             continue;
363354e1582Swinesync         }
364c6993373Swinesync         else if (!lstrcmpiW(str, L"reg:32"))
365c6993373Swinesync         {
366c6993373Swinesync             if (sam & KEY_WOW64_32KEY) goto invalid;
367c6993373Swinesync             sam |= KEY_WOW64_32KEY;
368b6bc8e13Swinesync             continue;
369c6993373Swinesync         }
370c6993373Swinesync         else if (!lstrcmpiW(str, L"reg:64"))
371c6993373Swinesync         {
372c6993373Swinesync             if (sam & KEY_WOW64_64KEY) goto invalid;
373c6993373Swinesync             sam |= KEY_WOW64_64KEY;
374c6993373Swinesync             continue;
375c6993373Swinesync         }
376354e1582Swinesync         else if (!str[0] || str[1])
377354e1582Swinesync             goto invalid;
378354e1582Swinesync 
379354e1582Swinesync         switch (towlower(*str))
380354e1582Swinesync         {
381354e1582Swinesync         case 'v':
382354e1582Swinesync             if (value_name || !(value_name = argvW[++i]))
383354e1582Swinesync                 goto invalid;
384354e1582Swinesync             break;
385354e1582Swinesync         case 's':
3868dc46f32Swinesync             if (recurse) goto invalid;
387354e1582Swinesync             recurse = TRUE;
388354e1582Swinesync             break;
389354e1582Swinesync         default:
390354e1582Swinesync             goto invalid;
391354e1582Swinesync         }
392354e1582Swinesync     }
393354e1582Swinesync 
394354e1582Swinesync     if (value_name && value_empty)
395354e1582Swinesync         goto invalid;
396354e1582Swinesync 
397c6993373Swinesync     if (sam == (KEY_WOW64_32KEY|KEY_WOW64_64KEY))
398c6993373Swinesync         goto invalid;
399c6993373Swinesync 
400a1c74056Swinesync     key_name = get_long_key(root, path);
401a1c74056Swinesync 
402354e1582Swinesync     return run_query(root, path, key_name, value_name, value_empty, recurse);
403354e1582Swinesync 
404354e1582Swinesync invalid:
4059cf114d7Swinesync     output_message(STRING_INVALID_SYNTAX);
406*1a6f523eSThomas Csovcsity     output_message(STRING_FUNC_HELP, _wcsupr(argvW[1]));
407354e1582Swinesync     return 1;
408354e1582Swinesync }
409