Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48000 Signed-off-by: Hugh McMaster hugh.mcmaster@outlook.com --- programs/reg/copy.c | 79 +++++++++++++++++++++++++++++++++++++++-- programs/reg/reg.rc | 5 ++- programs/reg/resource.h | 3 ++ 3 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/programs/reg/copy.c b/programs/reg/copy.c index 208adc46e00..3ede5440cb6 100644 --- a/programs/reg/copy.c +++ b/programs/reg/copy.c @@ -16,12 +16,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include <stdio.h> #include "reg.h"
struct key { HKEY root; /* system key */ - WCHAR *subkey; /* path to subkey */ + WCHAR *subkey; /* relative path to subkey */ HKEY hkey; /* handle to opened or created key */ + WCHAR *path; /* full path to subkey */ +}; + +enum operation { + COPY_NO, + COPY_YES, + COPY_ALL };
static void output_error(LONG rc) @@ -32,13 +40,50 @@ static void output_error(LONG rc) output_message(STRING_ACCESS_DENIED); }
+static enum operation ask_overwrite_value(WCHAR *path, WCHAR *value) +{ + HMODULE hmod; + static WCHAR Ybuffer[4]; + static WCHAR Nbuffer[4]; + static WCHAR Abuffer[4]; + static WCHAR defval[32]; + WCHAR answer[MAX_PATH]; + WCHAR *str; + DWORD count; + + hmod = GetModuleHandleW(NULL); + LoadStringW(hmod, STRING_YES, Ybuffer, ARRAY_SIZE(Ybuffer)); + LoadStringW(hmod, STRING_NO, Nbuffer, ARRAY_SIZE(Nbuffer)); + LoadStringW(hmod, STRING_ALL, Abuffer, ARRAY_SIZE(Abuffer)); + LoadStringW(hmod, STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval)); + + str = (value && *value) ? value : defval; + + while (1) + { + output_message(STRING_COPY_CONFIRM, path, str); + output_message(STRING_YESNOALL); + + ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), answer, ARRAY_SIZE(answer), &count, NULL); + + *answer = towupper(*answer); + + if (*answer == *Ybuffer) + return COPY_YES; + if (*answer == *Nbuffer) + return COPY_NO; + if (*answer == *Abuffer) + return COPY_ALL; + } +} + static int run_copy(struct key *src, struct key *dest, BOOL recurse, BOOL force) { LONG rc; DWORD max_subkey_len; DWORD max_name_len, name_len; DWORD max_data_size, data_size; - DWORD type, i; + DWORD type, dispos, i; WCHAR *name = NULL; BYTE *data = NULL;
@@ -49,7 +94,7 @@ static int run_copy(struct key *src, struct key *dest, BOOL recurse, BOOL force) }
if ((rc = RegCreateKeyExW(dest->root, dest->subkey, 0, NULL, REG_OPTION_NON_VOLATILE, - KEY_WRITE, NULL, &dest->hkey, NULL))) + KEY_READ|KEY_WRITE, NULL, &dest->hkey, &dispos))) { RegCloseKey(src->hkey); output_error(rc); @@ -83,6 +128,18 @@ static int run_copy(struct key *src, struct key *dest, BOOL recurse, BOOL force) if (rc == ERROR_NO_MORE_ITEMS) break; if (rc) goto cleanup;
+ if (!force && dispos == REG_OPENED_EXISTING_KEY) + { + if (!RegQueryValueExW(dest->hkey, name, NULL, NULL, NULL, NULL)) + { + enum operation op; + + op = ask_overwrite_value(src->path, name); + if (op == COPY_NO) continue; + if (op == COPY_ALL) force = TRUE; + } + } + if ((rc = RegSetValueExW(dest->hkey, name, 0, type, data, data_size))) { output_error(rc); @@ -93,6 +150,7 @@ static int run_copy(struct key *src, struct key *dest, BOOL recurse, BOOL force) for (i = 0; recurse; i++) { struct key subkey_src, subkey_dest; + size_t path_len;
name_len = max_name_len;
@@ -105,7 +163,20 @@ static int run_copy(struct key *src, struct key *dest, BOOL recurse, BOOL force) subkey_dest.root = dest->hkey; subkey_dest.subkey = name;
+ path_len = lstrlenW(src->path) + name_len + 2; + + if (!(subkey_src.path = malloc(path_len * sizeof(WCHAR)))) + { + rc = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + swprintf(subkey_src.path, path_len, L"%s\%s", src->path, name); + rc = run_copy(&subkey_src, &subkey_dest, TRUE, force); + + free(subkey_src.path); + if (rc) goto cleanup; }
@@ -169,6 +240,8 @@ int reg_copy(int argc, WCHAR *argvW[]) return 1; }
+ src.path = src.subkey; + return run_copy(&src, &dest, recurse, force);
invalid: diff --git a/programs/reg/reg.rc b/programs/reg/reg.rc index 89df2c45c4c..a3c53cf41b4 100644 --- a/programs/reg/reg.rc +++ b/programs/reg/reg.rc @@ -122,9 +122,11 @@ STRINGTABLE STRING_MISSING_HEXDATA, "reg: The option [/d] must be followed by a valid hexadecimal value\n" STRING_UNHANDLED_TYPE, "reg: Unhandled registry data type [/t 0x%1!x!, /d %2]\n" STRING_OVERWRITE_VALUE, "The registry value '%1' already exists. Do you want to overwrite it?" - STRING_YESNO, " (Yes|No)" STRING_YES, "#msgctxt#Yes key#Y" STRING_NO, "#msgctxt#No key#N" + STRING_ALL, "#msgctxt#All key#A" + STRING_YESNO, " (Yes|No)" + STRING_YESNOALL, " (Yes|No|All)" STRING_CANCELLED, "reg: The registry operation was cancelled\n" STRING_DEFAULT_VALUE, "(Default)" STRING_DELETE_VALUE, "Are you sure you want to delete the registry value '%1'?" @@ -199,4 +201,5 @@ STRINGTABLE \ This option does not modify subkeys and values that only exist in <key2>.\n\n"
STRING_COPY_SRC_DEST_SAME, "reg: The source and destination keys cannot be the same\n" + STRING_COPY_CONFIRM, "The value '%1\%2' already exists in the destination key. Do you want to overwrite it?" } diff --git a/programs/reg/resource.h b/programs/reg/resource.h index 92d82d80a9b..f33d3da69be 100644 --- a/programs/reg/resource.h +++ b/programs/reg/resource.h @@ -25,7 +25,9 @@ /* Shared */ #define STRING_YES 100 #define STRING_NO 101 +#define STRING_ALL 102 #define STRING_YESNO 103 +#define STRING_YESNOALL 104 #define STRING_INVALID_SYNTAX 105 #define STRING_FUNC_HELP 106 #define STRING_ACCESS_DENIED 107 @@ -61,6 +63,7 @@
/* copy.c */ #define STRING_COPY_SRC_DEST_SAME 250 +#define STRING_COPY_CONFIRM 251
/* delete.c */ #define STRING_DELETE_VALUE 300