diff options
Diffstat (limited to 'lem/io/core.c')
-rw-r--r-- | lem/io/core.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/lem/io/core.c b/lem/io/core.c index b5fe4d6..d41c3d0 100644 --- a/lem/io/core.c +++ b/lem/io/core.c @@ -318,6 +318,128 @@ error: return io_strerror(T, err); } +/* + * io.streamfile() + */ +struct streamfile { + struct lem_async a; + const char *filename; + int pipe[2]; + int file; +}; + +static void +io_streamfile_work(struct lem_async *a) +{ + struct streamfile *s = (struct streamfile *)a; + int file = s->file; + int pipe = s->pipe[1]; + +#ifdef __FreeBSD__ + sendfile(file, pipe, 0, 0, NULL, NULL, SF_SYNC); +#else +#ifdef __APPLE__ + off_t len = 0; + sendfile(file, pipe, 0, &len, NULL, 0); +#else + while (sendfile(pipe, file, NULL, 2147483647) > 0); +#endif +#endif + close(file); + close(pipe); +} + +static void +io_streamfile_open(struct lem_async *a) +{ + struct streamfile *s = (struct streamfile *)a; + int file = open(s->filename, +#ifdef O_CLOEXEC + O_CLOEXEC | +#endif + O_RDONLY); + if (file < 0) { + s->file = -errno; + return; + } +#ifndef O_CLOEXEC + if (fcntl(file, F_SETFD, FD_CLOEXEC) == -1) { + s->file = -errno; + goto err1; + } +#endif + + if (socketpair(AF_UNIX, +#ifdef SOCK_CLOEXEC + SOCK_CLOEXEC | +#endif + SOCK_STREAM, 0, s->pipe)) { + s->file = -errno; + goto err1; + } + if ( +#ifndef SOCK_CLOEXEC + fcntl(s->pipe[1], F_SETFD, FD_CLOEXEC) == -1 || + fcntl(s->pipe[0], F_SETFD, FD_CLOEXEC) == -1 || +#endif + shutdown(s->pipe[0], SHUT_WR)) { + s->file = -errno; + goto err2; + } + if (fcntl(s->pipe[0], F_SETFL, O_NONBLOCK) == -1) { + s->file = -errno; + goto err2; + } + s->file = file; + return; +err2: + close(s->pipe[0]); + close(s->pipe[1]); +err1: + close(file); +} + +static void +io_streamfile_reap(struct lem_async *a) +{ + struct streamfile *s = (struct streamfile *)a; + lua_State *T = s->a.T; + int ret; + + if (T == NULL) { + free(s); + return; + } + + ret = s->file; + if (ret < 0) { + free(s); + lem_queue(T, io_strerror(T, -ret)); + return; + } + lem_debug("s->file = %d, s->pipe[0] = %d, s->pipe[1] = %d", + ret, s->pipe[0], s->pipe[1]); + + lem_async_do(&s->a, NULL, io_streamfile_work, io_streamfile_reap); + + stream_new(T, s->pipe[0], 2); + lem_queue(T, 1); +} + +static int +io_streamfile(lua_State *T) +{ + const char *filename = lua_tostring(T, 1); + struct streamfile *s = lem_xmalloc(sizeof(struct streamfile)); + + s->filename = filename; + lem_async_do(&s->a, T, io_streamfile_open, io_streamfile_reap); + + lua_settop(T, 1); + lua_pushvalue(T, lua_upvalueindex(1)); + return lua_yield(T, 2); +} + static void push_stdstream(lua_State *L, int fd) { @@ -455,6 +577,10 @@ luaopen_lem_io_core(lua_State *L) lua_getfield(L, -1, "Stream"); /* upvalue 1 = Stream */ lua_pushcclosure(L, io_popen, 1); lua_setfield(L, -2, "popen"); + /* insert streamfile function */ + lua_getfield(L, -1, "Stream"); /* upvalue 1 = Stream */ + lua_pushcclosure(L, io_streamfile, 1); + lua_setfield(L, -2, "streamfile"); /* create tcp table */ lua_createtable(L, 0, 0); |