Signed-off-by: Hugh McMaster hugh.mcmaster@outlook.com --- programs/reg/Makefile.in | 1 + programs/reg/query.c | 329 +++++++++++++++++++++++++++++++++++++++ programs/reg/reg.c | 315 +------------------------------------ programs/reg/reg.h | 16 +- 4 files changed, 346 insertions(+), 315 deletions(-) create mode 100644 programs/reg/query.c
diff --git a/programs/reg/Makefile.in b/programs/reg/Makefile.in index 248b470eb31..3203126db66 100644 --- a/programs/reg/Makefile.in +++ b/programs/reg/Makefile.in @@ -7,6 +7,7 @@ EXTRADLLFLAGS = -mconsole -municode -mno-cygwin C_SRCS = \ export.c \ import.c \ + query.c \ reg.c
RC_SRCS = reg.rc diff --git a/programs/reg/query.c b/programs/reg/query.c new file mode 100644 index 00000000000..3d81d120bd2 --- /dev/null +++ b/programs/reg/query.c @@ -0,0 +1,329 @@ +/* + * Copyright 2016-2017, 2021 Hugh McMaster + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdio.h> +#include <windows.h> +#include <wine/heap.h> +#include "reg.h" + +static const WCHAR *reg_type_to_wchar(DWORD type) +{ + int i, array_size = ARRAY_SIZE(type_rels); + + for (i = 0; i < array_size; i++) + { + if (type == type_rels[i].type) + return type_rels[i].name; + } + + return NULL; +} + +static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes) +{ + WCHAR *buffer = NULL; + int i; + + switch (type) + { + case REG_SZ: + case REG_EXPAND_SZ: + buffer = heap_xalloc(size_bytes); + lstrcpyW(buffer, (WCHAR *)src); + break; + case REG_NONE: + case REG_BINARY: + { + WCHAR *ptr; + static const WCHAR fmt[] = {'%','0','2','X',0}; + + buffer = heap_xalloc((size_bytes * 2 + 1) * sizeof(WCHAR)); + ptr = buffer; + for (i = 0; i < size_bytes; i++) + ptr += swprintf(ptr, 3, fmt, src[i]); + break; + } + case REG_DWORD: + /* case REG_DWORD_LITTLE_ENDIAN: */ + case REG_DWORD_BIG_ENDIAN: + { + const int zero_x_dword = 10; + static const WCHAR fmt[] = {'0','x','%','x',0}; + + buffer = heap_xalloc((zero_x_dword + 1) * sizeof(WCHAR)); + swprintf(buffer, zero_x_dword + 1, fmt, *(DWORD *)src); + break; + } + case REG_MULTI_SZ: + { + const int two_wchars = 2 * sizeof(WCHAR); + DWORD tmp_size; + const WCHAR *tmp = (const WCHAR *)src; + int len, destindex; + + if (size_bytes <= two_wchars) + { + buffer = heap_xalloc(sizeof(WCHAR)); + *buffer = 0; + return buffer; + } + + tmp_size = size_bytes - two_wchars; /* exclude both null terminators */ + buffer = heap_xalloc(tmp_size * 2 + sizeof(WCHAR)); + len = tmp_size / sizeof(WCHAR); + + for (i = 0, destindex = 0; i < len; i++, destindex++) + { + if (tmp[i]) + buffer[destindex] = tmp[i]; + else + { + buffer[destindex++] = '\'; + buffer[destindex] = '0'; + } + } + buffer[destindex] = 0; + break; + } + } + return buffer; +} + +static const WCHAR newlineW[] = {'\n',0}; + +static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size) +{ + static const WCHAR fmt[] = {' ',' ',' ',' ','%','1',0}; + WCHAR defval[32]; + WCHAR *reg_data; + + if (value_name && value_name[0]) + output_string(fmt, value_name); + else + { + LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval)); + output_string(fmt, defval); + } + output_string(fmt, reg_type_to_wchar(type)); + + if (data) + { + reg_data = reg_data_to_wchar(type, data, data_size); + output_string(fmt, reg_data); + heap_free(reg_data); + } + else + { + LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval)); + output_string(fmt, defval); + } + output_string(newlineW); +} + +static unsigned int num_values_found = 0; + +static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) +{ + LONG rc; + DWORD max_data_bytes = 2048, data_size; + DWORD subkey_len; + DWORD type, path_len, i; + BYTE *data; + WCHAR fmt[] = {'%','1','\n',0}; + WCHAR *subkey_name, *subkey_path; + HKEY subkey; + + data = heap_xalloc(max_data_bytes); + + for (;;) + { + data_size = max_data_bytes; + rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size); + if (rc == ERROR_MORE_DATA) + { + max_data_bytes = data_size; + data = heap_xrealloc(data, max_data_bytes); + } + else break; + } + + if (rc == ERROR_SUCCESS) + { + output_string(fmt, path); + output_value(value_name, type, data, data_size); + output_string(newlineW); + num_values_found++; + } + + heap_free(data); + + if (!recurse) + { + if (rc == ERROR_FILE_NOT_FOUND) + { + if (value_name && *value_name) + { + output_message(STRING_CANNOT_FIND); + return 1; + } + output_string(fmt, path); + output_value(NULL, REG_SZ, NULL, 0); + } + return 0; + } + + subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); + + path_len = lstrlenW(path); + + i = 0; + for (;;) + { + subkey_len = MAX_SUBKEY_LEN; + rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); + if (rc == ERROR_SUCCESS) + { + subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); + if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey)) + { + query_value(subkey, value_name, subkey_path, recurse); + RegCloseKey(subkey); + } + heap_free(subkey_path); + i++; + } + else break; + } + + heap_free(subkey_name); + return 0; +} + +static int query_all(HKEY key, WCHAR *path, BOOL recurse) +{ + LONG rc; + DWORD max_value_len = 256, value_len; + DWORD max_data_bytes = 2048, data_size; + DWORD subkey_len; + DWORD i, type, path_len; + WCHAR fmt[] = {'%','1','\n',0}; + WCHAR fmt_path[] = {'%','1','\','%','2','\n',0}; + WCHAR *value_name, *subkey_name, *subkey_path; + BYTE *data; + HKEY subkey; + + output_string(fmt, path); + + value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); + data = heap_xalloc(max_data_bytes); + + i = 0; + for (;;) + { + value_len = max_value_len; + data_size = max_data_bytes; + rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size); + if (rc == ERROR_SUCCESS) + { + output_value(value_name, type, data, data_size); + i++; + } + else if (rc == ERROR_MORE_DATA) + { + if (data_size > max_data_bytes) + { + max_data_bytes = data_size; + data = heap_xrealloc(data, max_data_bytes); + } + else + { + max_value_len *= 2; + value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR)); + } + } + else break; + } + + heap_free(data); + heap_free(value_name); + + if (i || recurse) + output_string(newlineW); + + subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); + + path_len = lstrlenW(path); + + i = 0; + for (;;) + { + subkey_len = MAX_SUBKEY_LEN; + rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); + if (rc == ERROR_SUCCESS) + { + if (recurse) + { + subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); + if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey)) + { + query_all(subkey, subkey_path, recurse); + RegCloseKey(subkey); + } + heap_free(subkey_path); + } + else output_string(fmt_path, path, subkey_name); + i++; + } + else break; + } + + heap_free(subkey_name); + + if (i && !recurse) + output_string(newlineW); + + return 0; +} + +int reg_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, + BOOL value_empty, BOOL recurse) +{ + HKEY key; + int ret; + + if (RegOpenKeyExW(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS) + { + output_message(STRING_CANNOT_FIND); + return 1; + } + + output_string(newlineW); + + if (value_name || value_empty) + { + ret = query_value(key, value_name, key_name, recurse); + if (recurse) + output_message(STRING_MATCHES_FOUND, num_values_found); + } + else + ret = query_all(key, key_name, recurse); + + RegCloseKey(key); + + return ret; +} diff --git a/programs/reg/reg.c b/programs/reg/reg.c index 997a6703831..8b97c560118 100644 --- a/programs/reg/reg.c +++ b/programs/reg/reg.c @@ -61,12 +61,7 @@ static const WCHAR type_dword_le[] = {'R','E','G','_','D','W','O','R','D','_','L static const WCHAR type_dword_be[] = {'R','E','G','_','D','W','O','R','D','_','B','I','G','_','E','N','D','I','A','N',0}; static const WCHAR type_multi_sz[] = {'R','E','G','_','M','U','L','T','I','_','S','Z',0};
-static const struct -{ - DWORD type; - const WCHAR *name; -} -type_rels[] = +const struct reg_type_rels type_rels[] = { {REG_NONE, type_none}, {REG_SZ, type_sz}, @@ -78,8 +73,6 @@ type_rels[] = {REG_MULTI_SZ, type_multi_sz}, };
-static const WCHAR newlineW[] = {'\n',0}; - void *heap_xalloc(size_t size) { void *buf = heap_alloc(size); @@ -158,7 +151,7 @@ void WINAPIV output_message(unsigned int id, ...) __ms_va_end(va_args); }
-static void WINAPIV output_string(const WCHAR *fmt, ...) +void WINAPIV output_string(const WCHAR *fmt, ...) { __ms_va_list va_args;
@@ -517,117 +510,6 @@ static int reg_delete(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name return 0; }
-static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes) -{ - WCHAR *buffer = NULL; - int i; - - switch (type) - { - case REG_SZ: - case REG_EXPAND_SZ: - buffer = heap_xalloc(size_bytes); - lstrcpyW(buffer, (WCHAR *)src); - break; - case REG_NONE: - case REG_BINARY: - { - WCHAR *ptr; - static const WCHAR fmt[] = {'%','0','2','X',0}; - - buffer = heap_xalloc((size_bytes * 2 + 1) * sizeof(WCHAR)); - ptr = buffer; - for (i = 0; i < size_bytes; i++) - ptr += swprintf(ptr, 3, fmt, src[i]); - break; - } - case REG_DWORD: - /* case REG_DWORD_LITTLE_ENDIAN: */ - case REG_DWORD_BIG_ENDIAN: - { - const int zero_x_dword = 10; - static const WCHAR fmt[] = {'0','x','%','x',0}; - - buffer = heap_xalloc((zero_x_dword + 1) * sizeof(WCHAR)); - swprintf(buffer, zero_x_dword + 1, fmt, *(DWORD *)src); - break; - } - case REG_MULTI_SZ: - { - const int two_wchars = 2 * sizeof(WCHAR); - DWORD tmp_size; - const WCHAR *tmp = (const WCHAR *)src; - int len, destindex; - - if (size_bytes <= two_wchars) - { - buffer = heap_xalloc(sizeof(WCHAR)); - *buffer = 0; - return buffer; - } - - tmp_size = size_bytes - two_wchars; /* exclude both null terminators */ - buffer = heap_xalloc(tmp_size * 2 + sizeof(WCHAR)); - len = tmp_size / sizeof(WCHAR); - - for (i = 0, destindex = 0; i < len; i++, destindex++) - { - if (tmp[i]) - buffer[destindex] = tmp[i]; - else - { - buffer[destindex++] = '\'; - buffer[destindex] = '0'; - } - } - buffer[destindex] = 0; - break; - } - } - return buffer; -} - -static const WCHAR *reg_type_to_wchar(DWORD type) -{ - int i, array_size = ARRAY_SIZE(type_rels); - - for (i = 0; i < array_size; i++) - { - if (type == type_rels[i].type) - return type_rels[i].name; - } - return NULL; -} - -static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size) -{ - static const WCHAR fmt[] = {' ',' ',' ',' ','%','1',0}; - WCHAR defval[32]; - WCHAR *reg_data; - - if (value_name && value_name[0]) - output_string(fmt, value_name); - else - { - LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval)); - output_string(fmt, defval); - } - output_string(fmt, reg_type_to_wchar(type)); - - if (data) - { - reg_data = reg_data_to_wchar(type, data, data_size); - output_string(fmt, reg_data); - heap_free(reg_data); - } - else - { - LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval)); - output_string(fmt, defval); - } - output_string(newlineW); -} - WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) { WCHAR *subkey_path; @@ -639,199 +521,6 @@ WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD return subkey_path; }
-static unsigned int num_values_found = 0; - -static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, BOOL recurse) -{ - LONG rc; - DWORD max_data_bytes = 2048, data_size; - DWORD subkey_len; - DWORD type, path_len, i; - BYTE *data; - WCHAR fmt[] = {'%','1','\n',0}; - WCHAR *subkey_name, *subkey_path; - HKEY subkey; - - data = heap_xalloc(max_data_bytes); - - for (;;) - { - data_size = max_data_bytes; - rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size); - if (rc == ERROR_MORE_DATA) - { - max_data_bytes = data_size; - data = heap_xrealloc(data, max_data_bytes); - } - else break; - } - - if (rc == ERROR_SUCCESS) - { - output_string(fmt, path); - output_value(value_name, type, data, data_size); - output_string(newlineW); - num_values_found++; - } - - heap_free(data); - - if (!recurse) - { - if (rc == ERROR_FILE_NOT_FOUND) - { - if (value_name && *value_name) - { - output_message(STRING_CANNOT_FIND); - return 1; - } - output_string(fmt, path); - output_value(NULL, REG_SZ, NULL, 0); - } - return 0; - } - - subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); - - path_len = lstrlenW(path); - - i = 0; - for (;;) - { - subkey_len = MAX_SUBKEY_LEN; - rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); - if (rc == ERROR_SUCCESS) - { - subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); - if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey)) - { - query_value(subkey, value_name, subkey_path, recurse); - RegCloseKey(subkey); - } - heap_free(subkey_path); - i++; - } - else break; - } - - heap_free(subkey_name); - return 0; -} - -static int query_all(HKEY key, WCHAR *path, BOOL recurse) -{ - LONG rc; - DWORD max_value_len = 256, value_len; - DWORD max_data_bytes = 2048, data_size; - DWORD subkey_len; - DWORD i, type, path_len; - WCHAR fmt[] = {'%','1','\n',0}; - WCHAR fmt_path[] = {'%','1','\','%','2','\n',0}; - WCHAR *value_name, *subkey_name, *subkey_path; - BYTE *data; - HKEY subkey; - - output_string(fmt, path); - - value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); - data = heap_xalloc(max_data_bytes); - - i = 0; - for (;;) - { - value_len = max_value_len; - data_size = max_data_bytes; - rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size); - if (rc == ERROR_SUCCESS) - { - output_value(value_name, type, data, data_size); - i++; - } - else if (rc == ERROR_MORE_DATA) - { - if (data_size > max_data_bytes) - { - max_data_bytes = data_size; - data = heap_xrealloc(data, max_data_bytes); - } - else - { - max_value_len *= 2; - value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR)); - } - } - else break; - } - - heap_free(data); - heap_free(value_name); - - if (i || recurse) - output_string(newlineW); - - subkey_name = heap_xalloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); - - path_len = lstrlenW(path); - - i = 0; - for (;;) - { - subkey_len = MAX_SUBKEY_LEN; - rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); - if (rc == ERROR_SUCCESS) - { - if (recurse) - { - subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); - if (!RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey)) - { - query_all(subkey, subkey_path, recurse); - RegCloseKey(subkey); - } - heap_free(subkey_path); - } - else output_string(fmt_path, path, subkey_name); - i++; - } - else break; - } - - heap_free(subkey_name); - - if (i && !recurse) - output_string(newlineW); - - return 0; -} - -static int reg_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, - BOOL value_empty, BOOL recurse) -{ - HKEY key; - int ret; - - if (RegOpenKeyExW(root, path, 0, KEY_READ, &key) != ERROR_SUCCESS) - { - output_message(STRING_CANNOT_FIND); - return 1; - } - - output_string(newlineW); - - if (value_name || value_empty) - { - ret = query_value(key, value_name, key_name, recurse); - if (recurse) - output_message(STRING_MATCHES_FOUND, num_values_found); - } - else - ret = query_all(key, key_name, recurse); - - RegCloseKey(key); - - return ret; -} - static WCHAR *get_long_key(HKEY root, WCHAR *path) { DWORD i, array_size = ARRAY_SIZE(root_rels), len; diff --git a/programs/reg/reg.h b/programs/reg/reg.h index a27399d06a4..471ed9c4d55 100644 --- a/programs/reg/reg.h +++ b/programs/reg/reg.h @@ -24,19 +24,31 @@ #define MAX_SUBKEY_LEN 257
/* reg.c */ +struct reg_type_rels { + DWORD type; + const WCHAR *name; +}; + +extern const struct reg_type_rels type_rels[8]; + void *heap_xalloc(size_t size); void *heap_xrealloc(void *buf, size_t size); void output_writeconsole(const WCHAR *str, DWORD wlen); void WINAPIV output_message(unsigned int id, ...); +void WINAPIV output_string(const WCHAR *fmt, ...); BOOL ask_confirm(unsigned int msgid, WCHAR *reg_info); HKEY path_get_rootkey(const WCHAR *path); WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len); BOOL parse_registry_key(const WCHAR *key, HKEY *root, WCHAR **path, WCHAR **long_key);
+/* export.c */ +int reg_export(int argc, WCHAR *argv[]); + /* import.c */ int reg_import(const WCHAR *filename);
-/* export.c */ -int reg_export(int argc, WCHAR *argv[]); +/* query.c */ +int reg_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, + BOOL value_empty, BOOL recurse);
#endif /* __REG_H__ */
Signed-off-by: Hugh McMaster hugh.mcmaster@outlook.com --- programs/reg/Makefile.in | 1 + programs/reg/delete.c | 109 +++++++++++++++++++++++++++++++++++++++ programs/reg/reg.c | 88 ------------------------------- programs/reg/reg.h | 4 ++ 4 files changed, 114 insertions(+), 88 deletions(-) create mode 100644 programs/reg/delete.c
diff --git a/programs/reg/Makefile.in b/programs/reg/Makefile.in index 3203126db66..161be0062f1 100644 --- a/programs/reg/Makefile.in +++ b/programs/reg/Makefile.in @@ -5,6 +5,7 @@ DELAYIMPORTS = user32 EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
C_SRCS = \ + delete.c \ export.c \ import.c \ query.c \ diff --git a/programs/reg/delete.c b/programs/reg/delete.c new file mode 100644 index 00000000000..530d4513ece --- /dev/null +++ b/programs/reg/delete.c @@ -0,0 +1,109 @@ +/* + * Copyright 2016-2017, 2021 Hugh McMaster + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <windows.h> +#include <wine/heap.h> +#include "reg.h" + +int reg_delete(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, + BOOL value_empty, BOOL value_all, BOOL force) +{ + HKEY key; + + if (!force) + { + BOOL ret; + + if (value_name || value_empty) + ret = ask_confirm(STRING_DELETE_VALUE, value_name); + else if (value_all) + ret = ask_confirm(STRING_DELETE_VALUEALL, key_name); + else + ret = ask_confirm(STRING_DELETE_SUBKEY, key_name); + + if (!ret) + { + output_message(STRING_CANCELLED); + return 0; + } + } + + /* Delete subtree only if no /v* option is given */ + if (!value_name && !value_empty && !value_all) + { + if (RegDeleteTreeW(root, path) != ERROR_SUCCESS) + { + output_message(STRING_CANNOT_FIND); + return 1; + } + output_message(STRING_SUCCESS); + return 0; + } + + if (RegOpenKeyW(root, path, &key) != ERROR_SUCCESS) + { + output_message(STRING_CANNOT_FIND); + return 1; + } + + if (value_all) + { + DWORD max_value_len = 256, value_len; + WCHAR *value_name; + LONG rc; + + value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); + + while (1) + { + value_len = max_value_len; + rc = RegEnumValueW(key, 0, value_name, &value_len, NULL, NULL, NULL, NULL); + if (rc == ERROR_SUCCESS) + { + rc = RegDeleteValueW(key, value_name); + if (rc != ERROR_SUCCESS) + { + heap_free(value_name); + RegCloseKey(key); + output_message(STRING_VALUEALL_FAILED, key_name); + return 1; + } + } + else if (rc == ERROR_MORE_DATA) + { + max_value_len *= 2; + value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR)); + } + else break; + } + heap_free(value_name); + } + else if (value_name || value_empty) + { + if (RegDeleteValueW(key, value_empty ? NULL : value_name) != ERROR_SUCCESS) + { + RegCloseKey(key); + output_message(STRING_CANNOT_FIND); + return 1; + } + } + + RegCloseKey(key); + output_message(STRING_SUCCESS); + return 0; +} diff --git a/programs/reg/reg.c b/programs/reg/reg.c index 8b97c560118..079ed9b1a1e 100644 --- a/programs/reg/reg.c +++ b/programs/reg/reg.c @@ -422,94 +422,6 @@ static int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, return 0; }
-static int reg_delete(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, - BOOL value_empty, BOOL value_all, BOOL force) -{ - HKEY key; - - if (!force) - { - BOOL ret; - - if (value_name || value_empty) - ret = ask_confirm(STRING_DELETE_VALUE, value_name); - else if (value_all) - ret = ask_confirm(STRING_DELETE_VALUEALL, key_name); - else - ret = ask_confirm(STRING_DELETE_SUBKEY, key_name); - - if (!ret) - { - output_message(STRING_CANCELLED); - return 0; - } - } - - /* Delete subtree only if no /v* option is given */ - if (!value_name && !value_empty && !value_all) - { - if (RegDeleteTreeW(root, path) != ERROR_SUCCESS) - { - output_message(STRING_CANNOT_FIND); - return 1; - } - output_message(STRING_SUCCESS); - return 0; - } - - if (RegOpenKeyW(root, path, &key) != ERROR_SUCCESS) - { - output_message(STRING_CANNOT_FIND); - return 1; - } - - if (value_all) - { - DWORD max_value_len = 256, value_len; - WCHAR *value_name; - LONG rc; - - value_name = heap_xalloc(max_value_len * sizeof(WCHAR)); - - while (1) - { - value_len = max_value_len; - rc = RegEnumValueW(key, 0, value_name, &value_len, NULL, NULL, NULL, NULL); - if (rc == ERROR_SUCCESS) - { - rc = RegDeleteValueW(key, value_name); - if (rc != ERROR_SUCCESS) - { - heap_free(value_name); - RegCloseKey(key); - output_message(STRING_VALUEALL_FAILED, key_name); - return 1; - } - } - else if (rc == ERROR_MORE_DATA) - { - max_value_len *= 2; - value_name = heap_xrealloc(value_name, max_value_len * sizeof(WCHAR)); - } - else break; - } - heap_free(value_name); - } - else if (value_name || value_empty) - { - if (RegDeleteValueW(key, value_empty ? NULL : value_name) != ERROR_SUCCESS) - { - RegCloseKey(key); - output_message(STRING_CANNOT_FIND); - return 1; - } - } - - RegCloseKey(key); - output_message(STRING_SUCCESS); - return 0; -} - WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) { WCHAR *subkey_path; diff --git a/programs/reg/reg.h b/programs/reg/reg.h index 471ed9c4d55..c8baaa0f9a9 100644 --- a/programs/reg/reg.h +++ b/programs/reg/reg.h @@ -41,6 +41,10 @@ HKEY path_get_rootkey(const WCHAR *path); WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len); BOOL parse_registry_key(const WCHAR *key, HKEY *root, WCHAR **path, WCHAR **long_key);
+/* delete.c */ +int reg_delete(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, + BOOL value_empty, BOOL value_all, BOOL force); + /* export.c */ int reg_export(int argc, WCHAR *argv[]);
Signed-off-by: Hugh McMaster hugh.mcmaster@outlook.com --- programs/reg/Makefile.in | 1 + programs/reg/add.c | 213 +++++++++++++++++++++++++++++++++++++++ programs/reg/reg.c | 192 ----------------------------------- programs/reg/reg.h | 4 + 4 files changed, 218 insertions(+), 192 deletions(-) create mode 100644 programs/reg/add.c
diff --git a/programs/reg/Makefile.in b/programs/reg/Makefile.in index 161be0062f1..5ef0d0854aa 100644 --- a/programs/reg/Makefile.in +++ b/programs/reg/Makefile.in @@ -5,6 +5,7 @@ DELAYIMPORTS = user32 EXTRADLLFLAGS = -mconsole -municode -mno-cygwin
C_SRCS = \ + add.c \ delete.c \ export.c \ import.c \ diff --git a/programs/reg/add.c b/programs/reg/add.c new file mode 100644 index 00000000000..2d8521f9234 --- /dev/null +++ b/programs/reg/add.c @@ -0,0 +1,213 @@ +/* + * Copyright 2016-2017, 2021 Hugh McMaster + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <errno.h> +#include <stdlib.h> +#include <windows.h> +#include <wine/heap.h> +#include "reg.h" + +static DWORD wchar_get_type(const WCHAR *type_name) +{ + DWORD i; + + if (!type_name) + return REG_SZ; + + for (i = 0; i < ARRAY_SIZE(type_rels); i++) + { + if (!wcsicmp(type_rels[i].name, type_name)) + return type_rels[i].type; + } + + return ~0u; +} + +/* hexchar_to_byte from programs/regedit/hexedit.c */ +static inline BYTE hexchar_to_byte(WCHAR ch) +{ + if (ch >= '0' && ch <= '9') + return ch - '0'; + else if (ch >= 'a' && ch <= 'f') + return ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + return ch - 'A' + 10; + else + return -1; +} + +static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DWORD *reg_count) +{ + static const WCHAR empty; + LPBYTE out_data = NULL; + *reg_count = 0; + + if (!data) data = ∅ + + switch (reg_type) + { + case REG_NONE: + case REG_SZ: + case REG_EXPAND_SZ: + { + *reg_count = (lstrlenW(data) + 1) * sizeof(WCHAR); + out_data = heap_xalloc(*reg_count); + lstrcpyW((LPWSTR)out_data,data); + break; + } + case REG_DWORD: + /* case REG_DWORD_LITTLE_ENDIAN: */ + case REG_DWORD_BIG_ENDIAN: /* Yes, this is correct! */ + { + LPWSTR rest; + unsigned long val; + val = wcstoul(data, &rest, (towlower(data[1]) == 'x') ? 16 : 10); + if (*rest || data[0] == '-' || (val == ~0u && errno == ERANGE)) { + output_message(STRING_MISSING_INTEGER); + break; + } + *reg_count = sizeof(DWORD); + out_data = heap_xalloc(*reg_count); + ((LPDWORD)out_data)[0] = val; + break; + } + case REG_BINARY: + { + BYTE hex0, hex1; + int i = 0, destByteIndex = 0, datalen = lstrlenW(data); + *reg_count = ((datalen + datalen % 2) / 2) * sizeof(BYTE); + out_data = heap_xalloc(*reg_count); + if(datalen % 2) + { + hex1 = hexchar_to_byte(data[i++]); + if(hex1 == 0xFF) + goto no_hex_data; + out_data[destByteIndex++] = hex1; + } + for(;i + 1 < datalen;i += 2) + { + hex0 = hexchar_to_byte(data[i]); + hex1 = hexchar_to_byte(data[i + 1]); + if(hex0 == 0xFF || hex1 == 0xFF) + goto no_hex_data; + out_data[destByteIndex++] = (hex0 << 4) | hex1; + } + break; + no_hex_data: + /* cleanup, print error */ + heap_free(out_data); + output_message(STRING_MISSING_HEXDATA); + out_data = NULL; + break; + } + case REG_MULTI_SZ: + { + int i, destindex, len = lstrlenW(data); + WCHAR *buffer = heap_xalloc((len + 2) * sizeof(WCHAR)); + + for (i = 0, destindex = 0; i < len; i++, destindex++) + { + if (!separator && data[i] == '\' && data[i + 1] == '0') + { + buffer[destindex] = 0; + i++; + } + else if (data[i] == separator) + buffer[destindex] = 0; + else + buffer[destindex] = data[i]; + + if (destindex && !buffer[destindex - 1] && (!buffer[destindex] || destindex == 1)) + { + heap_free(buffer); + output_message(STRING_INVALID_STRING); + return NULL; + } + } + buffer[destindex] = 0; + if (destindex && buffer[destindex - 1]) + buffer[++destindex] = 0; + *reg_count = (destindex + 1) * sizeof(WCHAR); + return (BYTE *)buffer; + } + default: + output_message(STRING_UNHANDLED_TYPE, reg_type, data); + } + + return out_data; +} + +int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, + WCHAR *type, WCHAR separator, WCHAR *data, BOOL force) +{ + HKEY key; + + if (RegCreateKeyW(root, path, &key) != ERROR_SUCCESS) + { + output_message(STRING_INVALID_KEY); + return 1; + } + + if (value_name || value_empty || data) + { + DWORD reg_type; + DWORD reg_count = 0; + BYTE* reg_data = NULL; + + if (!force) + { + if (RegQueryValueExW(key, value_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + if (!ask_confirm(STRING_OVERWRITE_VALUE, value_name)) + { + RegCloseKey(key); + output_message(STRING_CANCELLED); + return 0; + } + } + } + + reg_type = wchar_get_type(type); + if (reg_type == ~0u) + { + RegCloseKey(key); + output_message(STRING_UNSUPPORTED_TYPE, type); + return 1; + } + if ((reg_type == REG_DWORD || reg_type == REG_DWORD_BIG_ENDIAN) && !data) + { + RegCloseKey(key); + output_message(STRING_INVALID_CMDLINE); + return 1; + } + + if (!(reg_data = get_regdata(data, reg_type, separator, ®_count))) + { + RegCloseKey(key); + return 1; + } + + RegSetValueExW(key, value_name, 0, reg_type, reg_data, reg_count); + heap_free(reg_data); + } + + RegCloseKey(key); + output_message(STRING_SUCCESS); + + return 0; +} diff --git a/programs/reg/reg.c b/programs/reg/reg.c index 079ed9b1a1e..071fb6f88ea 100644 --- a/programs/reg/reg.c +++ b/programs/reg/reg.c @@ -17,8 +17,6 @@ */
#include <windows.h> -#include <errno.h> -#include <stdio.h> #include <stdlib.h> #include <wine/debug.h> #include <wine/heap.h> @@ -213,136 +211,6 @@ HKEY path_get_rootkey(const WCHAR *path) return NULL; }
-static DWORD wchar_get_type(const WCHAR *type_name) -{ - DWORD i; - - if (!type_name) - return REG_SZ; - - for (i = 0; i < ARRAY_SIZE(type_rels); i++) - { - if (!wcsicmp(type_rels[i].name, type_name)) - return type_rels[i].type; - } - - return ~0u; -} - -/* hexchar_to_byte from programs/regedit/hexedit.c */ -static inline BYTE hexchar_to_byte(WCHAR ch) -{ - if (ch >= '0' && ch <= '9') - return ch - '0'; - else if (ch >= 'a' && ch <= 'f') - return ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - return ch - 'A' + 10; - else - return -1; -} - -static LPBYTE get_regdata(const WCHAR *data, DWORD reg_type, WCHAR separator, DWORD *reg_count) -{ - static const WCHAR empty; - LPBYTE out_data = NULL; - *reg_count = 0; - - if (!data) data = ∅ - - switch (reg_type) - { - case REG_NONE: - case REG_SZ: - case REG_EXPAND_SZ: - { - *reg_count = (lstrlenW(data) + 1) * sizeof(WCHAR); - out_data = heap_xalloc(*reg_count); - lstrcpyW((LPWSTR)out_data,data); - break; - } - case REG_DWORD: - /* case REG_DWORD_LITTLE_ENDIAN: */ - case REG_DWORD_BIG_ENDIAN: /* Yes, this is correct! */ - { - LPWSTR rest; - unsigned long val; - val = wcstoul(data, &rest, (towlower(data[1]) == 'x') ? 16 : 10); - if (*rest || data[0] == '-' || (val == ~0u && errno == ERANGE)) { - output_message(STRING_MISSING_INTEGER); - break; - } - *reg_count = sizeof(DWORD); - out_data = heap_xalloc(*reg_count); - ((LPDWORD)out_data)[0] = val; - break; - } - case REG_BINARY: - { - BYTE hex0, hex1; - int i = 0, destByteIndex = 0, datalen = lstrlenW(data); - *reg_count = ((datalen + datalen % 2) / 2) * sizeof(BYTE); - out_data = heap_xalloc(*reg_count); - if(datalen % 2) - { - hex1 = hexchar_to_byte(data[i++]); - if(hex1 == 0xFF) - goto no_hex_data; - out_data[destByteIndex++] = hex1; - } - for(;i + 1 < datalen;i += 2) - { - hex0 = hexchar_to_byte(data[i]); - hex1 = hexchar_to_byte(data[i + 1]); - if(hex0 == 0xFF || hex1 == 0xFF) - goto no_hex_data; - out_data[destByteIndex++] = (hex0 << 4) | hex1; - } - break; - no_hex_data: - /* cleanup, print error */ - heap_free(out_data); - output_message(STRING_MISSING_HEXDATA); - out_data = NULL; - break; - } - case REG_MULTI_SZ: - { - int i, destindex, len = lstrlenW(data); - WCHAR *buffer = heap_xalloc((len + 2) * sizeof(WCHAR)); - - for (i = 0, destindex = 0; i < len; i++, destindex++) - { - if (!separator && data[i] == '\' && data[i + 1] == '0') - { - buffer[destindex] = 0; - i++; - } - else if (data[i] == separator) - buffer[destindex] = 0; - else - buffer[destindex] = data[i]; - - if (destindex && !buffer[destindex - 1] && (!buffer[destindex] || destindex == 1)) - { - heap_free(buffer); - output_message(STRING_INVALID_STRING); - return NULL; - } - } - buffer[destindex] = 0; - if (destindex && buffer[destindex - 1]) - buffer[++destindex] = 0; - *reg_count = (destindex + 1) * sizeof(WCHAR); - return (BYTE *)buffer; - } - default: - output_message(STRING_UNHANDLED_TYPE, reg_type, data); - } - - return out_data; -} - static BOOL sane_path(const WCHAR *key) { unsigned int i = lstrlenW(key); @@ -362,66 +230,6 @@ static BOOL sane_path(const WCHAR *key) return TRUE; }
-static int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, - WCHAR *type, WCHAR separator, WCHAR *data, BOOL force) -{ - HKEY key; - - if (RegCreateKeyW(root, path, &key) != ERROR_SUCCESS) - { - output_message(STRING_INVALID_KEY); - return 1; - } - - if (value_name || value_empty || data) - { - DWORD reg_type; - DWORD reg_count = 0; - BYTE* reg_data = NULL; - - if (!force) - { - if (RegQueryValueExW(key, value_name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) - { - if (!ask_confirm(STRING_OVERWRITE_VALUE, value_name)) - { - RegCloseKey(key); - output_message(STRING_CANCELLED); - return 0; - } - } - } - - reg_type = wchar_get_type(type); - if (reg_type == ~0u) - { - RegCloseKey(key); - output_message(STRING_UNSUPPORTED_TYPE, type); - return 1; - } - if ((reg_type == REG_DWORD || reg_type == REG_DWORD_BIG_ENDIAN) && !data) - { - RegCloseKey(key); - output_message(STRING_INVALID_CMDLINE); - return 1; - } - - if (!(reg_data = get_regdata(data, reg_type, separator, ®_count))) - { - RegCloseKey(key); - return 1; - } - - RegSetValueExW(key, value_name, 0, reg_type, reg_data, reg_count); - heap_free(reg_data); - } - - RegCloseKey(key); - output_message(STRING_SUCCESS); - - return 0; -} - WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len) { WCHAR *subkey_path; diff --git a/programs/reg/reg.h b/programs/reg/reg.h index c8baaa0f9a9..b14470b2cbf 100644 --- a/programs/reg/reg.h +++ b/programs/reg/reg.h @@ -41,6 +41,10 @@ HKEY path_get_rootkey(const WCHAR *path); WCHAR *build_subkey_path(WCHAR *path, DWORD path_len, WCHAR *subkey_name, DWORD subkey_len); BOOL parse_registry_key(const WCHAR *key, HKEY *root, WCHAR **path, WCHAR **long_key);
+/* add.c */ +int reg_add(HKEY root, WCHAR *path, WCHAR *value_name, BOOL value_empty, + WCHAR *type, WCHAR separator, WCHAR *data, BOOL force); + /* delete.c */ int reg_delete(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL value_all, BOOL force);