winealsa: Use dedicated macros to call interface functions.
[wine.git] / programs / reg / copy.c
blob2970ab81cc1f8aa22f8a87a99c3a2472617d68d4
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, REGSAM sam, 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|sam, &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|sam, 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, sam, 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 REGSAM sam = 0;
198 int i;
200 if (argc == 3)
201 goto invalid;
203 if (!parse_registry_key(argvW[2], &src.root, &src.subkey))
204 return 1;
206 if (!parse_registry_key(argvW[3], &dest.root, &dest.subkey))
207 return 1;
209 for (i = 4; i < argc; i++)
211 WCHAR *str;
213 if (argvW[i][0] != '/' && argvW[i][0] != '-')
214 goto invalid;
216 str = &argvW[i][1];
218 if (!lstrcmpiW(str, L"reg:32"))
220 if (sam & KEY_WOW64_32KEY) goto invalid;
221 sam |= KEY_WOW64_32KEY;
222 continue;
224 else if (!lstrcmpiW(str, L"reg:64"))
226 if (sam & KEY_WOW64_64KEY) goto invalid;
227 sam |= KEY_WOW64_64KEY;
228 continue;
230 else if (!str[0] || str[1])
231 goto invalid;
233 switch (towlower(*str))
235 case 's':
236 if (recurse) goto invalid;
237 recurse = TRUE;
238 break;
239 case 'f':
240 if (force) goto invalid;
241 force = TRUE;
242 break;
243 default:
244 goto invalid;
248 if (sam == (KEY_WOW64_32KEY|KEY_WOW64_64KEY))
249 goto invalid;
251 if (src.root == dest.root && !lstrcmpiW(src.subkey, dest.subkey))
253 output_message(STRING_COPY_SRC_DEST_SAME);
254 return 1;
257 src.path = src.subkey;
259 return run_copy(&src, &dest, sam, recurse, force);
261 invalid:
262 output_message(STRING_INVALID_SYNTAX);
263 output_message(STRING_FUNC_HELP, wcsupr(argvW[1]));
264 return 1;