static int do_read(int fd, struct io_plan_arg *arg)
{
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;
+ }
arg->u1.cp += ret;
arg->u2.s -= ret;
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);
- 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;
+ }
*(size_t *)arg->u2.vp = ret;
return 1;
*
* 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
- * 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.
*
*
* 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
- * 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.
*
--- /dev/null
+#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();
+}