msvcrt: Fix EOF behavior on read from pipe or console.
The canonical way to detect EOF on read is when you request more than zero bytes, but zero bytes come back. Switching to this method seems to handle a few problem cases better. Also handle ERROR_BROKEN_PIPE properly just in case.
This commit is contained in:
parent
85703790fd
commit
316869b273
|
@ -1692,11 +1692,13 @@ static int read_i(int fd, void *buf, unsigned int count)
|
||||||
if (bufstart[i] == 0x1a)
|
if (bufstart[i] == 0x1a)
|
||||||
{
|
{
|
||||||
num_read = i;
|
num_read = i;
|
||||||
|
MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
|
||||||
|
TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (num_read != count)
|
if (count != 0 && num_read == 0)
|
||||||
{
|
{
|
||||||
MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
|
MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
|
||||||
TRACE(":EOF %s\n",debugstr_an(buf,num_read));
|
TRACE(":EOF %s\n",debugstr_an(buf,num_read));
|
||||||
|
@ -1707,6 +1709,7 @@ static int read_i(int fd, void *buf, unsigned int count)
|
||||||
if (GetLastError() == ERROR_BROKEN_PIPE)
|
if (GetLastError() == ERROR_BROKEN_PIPE)
|
||||||
{
|
{
|
||||||
TRACE(":end-of-pipe\n");
|
TRACE(":end-of-pipe\n");
|
||||||
|
MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -918,9 +918,14 @@ static void test_stat(void)
|
||||||
|
|
||||||
static const char* pipe_string="Hello world";
|
static const char* pipe_string="Hello world";
|
||||||
|
|
||||||
|
/* How many messages to transfer over the pipe */
|
||||||
|
#define N_TEST_MESSAGES 3
|
||||||
|
|
||||||
static void test_pipes_child(int argc, char** args)
|
static void test_pipes_child(int argc, char** args)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
int nwritten;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (argc < 5)
|
if (argc < 5)
|
||||||
{
|
{
|
||||||
|
@ -932,7 +937,15 @@ static void test_pipes_child(int argc, char** args)
|
||||||
ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
|
ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
|
||||||
|
|
||||||
fd=atoi(args[4]);
|
fd=atoi(args[4]);
|
||||||
write(fd, pipe_string, strlen(pipe_string));
|
|
||||||
|
for (i=0; i<N_TEST_MESSAGES; i++) {
|
||||||
|
nwritten=write(fd, pipe_string, strlen(pipe_string));
|
||||||
|
ok(nwritten == strlen(pipe_string), "i %d, expected to write %d bytes, wrote %d\n", i, strlen(pipe_string), nwritten);
|
||||||
|
/* let other process wake up so they can show off their "keep reading until EOF" behavior */
|
||||||
|
if (i < N_TEST_MESSAGES-1)
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
|
ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -943,7 +956,9 @@ static void test_pipes(const char* selfname)
|
||||||
FILE* file;
|
FILE* file;
|
||||||
const char* arg_v[6];
|
const char* arg_v[6];
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
char expected[4096];
|
||||||
int r;
|
int r;
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Test reading from a pipe with read() */
|
/* Test reading from a pipe with read() */
|
||||||
if (_pipe(pipes, 1024, O_BINARY) < 0)
|
if (_pipe(pipes, 1024, O_BINARY) < 0)
|
||||||
|
@ -961,11 +976,14 @@ static void test_pipes(const char* selfname)
|
||||||
proc_handles[0] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
|
proc_handles[0] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
|
||||||
ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
|
ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
|
||||||
|
|
||||||
|
for (i=0; i<N_TEST_MESSAGES; i++) {
|
||||||
r=read(pipes[0], buf, sizeof(buf)-1);
|
r=read(pipes[0], buf, sizeof(buf)-1);
|
||||||
ok(r == strlen(pipe_string), "expected to read %d bytes, got %d\n", strlen(pipe_string)+1, r);
|
ok(r == strlen(pipe_string), "i %d, expected to read %d bytes, got %d\n", i, strlen(pipe_string)+1, r);
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
buf[r]='\0';
|
buf[r]='\0';
|
||||||
ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf);
|
ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf);
|
||||||
|
}
|
||||||
|
|
||||||
r=read(pipes[0], buf, sizeof(buf)-1);
|
r=read(pipes[0], buf, sizeof(buf)-1);
|
||||||
ok(r == 0, "expected to read 0 bytes, got %d\n", r);
|
ok(r == 0, "expected to read 0 bytes, got %d\n", r);
|
||||||
ok(close(pipes[0]) == 0, "unable to close %d: %d\n", pipes[0], errno);
|
ok(close(pipes[0]) == 0, "unable to close %d: %d\n", pipes[0], errno);
|
||||||
|
@ -987,12 +1005,21 @@ static void test_pipes(const char* selfname)
|
||||||
ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
|
ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
|
||||||
file=fdopen(pipes[0], "r");
|
file=fdopen(pipes[0], "r");
|
||||||
|
|
||||||
|
/* In blocking mode, fread will keep calling read() until it gets
|
||||||
|
* enough bytes, or EOF, even on Unix. (If this were a Unix terminal
|
||||||
|
* in cooked mode instead of a pipe, it would also stop on EOL.)
|
||||||
|
*/
|
||||||
|
expected[0] = 0;
|
||||||
|
for (i=0; i<N_TEST_MESSAGES; i++)
|
||||||
|
strcat(expected, pipe_string);
|
||||||
r=fread(buf, 1, sizeof(buf)-1, file);
|
r=fread(buf, 1, sizeof(buf)-1, file);
|
||||||
ok(r == strlen(pipe_string), "fread() returned %d instead of %d: ferror=%d\n", r, strlen(pipe_string), ferror(file));
|
ok(r == strlen(expected), "fread() returned %d instead of %d: ferror=%d\n", r, strlen(expected), ferror(file));
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
buf[r]='\0';
|
buf[r]='\0';
|
||||||
ok(strcmp(buf, pipe_string) == 0, "got '%s' expected '%s'\n", buf, pipe_string);
|
ok(strcmp(buf, expected) == 0, "got '%s' expected '%s'\n", buf, expected);
|
||||||
|
|
||||||
|
/* Let child close the file before we read, so we can sense EOF reliably */
|
||||||
|
Sleep(100);
|
||||||
r=fread(buf, 1, sizeof(buf)-1, file);
|
r=fread(buf, 1, sizeof(buf)-1, file);
|
||||||
ok(r == 0, "fread() returned %d instead of 0\n", r);
|
ok(r == 0, "fread() returned %d instead of 0\n", r);
|
||||||
ok(ferror(file) == 0, "got ferror() = %d\n", ferror(file));
|
ok(ferror(file) == 0, "got ferror() = %d\n", ferror(file));
|
||||||
|
|
Loading…
Reference in New Issue