Signed-off-by: Kirill Erofeev erofeev.info@gmail.com --- dlls/msvcrt/tests/dir.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+)
diff --git a/dlls/msvcrt/tests/dir.c b/dlls/msvcrt/tests/dir.c index aa273ea..0750b34 100644 --- a/dlls/msvcrt/tests/dir.c +++ b/dlls/msvcrt/tests/dir.c @@ -23,6 +23,7 @@ #include <stdlib.h> #include <stdio.h> #include <fcntl.h> +#include <direct.h> #include <sys/stat.h> #include <io.h> #include <mbctype.h> @@ -416,6 +417,112 @@ static void test_splitpath(void) _setmbcp(prev_cp); }
+static void test_search_environment(void) +{ + const char* dirs[] = { + "c:\search_env_test", + "c:\search_env_test\dir1", + "c:\search_env_test\dir2", + "c:\search_env_test\dir3longer", + NULL }; + + const char* files[] = { + "c:\search_env_test\dir1\1.dat", + "c:\search_env_test\dir1\2.dat", + "c:\search_env_test\dir2\1.dat", + "c:\search_env_test\dir2\3.dat", + "c:\search_env_test\dir3longer\3.dat", + NULL }; + + FILE* tmp_file = NULL; + const char** file_name = files; + const char** dir_name = dirs; + char result[MAX_PATH]; + + const char eraser[] = "TEST_PATH=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + while (*dir_name){ + ok(!mkdir(*dir_name), "Failed to setup test environment (dir = %s)\n", *dir_name); + dir_name++; + } + + while (*file_name){ + tmp_file = fopen(*file_name, "wb"); + ok(tmp_file != NULL, "Failed to setup test environment (file = %s)\n", *file_name); + if (tmp_file) + fclose(tmp_file); + file_name++; + } + + + /*To catch some errors (usage of uninitialized memory) we will trick searchenv to set up memory to predefined values*/ + putenv(eraser); + _searchenv("1.dat", "TEST_PATH", result); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv("1.dat", "TEST_PATH", result); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + _searchenv("1.dat", "TEST_PATH", result); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv("3.dat", "TEST_PATH", result); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + putenv(eraser); + _searchenv("1.dat", "TEST_PATH", result); + putenv("TEST_PATH=;c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv("1.dat", "TEST_PATH", result); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + _searchenv("1.dat", "TEST_PATH", result); + putenv("TEST_PATH=c:\search_env_test\dir1;;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv("3.dat", "TEST_PATH", result); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + + + + + putenv(eraser); + _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv_s("3.dat", "TEST_PATH", result, MAX_PATH); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + putenv(eraser); + _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); + putenv("TEST_PATH=;c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); + putenv("TEST_PATH=c:\search_env_test\dir1;;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _searchenv_s("3.dat", "TEST_PATH", result, MAX_PATH); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + + + + putenv("TEST_PATH="); + + do { + file_name--; + ok(!remove(*file_name), "Failed cleanup test (file = %s)\n", *file_name); + }while(files != file_name); + + do { + dir_name--; + ok(!rmdir(*dir_name), "Failed cleanup test (dir = %s)\n", *dir_name); + }while(dirs != dir_name); +} + START_TEST(dir) { init(); @@ -424,4 +531,6 @@ START_TEST(dir) test_makepath(); test_makepath_s(); test_splitpath(); + + test_search_environment(); }
Signed-off-by: Kirill Erofeev erofeev.info@gmail.com --- dlls/msvcrt/tests/dir.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+)
diff --git a/dlls/msvcrt/tests/dir.c b/dlls/msvcrt/tests/dir.c index 0750b34..d3e7d4c 100644 --- a/dlls/msvcrt/tests/dir.c +++ b/dlls/msvcrt/tests/dir.c @@ -438,6 +438,9 @@ static void test_search_environment(void) const char** file_name = files; const char** dir_name = dirs; char result[MAX_PATH]; + WCHAR result_w[MAX_PATH]; + WCHAR filename_w[MAX_PATH]; + const WCHAR env_w[] = {'T', 'E', 'S', 'T', '_', 'P', 'A', 'T', 'H', '\0'};
const char eraser[] = "TEST_PATH=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; while (*dir_name){ @@ -484,6 +487,42 @@ static void test_search_environment(void)
putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "1.dat", -1, filename_w, MAX_PATH); + _wsearchenv(filename_w, env_w, result_w); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv(filename_w, env_w, result_w); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "3.dat", -1, filename_w, MAX_PATH); + _wsearchenv(filename_w, env_w, result_w); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv(filename_w, env_w, result_w); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "1.dat", -1, filename_w, MAX_PATH); + _wsearchenv(filename_w, env_w, result_w); + putenv("TEST_PATH=;c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv(filename_w, env_w, result_w); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "3.dat", -1, filename_w, MAX_PATH); + _wsearchenv(filename_w, env_w, result_w); + putenv("TEST_PATH=c:\search_env_test\dir1;;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv(filename_w, env_w, result_w); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + + + + + putenv(eraser); _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); _searchenv_s("1.dat", "TEST_PATH", result, MAX_PATH); @@ -510,6 +549,42 @@ static void test_search_environment(void)
+ putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "1.dat", -1, filename_w, MAX_PATH); + _wsearchenv_s(filename_w, env_w, result_w, MAX_PATH); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv_s(filename_w, env_w, result_w); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "3.dat", -1, filename_w, MAX_PATH); + _wsearchenv_s(filename_w, env_w, result_w, MAX_PATH); + putenv("TEST_PATH=c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv_s(filename_w, env_w, result_w, MAX_PATH); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "1.dat", -1, filename_w, MAX_PATH); + _wsearchenv_s(filename_w, env_w, result_w, MAX_PATH); + putenv("TEST_PATH=;c:\search_env_test\dir1;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv_s(filename_w, env_w, result_w, MAX_PATH); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir1\1.dat"), "Failed to found %s in %s got in %s\n", "1.dat", "c:\search_env_test\dir1", result); + + putenv(eraser); + MultiByteToWideChar( CP_ACP, 0, "3.dat", -1, filename_w, MAX_PATH); + _wsearchenv_s(filename_w, env_w, result_w, MAX_PATH); + putenv("TEST_PATH=c:\search_env_test\dir1;;c:\search_env_test\dir2;c:\search_env_test\dir3longer"); + _wsearchenv_s(filename_w, env_w, result_w, MAX_PATH); + WideCharToMultiByte(CP_ACP, 0, result_w, -1, result, MAX_PATH, NULL, NULL); + ok(!strcmp(result, "c:\search_env_test\dir2\3.dat"), "Failed to found %s in %s got in %s\n", "3.dat", "c:\search_env_test\dir2", result); + + + + + putenv("TEST_PATH=");
do {
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check? Full results can be found at https://testbot.winehq.org/JobDetails.pl?Key=35937
Your paranoid android.
=== w864 (64 bit dir) === dir.c:558: Test failed: Failed to found 1.dat in c:\search_env_test\dir1 got in
- in some cases the last '' was not appended to curPath. (reason char next to the last one was checked for delimiter) - not all PATH list elements processed in case leading ';' or double ';' are present in environment variable. I.e empty element stops further processing.
Signed-off-by: Kirill Erofeev erofeev.info@gmail.com --- dlls/msvcrt/dir.c | 89 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 40 deletions(-)
diff --git a/dlls/msvcrt/dir.c b/dlls/msvcrt/dir.c index f4edc28..b864a75 100644 --- a/dlls/msvcrt/dir.c +++ b/dlls/msvcrt/dir.c @@ -1658,6 +1658,8 @@ void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf) { char*envVal, *penv; char curPath[MAX_PATH]; + MSVCRT_size_t path_len; + const MSVCRT_size_t fname_len = strlen(file);
*buf = '\0';
@@ -1686,30 +1688,33 @@ void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf) char *end = penv;
while(*end && *end != ';') end++; /* Find end of next path */ - if (penv == end || !*penv) - { - msvcrt_set_errno(ERROR_FILE_NOT_FOUND); - return; - } - memcpy(curPath, penv, end - penv); - if (curPath[end - penv] != '/' && curPath[end - penv] != '\') - { - curPath[end - penv] = '\'; - curPath[end - penv + 1] = '\0'; - } - else - curPath[end - penv] = '\0'; + path_len = end - penv;
- strcat(curPath, file); - TRACE("Checking for file %s\n", curPath); - if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES) + if (penv != end && *penv && + (path_len + fname_len) < MAX_PATH)/*If temporary buffer is not enough just skip. Other way is to use dynamic memory. We will not.*/ { - strcpy(buf, curPath); - msvcrt_set_errno(ERROR_FILE_NOT_FOUND); - return; /* Found */ + memcpy(curPath, penv, path_len); + if (curPath[path_len - 1] != '/' && curPath[path_len - 1] != '\') + { + curPath[path_len] = '\'; + curPath[path_len + 1] = '\0'; + } + else + curPath[path_len] = '\0'; + + strcat(curPath, file); + TRACE("Checking for file %s\n", curPath); + if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES) + { + strcpy(buf, curPath); + break; /* Found */ + } } penv = *end ? end + 1 : end; - } while(1); + } while(*penv); + + msvcrt_set_errno(ERROR_FILE_NOT_FOUND); + return; }
/********************************************************************* @@ -1719,6 +1724,8 @@ int CDECL MSVCRT__searchenv_s(const char* file, const char* env, char *buf, MSVC { char*envVal, *penv; char curPath[MAX_PATH]; + MSVCRT_size_t path_len; + const MSVCRT_size_t fname_len = strlen(file);
if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL; @@ -1750,34 +1757,36 @@ int CDECL MSVCRT__searchenv_s(const char* file, const char* env, char *buf, MSVC char *end = penv;
while(*end && *end != ';') end++; /* Find end of next path */ - if (penv == end || !*penv) - { - *MSVCRT__errno() = MSVCRT_ENOENT; - return MSVCRT_ENOENT; - } - memcpy(curPath, penv, end - penv); - if (curPath[end - penv] != '/' && curPath[end - penv] != '\') + path_len = end - penv; + if (penv != end && *penv && + (path_len + fname_len) < MAX_PATH)/*If temporary buffer is not enough just skip. Other way is to use dynamic memory. We will not.*/ { - curPath[end - penv] = '\'; - curPath[end - penv + 1] = '\0'; - } - else - curPath[end - penv] = '\0'; + memcpy(curPath, penv, path_len); + if (curPath[path_len - 1] != '/' && curPath[path_len - 1] != '\') + { + curPath[path_len] = '\'; + curPath[path_len + 1] = '\0'; + } + else + curPath[path_len] = '\0';
- strcat(curPath, file); - TRACE("Checking for file %s\n", curPath); - if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES) - { - if (strlen(curPath) + 1 > count) + strcat(curPath, file); + TRACE("Checking for file %s\n", curPath); + if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES) { + if (strlen(curPath) + 1 > count) + { MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE); return MSVCRT_ERANGE; + } + strcpy(buf, curPath); + return 0; } - strcpy(buf, curPath); - return 0; } penv = *end ? end + 1 : end; - } while(1); + } while(*penv); + *MSVCRT__errno() = MSVCRT_ENOENT; + return MSVCRT_ENOENT; }
/*********************************************************************
- in some cases the last '' was not appended to curPath. (reason char next to the last one was checked for delimiter) - not all PATH list elements processed in case leading ';' or double ';' are present in environment variable. I.e empty element stops further processing.
Signed-off-by: Kirill Erofeev erofeev.info@gmail.com --- dlls/msvcrt/dir.c | 88 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 40 deletions(-)
diff --git a/dlls/msvcrt/dir.c b/dlls/msvcrt/dir.c index b864a75..5f094e1 100644 --- a/dlls/msvcrt/dir.c +++ b/dlls/msvcrt/dir.c @@ -1798,6 +1798,8 @@ void CDECL MSVCRT__wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* { MSVCRT_wchar_t *envVal, *penv; MSVCRT_wchar_t curPath[MAX_PATH]; + MSVCRT_size_t path_len; + const MSVCRT_size_t fname_len = strlenW(file);
*buf = '\0';
@@ -1826,30 +1828,31 @@ void CDECL MSVCRT__wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* MSVCRT_wchar_t *end = penv;
while(*end && *end != ';') end++; /* Find end of next path */ - if (penv == end || !*penv) - { - msvcrt_set_errno(ERROR_FILE_NOT_FOUND); - return; - } - memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t)); - if (curPath[end - penv] != '/' && curPath[end - penv] != '\') + path_len = end - penv; + if (penv != end && *penv && + (path_len + fname_len) < MAX_PATH)/*If temporary buffer is not enough just skip. Other way is to use dynamic memory. We will not.*/ { - curPath[end - penv] = '\'; - curPath[end - penv + 1] = '\0'; - } - else - curPath[end - penv] = '\0'; + memcpy(curPath, penv, path_len * sizeof(MSVCRT_wchar_t)); + if (curPath[path_len - 1] != '/' && curPath[path_len - 1] != '\') + { + curPath[path_len] = '\'; + curPath[path_len + 1] = '\0'; + } + else + curPath[end - penv] = '\0';
- strcatW(curPath, file); - TRACE("Checking for file %s\n", debugstr_w(curPath)); - if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES) - { - strcpyW(buf, curPath); - msvcrt_set_errno(ERROR_FILE_NOT_FOUND); - return; /* Found */ + strcatW(curPath, file); + TRACE("Checking for file %s\n", debugstr_w(curPath)); + if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES) + { + strcpyW(buf, curPath); + break; /* Found */ + } } penv = *end ? end + 1 : end; - } while(1); + } while(*penv); + msvcrt_set_errno(ERROR_FILE_NOT_FOUND); + return; }
/********************************************************************* @@ -1860,6 +1863,8 @@ int CDECL MSVCRT__wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* { MSVCRT_wchar_t* envVal, *penv; MSVCRT_wchar_t curPath[MAX_PATH]; + MSVCRT_size_t path_len; + const MSVCRT_size_t fname_len = strlenW(file);
if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL; if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL; @@ -1891,32 +1896,35 @@ int CDECL MSVCRT__wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* MSVCRT_wchar_t *end = penv;
while(*end && *end != ';') end++; /* Find end of next path */ - if (penv == end || !*penv) - { - *MSVCRT__errno() = MSVCRT_ENOENT; - return MSVCRT_ENOENT; - } - memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t)); - if (curPath[end - penv] != '/' && curPath[end - penv] != '\') + path_len = end - penv; + if (penv != end && *penv && + (path_len + fname_len) < MAX_PATH)/*If temporary buffer is not enough just skip. Other way is to use dynamic memory. We will not.*/ { - curPath[end - penv] = '\'; - curPath[end - penv + 1] = '\0'; - } - else - curPath[end - penv] = '\0'; + memcpy(curPath, penv, path_len * sizeof(MSVCRT_wchar_t)); + if (curPath[path_len - 1] != '/' && curPath[path_len - 1] != '\') + { + curPath[path_len] = '\'; + curPath[path_len + 1] = '\0'; + } + else + curPath[path_len] = '\0';
- strcatW(curPath, file); - TRACE("Checking for file %s\n", debugstr_w(curPath)); - if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES) - { - if (strlenW(curPath) + 1 > count) + strcatW(curPath, file); + TRACE("Checking for file %s\n", debugstr_w(curPath)); + if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES) { + if (strlenW(curPath) + 1 > count) + { MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE); return MSVCRT_ERANGE; + } + strcpyW(buf, curPath); + return 0; } - strcpyW(buf, curPath); - return 0; } penv = *end ? end + 1 : end; - } while(1); + } while(*penv); + *MSVCRT__errno() = MSVCRT_ENOENT; + return MSVCRT_ENOENT; } +
Hi,
Please ignore this variant of patch set. I will rework it . I can see that tests for secure variants should not be triggered on WinXP and W2003 (i.e. if not present)
On Wed, Feb 14, 2018 at 7:28 PM, Kirill Erofeev erofeev.info@gmail.com wrote:
Signed-off-by: Kirill Erofeev erofeev.info@gmail.com
dlls/msvcrt/tests/dir.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++