query.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. * Copyright 2016-2017, 2021 Hugh McMaster
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. */
  18. #include <stdio.h>
  19. #include "reg.h"
  20. static const WCHAR *reg_type_to_wchar(DWORD type)
  21. {
  22. int i, array_size = ARRAY_SIZE(type_rels);
  23. for (i = 0; i < array_size; i++)
  24. {
  25. if (type == type_rels[i].type)
  26. return type_rels[i].name;
  27. }
  28. return NULL;
  29. }
  30. static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes)
  31. {
  32. WCHAR *buffer = NULL;
  33. int i;
  34. switch (type)
  35. {
  36. case REG_SZ:
  37. case REG_EXPAND_SZ:
  38. buffer = malloc(size_bytes);
  39. lstrcpyW(buffer, (WCHAR *)src);
  40. break;
  41. case REG_NONE:
  42. case REG_BINARY:
  43. {
  44. WCHAR *ptr;
  45. buffer = malloc((size_bytes * 2 + 1) * sizeof(WCHAR));
  46. ptr = buffer;
  47. for (i = 0; i < size_bytes; i++)
  48. ptr += swprintf(ptr, 3, L"%02X", src[i]);
  49. break;
  50. }
  51. case REG_DWORD:
  52. /* case REG_DWORD_LITTLE_ENDIAN: */
  53. case REG_DWORD_BIG_ENDIAN:
  54. {
  55. const int zero_x_dword = 10;
  56. buffer = malloc((zero_x_dword + 1) * sizeof(WCHAR));
  57. swprintf(buffer, zero_x_dword + 1, L"0x%x", *(DWORD *)src);
  58. break;
  59. }
  60. case REG_MULTI_SZ:
  61. {
  62. const int two_wchars = 2 * sizeof(WCHAR);
  63. DWORD tmp_size;
  64. const WCHAR *tmp = (const WCHAR *)src;
  65. int len, destindex;
  66. if (size_bytes <= two_wchars)
  67. {
  68. buffer = malloc(sizeof(WCHAR));
  69. *buffer = 0;
  70. return buffer;
  71. }
  72. tmp_size = size_bytes - two_wchars; /* exclude both null terminators */
  73. buffer = malloc(tmp_size * 2 + sizeof(WCHAR));
  74. len = tmp_size / sizeof(WCHAR);
  75. for (i = 0, destindex = 0; i < len; i++, destindex++)
  76. {
  77. if (tmp[i])
  78. buffer[destindex] = tmp[i];
  79. else
  80. {
  81. buffer[destindex++] = '\\';
  82. buffer[destindex] = '0';
  83. }
  84. }
  85. buffer[destindex] = 0;
  86. break;
  87. }
  88. }
  89. return buffer;
  90. }
  91. static const WCHAR *newlineW = L"\n";
  92. static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size)
  93. {
  94. static const WCHAR *fmt = L" %1";
  95. WCHAR defval[32];
  96. WCHAR *reg_data;
  97. if (value_name && value_name[0])
  98. output_string(fmt, value_name);
  99. else
  100. {
  101. LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
  102. output_string(fmt, defval);
  103. }
  104. output_string(fmt, reg_type_to_wchar(type));
  105. if (data)
  106. {
  107. reg_data = reg_data_to_wchar(type, data, data_size);
  108. output_string(fmt, reg_data);
  109. free(reg_data);
  110. }
  111. else
  112. {
  113. LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval));
  114. output_string(fmt, defval);
  115. }
  116. output_string(newlineW);
  117. }
  118. static unsigned int num_values_found = 0;
  119. static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse)
  120. {
  121. LONG rc;
  122. DWORD max_data_bytes = 2048, data_size;
  123. DWORD subkey_len;
  124. DWORD type, path_len, i;
  125. BYTE *data;
  126. static const WCHAR *fmt = L"%1\n";
  127. WCHAR *subkey_name, *subkey_path;
  128. HKEY subkey;
  129. data = malloc(max_data_bytes);
  130. for (;;)
  131. {
  132. data_size = max_data_bytes;
  133. rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size);
  134. if (rc == ERROR_MORE_DATA)
  135. {
  136. max_data_bytes = data_size;
  137. data = realloc(data, max_data_bytes);
  138. }
  139. else break;
  140. }
  141. if (rc == ERROR_SUCCESS)
  142. {
  143. output_string(fmt, path);
  144. output_value(value_name, type, data, data_size);
  145. output_string(newlineW);
  146. num_values_found++;
  147. }
  148. free(data);
  149. if (!recurse)
  150. {
  151. if (rc == ERROR_FILE_NOT_FOUND)
  152. {
  153. if (value_name && *value_name)
  154. {
  155. output_message(STRING_VALUE_NONEXIST);
  156. return 1;
  157. }
  158. output_string(fmt, path);
  159. output_value(NULL, REG_SZ, NULL, 0);
  160. }
  161. return 0;
  162. }
  163. subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
  164. path_len = lstrlenW(path);
  165. i = 0;
  166. for (;;)
  167. {
  168. subkey_len = MAX_SUBKEY_LEN;
  169. rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
  170. if (rc == ERROR_SUCCESS)
  171. {
  172. subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
  173. if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
  174. {
  175. query_value(subkey, value_name, subkey_path, recurse);
  176. RegCloseKey(subkey);
  177. }
  178. free(subkey_path);
  179. i++;
  180. }
  181. else break;
  182. }
  183. free(subkey_name);
  184. return 0;
  185. }
  186. static int query_all(HKEY key, WCHAR *path, BOOL recurse)
  187. {
  188. LONG rc;
  189. DWORD max_value_len = 256, value_len;
  190. DWORD max_data_bytes = 2048, data_size;
  191. DWORD subkey_len;
  192. DWORD i, type, path_len;
  193. WCHAR *value_name, *subkey_name, *subkey_path;
  194. BYTE *data;
  195. HKEY subkey;
  196. output_string(L"%1\n", path);
  197. value_name = malloc(max_value_len * sizeof(WCHAR));
  198. data = malloc(max_data_bytes);
  199. i = 0;
  200. for (;;)
  201. {
  202. value_len = max_value_len;
  203. data_size = max_data_bytes;
  204. rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size);
  205. if (rc == ERROR_SUCCESS)
  206. {
  207. output_value(value_name, type, data, data_size);
  208. i++;
  209. }
  210. else if (rc == ERROR_MORE_DATA)
  211. {
  212. if (data_size > max_data_bytes)
  213. {
  214. max_data_bytes = data_size;
  215. data = realloc(data, max_data_bytes);
  216. }
  217. else
  218. {
  219. max_value_len *= 2;
  220. value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
  221. }
  222. }
  223. else break;
  224. }
  225. free(data);
  226. free(value_name);
  227. if (i || recurse)
  228. output_string(newlineW);
  229. subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
  230. path_len = lstrlenW(path);
  231. i = 0;
  232. for (;;)
  233. {
  234. subkey_len = MAX_SUBKEY_LEN;
  235. rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
  236. if (rc == ERROR_SUCCESS)
  237. {
  238. if (recurse)
  239. {
  240. subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
  241. if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey))
  242. {
  243. query_all(subkey, subkey_path, recurse);
  244. RegCloseKey(subkey);
  245. }
  246. free(subkey_path);
  247. }
  248. else output_string(L"%1\\%2\n", path, subkey_name);
  249. i++;
  250. }
  251. else break;
  252. }
  253. free(subkey_name);
  254. if (i && !recurse)
  255. output_string(newlineW);
  256. return 0;
  257. }
  258. static int run_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name,
  259. BOOL value_empty, BOOL recurse)
  260. {
  261. HKEY key;
  262. int ret;
  263. if (RegOpenKeyExW(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS)
  264. {
  265. output_message(STRING_KEY_NONEXIST);
  266. return 1;
  267. }
  268. output_string(newlineW);
  269. if (value_name || value_empty)
  270. {
  271. ret = query_value(key, value_name, key_name, recurse);
  272. if (recurse)
  273. output_message(STRING_MATCHES_FOUND, num_values_found);
  274. }
  275. else
  276. ret = query_all(key, key_name, recurse);
  277. RegCloseKey(key);
  278. return ret;
  279. }
  280. int reg_query(int argc, WCHAR *argvW[])
  281. {
  282. HKEY root;
  283. WCHAR *path, *key_name, *value_name = NULL;
  284. BOOL value_empty = FALSE, recurse = FALSE;
  285. int i;
  286. if (!parse_registry_key(argvW[2], &root, &path))
  287. return 1;
  288. for (i = 3; i < argc; i++)
  289. {
  290. WCHAR *str;
  291. if (argvW[i][0] != '/' && argvW[i][0] != '-')
  292. goto invalid;
  293. str = &argvW[i][1];
  294. if (!lstrcmpiW(str, L"ve"))
  295. {
  296. if (value_empty) goto invalid;
  297. value_empty = TRUE;
  298. continue;
  299. }
  300. else if (!lstrcmpiW(str, L"reg:32") || !lstrcmpiW(str, L"reg:64"))
  301. continue;
  302. else if (!str[0] || str[1])
  303. goto invalid;
  304. switch (towlower(*str))
  305. {
  306. case 'v':
  307. if (value_name || !(value_name = argvW[++i]))
  308. goto invalid;
  309. break;
  310. case 's':
  311. if (recurse) goto invalid;
  312. recurse = TRUE;
  313. break;
  314. default:
  315. goto invalid;
  316. }
  317. }
  318. if (value_name && value_empty)
  319. goto invalid;
  320. key_name = get_long_key(root, path);
  321. return run_query(root, path, key_name, value_name, value_empty, recurse);
  322. invalid:
  323. output_message(STRING_INVALID_SYNTAX);
  324. output_message(STRING_FUNC_HELP, wcsupr(argvW[1]));
  325. return 1;
  326. }