summaryrefslogtreecommitdiffstats
path: root/lem/io/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'lem/io/core.c')
-rw-r--r--lem/io/core.c126
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);