[PATCH] reg: Prompt the user to confirm whether they want to overwrite existing values when copying a key

Hugh McMaster hugh.mcmaster at outlook.com
Thu Jun 3 08:32:26 CDT 2021


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48000
Signed-off-by: Hugh McMaster <hugh.mcmaster at 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
-- 
2.32.0.rc2




More information about the wine-devel mailing list