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
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 */
35 static void output_error(LONG rc
)
37 if (rc
== ERROR_FILE_NOT_FOUND
)
38 output_message(STRING_KEY_NONEXIST
);
40 output_message(STRING_ACCESS_DENIED
);
43 static enum operation
ask_overwrite_value(WCHAR
*path
, WCHAR
*value
)
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
];
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
;
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
)
73 if (*answer
== *Nbuffer
)
75 if (*answer
== *Abuffer
)
80 static int run_copy(struct key
*src
, struct key
*dest
, BOOL recurse
, BOOL force
)
84 DWORD max_name_len
, name_len
;
85 DWORD max_data_size
, data_size
;
86 DWORD type
, dispos
, i
;
90 if ((rc
= RegOpenKeyExW(src
->root
, src
->subkey
, 0, KEY_READ
, &src
->hkey
)))
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
);
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
;
116 if (!(data
= malloc(max_data_size
)))
118 rc
= ERROR_NOT_ENOUGH_MEMORY
;
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
))
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
)))
150 for (i
= 0; recurse
; i
++)
152 struct key subkey_src
, subkey_dest
;
155 name_len
= max_name_len
;
157 rc
= RegEnumKeyExW(src
->hkey
, i
, name
, &name_len
, NULL
, NULL
, NULL
, NULL
);
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
;
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
;
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
;
202 if (!parse_registry_key(argvW
[2], &src
.root
, &src
.subkey
))
205 if (!parse_registry_key(argvW
[3], &dest
.root
, &dest
.subkey
))
208 for (i
= 4; i
< argc
; i
++)
212 if (argvW
[i
][0] != '/' && argvW
[i
][0] != '-')
217 if (!lstrcmpiW(str
, L
"reg:32") || !lstrcmpiW(str
, L
"reg:64"))
219 else if (!str
[0] || str
[1])
222 switch (towlower(*str
))
225 if (recurse
) goto invalid
;
229 if (force
) goto invalid
;
237 if (src
.root
== dest
.root
&& !lstrcmpiW(src
.subkey
, dest
.subkey
))
239 output_message(STRING_COPY_SRC_DEST_SAME
);
243 src
.path
= src
.subkey
;
245 return run_copy(&src
, &dest
, recurse
, force
);
248 output_message(STRING_INVALID_SYNTAX
);
249 output_message(STRING_FUNC_HELP
, wcsupr(argvW
[1]));