From: Paul Gofman <pgofman@codeweavers.com> --- dlls/msvcrt/file.c | 83 +++++++++---------------- dlls/msvcrt/tests/file.c | 128 +++++++++++++++++++++++++++++---------- 2 files changed, 123 insertions(+), 88 deletions(-) diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index 71972540c13..989755f3ec5 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -723,59 +723,39 @@ void msvcrt_init_io(void) STARTUPINFOA si; int i; ioinfo *fdinfo; + unsigned int count = 0; + HANDLE *handle_ptr = NULL; + BYTE *wxflag_ptr = NULL; GetStartupInfoA(&si); if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL) { - BYTE* wxflag_ptr; - HANDLE* handle_ptr; - unsigned int count; - count = *(unsigned*)si.lpReserved2; wxflag_ptr = si.lpReserved2 + sizeof(unsigned); handle_ptr = (HANDLE*)(wxflag_ptr + count); - count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1)); count = min(count, MSVCRT_MAX_FILES); - for (i = 0; i < count; i++) - { - if ((*wxflag_ptr & WX_OPEN) && GetFileType(*handle_ptr) != FILE_TYPE_UNKNOWN) - { - fdinfo = get_ioinfo_alloc_fd(i); - if(fdinfo != &MSVCRT___badioinfo) - msvcrt_set_fd(fdinfo, *handle_ptr, *wxflag_ptr); - release_ioinfo(fdinfo); - } - - wxflag_ptr++; handle_ptr++; - } } - fdinfo = get_ioinfo_alloc_fd(STDIN_FILENO); - if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) { - HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + for (i = 0; i < 3; ++i) + { + static const DWORD std_handle[3] = { STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE }; + HANDLE h = NULL; DWORD flags = WX_OPEN | WX_TEXT; - DWORD type = GetFileType(h); + DWORD type = FILE_TYPE_UNKNOWN; - if (type == FILE_TYPE_UNKNOWN) { - h = MSVCRT_NO_CONSOLE; - flags |= WX_TTY; - } else if ((type & 0xf) == FILE_TYPE_CHAR) { - flags |= WX_TTY; - } else if ((type & 0xf) == FILE_TYPE_PIPE) { - flags |= WX_PIPE; + if (count > i) + { + h = handle_ptr[i]; + type = GetFileType(h); + } + if (type == FILE_TYPE_UNKNOWN) + { + h = GetStdHandle(std_handle[i]); + type = GetFileType(h); } - msvcrt_set_fd(fdinfo, h, flags); - } - release_ioinfo(fdinfo); - - fdinfo = get_ioinfo_alloc_fd(STDOUT_FILENO); - if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) { - HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD flags = WX_OPEN | WX_TEXT; - DWORD type = GetFileType(h); - + fdinfo = get_ioinfo_alloc_fd(i); if (type == FILE_TYPE_UNKNOWN) { h = MSVCRT_NO_CONSOLE; flags |= WX_TTY; @@ -784,29 +764,20 @@ void msvcrt_init_io(void) } else if ((type & 0xf) == FILE_TYPE_PIPE) { flags |= WX_PIPE; } - msvcrt_set_fd(fdinfo, h, flags); + release_ioinfo(fdinfo); } - release_ioinfo(fdinfo); - fdinfo = get_ioinfo_alloc_fd(STDERR_FILENO); - if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) { - HANDLE h = GetStdHandle(STD_ERROR_HANDLE); - DWORD flags = WX_OPEN | WX_TEXT; - DWORD type = GetFileType(h); - - if (type == FILE_TYPE_UNKNOWN) { - h = MSVCRT_NO_CONSOLE; - flags |= WX_TTY; - } else if ((type & 0xf) == FILE_TYPE_CHAR) { - flags |= WX_TTY; - } else if ((type & 0xf) == FILE_TYPE_PIPE) { - flags |= WX_PIPE; + for (i = 3; i < count; i++) + { + if ((wxflag_ptr[i] & WX_OPEN) && GetFileType(handle_ptr[i]) != FILE_TYPE_UNKNOWN) + { + fdinfo = get_ioinfo_alloc_fd(i); + if (fdinfo != &MSVCRT___badioinfo) + msvcrt_set_fd(fdinfo, handle_ptr[i], wxflag_ptr[i]); + release_ioinfo(fdinfo); } - - msvcrt_set_fd(fdinfo, h, flags); } - release_ioinfo(fdinfo); TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo_nolock(STDIN_FILENO)->handle, get_ioinfo_nolock(STDOUT_FILENO)->handle, diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index 4942780d425..0ffe82cf667 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -1633,31 +1633,43 @@ static void test_file_write_read( void ) free(tempf); } -static void test_file_inherit_child(const char* fd_s, const char *handle_str) +static void test_file_inherit_child(const char* fd_s, const char *mode_str, const char *handle_str) { - HANDLE handle_value; + HANDLE handle_value, handle; int fd = atoi(fd_s); HANDLE *handle_ptr; unsigned int count; char buffer[32]; STARTUPINFOA si; - int ret; + int expected_mode = atoi(mode_str); + int ret, mode, pos; GetStartupInfoA(&si); count = *(unsigned *)si.lpReserved2; if (handle_str) { - ok(count == 3, "Got unexpected count %u.\n", count); + ok(count >= 3, "Got unexpected count %u.\n", count); sscanf(handle_str, "%p", &handle_value); handle_ptr = (HANDLE *)(si.lpReserved2 + sizeof(unsigned) + count); - ok(handle_value == handle_ptr[1], "Got unexpected handle %p.\n", handle_ptr[1]); + ok(handle_value == handle_ptr[fd], "Got unexpected handle %p.\n", handle_ptr[1]); + if (handle_value && handle_value != (HANDLE)0xdeadbeef && handle_value != INVALID_HANDLE_VALUE) + { + handle = (HANDLE)_get_osfhandle(fd); + ok(handle == handle_value, "got %p, %p.\n", handle, handle_value); + } } + mode = _setmode(fd, _O_BINARY); + ok(mode == expected_mode, "got %04x, fd %d, expected %04x.\n", mode, fd, expected_mode); + pos = lseek(fd, 0, SEEK_CUR); ret = write(fd, "Success", 8); ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno)); - lseek(fd, 0, SEEK_SET); - ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n"); - ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n"); + lseek(fd, pos, SEEK_SET); + ret = read(fd, buffer, sizeof (buffer)); + if (ret == -1 && errno == EBADF) + return; + ok(ret == 8, "Couldn't read back the data, got %d, errno %d\n", ret, errno); + ok(memcmp(buffer, "Success", 8) == 0, "Read back data mismatch\n"); } static void test_file_inherit_child_no(const char* fd_s) @@ -1685,7 +1697,7 @@ static void create_io_inherit_block( STARTUPINFOA *startup, unsigned int count, *(unsigned*)block = count; for (i = 0; i < count; i++) { - wxflag_ptr[i] = 0x81; + wxflag_ptr[i] = 0x1; handle_ptr[i] = handles[i]; } } @@ -1701,7 +1713,7 @@ static const char *read_file( HANDLE file ) } static void test_stdout_handle( STARTUPINFOA *startup, char *cmdline, HANDLE hstdout, BOOL expect_stdout, - const char *descr ) + const char *descr, BOOL set_invalid_stdout ) { const char *data; HANDLE hErrorFile; @@ -1717,7 +1729,7 @@ static void test_stdout_handle( STARTUPINFOA *startup, char *cmdline, HANDLE hst FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); startup->dwFlags = STARTF_USESTDHANDLES; startup->hStdInput = GetStdHandle( STD_INPUT_HANDLE ); - startup->hStdOutput = hErrorFile; + startup->hStdOutput = set_invalid_stdout ? INVALID_HANDLE_VALUE : hErrorFile; startup->hStdError = GetStdHandle( STD_ERROR_HANDLE ); CreateProcessA( NULL, cmdline, NULL, NULL, TRUE, @@ -1734,7 +1746,7 @@ static void test_stdout_handle( STARTUPINFOA *startup, char *cmdline, HANDLE hst { data = read_file( hstdout ); if (expect_stdout) - ok( !strcmp( data, "Success" ), "%s: Wrong stdout data (%s)\n", descr, data ); + ok( !strcmp( data, "Success" ), "%s: Wrong stdout data (%s)\n", descr, debugstr_a(data) ); else ok( strcmp( data, "Success" ), "%s: Stdout file shouldn't contain data\n", descr ); } @@ -1758,15 +1770,16 @@ static unsigned WINAPI read_pipe_thread(void *argument) static void test_file_inherit( const char* selfname ) { int fd; - const char* arg_v[5]; - char buffer[16]; + const char* arg_v[6]; + char buffer[16], buffer2[16]; char cmdline[MAX_PATH]; STARTUPINFOA startup; SECURITY_ATTRIBUTES sa; - HANDLE handles[3]; + HANDLE handles[4]; HANDLE thread_handle; int pipefds[2]; intptr_t ret; + int mode; fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE); ok(fd != -1, "Couldn't create test file\n"); @@ -1774,7 +1787,8 @@ static void test_file_inherit( const char* selfname ) arg_v[1] = "file"; arg_v[2] = "inherit"; arg_v[3] = buffer; sprintf(buffer, "%d", fd); - arg_v[4] = 0; + arg_v[4] = buffer2; sprintf(buffer2, "%d", O_BINARY); + arg_v[5] = 0; ret = _spawnvp(_P_WAIT, selfname, arg_v); ok(ret == 0, "_spawnvp returned %Id, errno %d\n", ret, errno); ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd)); @@ -1782,13 +1796,28 @@ static void test_file_inherit( const char* selfname ) ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n"); close (fd); ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n"); + + mode = _setmode(1, O_BINARY); + ok(mode != -1, "got %#x.\n", mode); + arg_v[0] = get_base_name(selfname); + arg_v[1] = "file"; + arg_v[2] = "inherit"; + arg_v[3] = buffer; sprintf(buffer, "%d", 1); + /* For std handle a mode on it is not going to be inherited and set to default text mode instead. */ + arg_v[4] = buffer2; sprintf(buffer2, "%d", O_TEXT); + arg_v[5] = 0; + ret = _spawnvp(_P_WAIT, selfname, arg_v); + mode = _setmode(1, mode); + ok(ret == 0, "_spawnvp returned %Id, errno %d\n", ret, errno); + ok(mode == O_BINARY, "got %#x.\n", mode); fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE); ok(fd != -1, "Couldn't create test file\n"); arg_v[1] = "file"; arg_v[2] = "inherit_no"; arg_v[3] = buffer; sprintf(buffer, "%d", fd); - arg_v[4] = 0; + arg_v[4] = buffer2; sprintf(buffer2, "%d", O_BINARY); + arg_v[5] = 0; ret = _spawnvp(_P_WAIT, selfname, arg_v); ok(ret == 0, "_spawnvp returned %Id, errno %d\n", ret, errno); ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd)); @@ -1805,7 +1834,8 @@ static void test_file_inherit( const char* selfname ) arg_v[1] = "tests/file.c"; arg_v[2] = "inherit"; arg_v[3] = buffer; sprintf(buffer, "%d", fd); - arg_v[4] = 0; + arg_v[4] = buffer2; sprintf(buffer2, "%d", O_BINARY); + arg_v[5] = 0; ret = _spawnvp(_P_WAIT, selfname, arg_v); ok(ret == 0, "_spawnvp returned %Id, errno %d\n", ret, errno); ret = tell(fd); @@ -1824,13 +1854,13 @@ static void test_file_inherit( const char* selfname ) sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; - sprintf(cmdline, "%s file inherit 1", selfname); + sprintf(cmdline, "%s file inherit 1 %d", selfname, O_TEXT); /* init an empty Reserved2, which should not be recognized as inherit-block */ ZeroMemory(&startup, sizeof(startup)); startup.cb = sizeof(startup); create_io_inherit_block( &startup, 0, NULL ); - test_stdout_handle( &startup, cmdline, 0, FALSE, "empty block" ); + test_stdout_handle( &startup, cmdline, 0, FALSE, "empty block", FALSE ); /* test with valid inheritblock */ handles[0] = GetStdHandle( STD_INPUT_HANDLE ); @@ -1838,7 +1868,7 @@ static void test_file_inherit( const char* selfname ) FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); handles[2] = GetStdHandle( STD_ERROR_HANDLE ); create_io_inherit_block( &startup, 3, handles ); - test_stdout_handle( &startup, cmdline, handles[1], TRUE, "valid block" ); + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "valid block", FALSE ); CloseHandle( handles[1] ); DeleteFileA("fdopen.tst"); @@ -1847,7 +1877,7 @@ static void test_file_inherit( const char* selfname ) FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); create_io_inherit_block( &startup, 3, handles ); *(unsigned int *)startup.lpReserved2 = 0; - test_stdout_handle( &startup, cmdline, handles[1], FALSE, "zero count block" ); + test_stdout_handle( &startup, cmdline, handles[1], FALSE, "zero count block", FALSE ); CloseHandle( handles[1] ); DeleteFileA("fdopen.tst"); @@ -1856,7 +1886,7 @@ static void test_file_inherit( const char* selfname ) FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); create_io_inherit_block( &startup, 3, handles ); startup.cbReserved2 -= 3; - test_stdout_handle( &startup, cmdline, handles[1], TRUE, "small size block" ); + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "small size block", FALSE ); CloseHandle( handles[1] ); DeleteFileA("fdopen.tst"); @@ -1865,7 +1895,7 @@ static void test_file_inherit( const char* selfname ) FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); create_io_inherit_block( &startup, 3, handles ); startup.cbReserved2 = sizeof(unsigned int) + sizeof(HANDLE) + sizeof(char); - test_stdout_handle( &startup, cmdline, handles[1], FALSE, "smaller size block" ); + test_stdout_handle( &startup, cmdline, handles[1], FALSE, "smaller size block", FALSE ); CloseHandle( handles[1] ); DeleteFileA("fdopen.tst"); @@ -1874,25 +1904,59 @@ static void test_file_inherit( const char* selfname ) FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); create_io_inherit_block( &startup, 3, handles ); startup.cbReserved2 += 7; - test_stdout_handle( &startup, cmdline, handles[1], TRUE, "large size block" ); + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "large size block", FALSE ); CloseHandle( handles[1] ); DeleteFileA("fdopen.tst"); /* test inherit block with invalid handle */ handles[1] = INVALID_HANDLE_VALUE; create_io_inherit_block( &startup, 3, handles ); - sprintf(cmdline, "%s file inherit 1 %p", selfname, handles[1]); - test_stdout_handle( &startup, cmdline, NULL, FALSE, "INVALID_HANDLE_VALUE stdout handle" ); + sprintf(cmdline, "%s file inherit 1 %d %p", selfname, O_TEXT, handles[1]); + test_stdout_handle( &startup, cmdline, NULL, FALSE, "INVALID_HANDLE_VALUE stdout handle", FALSE ); handles[1] = NULL; create_io_inherit_block( &startup, 3, handles ); - sprintf(cmdline, "%s file inherit 1 %p", selfname, handles[1]); - test_stdout_handle( &startup, cmdline, NULL, FALSE, "NULL stdout handle" ); + sprintf(cmdline, "%s file inherit 1 %d %p", selfname, O_TEXT, handles[1]); + test_stdout_handle( &startup, cmdline, NULL, FALSE, "NULL stdout handle", FALSE ); handles[1] = (void *)0xdeadbeef; create_io_inherit_block( &startup, 3, handles ); - sprintf(cmdline, "%s file inherit 1 %p", selfname, handles[1]); - test_stdout_handle( &startup, cmdline, NULL, FALSE, "invalid stdout handle" ); + sprintf(cmdline, "%s file inherit 1 %d %p", selfname, O_TEXT, handles[1]); + test_stdout_handle( &startup, cmdline, NULL, FALSE, "invalid stdout handle", FALSE ); + + /* std handle doesn't respect open mode from inherited block, while non-std handle does. */ + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + create_io_inherit_block( &startup, 3, handles ); + sprintf(cmdline, "%s file inherit 1 %d %p", selfname, O_TEXT, handles[1]); + winetest_push_context("valid stdout handle"); + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "valid stdout handle", FALSE ); + winetest_pop_context(); + CloseHandle( handles[1] ); + DeleteFileA("fdopen.tst"); + + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + create_io_inherit_block( &startup, 3, handles ); + sprintf(cmdline, "%s file inherit 1 %d %p", selfname, O_TEXT, handles[1]); + winetest_push_context("valid stdout handle"); + test_stdout_handle( &startup, cmdline, handles[1], TRUE, "valid CRT, invalid kernelbase", TRUE ); + winetest_pop_context(); + CloseHandle( handles[1] ); + DeleteFileA("fdopen.tst"); + + handles[3] = CreateFileA( "fdopen2.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL ); + create_io_inherit_block( &startup, 4, handles ); + sprintf(cmdline, "%s file inherit 3 %d %p", selfname, O_BINARY, handles[3]); + winetest_push_context("valid stdout handle"); + test_stdout_handle( &startup, cmdline, handles[3], TRUE, "non-std handle", FALSE ); + winetest_pop_context(); + CloseHandle( handles[1] ); + DeleteFileA("fdopen.tst"); + DeleteFileA("fdopen2.tst"); } static void test_invalid_stdin_child( void ) @@ -3183,7 +3247,7 @@ START_TEST(file) if (arg_c >= 3) { if (strcmp(arg_v[2], "inherit") == 0) - test_file_inherit_child(arg_v[3], arg_c > 4 ? arg_v[4] : NULL); + test_file_inherit_child(arg_v[3], arg_v[4], arg_c > 5 ? arg_v[5] : NULL); else if (strcmp(arg_v[2], "inherit_no") == 0) test_file_inherit_child_no(arg_v[3]); else if (strcmp(arg_v[2], "pipes") == 0) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11710