From 0d458e0d99bcd320bafca2a351578afc0e6cfb90 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Mon, 21 Mar 2016 17:12:35 +0100 Subject: [PATCH] Added patch to implement query operation in reg.exe. --- patches/patchinstall.sh | 21 ++ ...alues-and-subkeys-in-a-specified-key.patch | 338 ++++++++++++++++++ ...for-querying-the-registry-with-the-v.patch | 129 +++++++ patches/reg-Implement_Query/definition | 1 + 4 files changed, 489 insertions(+) create mode 100644 patches/reg-Implement_Query/0001-reg-Query-all-values-and-subkeys-in-a-specified-key.patch create mode 100644 patches/reg-Implement_Query/0002-reg-Add-support-for-querying-the-registry-with-the-v.patch create mode 100644 patches/reg-Implement_Query/definition diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index c666e919..0ca91211 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -264,6 +264,7 @@ patch_enable_all () enable_quartz_MediaSeeking_Positions="$1" enable_quartz_Silence_FIXMEs="$1" enable_rasapi32_RasEnumDevicesA="$1" + enable_reg_Implement_Query="$1" enable_riched20_IText_Interface="$1" enable_rpcrt4_Pipe_Transport="$1" enable_rpcrt4_RpcBindingServerFromClient="$1" @@ -964,6 +965,9 @@ patch_enable () rasapi32-RasEnumDevicesA) enable_rasapi32_RasEnumDevicesA="$2" ;; + reg-Implement_Query) + enable_reg_Implement_Query="$2" + ;; riched20-IText_Interface) enable_riched20_IText_Interface="$2" ;; @@ -5691,6 +5695,23 @@ if test "$enable_rasapi32_RasEnumDevicesA" -eq 1; then ) >> "$patchlist" fi +# Patchset reg-Implement_Query +# | +# | This patchset fixes the following Wine bugs: +# | * [#24017] Implement query operation in reg.exe +# | +# | Modified files: +# | * programs/reg/reg.c +# | +if test "$enable_reg_Implement_Query" -eq 1; then + patch_apply reg-Implement_Query/0001-reg-Query-all-values-and-subkeys-in-a-specified-key.patch + patch_apply reg-Implement_Query/0002-reg-Add-support-for-querying-the-registry-with-the-v.patch + ( + echo '+ { "Hugh McMaster", "reg: Query all values and subkeys in a specified key.", 1 },'; + echo '+ { "Hugh McMaster", "reg: Add support for querying the registry with the /v and /ve switches.", 1 },'; + ) >> "$patchlist" +fi + # Patchset riched20-IText_Interface # | # | Modified files: diff --git a/patches/reg-Implement_Query/0001-reg-Query-all-values-and-subkeys-in-a-specified-key.patch b/patches/reg-Implement_Query/0001-reg-Query-all-values-and-subkeys-in-a-specified-key.patch new file mode 100644 index 00000000..ab8231b0 --- /dev/null +++ b/patches/reg-Implement_Query/0001-reg-Query-all-values-and-subkeys-in-a-specified-key.patch @@ -0,0 +1,338 @@ +From 52a65aa581b8bdcc972efcb8f8a9320481124812 Mon Sep 17 00:00:00 2001 +From: Hugh McMaster +Date: Thu, 17 Mar 2016 16:10:25 +1100 +Subject: reg: Query all values and subkeys in a specified key + +Displays all values and subkeys in a specified key. Recursion is supported. + +Signed-off-by: Hugh McMaster +--- + programs/reg/reg.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 286 insertions(+), 8 deletions(-) + +diff --git a/programs/reg/reg.c b/programs/reg/reg.c +index 9dbce32..75c5292 100644 +--- a/programs/reg/reg.c ++++ b/programs/reg/reg.c +@@ -546,14 +546,292 @@ static int reg_delete(WCHAR *key_name, WCHAR *value_name, BOOL value_empty, + return 0; + } + +-static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty, +- BOOL subkey) ++static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes) + { ++ WCHAR *buffer = NULL, *ptr = NULL; ++ WCHAR hex_fmt[] = {'%','0','2','x',0}; ++ int i; ++ ++ switch (type) ++ { ++ case REG_NONE: ++ case REG_SZ: ++ case REG_EXPAND_SZ: ++ buffer = HeapAlloc(GetProcessHeap(), 0, size_bytes); ++ strcpyW(buffer, (WCHAR *)src); ++ break; ++ case REG_BINARY: ++ buffer = HeapAlloc(GetProcessHeap(), 0, (size_bytes * 2 + 1) * sizeof(WCHAR)); ++ ptr = buffer; ++ for (i = 0; i < size_bytes; i++) ++ ptr += sprintfW(ptr, hex_fmt, src[i]); ++ break; ++ case REG_DWORD: ++ /* case REG_DWORD_LITTLE_ENDIAN: */ ++ case REG_DWORD_BIG_ENDIAN: ++ { ++ const int zero_x_dword = 10; ++ WCHAR zero_x[] = {'0','x',0}; ++ ++ buffer = HeapAlloc(GetProcessHeap(), 0, (zero_x_dword + 1) * sizeof(WCHAR)); ++ strcpyW(buffer, zero_x); ++ ptr = buffer + 2; ++ ++ for (i = size_bytes; i-- > 0;) ++ ptr += sprintfW(ptr, hex_fmt, src[i]); ++ break; ++ } ++ case REG_MULTI_SZ: ++ { ++ const int two_wchars = 2 * sizeof(WCHAR); ++ DWORD tmp_size; ++ WCHAR *tmp; ++ int len, destindex; ++ ++ if (size_bytes <= two_wchars) ++ { ++ buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)); ++ *buffer = 0; ++ return buffer; ++ } ++ ++ tmp_size = size_bytes - two_wchars; /* exclude both null terminators */ ++ tmp = HeapAlloc(GetProcessHeap(), 0, tmp_size); ++ memcpy(tmp, (WCHAR *)src, tmp_size); ++ buffer = HeapAlloc(GetProcessHeap(), 0, tmp_size * 2); ++ len = tmp_size / sizeof(WCHAR); ++ ++ for (i = 0, destindex = 0; i < len; i++, destindex++) ++ { ++ if (tmp[i]) ++ buffer[destindex] = tmp[i]; ++ else ++ { ++ buffer[destindex++] = '\\'; ++ buffer[destindex] = '0'; ++ } ++ } ++ buffer[destindex] = 0; ++ HeapFree(GetProcessHeap(), 0, tmp); ++ break; ++ } ++ } ++ return buffer; ++} ++ ++static const WCHAR *reg_type_to_wchar(DWORD type) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(type_rels); i++) ++ { ++ if (type == type_rels[i].type) ++ return type_rels[i].name; ++ } ++ ++ return NULL; ++} ++ ++static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size) ++{ ++ WCHAR fmt[] = {' ',' ',' ',' ','%','1',0}; ++ WCHAR *reg_data; ++ WCHAR newlineW[] = {'\n',0}; ++ ++ if (value_name && *value_name) ++ output_string(fmt, value_name); ++ else ++ { ++ WCHAR defval[32]; ++ LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval)); ++ output_string(fmt, defval); ++ } ++ output_string(fmt, reg_type_to_wchar(type)); ++ reg_data = reg_data_to_wchar(type, data, data_size); ++ output_string(fmt, reg_data); ++ HeapFree(GetProcessHeap(), 0, reg_data); ++ output_string(newlineW); ++} ++ ++static WCHAR *build_subkey_path(WCHAR *path, WCHAR *subkey_name, DWORD len) ++{ ++ WCHAR *subkey_path; ++ WCHAR fmt[] = {'%','s','\\','%','s',0}; ++ ++ subkey_path = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); ++ if (!subkey_path) ++ { ++ ERR("Failed to allocate memory for subkey_path\n"); ++ return NULL; ++ } ++ sprintfW(subkey_path, fmt, path, subkey_name); ++ return subkey_path; ++} ++ ++static int query_all(HKEY key, WCHAR *path, DWORD path_len, BOOL recurse) ++{ ++ LONG rc; ++ DWORD num_subkeys, max_subkey_len, subkey_len, subkey_path_len; ++ DWORD num_values, max_value_len, value_len; ++ DWORD max_data_bytes, data_size; ++ DWORD type; ++ WCHAR *value_name, *subkey_name, *subkey_path; ++ WCHAR fmt[] = {'%','1','\n',0}; ++ WCHAR fmt_path[] = {'%','1','\\','%','2','\n',0}; ++ WCHAR newlineW[] = {'\n',0}; ++ BYTE *data; ++ int i; ++ HKEY subkey; ++ ++ rc = RegQueryInfoKeyW(key, NULL, NULL, NULL, &num_subkeys, &max_subkey_len, NULL, ++ &num_values, &max_value_len, &max_data_bytes, NULL, NULL); ++ if (rc) ++ { ++ ERR("RegQueryInfoKey failed: %d\n", rc); ++ return 1; ++ } ++ ++ max_value_len++; ++ max_subkey_len++; ++ ++ value_name = HeapAlloc(GetProcessHeap(), 0, max_value_len * sizeof(WCHAR)); ++ if (!value_name) ++ { ++ ERR("Failed to allocate memory for value_name\n"); ++ return 1; ++ } ++ ++ data = HeapAlloc(GetProcessHeap(), 0, max_data_bytes); ++ if (!data) ++ { ++ HeapFree(GetProcessHeap(), 0, value_name); ++ ERR("Failed to allocate memory for data\n"); ++ return 1; ++ } ++ ++ output_string(fmt, path); ++ ++ for (i = 0; i < num_values; i++) ++ { ++ value_len = max_value_len; ++ data_size = max_data_bytes; ++ rc = RegEnumValueW(key, i, value_name, &value_len, NULL, &type, data, &data_size); ++ if (rc == ERROR_SUCCESS) ++ output_value(value_name, type, data, data_size); ++ } ++ ++ HeapFree(GetProcessHeap(), 0, data); ++ HeapFree(GetProcessHeap(), 0, value_name); ++ ++ if (num_values || recurse) ++ output_string(newlineW); ++ ++ subkey_name = HeapAlloc(GetProcessHeap(), 0, max_subkey_len * sizeof(WCHAR)); ++ if (!subkey_name) ++ { ++ ERR("Failed to allocate memory for subkey_name\n"); ++ return 1; ++ } ++ ++ for (i = 0; i < num_subkeys; i++) ++ { ++ subkey_len = max_subkey_len; ++ rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); ++ if (rc == ERROR_SUCCESS) ++ { ++ if (recurse) ++ { ++ subkey_path_len = path_len + subkey_len + 1; ++ subkey_path = build_subkey_path(path, subkey_name, subkey_path_len); ++ RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey); ++ query_all(subkey, subkey_path, subkey_path_len, recurse); ++ RegCloseKey(subkey); ++ HeapFree(GetProcessHeap(), 0, subkey_path); ++ } ++ else output_string(fmt_path, path, subkey_name); ++ } ++ } ++ ++ HeapFree(GetProcessHeap(), 0, subkey_name); ++ return 0; ++} ++ ++static WCHAR *get_long_path(HKEY root, WCHAR *path) ++{ ++ int i, len; ++ WCHAR *long_path; ++ WCHAR fmt[] = {'%','s','\\','%','s',0}; ++ ++ for (i = 0; i < ARRAY_SIZE(root_rels); i++) ++ { ++ if (root == root_rels[i].key) ++ break; ++ } ++ ++ len = strlenW(root_rels[i].long_name); ++ ++ if (!path) ++ { ++ long_path = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); ++ strcpyW(long_path, root_rels[i].long_name); ++ return long_path; ++ } ++ ++ len += strlenW(path) + 1; /* add one for the backslash */ ++ long_path = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); ++ sprintfW(long_path, fmt, root_rels[i].long_name, path); ++ return long_path; ++} ++ ++static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL recurse) ++{ ++ WCHAR *p, *path; ++ HKEY root, key; + static const WCHAR stubW[] = {'S','T','U','B',' ','Q','U','E','R','Y',' ', +- '-',' ','%','1',' ','%','2',' ','%','3','!','d','!',' ','%','4','!','d','!','\n',0}; +- output_string(stubW, key_name, value_name, value_empty, subkey); ++ '-',' ','%','1',' ','%','2',' ','%','3','!','d','!',' ','%','4','!','d','!','\n',0}; ++ DWORD path_len; ++ int ret; ++ ++ if (!sane_path(key_name)) ++ return 1; ++ ++ if (value_name && value_empty) ++ { ++ output_message(STRING_INVALID_CMDLINE); ++ return 1; ++ } ++ ++ root = path_get_rootkey(key_name); ++ if (!root) ++ { ++ output_message(STRING_INVALID_KEY); ++ return 1; ++ } ++ ++ p = strchrW(key_name, '\\'); ++ if (p) p++; ++ ++ if (RegOpenKeyExW(root, p, 0, KEY_READ, &key) != ERROR_SUCCESS) ++ { ++ output_message(STRING_CANNOT_FIND); ++ return 1; ++ } ++ ++ path = get_long_path(root, p); ++ path_len = strlenW(path); ++ ++ if (value_name || value_empty) ++ { ++ output_string(stubW, key_name, value_name, value_empty, recurse); ++ return 1; ++ } ++ ++ ret = query_all(key, path, path_len, recurse); ++ ++ HeapFree(GetProcessHeap(), 0, path); ++ RegCloseKey(key); + +- return 1; ++ return ret; + } + + int wmain(int argc, WCHAR *argvW[]) +@@ -677,7 +955,7 @@ int wmain(int argc, WCHAR *argvW[]) + else if (!lstrcmpiW(argvW[1], queryW)) + { + WCHAR *key_name, *value_name = NULL; +- BOOL value_empty = FALSE, subkey = FALSE; ++ BOOL value_empty = FALSE, recurse = FALSE; + + if (argc < 3) + { +@@ -705,9 +983,9 @@ int wmain(int argc, WCHAR *argvW[]) + else if (!lstrcmpiW(argvW[i], slashVEW)) + value_empty = TRUE; + else if (!lstrcmpiW(argvW[i], slashSW)) +- subkey = TRUE; ++ recurse = TRUE; + } +- return reg_query(key_name, value_name, value_empty, subkey); ++ return reg_query(key_name, value_name, value_empty, recurse); + } + else + { +-- +2.7.1 + diff --git a/patches/reg-Implement_Query/0002-reg-Add-support-for-querying-the-registry-with-the-v.patch b/patches/reg-Implement_Query/0002-reg-Add-support-for-querying-the-registry-with-the-v.patch new file mode 100644 index 00000000..5d6c41f4 --- /dev/null +++ b/patches/reg-Implement_Query/0002-reg-Add-support-for-querying-the-registry-with-the-v.patch @@ -0,0 +1,129 @@ +From bf459e7bcaca10acae3f07756d4e63812e7da0c0 Mon Sep 17 00:00:00 2001 +From: Hugh McMaster +Date: Fri, 18 Mar 2016 15:50:31 +1100 +Subject: reg: Add support for querying the registry with the /v and /ve + switches + +Recursion is supported. + +Signed-off-by: Hugh McMaster +--- + programs/reg/reg.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 80 insertions(+), 8 deletions(-) + +diff --git a/programs/reg/reg.c b/programs/reg/reg.c +index 75c5292..3722841 100644 +--- a/programs/reg/reg.c ++++ b/programs/reg/reg.c +@@ -756,6 +756,83 @@ static int query_all(HKEY key, WCHAR *path, DWORD path_len, BOOL recurse) + return 0; + } + ++static int num_values_found = 0; ++ ++static int query_value(HKEY key, WCHAR *value_name, WCHAR *path, DWORD path_len, BOOL recurse) ++{ ++ LONG rc; ++ DWORD num_subkeys, max_subkey_len, subkey_len, subkey_path_len; ++ DWORD max_data_bytes, data_size; ++ DWORD type; ++ BYTE *data; ++ WCHAR fmt[] = {'%','1','\n',0}; ++ WCHAR newlineW[] = {'\n',0}; ++ WCHAR *subkey_name, *subkey_path; ++ int i; ++ HKEY subkey; ++ ++ rc = RegQueryInfoKeyW(key, NULL, NULL, NULL, &num_subkeys, &max_subkey_len, ++ NULL, NULL, NULL, &max_data_bytes, NULL, NULL); ++ if (rc) ++ { ++ ERR("RegQueryInfoKey failed: %d\n", rc); ++ return 1; ++ } ++ ++ max_subkey_len++; ++ ++ data = HeapAlloc(GetProcessHeap(), 0, max_data_bytes); ++ if (!data) ++ { ++ ERR("Failed to allocate memory for data\n"); ++ return 1; ++ } ++ ++ data_size = max_data_bytes; ++ rc = RegQueryValueExW(key, value_name, NULL, &type, data, &data_size); ++ if (rc == ERROR_SUCCESS) ++ { ++ output_string(fmt, path); ++ output_value(value_name, type, data, data_size); ++ output_string(newlineW); ++ num_values_found++; ++ } ++ ++ HeapFree(GetProcessHeap(), 0, data); ++ ++ if (!recurse) ++ { ++ if (rc == ERROR_FILE_NOT_FOUND) ++ return 1; ++ return 0; ++ } ++ ++ subkey_name = HeapAlloc(GetProcessHeap(), 0, max_subkey_len * sizeof(WCHAR)); ++ if (!subkey_name) ++ { ++ ERR("Failed to allocate memory for subkey_name\n"); ++ return 1; ++ } ++ ++ for (i = 0; i < num_subkeys; i++) ++ { ++ subkey_len = max_subkey_len; ++ rc = RegEnumKeyExW(key, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); ++ if (rc == ERROR_SUCCESS) ++ { ++ subkey_path_len = path_len + subkey_len + 1; ++ subkey_path = build_subkey_path(path, subkey_name, subkey_path_len); ++ RegOpenKeyExW(key, subkey_name, 0, KEY_READ, &subkey); ++ query_value(subkey, value_name, subkey_path, subkey_path_len, recurse); ++ RegCloseKey(subkey); ++ HeapFree(GetProcessHeap(), 0, subkey_path); ++ } ++ } ++ ++ HeapFree(GetProcessHeap(), 0, subkey_name); ++ return 0; ++} ++ + static WCHAR *get_long_path(HKEY root, WCHAR *path) + { + int i, len; +@@ -787,8 +864,6 @@ static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL + { + WCHAR *p, *path; + HKEY root, key; +- static const WCHAR stubW[] = {'S','T','U','B',' ','Q','U','E','R','Y',' ', +- '-',' ','%','1',' ','%','2',' ','%','3','!','d','!',' ','%','4','!','d','!','\n',0}; + DWORD path_len; + int ret; + +@@ -821,12 +896,9 @@ static int reg_query(WCHAR *key_name, WCHAR *value_name, BOOL value_empty, BOOL + path_len = strlenW(path); + + if (value_name || value_empty) +- { +- output_string(stubW, key_name, value_name, value_empty, recurse); +- return 1; +- } +- +- ret = query_all(key, path, path_len, recurse); ++ ret = query_value(key, value_name, path, path_len, recurse); ++ else ++ ret = query_all(key, path, path_len, recurse); + + HeapFree(GetProcessHeap(), 0, path); + RegCloseKey(key); +-- +2.7.1 + diff --git a/patches/reg-Implement_Query/definition b/patches/reg-Implement_Query/definition new file mode 100644 index 00000000..f97cefe0 --- /dev/null +++ b/patches/reg-Implement_Query/definition @@ -0,0 +1 @@ +Fixes: [24017] Implement query operation in reg.exe