17fcb8acaSwinesync /* 27fcb8acaSwinesync * Copyright 2014 Akihiro Sagawa 37fcb8acaSwinesync * Copyright 2016-2018, 2021 Hugh McMaster 47fcb8acaSwinesync * 57fcb8acaSwinesync * This library is free software; you can redistribute it and/or 67fcb8acaSwinesync * modify it under the terms of the GNU Lesser General Public 77fcb8acaSwinesync * License as published by the Free Software Foundation; either 87fcb8acaSwinesync * version 2.1 of the License, or (at your option) any later version. 97fcb8acaSwinesync * 107fcb8acaSwinesync * This library is distributed in the hope that it will be useful, 117fcb8acaSwinesync * but WITHOUT ANY WARRANTY; without even the implied warranty of 127fcb8acaSwinesync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 137fcb8acaSwinesync * Lesser General Public License for more details. 147fcb8acaSwinesync * 157fcb8acaSwinesync * You should have received a copy of the GNU Lesser General Public 167fcb8acaSwinesync * License along with this library; if not, write to the Free Software 177fcb8acaSwinesync * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 187fcb8acaSwinesync */ 197fcb8acaSwinesync 207fcb8acaSwinesync #include "reg_test.h" 217fcb8acaSwinesync 225132d26cSwinesync static void read_from_pipe(HANDLE child_proc_stdout, BYTE *buf, DWORD buf_size) 235132d26cSwinesync { 245132d26cSwinesync DWORD read, len = 0; 255132d26cSwinesync BOOL ret; 265132d26cSwinesync 275132d26cSwinesync while (1) 285132d26cSwinesync { 295132d26cSwinesync ret = ReadFile(child_proc_stdout, buf + len, buf_size - len, &read, NULL); 305132d26cSwinesync if (!ret || !read) break; 315132d26cSwinesync 325132d26cSwinesync len += read; 335132d26cSwinesync } 345132d26cSwinesync 355132d26cSwinesync buf[len] = 0; 365132d26cSwinesync } 375132d26cSwinesync 385132d26cSwinesync #define read_reg_output(c,b,s,r) read_reg_output_(__FILE__,__LINE__,c,b,s,r) 395132d26cSwinesync static BOOL read_reg_output_(const char *file, unsigned line, const char *cmd, 405132d26cSwinesync BYTE *buf, DWORD buf_size, DWORD *rc) 415132d26cSwinesync { 425132d26cSwinesync SECURITY_ATTRIBUTES sa; 435132d26cSwinesync HANDLE pipe_stdout_rd, pipe_stdout_wr; 445132d26cSwinesync STARTUPINFOA si = {0}; 455132d26cSwinesync PROCESS_INFORMATION pi; 465132d26cSwinesync char cmdline[256]; 475132d26cSwinesync BOOL bret; 485132d26cSwinesync DWORD ret; 495132d26cSwinesync 505132d26cSwinesync sa.nLength = sizeof(SECURITY_ATTRIBUTES); 515132d26cSwinesync sa.bInheritHandle = TRUE; 525132d26cSwinesync sa.lpSecurityDescriptor = NULL; 535132d26cSwinesync 545132d26cSwinesync if (!CreatePipe(&pipe_stdout_rd, &pipe_stdout_wr, &sa, 0)) 555132d26cSwinesync return FALSE; 565132d26cSwinesync 575132d26cSwinesync if (!SetHandleInformation(pipe_stdout_rd, HANDLE_FLAG_INHERIT, 0)) 585132d26cSwinesync return FALSE; 595132d26cSwinesync 605132d26cSwinesync si.cb = sizeof(si); 615132d26cSwinesync si.dwFlags = STARTF_USESTDHANDLES; 625132d26cSwinesync si.hStdInput = INVALID_HANDLE_VALUE; 635132d26cSwinesync si.hStdOutput = pipe_stdout_wr; 645132d26cSwinesync si.hStdError = INVALID_HANDLE_VALUE; 655132d26cSwinesync 665132d26cSwinesync strcpy(cmdline, cmd); 675132d26cSwinesync if (!CreateProcessA(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) 685132d26cSwinesync return FALSE; 695132d26cSwinesync 705132d26cSwinesync CloseHandle(pipe_stdout_wr); 715132d26cSwinesync 725132d26cSwinesync read_from_pipe(pipe_stdout_rd, buf, buf_size); 735132d26cSwinesync 745132d26cSwinesync ret = WaitForSingleObject(pi.hProcess, 10000); 755132d26cSwinesync if (ret == WAIT_TIMEOUT) 765132d26cSwinesync TerminateProcess(pi.hProcess, 1); 775132d26cSwinesync 785132d26cSwinesync bret = GetExitCodeProcess(pi.hProcess, rc); 795132d26cSwinesync lok(bret, "GetExitCodeProcess failed: %d\n", GetLastError()); 805132d26cSwinesync 815132d26cSwinesync CloseHandle(pipe_stdout_rd); 825132d26cSwinesync CloseHandle(pi.hThread); 835132d26cSwinesync CloseHandle(pi.hProcess); 845132d26cSwinesync return bret; 855132d26cSwinesync } 865132d26cSwinesync 87e77afe91Swinesync #define compare_query(b,e,c,todo) compare_query_(__FILE__,__LINE__,b,e,c,todo) 885132d26cSwinesync static void compare_query_(const char *file, unsigned line, const BYTE *buf, 89e77afe91Swinesync const char *expected, BOOL cmp_len, DWORD todo) 90e77afe91Swinesync { 91e77afe91Swinesync const char *str = (const char *)buf; 92e77afe91Swinesync const char *err = "query output does not match expected output"; 93e77afe91Swinesync 94e77afe91Swinesync if (!cmp_len) 955132d26cSwinesync { 965132d26cSwinesync todo_wine_if (todo & TODO_REG_COMPARE) 97e77afe91Swinesync lok(!strcmp(str, expected), "%s\n", err); 98e77afe91Swinesync } 99e77afe91Swinesync else 100e77afe91Swinesync { 101e77afe91Swinesync todo_wine_if (todo & TODO_REG_COMPARE) 102e77afe91Swinesync lok(!strncmp(str, expected, strlen(expected)), "%s\n", err); 103e77afe91Swinesync } 1045132d26cSwinesync } 1055132d26cSwinesync 1065132d26cSwinesync /* Unit tests */ 1075132d26cSwinesync 1087fcb8acaSwinesync static void test_query(void) 1097fcb8acaSwinesync { 1105132d26cSwinesync const char *test1 = "\r\n" 1115132d26cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\r\n" 1125132d26cSwinesync " Test1 REG_SZ Hello, World\r\n" 1135132d26cSwinesync " Test2 REG_DWORD 0x123\r\n\r\n"; 1145132d26cSwinesync 1155132d26cSwinesync const char *test2 = "\r\n" 1165132d26cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\r\n" 1175132d26cSwinesync " Test1 REG_SZ Hello, World\r\n\r\n"; 1185132d26cSwinesync 1195132d26cSwinesync const char *test3 = "\r\n" 1205132d26cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\r\n" 1215132d26cSwinesync " Test1 REG_SZ Hello, World\r\n" 1225132d26cSwinesync " Test2 REG_DWORD 0x123\r\n" 1235132d26cSwinesync " Wine REG_SZ First instance\r\n\r\n" 1245132d26cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey\r\n"; 1255132d26cSwinesync 1265132d26cSwinesync const char *test4 = "\r\n" 1275132d26cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey\r\n" 1285132d26cSwinesync " Test3 REG_SZ Some string data\r\n" 1295132d26cSwinesync " Test4 REG_DWORD 0xabc\r\n\r\n"; 1305132d26cSwinesync 1315132d26cSwinesync const char *test5 = "\r\n" 1325132d26cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey\r\n" 1335132d26cSwinesync " Test4 REG_DWORD 0xabc\r\n\r\n"; 1345132d26cSwinesync 135e77afe91Swinesync const char *test6 = "\r\n" 136e77afe91Swinesync "HKEY_CURRENT_USER\\" KEY_BASE "\r\n" 137e77afe91Swinesync " Test1 REG_SZ Hello, World\r\n" 138e77afe91Swinesync " Test2 REG_DWORD 0x123\r\n" 139e77afe91Swinesync " Wine REG_SZ First instance\r\n\r\n" 140e77afe91Swinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey\r\n" 141e77afe91Swinesync " Test3 REG_SZ Some string data\r\n" 142e77afe91Swinesync " Test4 REG_DWORD 0xabc\r\n" 143e77afe91Swinesync " Wine REG_SZ Second instance\r\n\r\n"; 144e77afe91Swinesync 145e77afe91Swinesync const char *test7 = "\r\n" 146e77afe91Swinesync "HKEY_CURRENT_USER\\" KEY_BASE "\r\n" 147e77afe91Swinesync " Wine REG_SZ First instance\r\n\r\n" 148e77afe91Swinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey\r\n" 149e77afe91Swinesync " Wine REG_SZ Second instance\r\n\r\n"; 150e77afe91Swinesync 1514771673cSwinesync const char *test8a = "\r\n" 1524771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey1\r\n" 1534771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey2\r\n" 1544771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey3\r\n" 1554771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey4\r\n"; 1564771673cSwinesync 1574771673cSwinesync const char *test8b = "\r\n" 1584771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey1\r\n\r\n" 1594771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey2\r\n\r\n" 1604771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey3\r\n\r\n" 1614771673cSwinesync "HKEY_CURRENT_USER\\" KEY_BASE "\\subkey4\r\n\r\n"; 1624771673cSwinesync 163a12c8448Swinesync DWORD r, dword = 0x123; 164d552b44fSwinesync HKEY hkey, subkey; 1655132d26cSwinesync BYTE buf[512]; 1667fcb8acaSwinesync 1677fcb8acaSwinesync delete_tree(HKEY_CURRENT_USER, KEY_BASE); 1687fcb8acaSwinesync verify_key_nonexist(HKEY_CURRENT_USER, KEY_BASE); 1697fcb8acaSwinesync 1707fcb8acaSwinesync run_reg_exe("reg query", &r); 1717fcb8acaSwinesync ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r); 1727fcb8acaSwinesync 1737fcb8acaSwinesync run_reg_exe("reg query /?", &r); 1747fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 1757fcb8acaSwinesync 1767fcb8acaSwinesync run_reg_exe("reg query /h", &r); 1777fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 1787fcb8acaSwinesync 1797fcb8acaSwinesync run_reg_exe("reg query -H", &r); 1807fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 1817fcb8acaSwinesync 1822535ff3fSwinesync /* Key not present */ 1832535ff3fSwinesync run_reg_exe("reg query HKCU\\" KEY_BASE, &r); 1842535ff3fSwinesync ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r); 1852535ff3fSwinesync 1867fcb8acaSwinesync /* Create a test key */ 187d552b44fSwinesync add_key(HKEY_CURRENT_USER, KEY_BASE, &hkey); 188d552b44fSwinesync add_value(hkey, "Test1", REG_SZ, "Hello, World", 13); 189d552b44fSwinesync add_value(hkey, "Test2", REG_DWORD, &dword, sizeof(dword)); 1907fcb8acaSwinesync 1917fcb8acaSwinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /v", &r); 1927fcb8acaSwinesync ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r); 1937fcb8acaSwinesync 1947fcb8acaSwinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /v Missing", &r); 1957fcb8acaSwinesync ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r); 1967fcb8acaSwinesync 197a12c8448Swinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /v Test1 /v Test2", &r); 198b12d7980Swinesync ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r); 199b12d7980Swinesync 200a12c8448Swinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /v Test1 /ve", &r); 201b12d7980Swinesync ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r); 202b12d7980Swinesync 203b12d7980Swinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /s /s", &r); 204b12d7980Swinesync ok(r == REG_EXIT_FAILURE, "got exit code %d, expected 1\n", r); 205b12d7980Swinesync 2065132d26cSwinesync read_reg_output("reg query HKCU\\" KEY_BASE, buf, sizeof(buf), &r); 207a12c8448Swinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 208e77afe91Swinesync compare_query(buf, test1, FALSE, 0); 209a12c8448Swinesync 210b12d7980Swinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /ve", &r); 211b12d7980Swinesync ok(r == REG_EXIT_SUCCESS || broken(r == REG_EXIT_FAILURE /* WinXP */), 212b12d7980Swinesync "got exit code %d, expected 0\n", r); 213b12d7980Swinesync 2145132d26cSwinesync read_reg_output("reg query HKCU\\" KEY_BASE " /v Test1", buf, sizeof(buf), &r); 215b12d7980Swinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 216e77afe91Swinesync compare_query(buf, test2, FALSE, 0); 217b12d7980Swinesync 218a12c8448Swinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /v Test2", &r); 2197fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 2207fcb8acaSwinesync 221d552b44fSwinesync add_value(hkey, "Wine", REG_SZ, "First instance", 15); 2227fcb8acaSwinesync 2237fcb8acaSwinesync /* Create a test subkey */ 224d552b44fSwinesync add_key(hkey, "subkey", &subkey); 2255132d26cSwinesync 2265132d26cSwinesync read_reg_output("reg query HKCU\\" KEY_BASE, buf, sizeof(buf), &r); 2275132d26cSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 228*a3bf868eSwinesync compare_query(buf, test3, FALSE, 0); 2295132d26cSwinesync 230a12c8448Swinesync add_value(subkey, "Test3", REG_SZ, "Some string data", 16); 231a12c8448Swinesync dword = 0xabc; 232a12c8448Swinesync add_value(subkey, "Test4", REG_DWORD, &dword, sizeof(dword)); 2337fcb8acaSwinesync 2345132d26cSwinesync read_reg_output("reg query HKCU\\" KEY_BASE "\\subkey", buf, sizeof(buf), &r); 2357fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 236e77afe91Swinesync compare_query(buf, test4, FALSE, 0); 2377fcb8acaSwinesync 238a12c8448Swinesync run_reg_exe("reg query HKCU\\" KEY_BASE "\\subkey /v Test3", &r); 2397fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 2407fcb8acaSwinesync 2415132d26cSwinesync read_reg_output("reg query HKCU\\" KEY_BASE "\\subkey /v Test4", buf, sizeof(buf), &r); 2427fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 243e77afe91Swinesync compare_query(buf, test5, FALSE, 0); 2447fcb8acaSwinesync 245a12c8448Swinesync add_value(subkey, "Wine", REG_SZ, "Second instance", 16); 2467fcb8acaSwinesync 2477fcb8acaSwinesync /* Test recursion */ 248e77afe91Swinesync read_reg_output("reg query HKCU\\" KEY_BASE " /s", buf, sizeof(buf), &r); 2497fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 250e77afe91Swinesync compare_query(buf, test6, FALSE, 0); 2517fcb8acaSwinesync 25216cc1ad7Swinesync read_reg_output("reg query HKCU\\" KEY_BASE "\\ /s", buf, sizeof(buf), &r); 25316cc1ad7Swinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 254a0060cdcSwinesync compare_query(buf, test6, FALSE, 0); 25516cc1ad7Swinesync 256e77afe91Swinesync read_reg_output("reg query HKCU\\" KEY_BASE " /v Wine /s", buf, sizeof(buf), &r); 2577fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS || r == REG_EXIT_FAILURE /* WinXP */, 2587fcb8acaSwinesync "got exit code %d, expected 0\n", r); 259e77afe91Swinesync compare_query(buf, test7, TRUE, 0); 2607fcb8acaSwinesync 261d552b44fSwinesync add_value(hkey, NULL, REG_SZ, "Empty", 6); 262a12c8448Swinesync add_value(subkey, NULL, REG_SZ, "Empty", 6); 263a12c8448Swinesync close_key(subkey); 264d552b44fSwinesync close_key(hkey); 265a12c8448Swinesync 266a12c8448Swinesync run_reg_exe("reg query HKCU\\" KEY_BASE "\\subkey /ve", &r); 267a12c8448Swinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 268a12c8448Swinesync 2697fcb8acaSwinesync run_reg_exe("reg query HKCU\\" KEY_BASE " /ve /s", &r); 2707fcb8acaSwinesync ok(r == REG_EXIT_SUCCESS || r == REG_EXIT_FAILURE /* WinXP */, 2717fcb8acaSwinesync "got exit code %d, expected 0\n", r); 2727fcb8acaSwinesync 2732535ff3fSwinesync delete_tree(HKEY_CURRENT_USER, KEY_BASE); 2744771673cSwinesync 2754771673cSwinesync /* Subkeys only */ 2764771673cSwinesync add_key(HKEY_CURRENT_USER, KEY_BASE, &hkey); 2774771673cSwinesync add_key(hkey, "subkey1", NULL); 2784771673cSwinesync add_key(hkey, "subkey2", NULL); 2794771673cSwinesync add_key(hkey, "subkey3", NULL); 2804771673cSwinesync add_key(hkey, "subkey4", NULL); 2814771673cSwinesync close_key(hkey); 2824771673cSwinesync 2834771673cSwinesync read_reg_output("reg query HKCU\\" KEY_BASE, buf, sizeof(buf), &r); 2844771673cSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 2854771673cSwinesync compare_query(buf, test8a, FALSE, TODO_REG_COMPARE); 2864771673cSwinesync 2874771673cSwinesync read_reg_output("reg query HKCU\\" KEY_BASE " /s", buf, sizeof(buf), &r); 2884771673cSwinesync ok(r == REG_EXIT_SUCCESS, "got exit code %d, expected 0\n", r); 2894771673cSwinesync compare_query(buf, test8b, FALSE, TODO_REG_COMPARE); 2904771673cSwinesync 2914771673cSwinesync delete_tree(HKEY_CURRENT_USER, KEY_BASE); 2927fcb8acaSwinesync } 2937fcb8acaSwinesync 2947fcb8acaSwinesync START_TEST(query) 2957fcb8acaSwinesync { 2967fcb8acaSwinesync DWORD r; 2977fcb8acaSwinesync 2987fcb8acaSwinesync if (!run_reg_exe("reg.exe /?", &r)) { 2997fcb8acaSwinesync win_skip("reg.exe not available, skipping 'query' tests\n"); 3007fcb8acaSwinesync return; 3017fcb8acaSwinesync } 3027fcb8acaSwinesync 3037fcb8acaSwinesync test_query(); 3047fcb8acaSwinesync } 305