Commit fedf5151 authored by Rusty Russell's avatar Rusty Russell

io: don't leave errno as a random value when we hit EOF.

It's used inside io_finish; setting to 0 allows that to know we hit
EOF on a read.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent b6e8d929
...@@ -202,8 +202,12 @@ struct io_plan *io_write_(struct io_conn *conn, const void *data, size_t len, ...@@ -202,8 +202,12 @@ struct io_plan *io_write_(struct io_conn *conn, const void *data, size_t len,
static int do_read(int fd, struct io_plan_arg *arg) static int do_read(int fd, struct io_plan_arg *arg)
{ {
ssize_t ret = read(fd, arg->u1.cp, arg->u2.s); ssize_t ret = read(fd, arg->u1.cp, arg->u2.s);
if (ret <= 0) if (ret <= 0) {
/* Errno isn't set if we hit EOF, so set it to distinct value */
if (ret == 0)
errno = 0;
return -1; return -1;
}
arg->u1.cp += ret; arg->u1.cp += ret;
arg->u2.s -= ret; arg->u2.s -= ret;
...@@ -230,8 +234,12 @@ struct io_plan *io_read_(struct io_conn *conn, ...@@ -230,8 +234,12 @@ struct io_plan *io_read_(struct io_conn *conn,
static int do_read_partial(int fd, struct io_plan_arg *arg) static int do_read_partial(int fd, struct io_plan_arg *arg)
{ {
ssize_t ret = read(fd, arg->u1.cp, *(size_t *)arg->u2.vp); ssize_t ret = read(fd, arg->u1.cp, *(size_t *)arg->u2.vp);
if (ret <= 0) if (ret <= 0) {
/* Errno isn't set if we hit EOF, so set it to distinct value */
if (ret == 0)
errno = 0;
return -1; return -1;
}
*(size_t *)arg->u2.vp = ret; *(size_t *)arg->u2.vp = ret;
return 1; return 1;
......
...@@ -223,7 +223,8 @@ struct io_plan *io_write_(struct io_conn *conn, ...@@ -223,7 +223,8 @@ struct io_plan *io_write_(struct io_conn *conn,
* *
* This creates a plan to read data into a buffer. Once it's all * This creates a plan to read data into a buffer. Once it's all
* read, the @next function will be called: on an error, the finish * read, the @next function will be called: on an error, the finish
* function is called instead. * function is called instead. If read() returns 0 (EOF) errno is set
* to 0.
* *
* Note that the I/O may actually be done immediately. * Note that the I/O may actually be done immediately.
* *
...@@ -256,7 +257,8 @@ struct io_plan *io_read_(struct io_conn *conn, ...@@ -256,7 +257,8 @@ struct io_plan *io_read_(struct io_conn *conn,
* *
* This creates a plan to read data into a buffer. Once any data is * This creates a plan to read data into a buffer. Once any data is
* read, @len is updated and the @next function will be called: on an * read, @len is updated and the @next function will be called: on an
* error, the finish function is called instead. * error, the finish function is called instead. If read() returns 0 (EOF)
* errno is set to 0.
* *
* Note that the I/O may actually be done immediately. * Note that the I/O may actually be done immediately.
* *
......
#include <ccan/io/io.h>
/* Include the C files directly. */
#include <ccan/io/poll.c>
#include <ccan/io/io.c>
#include <ccan/tap/tap.h>
#include <sys/wait.h>
#include <stdio.h>
static size_t len;
static void finished_read(struct io_conn *conn, int *expect)
{
ok1(errno == *expect);
}
static struct io_plan *init_conn_read(struct io_conn *conn, int *expect)
{
io_set_finish(conn, finished_read, expect);
return io_read(conn, &expect, sizeof(expect), io_never, expect);
}
static struct io_plan *init_conn_read_partial(struct io_conn *conn, int *expect)
{
io_set_finish(conn, finished_read, expect);
return io_read_partial(conn, &expect, sizeof(expect), &len,
io_never, expect);
}
int main(void)
{
int fd, expect_errno = 0;
/* This is how many tests you plan to run */
plan_tests(2);
fd = open("/dev/null", O_RDONLY);
io_new_conn(NULL, fd, init_conn_read, &expect_errno);
fd = open("/dev/null", O_RDONLY);
io_new_conn(NULL, fd, init_conn_read_partial, &expect_errno);
io_loop(NULL, NULL);
/* This exits depending on whether all tests passed */
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment