In order to improve cmd.exe's test, we need to generate arbitrary binary files.
There's already a hack in tests to generate from test executable some binary that will be lated used by the tests in .cmd file.
That's not neati: this spreads tests across three different spots (batch input, batch output, binary file generator).
We introduced the @\x??@ sequence in .cmd tests. Even if this supports most of the wanted BYTE:s, it doesn't work with EOF, \r and ctrl-Z (as they are always interpreted in ECHO command) (we can work around \n even it's ugly).
After various testings, it looks like adding hex decoding to certutil is the decent solution: - it's supported on all Windows versions from the testbot VM, - it's rather straightforward to use (if you keep tests simple and short, which a good idea anyway).
Even if our certutil implementation is empty, we have preliminary material from bcryp32 that shall provide the correct implementation.
So this MR: - adds the -decodehex command to programs/certutil, - make use of it in order to generate existing binary test file inside the .cmd file.
Pending MR!8920 will also make use of it.
From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/certutil/Makefile.in | 1 + programs/certutil/main.c | 86 +++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 5 deletions(-)
diff --git a/programs/certutil/Makefile.in b/programs/certutil/Makefile.in index 4956fd166db..2c9909cd34d 100644 --- a/programs/certutil/Makefile.in +++ b/programs/certutil/Makefile.in @@ -1,6 +1,7 @@ MODULE = certutil.exe
EXTRADLLFLAGS = -mconsole -municode +IMPORTS = crypt32
SOURCES = \ main.c diff --git a/programs/certutil/main.c b/programs/certutil/main.c index 2b94819fb00..6b0873d7a64 100644 --- a/programs/certutil/main.c +++ b/programs/certutil/main.c @@ -16,18 +16,94 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "windows.h" +#include "wincrypt.h" + #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(certutil);
+static HRESULT decode_hex(const WCHAR *from, const WCHAR *into) +{ + HRESULT hres = S_OK; + HANDLE in = NULL, out = NULL; + char in_buffer[1024]; + BYTE out_buffer[ARRAY_SIZE(in_buffer) / 2]; + ULONG64 total_written = 0; + LARGE_INTEGER li; + + if ((in = CreateFileW(from, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE || + !GetFileSizeEx(in, &li) || + (out = CreateFileW(into, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) + hres = HRESULT_FROM_WIN32(GetLastError()); + + if (hres == S_OK) + printf("Input Length = %I64u\n", li.QuadPart); + + while (hres == S_OK) + { + DWORD in_dw, out_dw; + + if (ReadFile(in, in_buffer, ARRAY_SIZE(in_buffer), &in_dw, NULL)) + { + char *ptr = memchr(in_buffer, '\n', in_dw); + char *ptr2 = memchr(in_buffer, '\r', in_dw); + DWORD dw; + + if (!in_dw) break; /* EOF */ + if (ptr2 && (!ptr || ptr2 < ptr)) ptr = ptr2; + if (ptr) + { + /* rewind just after the eol character */ + li.QuadPart = ptr + 1 - (in_buffer + in_dw); + if (!SetFilePointerEx(in, li, NULL, FILE_CURRENT)) + { + hres = HRESULT_FROM_WIN32(GetLastError()); + break; + } + in_dw = ptr - in_buffer; + } + out_dw = ARRAY_SIZE(out_buffer); + if (CryptStringToBinaryA(in_buffer, in_dw, CRYPT_STRING_HEX, + out_buffer, &out_dw, NULL, NULL) && + WriteFile(out, out_buffer, out_dw, &dw, NULL)) + { + if (dw == out_dw) + total_written += out_dw; + else + hres = HRESULT_FROM_WIN32(ERROR_CANTWRITE); + continue; + } + } + hres = HRESULT_FROM_WIN32(GetLastError()); + } + CloseHandle(in); + CloseHandle(out); + + if (hres == S_OK) + printf("Output Length = %I64u\n", total_written); + return hres; +} + int __cdecl wmain(int argc, WCHAR *argv[]) { + HRESULT hres = -1; int i;
- WINE_FIXME("stub:"); - for (i = 0; i < argc; i++) - WINE_FIXME(" %s", wine_dbgstr_w(argv[i])); - WINE_FIXME("\n"); + if (argc == 4 && !wcscmp(argv[1], L"-decodehex")) + hres = decode_hex(argv[2], argv[3]); + else /* not a recognized command */ + { + WINE_FIXME("stub:"); + for (i = 0; i < argc; i++) + WINE_FIXME(" %s", wine_dbgstr_w(argv[i])); + WINE_FIXME("\n");
- return 0; + return 0; + } + if (hres == S_OK) + printf("CertUtil: %ls command completed successfully.\n", argv[1]); + else + printf("CertUtil: %ls command FAILED: %08lx\n", argv[1], hres); + return hres; }
From: Eric Pouech epouech@codeweavers.com
And get rid of some hacks.
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/tests/batch.c | 22 ---------------------- programs/cmd/tests/test_builtins.cmd | 9 ++++++--- 2 files changed, 6 insertions(+), 25 deletions(-)
diff --git a/programs/cmd/tests/batch.c b/programs/cmd/tests/batch.c index 03a05f34215..5c5b0ab7287 100644 --- a/programs/cmd/tests/batch.c +++ b/programs/cmd/tests/batch.c @@ -513,24 +513,6 @@ static int cmd_available(void) return FALSE; }
-void create_nul_test_file(void) -{ - HANDLE file; - DWORD size; - BOOL bres; - char contents[] = "a b c\nd e\0f\ng h i"; - - file = CreateFileA("nul_test_file", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - ok(file != INVALID_HANDLE_VALUE, "CreateFile failed\n"); - if(file == INVALID_HANDLE_VALUE) - return; - - bres = WriteFile(file, contents, ARRAYSIZE(contents), &size, NULL); - ok(bres, "Could not write to file: %lu\n", GetLastError()); - CloseHandle(file); -} - START_TEST(batch) { int argc; @@ -555,13 +537,9 @@ START_TEST(batch) } shortpath_len = GetShortPathNameA(path, shortpath, ARRAY_SIZE(shortpath));
- create_nul_test_file(); - argc = winetest_get_mainargs(&argv); if(argc > 2) run_from_file(argv[2]); else EnumResourceNamesA(NULL, "TESTCMD", test_enum_proc, 0); - - DeleteFileA("nul_test_file"); } diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 9f144bb4e0a..b66beadca98 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -2641,9 +2641,12 @@ FOR /F "delims=. tokens=1*" %%A IN (testfile) DO @echo 5:%%A,%%B FOR /F "delims=. tokens=2*" %%A IN (testfile) DO @echo 6:%%A,%%B FOR /F "delims=. tokens=3*" %%A IN (testfile) DO @echo 7:%%A,%%B del testfile -rem file contains NUL, created by the .exe -for /f %%A in (nul_test_file) DO echo %%A -for /f "tokens=*" %%A in (nul_test_file) DO echo %%A +rem generate "a b c\nd e\0f\ng h i" +echo 61206220630a64206500660a6720682069> a.seq +call certutil.exe -decodehex a.seq testfile > NUL +for /f %%A in (testfile) DO echo %%A +for /f "tokens=*" %%A in (testfile) DO echo %%A +del a.seq testfile
echo ------------ Testing del ------------ echo abc > file