ntoskrnl.exe/tests: Add some IOCTL_HID_WRITE_REPORT tests.
[wine.git] / programs / reg / copy.c
blob3ede5440cb6798349b96fd0e922bad2152740b75
1 /*
2 * Copyright 2021 Hugh McMaster
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.
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.
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
19 #include <stdio.h>
20 #include "reg.h"
22 struct key {
23 HKEY root; /* system key */
24 WCHAR *subkey; /* relative path to subkey */
25 HKEY hkey; /* handle to opened or created key */
26 WCHAR *path; /* full path to subkey */
29 enum operation {
30 COPY_NO,
31 COPY_YES,
32 COPY_ALL
35 static void output_error(LONG rc)
37 if (rc == ERROR_FILE_NOT_FOUND)
38 output_message(STRING_KEY_NONEXIST);
39 else
40 output_message(STRING_ACCESS_DENIED);
43 static enum operation ask_overwrite_value(WCHAR *path, WCHAR *value)
45 HMODULE hmod;
46 static WCHAR Ybuffer[4];
47 static WCHAR Nbuffer[4];
48 static WCHAR Abuffer[4];
49 static WCHAR defval[32];
50 WCHAR answer[MAX_PATH];
51 WCHAR *str;
52 DWORD count;
54 hmod = GetModuleHandleW(NULL);
55 LoadStringW(hmod, STRING_YES, Ybuffer, ARRAY_SIZE(Ybuffer));
56 LoadStringW(hmod, STRING_NO, Nbuffer, ARRAY_SIZE(Nbuffer));
57 LoadStringW(hmod, STRING_ALL, Abuffer, ARRAY_SIZE(Abuffer));
58 LoadStringW(hmod, STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
60 str = (value && *value) ? value : defval;
62 while (1)
64 output_message(STRING_COPY_CONFIRM, path, str);
65 output_message(STRING_YESNOALL);
67 ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), answer, ARRAY_SIZE(answer), &count, NULL);
69 *answer = towupper(*answer);
71 if (*answer == *Ybuffer)
72 return COPY_YES;
73 if (*answer == *Nbuffer)
74 return COPY_NO;
75 if (*answer == *Abuffer)
76 return COPY_ALL;
80 static int run_copy(struct key *src, struct key *dest, BOOL recurse, BOOL force)
82 LONG rc;
83 DWORD max_subkey_len;
84 DWORD max_name_len, name_len;
85 DWORD max_data_size, data_size;
86 DWORD type, dispos, i;
87 WCHAR *name = NULL;
88 BYTE *data = NULL;
90 if ((rc = RegOpenKeyExW(src->root, src->subkey, 0, KEY_READ, &src->hkey)))
92 output_error(rc);
93 return 1;
96 if ((rc = RegCreateKeyExW(dest->root, dest->subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
97 KEY_READ|KEY_WRITE, NULL, &dest->hkey, &dispos)))
99 RegCloseKey(src->hkey);
100 output_error(rc);
101 return 1;
104 rc = RegQueryInfoKeyW(src->hkey, NULL, NULL, NULL, NULL, &max_subkey_len, NULL,
105 NULL, &max_name_len, &max_data_size, NULL, NULL);
106 if (rc) goto cleanup;
108 max_name_len = max(max_subkey_len, max_name_len) + 1;
110 if (!(name = malloc(max_name_len * sizeof(WCHAR))))
112 rc = ERROR_NOT_ENOUGH_MEMORY;
113 goto cleanup;
116 if (!(data = malloc(max_data_size)))
118 rc = ERROR_NOT_ENOUGH_MEMORY;
119 goto cleanup;
122 for (i = 0; ; i++)
124 name_len = max_name_len;
125 data_size = max_data_size;
127 rc = RegEnumValueW(src->hkey, i, name, &name_len, NULL, &type, data, &data_size);
128 if (rc == ERROR_NO_MORE_ITEMS) break;
129 if (rc) goto cleanup;
131 if (!force && dispos == REG_OPENED_EXISTING_KEY)
133 if (!RegQueryValueExW(dest->hkey, name, NULL, NULL, NULL, NULL))
135 enum operation op;
137 op = ask_overwrite_value(src->path, name);
138 if (op == COPY_NO) continue;
139 if (op == COPY_ALL) force = TRUE;
143 if ((rc = RegSetValueExW(dest->hkey, name, 0, type, data, data_size)))
145 output_error(rc);
146 goto cleanup;
150 for (i = 0; recurse; i++)
152 struct key subkey_src, subkey_dest;
153 size_t path_len;
155 name_len = max_name_len;
157 rc = RegEnumKeyExW(src->hkey, i, name, &name_len, NULL, NULL, NULL, NULL);
158 if (rc) break;
160 subkey_src.root = src->hkey;
161 subkey_src.subkey = name;
163 subkey_dest.root = dest->hkey;
164 subkey_dest.subkey = name;
166 path_len = lstrlenW(src->path) + name_len + 2;
168 if (!(subkey_src.path = malloc(path_len * sizeof(WCHAR))))
170 rc = ERROR_NOT_ENOUGH_MEMORY;
171 goto cleanup;
174 swprintf(subkey_src.path, path_len, L"%s\\%s", src->path, name);
176 rc = run_copy(&subkey_src, &subkey_dest, TRUE, force);
178 free(subkey_src.path);
180 if (rc) goto cleanup;
183 cleanup:
184 free(name);
185 free(data);
187 RegCloseKey(src->hkey);
188 RegCloseKey(dest->hkey);
190 return rc != ERROR_NO_MORE_ITEMS;
193 int reg_copy(int argc, WCHAR *argvW[])
195 struct key src, dest;
196 BOOL recurse = FALSE, force = FALSE;
197 int i;
199 if (argc == 3)
200 goto invalid;
202 if (!parse_registry_key(argvW[2], &src.root, &src.subkey))
203 return 1;
205 if (!parse_registry_key(argvW[3], &dest.root, &dest.subkey))
206 return 1;
208 for (i = 4; i < argc; i++)
210 WCHAR *str;
212 if (argvW[i][0] != '/' && argvW[i][0] != '-')
213 goto invalid;
215 str = &argvW[i][1];
217 if (!lstrcmpiW(str, L"reg:32") || !lstrcmpiW(str, L"reg:64"))
218 continue;
219 else if (!str[0] || str[1])
220 goto invalid;
222 switch (towlower(*str))
224 case 's':
225 if (recurse) goto invalid;
226 recurse = TRUE;
227 break;
228 case 'f':
229 if (force) goto invalid;
230 force = TRUE;
231 break;
232 default:
233 goto invalid;
237 if (src.root == dest.root && !lstrcmpiW(src.subkey, dest.subkey))
239 output_message(STRING_COPY_SRC_DEST_SAME);
240 return 1;
243 src.path = src.subkey;
245 return run_copy(&src, &dest, recurse, force);
247 invalid:
248 output_message(STRING_INVALID_SYNTAX);
249 output_message(STRING_FUNC_HELP, wcsupr(argvW[1]));
250 return 1;